Skip to content
Commits on Source (9)
......@@ -161,5 +161,8 @@ $<$<BOOL:$<TARGET_PROPERTY:${module_name},INCLUDE_DIRECTORIES>>:
${INPUT_FILES}
VERBATIM
)
add_custom_target(${module_name}Hierarchy
DEPENDS
${OUTPUT_DIR}/${module_name}Hierarchy.stamp.txt)
endmacro()
......@@ -19,7 +19,7 @@ include(CTest)
# Project version
set(DICOM_MAJOR_VERSION 0)
set(DICOM_MINOR_VERSION 8)
set(DICOM_PATCH_VERSION 7)
set(DICOM_PATCH_VERSION 8)
set(DICOM_SHORT_VERSION "${DICOM_MAJOR_VERSION}.${DICOM_MINOR_VERSION}")
set(DICOM_VERSION "${DICOM_SHORT_VERSION}.${DICOM_PATCH_VERSION}")
......@@ -157,7 +157,11 @@ if(USE_DCMTK)
if(NOT DCMTK_FOUND)
message(FATAL_ERROR "DCMTK not found or incomplete.")
endif()
if(${DCMTK_charls_LIBRARY})
set(DCMTK_LIBS ${DCMTK_LIBRARIES} ${DCMTK_charls_LIBRARY})
else()
set(DCMTK_LIBS ${DCMTK_LIBRARIES})
endif()
if(APPLE)
list(APPEND DCMTK_LIBS iconv)
endif()
......@@ -289,10 +293,14 @@ if(NOT Module_vtkDICOM)
find_package(Java REQUIRED)
find_package(JNI REQUIRED)
set(VTK_JAVA_SOURCE_VERSION "1.5" CACHE STRING "javac source version")
set(VTK_JAVA_TARGET_VERSION "1.5" CACHE STRING "javac target version")
if(NOT VTK_JAVA_SOURCE_VERSION)
set(VTK_JAVA_SOURCE_VERSION "1.6" CACHE STRING "javac source version")
mark_as_advanced(VTK_JAVA_SOURCE_VERSION)
endif()
if(NOT VTK_JAVA_TARGET_VERSION)
set(VTK_JAVA_TARGET_VERSION "1.6" CACHE STRING "javac target version")
mark_as_advanced(VTK_JAVA_TARGET_VERSION)
endif()
if(APPLE)
set(JAVAC_OPTIONS -J-Xmx512m)
......@@ -318,9 +326,6 @@ if(MSVC_VERSION EQUAL 1400 OR MSVC_VERSION GREATER 1400 OR MSVC10)
add_definitions(-D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS)
endif()
# For use by subdirectories
set(KWSYS_LIBS vtksys)
# The main library
add_subdirectory(Source)
......
......@@ -18,7 +18,7 @@ endif()
set(BASE_LIBS vtkDICOM ${VTK_LIBS})
add_executable(TestDICOMCompiler TestDICOMCompiler.cxx)
target_link_libraries(TestDICOMCompiler ${BASE_LIBS} ${KWSYS_LIBS})
target_link_libraries(TestDICOMCompiler ${BASE_LIBS})
add_executable(TestDICOMDirectory TestDICOMDirectory.cxx)
target_link_libraries(TestDICOMDirectory ${BASE_LIBS})
......
......@@ -31,7 +31,7 @@ foreach(src ${PROGRAM_SRCS})
string(REGEX REPLACE "\\.(cxx|c|mm|m)$" "" prog ${src})
add_executable(${prog} ${src})
target_link_libraries(${prog} ${BASE_LIBS} ${CLI_LIBS}
${VTK_IMAGING_LIBS} ${KWSYS_LIBS})
${VTK_IMAGING_LIBS})
list(APPEND PROGRAM_EXES ${prog})
endforeach()
......
......@@ -19,6 +19,7 @@
#include "vtkDICOMParser.h"
#include "vtkDICOMReader.h"
#include "vtkDICOMFileSorter.h"
#include "vtkDICOMSliceSorter.h"
#include "vtkDICOMToRAS.h"
#include "vtkDICOMCTRectifier.h"
#include "vtkDICOMFile.h"
......@@ -55,6 +56,7 @@
// from dicomcli
#include "vtkConsoleOutputWindow.h"
#include "mainmacro.h"
#include "readquery.h"
// Simple structure for command-line options
struct dicomtonifti_options
......@@ -73,7 +75,12 @@ struct dicomtonifti_options
bool silent;
bool verbose;
int volume;
double time_delta;
int time_units;
vtkDICOMTagPath time_tagpath;
vtkDICOMTagPath time_delta_tagpath;
const char *output;
unsigned int conversions_attempted;
};
......@@ -126,7 +133,10 @@ void dicomtonifti_usage(FILE *file, const char *command_name)
" --no-reordering Never reorder slices, rows, or columns.\n"
" --no-qform Don't include a qform in the NIFTI file.\n"
" --no-sform Don't include an sform in the NIFTI file.\n"
" --volume N Set the volume to output (starts at 0).\n"
" --time-tag Set the tag to use for time coordinate.\n"
" --time-delta-tag Set the tag to use for time spacing.\n"
" --time-delta Force the time spacing to be the given value.\n"
" --volume N Set which volume to output (starts at 0).\n"
" --version Print the version and exit.\n"
" --build-version Print source and build version.\n"
" --help Documentation for dicomtonifti.\n"
......@@ -173,6 +183,16 @@ void dicomtonifti_help(FILE *file, const char *command_name)
"increasing from posterior to anterior. This will also convert the data\n"
"type from unsigned 16-bit to signed 16-bit if necessary.\n"
"\n");
fprintf(file,
"The --time-tag, --time-delta-tag, and --time-delta options can be used\n"
"to tweak the time information. By default, tags such as TriggerTime,\n"
"TemporalPositionIdentifier, or TriggerTime are used to perform\n"
"temporal sorting, but --time-tag can be used to explicitly name a tag.\n"
"The --time-delta-tag option can be used to set which tag gives temporal\n"
"spacing, if there is no tag that gives the temporal coordinate.\n"
"The --time-delta option will force the temporal spacing to be a specific\n"
"value, e.g. 500ms, 2s, or 2600us.\n"
"\n");
fprintf(file,
"If batch mode is selected, the output file given with \"-o\" can be\n"
"constructed from DICOM attributes, by providing the attribute names\n"
......@@ -261,6 +281,50 @@ bool dicomtonifti_check_error(vtkObject *o)
return true;
}
bool dicomtonifti_time_delta(const char *arg, dicomtonifti_options *options)
{
const char *unit_list[6] = {
"s", "ms", "us", "Hz", "ppm", "rads"
};
int unit_consts[6] = {
8, 16, 24, 32, 40, 48 // from NIFTI header
};
char *units;
double t = strtod(arg, &units);
if (units == arg || t == 0.0)
{
fprintf(stderr, "Illegal value for --time-delta: %s\n", arg);
return false;
}
options->time_delta = t;
if (units[0] != '\0')
{
options->time_units = 0;
for (int i = 0; i < 6; i++)
{
if (strcmp(units, unit_list[i]) == 0)
{
options->time_units = unit_consts[i];
break;
}
}
if (options->time_units == 0)
{
fprintf(stderr, "Illegal value for --time-delta: %s\n", arg);
fprintf(stderr, "Units must be s, ms, Hz, ppm, or rads.\n");
return false;
}
}
return true;
}
// Read the options
void dicomtonifti_read_options(
int argc, char *argv[],
......@@ -280,7 +344,12 @@ void dicomtonifti_read_options(
options->silent = false;
options->verbose = false;
options->volume = -1;
options->time_delta = 0.0;
options->time_units = 16; // default to msec
options->time_tagpath = vtkDICOMTagPath();
options->time_delta_tagpath = vtkDICOMTagPath();
options->output = 0;
options->conversions_attempted = 0;
// read the options from the command line
int argi = 1;
......@@ -340,6 +409,43 @@ void dicomtonifti_read_options(
{
options->no_sform = true;
}
else if (strcmp(arg, "--time-delta") == 0 ||
strcmp(arg, "--time-delta-tag") == 0 ||
strcmp(arg, "--time-tag") == 0)
{
if (argi >= argc || argv[argi][0] == '-')
{
fprintf(stderr, "\nAn argument must follow \'%s\'\n\n", arg);
dicomtonifti_usage(stderr, argv[0]);
exit(1);
}
const char *optarg = arg;
arg = argv[argi++];
if (strcmp(optarg, "--time-delta") == 0)
{
if (!dicomtonifti_time_delta(arg, options))
{
exit(1);
}
}
else
{
vtkDICOMItem data;
QueryTagList qtlist;
if (!dicomcli_readkey(arg, &data, &qtlist))
{
exit(1);
}
if (strcmp(optarg, "--time-delta-tag") == 0)
{
options->time_delta_tagpath = qtlist[0];
}
else
{
options->time_tagpath = qtlist[0];
}
}
}
else if (strcmp(arg, "--batch") == 0)
{
options->batch = true;
......@@ -562,15 +668,41 @@ std::string dicomtonifti_make_filename(
// Convert one DICOM series into one NIFTI file
void dicomtonifti_convert_one(
const dicomtonifti_options *options, vtkStringArray *a,
dicomtonifti_options *options, vtkStringArray *a,
const char *outfile)
{
// make sure there are files to read
if (a->GetNumberOfValues() == 0) {
return;
}
// increment the number of conversions attempted
options->conversions_attempted++;
// read the files
vtkSmartPointer<vtkDICOMReader> reader =
vtkSmartPointer<vtkDICOMReader>::New();
reader->SetMemoryRowOrderToFileNative();
reader->TimeAsVectorOn();
reader->SetFileNames(a);
// check for user-supplied time info
if (options->time_delta != 0.0 ||
options->time_delta_tagpath.GetSize() > 0)
{
reader->GetSorter()->RepeatsAsTimeOn();
}
if (options->time_tagpath.GetSize() > 0)
{
vtkDICOMTagPath tagpath = options->time_tagpath;
vtkDICOMTag tag = tagpath.GetHead();
while (tagpath.HasTail())
{
reader->GetSorter()->SetTimeSequence(tag);
tagpath = tagpath.GetTail();
tag = tagpath.GetHead();
}
reader->GetSorter()->SetTimeTag(tag);
}
reader->Update();
if (dicomtonifti_check_error(reader)) {
return;
......@@ -796,7 +928,7 @@ void dicomtonifti_convert_one(
descrip = descrip.substr(0, 79);
// assume the units are millimetres/milliseconds
hdr->SetXYZTUnits(0x12);
hdr->SetXYZTUnits(0x02 + options->time_units);
// get the phase encoding direction
std::string phase = meta->Get(
......@@ -892,6 +1024,21 @@ void dicomtonifti_convert_one(
{
writer->SetTimeDimension(reader->GetTimeDimension());
writer->SetTimeSpacing(reader->GetTimeSpacing());
if (options->time_delta != 0.0)
{
// override if user gave --time-delta
writer->SetTimeSpacing(options->time_delta);
}
else if (options->time_delta_tagpath.GetSize() > 0)
{
// override if user gave --time-delta-tag
const vtkDICOMValue& tsv =
meta->Get(firstFile, firstFrame, options->time_delta_tagpath);
if (tsv.IsValid())
{
writer->SetTimeSpacing(tsv.AsDouble());
}
}
}
if ((options->no_slice_reordering && slicesReordered) ||
options->fsl)
......@@ -915,7 +1062,7 @@ void dicomtonifti_convert_one(
// Process a list of DICOM files
void dicomtonifti_convert_files(
dicomtonifti_options *options, vtkStringArray *files,
const char *outpath)
const char *outpath, unsigned int depth)
{
// sort the files by filename first, as a fallback
vtkSmartPointer<vtkSortFileNames> presorter =
......@@ -947,8 +1094,13 @@ void dicomtonifti_convert_files(
outfile.append(".gz");
}
}
// if filenames given directly on command line, use them directly,
// but files were found in a given directory, sort them first
if (depth != 0) {
files = sorter->GetOutputFileNames();
}
dicomtonifti_convert_one(
options, sorter->GetOutputFileNames(), outfile.c_str());
options, files, outfile.c_str());
}
else
{
......@@ -1018,7 +1170,8 @@ void dicomtonifti_convert_files(
// Process a list of files and directories
void dicomtonifti_files_and_dirs(
dicomtonifti_options *options, vtkStringArray *files,
const char *outpath, std::set<std::string> *pastdirs)
const char *outpath, std::set<std::string> *pastdirs,
unsigned int depth)
{
// look for directories among the files
vtkSmartPointer<vtkStringArray> directories =
......@@ -1049,7 +1202,7 @@ void dicomtonifti_files_and_dirs(
if (newfiles->GetNumberOfValues() > 0)
{
dicomtonifti_convert_files(options, newfiles, outpath);
dicomtonifti_convert_files(options, newfiles, outpath, depth);
}
n = directories->GetNumberOfValues();
......@@ -1084,7 +1237,7 @@ void dicomtonifti_files_and_dirs(
path.PopBack();
}
}
dicomtonifti_files_and_dirs(options, files, outpath, pastdirs);
dicomtonifti_files_and_dirs(options, files, outpath, pastdirs, depth+1);
}
}
}
......@@ -1140,7 +1293,11 @@ int MAINMACRO(int argc, char *argv[])
}
std::set<std::string> pastdirs;
dicomtonifti_files_and_dirs(&options, files, outpath, &pastdirs);
dicomtonifti_files_and_dirs(&options, files, outpath, &pastdirs, 0);
if (!options.batch && options.conversions_attempted == 0) {
fprintf(stderr, "No input DICOM files were found!\n\n");
}
return 0;
}
......@@ -507,7 +507,7 @@ void niftitodicom_convert_one(
xformCode = hdr->GetSFormCode();
}
// convert to NIFTI coordinate system
// convert from NIFTI coordinate system to DICOM coordinate system
vtkSmartPointer<vtkDICOMToRAS> converter =
vtkSmartPointer<vtkDICOMToRAS>::New();
converter->SetInputConnection(reader->GetOutputPort());
......
......@@ -149,7 +149,7 @@ if("${VTK_MAJOR_VERSION}" GREATER 5)
set_source_files_properties(${LIB_SPECIAL} PROPERTIES WRAP_SPECIAL ON)
set(MODULE_HIERARCHY_NAME ${LIB_NAME}Hierarchy)
# _LINK_DEPENDS is a variable suffix from the VTK 6 module macros
set(${LIB_NAME}_LINK_DEPENDS ${VTK_LIBS} ${KWSYS_LIBS} ${ZLIB_LIBS})
set(${LIB_NAME}_LINK_DEPENDS ${VTK_LIBS} ${ZLIB_LIBS})
include(vtkWrapHierarchy)
vtk_wrap_hierarchy(${LIB_NAME} ${CMAKE_CURRENT_BINARY_DIR} "${LIB_SRCS}")
set(KIT_HIERARCHY_FILE ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_HIERARCHY_NAME}.txt)
......@@ -178,23 +178,27 @@ if(BUILD_PYTHON_WRAPPERS OR BUILD_TCL_WRAPPERS OR BUILD_JAVA_WRAPPERS AND
endif()
target_link_libraries(${LIB_NAME} LINK_PUBLIC ${VTK_LIBS})
target_link_libraries(${LIB_NAME} LINK_PRIVATE
${KWSYS_LIBS} ${ZLIB_LIBS} ${GDCM_LIBS} ${DCMTK_LIBS} ${SQLITE_LIBS})
${ZLIB_LIBS} ${GDCM_LIBS} ${DCMTK_LIBS} ${SQLITE_LIBS})
# Wrappers
if(BUILD_PYTHON_WRAPPERS)
set(MODULE_PYTHON_NAME ${LIB_NAME}Python)
set(${LIB_NAME}_WRAP_DEPENDS ${VTK_LIBS})
if(VTK_PYTHON_INCLUDE_DIR)
include_directories("${VTK_PYTHON_INCLUDE_DIR}")
endif()
if("${VTK_MAJOR_VERSION}" GREATER 5)
include(vtkWrapPython)
include_directories(${vtkPython_INCLUDE_DIRS})
set(VTK_PYTHON_LIBRARIES ${vtkPython_LIBRARIES})
set(LIB_PYTHON_LIBS vtkWrappingPythonCore)
else()
# Tell vtkWrapPython to locate the python libraries for us.
set(VTK_WRAP_PYTHON_FIND_LIBS ON)
include(vtkWrapPython)
vtk_wrap_python3(${MODULE_PYTHON_NAME} LIB_PYTHON_SRCS "${LIB_SRCS}")
if(VTK_PYTHON_INCLUDE_DIR)
include_directories("${VTK_PYTHON_INCLUDE_DIR}")
endif()
set(LIB_PYTHON_LIBS vtkPythonCore)
if("${VTK_MAJOR_VERSION}" GREATER 5)
set(LIB_PYTHON_LIBS vtkWrappingPythonCore)
endif()
vtk_wrap_python3(${MODULE_PYTHON_NAME} LIB_PYTHON_SRCS "${LIB_SRCS}")
if(DICOM_PYTHON_LIBRARIES)
# do things the old way, with PythonD libraries
set(XY) # Get python version, e.g. 27 for python 2.7
......
......@@ -39,6 +39,7 @@ vtkDICOMCTRectifier::vtkDICOMCTRectifier()
this->RectifiedMatrix = vtkMatrix4x4::New();
this->Matrix = vtkMatrix4x4::New();
this->Reverse = 0;
this->InterpolationMode = WindowedSinc;
}
//----------------------------------------------------------------------------
......@@ -96,6 +97,7 @@ void vtkDICOMCTRectifier::PrintSelf(ostream& os, vtkIndent indent)
}
os << indent << "Reverse: " << this->Reverse << "\n";
os << indent << "InterpolationMode: " << this->InterpolationMode << "\n";
}
//----------------------------------------------------------------------------
......@@ -109,6 +111,24 @@ void vtkDICOMCTRectifier::SetReverse(int val)
}
}
//----------------------------------------------------------------------------
void vtkDICOMCTRectifier::SetInterpolationMode(int val)
{
if (val < 0)
{
val = 0;
}
else if (val > WindowedSinc)
{
val = WindowedSinc;
}
if (val != this->InterpolationMode)
{
this->InterpolationMode = val;
this->Modified();
}
}
//----------------------------------------------------------------------------
void vtkDICOMCTRectifier::ComputeMatrix(
const double volumeMatrix[16], const int extent[6],
......@@ -321,15 +341,30 @@ int vtkDICOMCTRectifier::RequestData(
reslice->SetOutputSpacing(spacing);
reslice->SetOutputOrigin(origin);
reslice->SetOutputExtent(extent);
if (this->InterpolationMode == Nearest)
{
reslice->SetInterpolationModeToNearestNeighbor();
}
else if (this->InterpolationMode == Linear)
{
reslice->SetInterpolationModeToLinear();
}
else if (this->InterpolationMode == Cubic)
{
reslice->SetInterpolationModeToCubic();
}
else
{
#if (VTK_MAJOR_VERSION > 5) || (VTK_MINOR_VERSION > 9)
vtkSmartPointer<vtkImageSincInterpolator> interpolator =
vtkSmartPointer<vtkImageSincInterpolator>::New();
interpolator->SetWindowFunctionToBlackman();
reslice->SetInterpolator(interpolator);
#else
reslice->SetInterpolationModeToCubic();
#endif
}
#if (VTK_MAJOR_VERSION > 5)
reslice->SetInterpolator(interpolator);
reslice->SetInputData(image);
this->AllocateOutputData(outData, outInfo, extent);
reslice->SetOutput(outData);
......
......@@ -43,6 +43,17 @@ public:
void PrintSelf(ostream& os, vtkIndent indent);
#endif
//@{
//! Interpolation constants.
enum
{
Nearest,
Linear,
Cubic,
WindowedSinc
};
//@}
//@{
//! Reverse the default operation.
/*!
......@@ -66,6 +77,25 @@ public:
vtkMatrix4x4 *GetVolumeMatrix() { return this->VolumeMatrix; }
//@}
//@{
//! Set the interpolation method for resampling the data.
/*!
* The default interpolation method is WindowedSinc, which gives the
* highest quality output. Linear interpolation is much faster and
* will give satisfactory results in most situations.
*/
void SetInterpolationMode(int t);
void SetInterpolationModeToNearest() {
this->SetInterpolationMode(Nearest); }
void SetInterpolationModeToLinear() {
this->SetInterpolationMode(Linear); }
void SetInterpolationModeToCubic() {
this->SetInterpolationMode(Cubic); }
void SetInterpolationModeToWindowedSinc() {
this->SetInterpolationMode(WindowedSinc); }
int GetInterpolationMode() { return this->InterpolationMode; }
//@}
//@{
//! Get the matrix that describes the rectified geometry.
/*!
......@@ -146,6 +176,7 @@ protected:
vtkMatrix4x4 *RectifiedMatrix;
vtkMatrix4x4 *Matrix;
int Reverse;
int InterpolationMode;
private:
#ifdef VTK_DELETE_FUNCTION
......
This diff is collapsed.
......@@ -176,6 +176,7 @@ ReferencedInstanceSequence = 0x0008114A, // SQ M1 0
ReferencedRealWorldValueMappingInstanceSequence = 0x0008114B, // SQ M1 0
ReferencedSOPClassUID = 0x00081150, // UI M1 0
ReferencedSOPInstanceUID = 0x00081155, // UI M1 0
DefinitionSourceSequence = 0x00081156, // SQ M1 0
SOPClassesSupported = 0x0008115A, // UI M1TN 0
ReferencedFrameNumber = 0x00081160, // IS M1TN 0
SimpleFrameList = 0x00081161, // UL M1TN 0
......@@ -2168,6 +2169,7 @@ SpecimenPreparationSequence = 0x00400610, // SQ M1 0
SpecimenPreparationStepContentItemSequence = 0x00400612, // SQ M1 0
SpecimenLocalizationContentItemSequence = 0x00400620, // SQ M1 0
SlideIdentifier = 0x004006FA, // LO M1 1
WholeSlideMicroscopyImageFrameTypeSequence = 0x00400710, // SQ M1 0
ImageCenterPointCoordinatesSequence = 0x0040071A, // SQ M1 0
XOffsetInSlideCoordinateSystem = 0x0040072A, // DS M1 0
YOffsetInSlideCoordinateSystem = 0x0040073A, // DS M1 0
......@@ -2214,7 +2216,8 @@ GeneralPurposeScheduledProcedureStepPriority = 0x00404003, // CS M1 1
ScheduledProcessingApplicationsCodeSequence = 0x00404004, // SQ M1 1
ScheduledProcedureStepStartDateTime = 0x00404005, // DT M1 0
MultipleCopiesFlag = 0x00404006, // CS M1 1
PerformedProcessingApplicationsCodeSequence = 0x00404007, // SQ M1 0
PerformedProcessingApplicationsCodeSequence = 0x00404007, // SQ M1 1
ScheduledProcedureStepExpirationDateTime = 0x00404008, // DT M1 0
HumanPerformerCodeSequence = 0x00404009, // SQ M1 0
ScheduledProcedureStepModificationDateTime = 0x00404010, // DT M1 0
ExpectedCompletionDateTime = 0x00404011, // DT M1 0
......@@ -2534,6 +2537,8 @@ PlanePositionSlideSequence = 0x0048021A, // SQ M1 0
ColumnPositionInTotalImagePixelMatrix = 0x0048021E, // SL M1 0
RowPositionInTotalImagePixelMatrix = 0x0048021F, // SL M1 0
PixelOriginInterpretation = 0x00480301, // CS M1 0
NumberOfOpticalPaths = 0x00480302, // UL M1 0
TotalPixelMatrixFocalPlanes = 0x00480303, // UL M1 0
CalibrationImage = 0x00500004, // CS M1 0
DeviceSequence = 0x00500010, // SQ M1 0
ContainerComponentTypeCodeSequence = 0x00500012, // SQ M1 0
......@@ -2682,6 +2687,7 @@ SegmentedPropertyTypeCodeSequence = 0x0062000F, // SQ M1 0
SegmentationFractionalType = 0x00620010, // CS M1 0
SegmentedPropertyTypeModifierCodeSequence = 0x00620011, // SQ M1 0
UsedSegmentsSequence = 0x00620012, // SQ M1 0
SegmentsOverlap = 0x00620013, // CS M1 0
TrackingID = 0x00620020, // UT M1 0
TrackingUID = 0x00620021, // UI M1 0
DeformableRegistrationSequence = 0x00640002, // SQ M1 0
......@@ -2829,6 +2835,9 @@ TwoDPlaneCoordinatesSequence = 0x006865E0, // SQ M1 0
TwoDPlaneIntersection = 0x006865F0, // FD M4 0
ThreeDPlaneOrigin = 0x00686610, // FD M3 0
ThreeDPlaneNormal = 0x00686620, // FD M3 0
ModelModification = 0x00687001, // CS M1 0
ModelMirroring = 0x00687002, // CS M1 0
ModelUsageCodeSequence = 0x00687003, // SQ M1 0
GraphicAnnotationSequence = 0x00700001, // SQ M1 0
GraphicLayer = 0x00700002, // CS M1 0
BoundingBoxAnnotationUnits = 0x00700003, // CS M1 0
......@@ -2929,6 +2938,7 @@ ContourUncertaintyRadius = 0x00700312, // FD M1 0
UsedFiducialsSequence = 0x00700314, // SQ M1 0
GraphicCoordinatesDataSequence = 0x00700318, // SQ M1 0
FiducialUID = 0x0070031A, // UI M1 0
ReferencedFiducialUID = 0x0070031B, // UI M1 0
FiducialSetSequence = 0x0070031C, // SQ M1 0
FiducialSequence = 0x0070031E, // SQ M1 0
FiducialsPropertyCategoryCodeSequence = 0x0070031F, // SQ M1 0
......@@ -3260,8 +3270,8 @@ SurfacePointPresentationValueData = 0x00800006, // US M1TN 0
SurfacePointColorCIELabValueData = 0x00800007, // US M3T3N 0
UVMappingSequence = 0x00800008, // SQ M1 0
TextureLabel = 0x00800009, // SH M1 0
UValueData = 0x00800010, // OF M1TN 0
VValueData = 0x00800011, // OF M1TN 0
UValueData = 0x00800010, // OF M1 0
VValueData = 0x00800011, // OF M1 0
ReferencedTextureSequence = 0x00800012, // SQ M1 0
ReferencedSurfaceDataSequence = 0x00800013, // SQ M1 0
AssessmentSummary = 0x00820001, // CS M1 0
......@@ -3323,6 +3333,7 @@ AttributeModificationDateTime = 0x04000562, // DT M1 0
ModifyingSystem = 0x04000563, // LO M1 0
SourceOfPreviousValues = 0x04000564, // LO M1 0
ReasonForTheAttributeModification = 0x04000565, // CS M1 0
InstanceOriginStatus = 0x04000600, // CS M1 0
EscapeTriplet = 0x10000000, // US M3 1
RunLengthTriplet = 0x10000001, // US M3 1
HuffmanTableSize = 0x10000002, // US M1 1
......@@ -3516,6 +3527,7 @@ ROIVolume = 0x3006002C, // DS M1 0
RTRelatedROISequence = 0x30060030, // SQ M1 0
RTROIRelationship = 0x30060033, // CS M1 0
ROIGenerationAlgorithm = 0x30060036, // CS M1 0
ROIDerivationAlgorithmIdentificationSequence = 0x30060037, // SQ M1 0
ROIGenerationDescription = 0x30060038, // LO M1 0
ROIContourSequence = 0x30060039, // SQ M1 0
ContourSequence = 0x30060040, // SQ M1 0
......@@ -3712,6 +3724,7 @@ BeamDoseType = 0x300A0090, // CS M1 0
AlternateBeamDose = 0x300A0091, // DS M1 0
AlternateBeamDoseType = 0x300A0092, // CS M1 0
DepthValueAveragingFlag = 0x300A0093, // CS M1 0
BeamDosePointSourceToExternalContourDistance = 0x300A0094, // DS M1 0
NumberOfBrachyApplicationSetups = 0x300A00A0, // IS M1 0
BrachyApplicationSetupDoseSpecificationPoint = 0x300A00A2, // DS M3 0
BrachyApplicationSetupDose = 0x300A00A4, // DS M1 0
......
......@@ -238,7 +238,7 @@ void SortedTags::SetFrom(const vtkDICOMItem& patientRecord,
vtkDICOMTag tag = iter->GetTag();
std::vector<vtkDICOMTag>::iterator pos =
std::lower_bound(begin(), end(), tag);
if (*pos != tag)
if (pos == end() || *pos != tag)
{
this->insert(pos, tag);
}
......@@ -1116,7 +1116,7 @@ void vtkDICOMDirectory::FillImageRecord(
{
++skip;
}
if (tag == DC::SpecificCharacterSet || tag != *skip)
if (skip == skipEnd || *skip > tag || tag == DC::SpecificCharacterSet)
{
item->Set(tag, iter->GetValue());
}
......
......@@ -17,6 +17,7 @@
#include "vtkAlgorithm.h"
#include "vtkDICOMModule.h" // For export macro
#include "vtkDICOMCharacterSet.h" // For character sets
#include "vtkVersion.h"
class vtkStringArray;
class vtkIntArray;
......
......@@ -14,8 +14,8 @@
#ifndef vtkDICOMMRGenerator_h
#define vtkDICOMMRGenerator_h
#include "vtkDICOMModule.h" // For export macro
#include "vtkDICOMGenerator.h"
#include "vtkDICOMModule.h" // For export macro
//! Generate DICOM data objects for MR images.
/*!
......
......@@ -36,6 +36,7 @@ vtkDICOMSliceSorter::vtkDICOMSliceSorter()
this->FrameIndexArray = vtkIntArray::New();
this->StackIDs = vtkStringArray::New();
this->MetaData = 0;
this->RepeatsAsTime = 0;
this->TimeAsVector = 0;
this->DesiredTimeIndex = -1;
this->TimeDimension = 0;
......@@ -92,11 +93,16 @@ void vtkDICOMSliceSorter::PrintSelf(ostream& os, vtkIndent indent)
<< (this->ReverseSlices ? "On\n" : "Off\n");
os << indent << "SliceSpacing: " << this->SliceSpacing << "\n";
os << indent << "RepeatsAsTime: "
<< (this->RepeatsAsTime ? "On\n" : "Off\n");
os << indent << "TimeAsVector: "
<< (this->TimeAsVector ? "On\n" : "Off\n");
os << indent << "TimeDimension: " << this->TimeDimension << "\n";
os << indent << "TimeSpacing: " << this->TimeSpacing << "\n";
os << indent << "DesiredTimeIndex: " << this->DesiredTimeIndex << "\n";
os << indent << "TimeTag: " << this->TimeTag << "\n";
os << indent << "TimeSequence: " << this->TimeSequence << "\n";
}
//----------------------------------------------------------------------------
......@@ -134,6 +140,26 @@ void vtkDICOMSliceSorter::SetDesiredStackID(const char *stackId)
}
}
//----------------------------------------------------------------------------
void vtkDICOMSliceSorter::SetTimeTag(vtkDICOMTag tag)
{
if (tag != this->TimeTag)
{
this->TimeTag = tag;
this->Modified();
}
}
//----------------------------------------------------------------------------
void vtkDICOMSliceSorter::SetTimeSequence(vtkDICOMTag tag)
{
if (tag != this->TimeSequence)
{
this->TimeSequence = tag;
this->Modified();
}
}
//----------------------------------------------------------------------------
namespace {
......@@ -469,7 +495,7 @@ void vtkDICOMSliceSorter::SortFiles(vtkIntArray *files, vtkIntArray *frames)
}
// important time-related variables
int temporalSpacing = 1.0;
double temporalSpacing = 1.0;
if (meta->Has(DC::SharedFunctionalGroupsSequence))
{
......@@ -512,8 +538,17 @@ void vtkDICOMSliceSorter::SortFiles(vtkIntArray *files, vtkIntArray *frames)
if (numberOfFrames > 0)
{
// time information can come from these attributes
if (vtkDICOMSliceSorterGetFrame(
// search for time information in the functional groups
if (this->TimeSequence.GetGroup() != 0 &&
this->TimeTag.GetGroup() != 0 &&
vtkDICOMSliceSorterGetFrame(
frameSeq, sharedSeq, 0, this->TimeSequence,
this->TimeTag).IsValid())
{
timeSequence = this->TimeSequence;
timeTag = this->TimeTag;
}
else if (vtkDICOMSliceSorterGetFrame(
frameSeq, sharedSeq, 0, DC::CardiacSynchronizationSequence,
DC::NominalCardiacTriggerDelayTime).IsValid())
{
......@@ -643,7 +678,12 @@ void vtkDICOMSliceSorter::SortFiles(vtkIntArray *files, vtkIntArray *frames)
{
// ways to get time information
vtkDICOMTag timeTag;
if (meta->Get(DC::CardiacNumberOfImages).AsInt() > 1)
if (this->TimeTag.GetGroup() != 0 &&
meta->Get(this->TimeTag).IsValid())
{
timeTag = this->TimeTag;
}
else if (meta->Get(DC::CardiacNumberOfImages).AsInt() > 1)
{
timeTag = DC::TriggerTime;
}
......@@ -946,6 +986,10 @@ void vtkDICOMSliceSorter::SortFiles(vtkIntArray *files, vtkIntArray *frames)
{
temporalSpacing *= (tMax - tMin)/(temporalPositions - 1);
}
else if (this->RepeatsAsTime)
{
temporalPositions = slicesPerLocation;
}
// compute the number of slices in the output image
int spatialLocations = numSlices/slicesPerLocation;
......
......@@ -17,6 +17,8 @@
#include "vtkObject.h"
#include "vtkDICOMModule.h" // For export macro
#include "vtkDICOMTag.h" // For vtkDICOMTag
class vtkIntArray;
class vtkStringArray;
class vtkDICOMMetaData;
......@@ -91,6 +93,20 @@ public:
vtkDICOMMetaData *GetMetaData() { return this->MetaData; }
//@}
//@{
//! Force repeated slices to be at different times (default: Off).
/*!
* If this is on, then repeated slices at the same spatial position
* will always be considered to be at different time points. If this
* is off, then the repeated slices will either become the temporal
* dimension or the vector dimension, depending on the presence of
* temporal attributes in the meta data.
*/
vtkGetMacro(RepeatsAsTime, int);
vtkSetMacro(RepeatsAsTime, int);
vtkBooleanMacro(RepeatsAsTime, int);
//@}
//@{
//! Read the time dimension as scalar components (default: Off).
/*!
......@@ -117,6 +133,36 @@ public:
vtkGetMacro(DesiredTimeIndex, int);
//@}
//@{
//! Set the DICOM tag to use for time measurement.
/*!
* This method can be used to explicitly set the tag to use for temporal
* sorting. By default (i.e. if this method is not used), the sorter
* will search the meta-data for the following temporal tags and will
* automatically apply them if present:
* - TriggerTime (for cardiac images)
* - EchoTime (for relaxometry)
* - TemporalPositionIdentifier (fMRI)
*/
void SetTimeTag(vtkDICOMTag tag);
vtkDICOMTag GetTimeTag() { return this->TimeTag; }
//@}
//@{
//! Set the DICOM sequence to use for timing information.
/*!
* This is only used for enhanced multi-frame images. If used, then
* SetTimeTag() must also be used to specify which tag in the sequence
* to use for temporal sorting. By default, the following sequence/tag
* conbinations are automatically detected and applied:
* - CardiacSynchronizationSequence/NominalCardiacTriggerDelayTime
* - TemporalPositionSequence/TemporalPositionTimeOffset
* - FrameContentSequence/TemporalPositionIndex
* - MREchoSequence/EffectiveEchoTime
*/
void SetTimeSequence(vtkDICOMTag tag);
vtkDICOMTag GetTimeSequence() { return this->TimeSequence; }
//@{
//! Set whether to reverse the slice order.
/*!
......@@ -141,42 +187,39 @@ protected:
vtkDICOMSliceSorter();
~vtkDICOMSliceSorter();
// Description:
// Sort the input files, put the sort in the supplied arrays.
virtual void SortFiles(vtkIntArray *fileArray, vtkIntArray *frameArray);
// Description:
// The meta data for the image.
vtkDICOMMetaData *MetaData;
// Description:
// An array to convert slice indices to input files
vtkIntArray *FileIndexArray;
// Description:
// An array to convert slice indices to input frames
vtkIntArray *FrameIndexArray;
// Description:
// An array that holds the stack IDs.
vtkStringArray *StackIDs;
// Description:
// Time dimension variables.
int RepeatsAsTime;
int TimeAsVector;
int TimeDimension;
int DesiredTimeIndex;
double TimeSpacing;
// Description:
// The stack to load.
char DesiredStackID[20];
// Description:
// Whether to reverse the slice order.
int ReverseSlices;
double SliceSpacing;
// The tags to use for time information.
vtkDICOMTag TimeTag;
vtkDICOMTag TimeSequence;
private:
#ifdef VTK_DELETE_FUNCTION
vtkDICOMSliceSorter(const vtkDICOMSliceSorter&) VTK_DELETE_FUNCTION;
......
......@@ -265,7 +265,7 @@ std::string vtkDICOMUtilities::GenerateDateTime(
S -= M*60;
// create a DICOM datetime string
char dt[32];
char dt[40];
sprintf(dt, "%04d%02d%02d%02d%02d%02d.%06d%s",
y, m, d, H, M, S, us, z);
......
......@@ -22,16 +22,16 @@ const UIDTableEntry UIDTable[] = {
{ 181, 1, 1, 0, 0 },
{ 207, 1, 2, 0, 0 },
{ 208, 1, 1, 0, 0 },
{ 1247, 1, 1, 0, 0 },
{ 2445, 1, 1, 0, 0 },
{ 2448, 1, 1, 0, 0 },
{ 2450, 24, 1, 0, 0 },
{ 1248, 1, 1, 0, 0 },
{ 2456, 1, 1, 0, 0 },
{ 2459, 1, 1, 0, 0 },
{ 2461, 24, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 2474, 2, 0, 0, 0 },
{ 2485, 2, 0, 0, 0 },
{ 0, 0, 0, 0, // 1.2.840.10008.1.1
"Verification SOP Class" },
{ 58, 6, 1, 0, // 1.2.840.10008.1.2
......@@ -185,9 +185,9 @@ const UIDTableEntry UIDTable[] = {
"HEVC/H.265 Main Profile / Level 5.1" },
{ 0, 0, 0, 0, // 1.2.840.10008.1.2.4.108
"HEVC/H.265 Main 10 Profile / Level 5.1" },
{ 0, 0, 0, 0, // 1.2.840.10008.1.2.6.1
{ 0, 0, 0, 0, // 1.2.840.10008.1.2.6.1 (Retired)
"RFC 2557 MIME encapsulation" },
{ 0, 0, 0, 0, // 1.2.840.10008.1.2.6.2
{ 0, 0, 0, 0, // 1.2.840.10008.1.2.6.2 (Retired)
"XML Encoding" },
{ 0, 0, 0, 0, // 1.2.840.10008.1.3.10
"Media Storage Directory Storage" },
......@@ -428,7 +428,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1199, 3, 1, 0, 0 },
{ 1200, 3, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
......@@ -441,26 +441,26 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.31
"Modality Worklist Information Model - FIND" },
{ 1202, 3, 1, 0, // 1.2.840.10008.5.1.4.32 (Retired)
{ 1203, 3, 1, 0, // 1.2.840.10008.5.1.4.32 (Retired)
"General Purpose Worklist Management Meta SOP Class" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.33
"Instance Availability Notification SOP Class" },
{ 1205, 10, 1, 0, 0 },
{ 1206, 10, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1224, 3, 1, 0, 0 },
{ 1227, 4, 1, 0, 0 },
{ 1231, 4, 1, 0, 0 },
{ 1225, 3, 1, 0, 0 },
{ 1228, 4, 1, 0, 0 },
{ 1232, 4, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.41
"Product Characteristics Query" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.42
"Substance Approval Query" },
{ 1235, 4, 1, 0, 0 },
{ 1239, 4, 1, 0, 0 },
{ 1243, 4, 1, 0, 0 },
{ 1236, 4, 1, 0, 0 },
{ 1240, 4, 1, 0, 0 },
{ 1244, 4, 1, 0, 0 },
{ 308, 601, 1, 0, 0 },
{ 1182, 5, 1, 0, 0 },
{ 1183, 5, 1, 0, 0 },
{ 909, 3, 1, 0, // 1.2.840.10008.5.1.4.1.1.1
"Computed Radiography Image Storage" },
{ 915, 2, 1, 0, // 1.2.840.10008.5.1.4.1.1.2
......@@ -580,7 +580,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1154, 2, 1, 0, 0 },
{ 1154, 3, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
......@@ -604,7 +604,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1156, 1, 1, 0, // 1.2.840.10008.5.1.4.1.1.128
{ 1157, 1, 1, 0, // 1.2.840.10008.5.1.4.1.1.128
"Positron Emission Tomography Image Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.129 (Retired)
"Standalone PET Curve Storage" },
......@@ -680,7 +680,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1157, 6, 1, 0, 0 },
{ 1158, 6, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
......@@ -961,7 +961,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1163, 9, 1, 0, 0 },
{ 1164, 9, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
......@@ -981,7 +981,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1172, 6, 1, 0, 0 },
{ 1173, 6, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
......@@ -1081,7 +1081,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1180, 2, 1, 0, 0 },
{ 1181, 2, 1, 0, 0 },
{ 912, 1, 1, 0, // 1.2.840.10008.5.1.4.1.1.1.1
"Digital X-Ray Image Storage - For Presentation" },
{ 913, 1, 1, 0, // 1.2.840.10008.5.1.4.1.1.1.2
......@@ -1160,7 +1160,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.11.7
"Compositing Planar MPR Volumetric Presentation State Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.11.8
"Advanced Blending Volumetric Presentation State Storage" },
"Advanced Blending Presentation State Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.11.9
"Volume Rendering Volumetric Presentation State Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.11.10
......@@ -1443,6 +1443,8 @@ const UIDTableEntry UIDTable[] = {
"Encapsulated PDF Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.104.2
"Encapsulated CDA Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.104.3
"Encapsulated STL Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.128.1
"Legacy Converted Enhanced PET Image Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.200.1
......@@ -1477,7 +1479,7 @@ const UIDTableEntry UIDTable[] = {
"RT Ion Beams Treatment Record Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.501.1
"DICOS CT Image Storage" },
{ 1178, 2, 1, 0, 0 },
{ 1179, 2, 1, 0, 0 },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.501.3
"DICOS Threat Detection Report Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.501.4
......@@ -1494,11 +1496,11 @@ const UIDTableEntry UIDTable[] = {
"Eddy Current Image Storage" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.1.601.2
"Eddy Current Multi-frame Image Storage" },
{ 1187, 3, 1, 0, 0 },
{ 1190, 3, 1, 0, 0 },
{ 1193, 3, 1, 0, 0 },
{ 1196, 2, 2, 0, 0 },
{ 1198, 1, 3, 0, 0 },
{ 1188, 3, 1, 0, 0 },
{ 1191, 3, 1, 0, 0 },
{ 1194, 3, 1, 0, 0 },
{ 1197, 2, 2, 0, 0 },
{ 1199, 1, 3, 0, 0 },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.2.1.1
"Patient Root Query/Retrieve Information Model - FIND" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.1.2.1.2
......@@ -1541,11 +1543,11 @@ const UIDTableEntry UIDTable[] = {
"RT Conventional Machine Verification - Trial" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.34.3 (Retired)
"RT Ion Machine Verification - Trial" },
{ 1215, 4, 1, 0, // 1.2.840.10008.5.1.4.34.4 (Retired)
{ 1216, 4, 1, 0, // 1.2.840.10008.5.1.4.34.4 (Retired)
"Unified Worklist and Procedure Step Service Class - Trial" },
{ 1219, 1, 1, 0, // 1.2.840.10008.5.1.4.34.5
{ 1220, 1, 1, 0, // 1.2.840.10008.5.1.4.34.5
"UPS Global Subscription SOP Instance" },
{ 1220, 4, 1, 0, // 1.2.840.10008.5.1.4.34.6
{ 1221, 4, 1, 0, // 1.2.840.10008.5.1.4.34.6
"Unified Worklist and Procedure Step Service Class" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.34.7
"RT Beams Delivery Instruction Storage" },
......@@ -1619,7 +1621,7 @@ const UIDTableEntry UIDTable[] = {
"Implant Template Group Information Model - MOVE" },
{ 0, 0, 0, 0, // 1.2.840.10008.5.1.4.45.4
"Implant Template Group Information Model - GET" },
{ 1248, 1197, 1, 0, 0 },
{ 1249, 1207, 1, 0, 0 },
{ 0, 0, 0, 2, // 1.2.840.10008.6.1.1
"Anatomic Modifier" },
{ 0, 0, 0, 4, // 1.2.840.10008.6.1.2
......@@ -3899,7 +3901,7 @@ const UIDTableEntry UIDTable[] = {
{ 0, 0, 0, 7193, // 1.2.840.10008.6.1.1192
"Physical Object Segmentation Property Types" },
{ 0, 0, 0, 7194, // 1.2.840.10008.6.1.1193
"Morphological Abnormal Structure Segmentation Property Types" },
"Morphologically Abnormal Structure Segmentation Property Types" },
{ 0, 0, 0, 7195, // 1.2.840.10008.6.1.1194
"Function Segmentation Property Types" },
{ 0, 0, 0, 7196, // 1.2.840.10008.6.1.1195
......@@ -3908,12 +3910,32 @@ const UIDTableEntry UIDTable[] = {
"Body Substance Segmentation Property Types" },
{ 0, 0, 0, 7198, // 1.2.840.10008.6.1.1197
"Substance Segmentation Property Types" },
{ 2446, 2, 1, 0, 0 },
{ 0, 0, 0, 9303, // 1.2.840.10008.6.1.1198
"Interpretation Request Discontinuation Reasons" },
{ 0, 0, 0, 7475, // 1.2.840.10008.6.1.1199
"Gray Level Run Length Based Features" },
{ 0, 0, 0, 7476, // 1.2.840.10008.6.1.1200
"Gray Level Size Zone Based Features" },
{ 0, 0, 0, 7060, // 1.2.840.10008.6.1.1201
"Encapsulated Document Source Purposes of Reference" },
{ 0, 0, 0, 7061, // 1.2.840.10008.6.1.1202
"Model Document Titles" },
{ 0, 0, 0, 7062, // 1.2.840.10008.6.1.1203
"Purpose of Reference to Predecessor 3D Model" },
{ 0, 0, 0, 7063, // 1.2.840.10008.6.1.1204
"Model Scale Units" },
{ 0, 0, 0, 7064, // 1.2.840.10008.6.1.1205
"Model Usage" },
{ 0, 0, 0, 10071, // 1.2.840.10008.6.1.1206
"Radiation Dose Units" },
{ 0, 0, 0, 7112, // 1.2.840.10008.6.1.1207
"Radiotherapy Fiducials" },
{ 2457, 2, 1, 0, 0 },
{ 0, 0, 0, 0, // 1.2.840.10008.7.1.1
"Native DICOM Model" },
{ 0, 0, 0, 0, // 1.2.840.10008.7.1.2
"Abstract Multi-Dimensional Image Model" },
{ 2449, 1, 1, 0, 0 },
{ 2460, 1, 1, 0, 0 },
{ 0, 0, 0, 0, // 1.2.840.10008.8.1.1
"DICOM Content Mapping Resource" },
{ 0, 0, 0, 0, // 1.2.840.10008.9.1
......@@ -3964,10 +3986,10 @@ const UIDTableEntry UIDTable[] = {
"General Section Entries" },
{ 0, 0, 0, 0, // 1.2.840.10008.9.24
"Imaging Addendum Report" },
{ 2476, 2, 3, 0, 0 },
{ 2517, 1, 1, 0, 0 },
{ 2478, 31, 1, 0, 0 },
{ 2509, 8, 1, 0, 0 },
{ 2487, 2, 3, 0, 0 },
{ 2528, 1, 1, 0, 0 },
{ 2489, 31, 1, 0, 0 },
{ 2520, 8, 1, 0, 0 },
{ 0, 0, 0, 0, // 1.2.840.10008.15.0.3.1
"dicomDeviceName" },
{ 0, 0, 0, 0, // 1.2.840.10008.15.0.3.2
......
......@@ -2066,6 +2066,13 @@ void vtkDICOMValue::AppendValueToString(
while (ti < l && text[ti] != 'e') { ti++; }
size_t tj = ti;
while (tj > 1 && text[tj-1] == '0' && text[tj-2] != '.') { tj--; }
// in scientific notation, remove decimal if followed by zero
if (ti < l && text[ti] == 'e')
{
if (tj > 2 && text[tj-1] == '0' && text[tj-2] == '.') { tj -= 2; }
else if (tj > 1 && text[tj-1] == '.') { tj -= 1; }
}
// this performs the actual removal
while (ti < l) { text[tj++] = text[ti++]; }
l = tj;
......