/*========================================================================= Program: Visualization Toolkit Module: vtkFixedPointVolumeRayCastMIPHelper.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm 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 "vtkFixedPointVolumeRayCastMIPHelper.h" #include "vtkCommand.h" #include "vtkDataArray.h" #include "vtkFixedPointRayCastImage.h" #include "vtkFixedPointVolumeRayCastMapper.h" #include "vtkImageData.h" #include "vtkObjectFactory.h" #include "vtkRectilinearGrid.h" #include "vtkRenderWindow.h" #include "vtkVolume.h" #include "vtkVolumeProperty.h" #include vtkStandardNewMacro(vtkFixedPointVolumeRayCastMIPHelper); // Construct a new vtkFixedPointVolumeRayCastMIPHelper with default values vtkFixedPointVolumeRayCastMIPHelper::vtkFixedPointVolumeRayCastMIPHelper() = default; // Destruct a vtkFixedPointVolumeRayCastMIPHelper - clean up any memory used vtkFixedPointVolumeRayCastMIPHelper::~vtkFixedPointVolumeRayCastMIPHelper() = default; // This method is called when the interpolation type is nearest neighbor and // the data contains one component. In the inner loop we will compute the // maximum value (in native type). After we have a maximum value for the ray // we will convert it to unsigned short using the scale/shift, then use this // index to lookup the final color/opacity. template void vtkFixedPointMIPHelperGenerateImageOneNN(T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vtkNotUsed(vol)) { VTKKWRCHelper_InitializationAndLoopStartNN(); VTKKWRCHelper_InitializeMIPOneNN(); VTKKWRCHelper_SpaceLeapSetup(); if (cropping) { int maxValueDefined = 0; unsigned short maxIdx = 0; for (k = 0; k < numSteps; k++) { if (k) { mapper->FixedPointIncrement(pos, dir); } VTKKWRCHelper_MIPSpaceLeapCheck(maxIdx, maxValueDefined, mapper->GetFlipMIPComparison()); if (!mapper->CheckIfCropped(pos)) { mapper->ShiftVectorDown(pos, spos); dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2]; if (!maxValueDefined || ((mapper->GetFlipMIPComparison() && *dptr < maxValue) || (!mapper->GetFlipMIPComparison() && *dptr > maxValue))) { maxValue = *dptr; maxIdx = static_cast((maxValue + shift[0]) * scale[0]); maxValueDefined = 1; } } } if (maxValueDefined) { VTKKWRCHelper_LookupColorMax(colorTable[0], scalarOpacityTable[0], maxIdx, imagePtr); } else { imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0; } } else { unsigned short maxIdx = static_cast((maxValue + shift[0]) * scale[0]); for (k = 0; k < numSteps; k++) { if (k) { mapper->FixedPointIncrement(pos, dir); } VTKKWRCHelper_MIPSpaceLeapCheck(maxIdx, 1, mapper->GetFlipMIPComparison()); mapper->ShiftVectorDown(pos, spos); dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2]; if (mapper->GetFlipMIPComparison()) { maxValue = (*dptr < maxValue) ? (*dptr) : (maxValue); } else { maxValue = (*dptr > maxValue) ? (*dptr) : (maxValue); } maxIdx = static_cast((maxValue + shift[0]) * scale[0]); } VTKKWRCHelper_LookupColorMax(colorTable[0], scalarOpacityTable[0], maxIdx, imagePtr); } VTKKWRCHelper_IncrementAndLoopEnd(); } // This method is called when the interpolation type is nearest neighbor and // the data has two or four dependent components. If it is four, they must be // unsigned char components. Compute max of last components in native type, // then use first component to look up a color (2 component data) or first three // as the color directly (four component data). Lookup alpha off the last component. template void vtkFixedPointMIPHelperGenerateImageDependentNN(T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vtkNotUsed(vol)) { VTKKWRCHelper_InitializationAndLoopStartNN(); VTKKWRCHelper_InitializeMIPMultiNN(); VTKKWRCHelper_SpaceLeapSetup(); int maxValueDefined = 0; unsigned short maxIdxS = 0; for (k = 0; k < numSteps; k++) { if (k) { mapper->FixedPointIncrement(pos, dir); } VTKKWRCHelper_MIPSpaceLeapCheck(maxIdxS, maxValueDefined, mapper->GetFlipMIPComparison()); VTKKWRCHelper_CroppingCheckNN(pos); mapper->ShiftVectorDown(pos, spos); dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2]; if (!maxValueDefined || ((mapper->GetFlipMIPComparison() && *(dptr + components - 1) < maxValue[components - 1]) || (!mapper->GetFlipMIPComparison() && *(dptr + components - 1) > maxValue[components - 1]))) { for (c = 0; c < components; c++) { maxValue[c] = *(dptr + c); } maxIdxS = static_cast( (maxValue[components - 1] + shift[components - 1]) * scale[components - 1]); maxValueDefined = 1; } } if (maxValueDefined) { unsigned short maxIdx[4] = { 0, 0, 0, 0 }; if (components == 2) { maxIdx[0] = static_cast((maxValue[0] + shift[0]) * scale[0]); maxIdx[1] = static_cast((maxValue[1] + shift[1]) * scale[1]); } else { maxIdx[0] = static_cast(maxValue[0]); maxIdx[1] = static_cast(maxValue[1]); maxIdx[2] = static_cast(maxValue[2]); maxIdx[3] = static_cast((maxValue[3] + shift[3]) * scale[3]); } for (c = 0; c < components; c++) { } VTKKWRCHelper_LookupDependentColorUS( colorTable[0], scalarOpacityTable[0], maxIdx, components, imagePtr); } else { imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0; } VTKKWRCHelper_IncrementAndLoopEnd(); } // This method is called when the interpolation type is nearest neighbor and // the data has more than one independent components. We compute the max of // each component along the ray in native type, then use the scale/shift to // convert this into an unsigned short index value. We use the index values // to lookup the color/opacity per component, then use the component weights to // blend these into one final color. template void vtkFixedPointMIPHelperGenerateImageIndependentNN( T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol) { VTKKWRCHelper_InitializeWeights(); VTKKWRCHelper_InitializationAndLoopStartNN(); VTKKWRCHelper_InitializeMIPMultiNN(); VTKKWRCHelper_SpaceLeapSetupMulti(); int maxValueDefined = 0; unsigned short maxIdx[4] = { 0, 0, 0, 0 }; for (k = 0; k < numSteps; k++) { if (k) { mapper->FixedPointIncrement(pos, dir); } VTKKWRCHelper_CroppingCheckNN(pos); VTKKWRCHelper_MIPSpaceLeapPopulateMulti(maxIdx, mapper->GetFlipMIPComparison()) mapper->ShiftVectorDown(pos, spos); dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2]; if (!maxValueDefined) { for (c = 0; c < components; c++) { maxValue[c] = *(dptr + c); maxIdx[c] = static_cast((maxValue[c] + shift[c]) * scale[c]); } maxValueDefined = 1; } else { for (c = 0; c < components; c++) { if (VTKKWRCHelper_MIPSpaceLeapCheckMulti(c, mapper->GetFlipMIPComparison()) && ((mapper->GetFlipMIPComparison() && *(dptr + c) < maxValue[c]) || (!mapper->GetFlipMIPComparison() && *(dptr + c) > maxValue[c]))) { maxValue[c] = *(dptr + c); maxIdx[c] = static_cast((maxValue[c] + shift[c]) * scale[c]); } } } } imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0; if (maxValueDefined) { VTKKWRCHelper_LookupAndCombineIndependentColorsMax( colorTable, scalarOpacityTable, maxIdx, weights, components, imagePtr); } VTKKWRCHelper_IncrementAndLoopEnd(); } // This method is called when the interpolation type is linear, the // data contains one component and scale = 1.0 and shift = 0.0. This is // the simple case were we do not need to apply scale/shift in the // inner loop. In the inner loop we compute the eight cell vertex values // (if we have changed cells). We compute our weights within the cell // according to our fractional position within the cell, and apply trilinear // interpolation to compute the index. We find the maximum index along // the ray, and then use this to look up a final color. template void vtkFixedPointMIPHelperGenerateImageOneSimpleTrilin(T* dataPtr, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vtkNotUsed(vol)) { VTKKWRCHelper_InitializationAndLoopStartTrilin(); VTKKWRCHelper_InitializeMIPOneTrilin(); VTKKWRCHelper_SpaceLeapSetup(); int maxValueDefined = 0; unsigned short maxIdx = 0; unsigned int maxScalar = 0; for (k = 0; k < numSteps; k++) { if (k) { mapper->FixedPointIncrement(pos, dir); } VTKKWRCHelper_MIPSpaceLeapCheck(maxIdx, maxValueDefined, mapper->GetFlipMIPComparison()); VTKKWRCHelper_CroppingCheckTrilin(pos); mapper->ShiftVectorDown(pos, spos); if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2]) { oldSPos[0] = spos[0]; oldSPos[1] = spos[1]; oldSPos[2] = spos[2]; dptr = dataPtr + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2]; VTKKWRCHelper_GetCellScalarValuesSimple(dptr); if (mapper->GetFlipMIPComparison()) { maxScalar = (A < B) ? (A) : (B); maxScalar = (C < maxScalar) ? (C) : (maxScalar); maxScalar = (D < maxScalar) ? (D) : (maxScalar); maxScalar = (E < maxScalar) ? (E) : (maxScalar); maxScalar = (F < maxScalar) ? (F) : (maxScalar); maxScalar = (G < maxScalar) ? (G) : (maxScalar); maxScalar = (H < maxScalar) ? (H) : (maxScalar); } else { maxScalar = (A > B) ? (A) : (B); maxScalar = (C > maxScalar) ? (C) : (maxScalar); maxScalar = (D > maxScalar) ? (D) : (maxScalar); maxScalar = (E > maxScalar) ? (E) : (maxScalar); maxScalar = (F > maxScalar) ? (F) : (maxScalar); maxScalar = (G > maxScalar) ? (G) : (maxScalar); maxScalar = (H > maxScalar) ? (H) : (maxScalar); } } if (!maxValueDefined || ((mapper->GetFlipMIPComparison() && maxScalar < static_cast(maxValue)) || (!mapper->GetFlipMIPComparison() && maxScalar > static_cast(maxValue)))) { VTKKWRCHelper_ComputeWeights(pos); VTKKWRCHelper_InterpolateScalar(val); if (!maxValueDefined || ((mapper->GetFlipMIPComparison() && val < maxValue) || (!mapper->GetFlipMIPComparison() && val > maxValue))) { maxValue = val; maxIdx = static_cast(maxValue); maxValueDefined = 1; } } } if (maxValueDefined) { VTKKWRCHelper_LookupColorMax(colorTable[0], scalarOpacityTable[0], maxIdx, imagePtr); } else { imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0; } VTKKWRCHelper_IncrementAndLoopEnd(); } // This method is called when the interpolation type is linear, the // data contains one component and scale != 1.0 or shift != 0.0. This // means that we need to apply scale/shift in the inner loop to compute // an unsigned short index value. In the inner loop we compute the eight cell // vertex values (as unsigned short indices, if we have changed cells). We // compute our weights within the cell according to our fractional position // within the cell, and apply trilinear interpolation to compute the index. // We find the maximum index along the ray, and then use this to look up a // final color. template void vtkFixedPointMIPHelperGenerateImageOneTrilin(T* dataPtr, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vtkNotUsed(vol)) { VTKKWRCHelper_InitializationAndLoopStartTrilin(); VTKKWRCHelper_InitializeMIPOneTrilin(); VTKKWRCHelper_SpaceLeapSetup(); int maxValueDefined = 0; unsigned short maxIdx = 0; for (k = 0; k < numSteps; k++) { if (k) { mapper->FixedPointIncrement(pos, dir); } VTKKWRCHelper_CroppingCheckTrilin(pos); VTKKWRCHelper_MIPSpaceLeapCheck(maxIdx, maxValueDefined, mapper->GetFlipMIPComparison()); mapper->ShiftVectorDown(pos, spos); if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2]) { oldSPos[0] = spos[0]; oldSPos[1] = spos[1]; oldSPos[2] = spos[2]; dptr = dataPtr + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2]; VTKKWRCHelper_GetCellScalarValues(dptr, scale[0], shift[0]); } VTKKWRCHelper_ComputeWeights(pos); VTKKWRCHelper_InterpolateScalar(val); if (!maxValueDefined || ((mapper->GetFlipMIPComparison() && val < maxValue) || (!mapper->GetFlipMIPComparison() && val > maxValue))) { maxValue = val; maxIdx = static_cast(maxValue); maxValueDefined = 1; } } if (maxValueDefined) { VTKKWRCHelper_LookupColorMax(colorTable[0], scalarOpacityTable[0], maxIdx, imagePtr); } else { imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0; } VTKKWRCHelper_IncrementAndLoopEnd(); } // This method is used when the interpolation type is linear, the data has // two or four components and the components are not considered independent. // For four component d>>(VTKKW_FP_SHIFT - 8));ata, the data must be unsigned char in type. In the // inner loop we get the data value for the eight cell corners (if we have // changed cells) for all components as unsigned shorts (we use the // scale/shift to ensure the correct range). We compute our weights within // the cell according to our fractional position within the cell, and apply // trilinear interpolation to compute the index values. For two component data, // We use the first index to lookup a color and the second to look up an opacity // for this sample. For four component data we use the first three components // directly as a color, then we look up the opacity using the fourth component. // We then composite this into the color computed so far along the ray, and // check if we can terminate at this point (if the accumulated opacity is // higher than some threshold). template void vtkFixedPointMIPHelperGenerateImageDependentTrilin(T* dataPtr, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vtkNotUsed(vol)) { VTKKWRCHelper_InitializationAndLoopStartTrilin(); VTKKWRCHelper_InitializeMIPMultiTrilin(); VTKKWRCHelper_SpaceLeapSetup(); int maxValueDefined = 0; unsigned short maxIdx = 0; for (k = 0; k < numSteps; k++) { if (k) { mapper->FixedPointIncrement(pos, dir); } VTKKWRCHelper_CroppingCheckTrilin(pos); VTKKWRCHelper_MIPSpaceLeapCheck(maxIdx, maxValueDefined, mapper->GetFlipMIPComparison()); mapper->ShiftVectorDown(pos, spos); if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2]) { oldSPos[0] = spos[0]; oldSPos[1] = spos[1]; oldSPos[2] = spos[2]; if (components == 2) { for (c = 0; c < components; c++) { dptr = dataPtr + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2] + c; VTKKWRCHelper_GetCellComponentScalarValues(dptr, c, scale[c], shift[c]); } } else { for (c = 0; c < 3; c++) { dptr = dataPtr + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2] + c; VTKKWRCHelper_GetCellComponentRawScalarValues(dptr, c); } dptr = dataPtr + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2] + c; VTKKWRCHelper_GetCellComponentScalarValues(dptr, 3, scale[3], shift[3]); } } VTKKWRCHelper_ComputeWeights(pos); VTKKWRCHelper_InterpolateScalarComponent(val, c, components); if (!maxValueDefined || ((mapper->GetFlipMIPComparison() && (val[components - 1] < maxValue[components - 1])) || (!mapper->GetFlipMIPComparison() && (val[components - 1] > maxValue[components - 1])))) { for (c = 0; c < components; c++) { maxValue[c] = val[c]; } maxIdx = static_cast( (maxValue[components - 1] + shift[components - 1]) * scale[components - 1]); maxValueDefined = 1; } } if (maxValueDefined) { VTKKWRCHelper_LookupDependentColorUS( colorTable[0], scalarOpacityTable[0], maxValue, components, imagePtr); } else { imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0; } VTKKWRCHelper_IncrementAndLoopEnd(); } // This method is used when the interpolation type is linear, the data has // more than one component and the components are considered independent. In // the inner loop we get the data value for the eight cell corners (if we have // changed cells) for all components as an unsigned shorts (we have to use the // scale/shift to ensure that we obtained unsigned short indices) We compute // our weights within the cell according to our fractional position within the // cell, and apply trilinear interpolation to compute a value for each // component. We do this for each sample along the ray to find a maximum value // per component, then we look up a color/opacity for each component and blend // them according to the component weights. template void vtkFixedPointMIPHelperGenerateImageIndependentTrilin(T* dataPtr, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol) { VTKKWRCHelper_InitializeWeights(); VTKKWRCHelper_InitializationAndLoopStartTrilin(); VTKKWRCHelper_InitializeMIPMultiTrilin(); int maxValueDefined = 0; for (k = 0; k < numSteps; k++) { if (k) { mapper->FixedPointIncrement(pos, dir); } VTKKWRCHelper_CroppingCheckTrilin(pos); mapper->ShiftVectorDown(pos, spos); if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2]) { oldSPos[0] = spos[0]; oldSPos[1] = spos[1]; oldSPos[2] = spos[2]; for (c = 0; c < components; c++) { dptr = dataPtr + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2] + c; VTKKWRCHelper_GetCellComponentScalarValues(dptr, c, scale[c], shift[c]); } } VTKKWRCHelper_ComputeWeights(pos); VTKKWRCHelper_InterpolateScalarComponent(val, c, components); if (!maxValueDefined) { for (c = 0; c < components; c++) { maxValue[c] = val[c]; } maxValueDefined = 1; } else { for (c = 0; c < components; c++) { if ((mapper->GetFlipMIPComparison() && val[c] < maxValue[c]) || (!mapper->GetFlipMIPComparison() && val[c] > maxValue[c])) { maxValue[c] = val[c]; } } } } imagePtr[0] = imagePtr[1] = imagePtr[2] = imagePtr[3] = 0; if (maxValueDefined) { VTKKWRCHelper_LookupAndCombineIndependentColorsMax( colorTable, scalarOpacityTable, maxValue, weights, components, imagePtr); } VTKKWRCHelper_IncrementAndLoopEnd(); } void vtkFixedPointVolumeRayCastMIPHelper::GenerateImage( int threadID, int threadCount, vtkVolume* vol, vtkFixedPointVolumeRayCastMapper* mapper) { void* dataPtr = mapper->GetCurrentScalars()->GetVoidPointer(0); int scalarType = mapper->GetCurrentScalars()->GetDataType(); // Nearest Neighbor interpolate if (mapper->ShouldUseNearestNeighborInterpolation(vol)) { // One component data if (mapper->GetCurrentScalars()->GetNumberOfComponents() == 1) { switch (scalarType) { vtkTemplateMacro(vtkFixedPointMIPHelperGenerateImageOneNN( static_cast(dataPtr), threadID, threadCount, mapper, vol)); } } // More that one independent components else if (vol->GetProperty()->GetIndependentComponents()) { switch (scalarType) { vtkTemplateMacro(vtkFixedPointMIPHelperGenerateImageIndependentNN( static_cast(dataPtr), threadID, threadCount, mapper, vol)); } } // Dependent (color) components else { switch (scalarType) { vtkTemplateMacro(vtkFixedPointMIPHelperGenerateImageDependentNN( static_cast(dataPtr), threadID, threadCount, mapper, vol)); } } } // Trilinear Interpolation else { // One component if (mapper->GetCurrentScalars()->GetNumberOfComponents() == 1) { // Scale == 1.0 and shift == 0.0 - simple case (faster) if (mapper->GetTableScale()[0] == 1.0 && mapper->GetTableShift()[0] == 0.0) { switch (scalarType) { vtkTemplateMacro(vtkFixedPointMIPHelperGenerateImageOneSimpleTrilin( static_cast(dataPtr), threadID, threadCount, mapper, vol)); } } // Scale != 1.0 or shift != 0.0 - must apply scale/shift in inner loop else { switch (scalarType) { vtkTemplateMacro(vtkFixedPointMIPHelperGenerateImageOneTrilin( static_cast(dataPtr), threadID, threadCount, mapper, vol)); } } } // Independent components (more than one) else if (vol->GetProperty()->GetIndependentComponents()) { switch (scalarType) { vtkTemplateMacro(vtkFixedPointMIPHelperGenerateImageIndependentTrilin( static_cast(dataPtr), threadID, threadCount, mapper, vol)); } } // Dependent components else { switch (scalarType) { vtkTemplateMacro(vtkFixedPointMIPHelperGenerateImageDependentTrilin( static_cast(dataPtr), threadID, threadCount, mapper, vol)); } } } } // Print method for vtkFixedPointVolumeRayCastMIPHelper void vtkFixedPointVolumeRayCastMIPHelper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }