/*========================================================================= Program: Visualization Toolkit Module: vtkProjectedTetrahedraMapper.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. =========================================================================*/ /* * Copyright 2003 Sandia Corporation. * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive * license for use of this work by or on behalf of the * U.S. Government. Redistribution and use in source and binary forms, with * or without modification, are permitted provided that this Notice and any * statement of authorship are reproduced on all copies. */ #include "vtkProjectedTetrahedraMapper.h" #include "vtkArrayDispatch.h" #include "vtkCellArray.h" #include "vtkCellCenterDepthSort.h" #include "vtkCellData.h" #include "vtkColorTransferFunction.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkGarbageCollector.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPiecewiseFunction.h" #include "vtkPointData.h" #include "vtkTimerLog.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVisibilitySort.h" #include "vtkVolume.h" #include "vtkVolumeProperty.h" #include #include //------------------------------------------------------------------------------ vtkCxxSetObjectMacro(vtkProjectedTetrahedraMapper, VisibilitySort, vtkVisibilitySort); //------------------------------------------------------------------------------ // Return nullptr if no override is supplied. vtkAbstractObjectFactoryNewMacro(vtkProjectedTetrahedraMapper); //------------------------------------------------------------------------------ vtkProjectedTetrahedraMapper::vtkProjectedTetrahedraMapper() { this->VisibilitySort = vtkCellCenterDepthSort::New(); } vtkProjectedTetrahedraMapper::~vtkProjectedTetrahedraMapper() { this->SetVisibilitySort(nullptr); } void vtkProjectedTetrahedraMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "VisibilitySort: " << this->VisibilitySort << endl; } //------------------------------------------------------------------------------ void vtkProjectedTetrahedraMapper::ReportReferences(vtkGarbageCollector* collector) { this->Superclass::ReportReferences(collector); vtkGarbageCollectorReport(collector, this->VisibilitySort, "VisibilitySort"); } //------------------------------------------------------------------------------ namespace { struct TransformPointsWorker { const float* Proj; const float* ModelView; float* OutPoints; TransformPointsWorker(const float* proj, const float* mv, float* out) : Proj(proj) , ModelView(mv) , OutPoints(out) { } template void operator()(ArrayT* in_points) { float mat[16]; int row, col; vtkIdType i; vtkIdType num_points = in_points->GetNumberOfTuples(); typename ArrayT::ValueType in_p[3]; float* out_p; // Combine two transforms into one transform. for (col = 0; col < 4; col++) { for (row = 0; row < 4; row++) { mat[col * 4 + row] = (this->Proj[0 * 4 + row] * this->ModelView[col * 4 + 0] + this->Proj[1 * 4 + row] * this->ModelView[col * 4 + 1] + this->Proj[2 * 4 + row] * this->ModelView[col * 4 + 2] + this->Proj[3 * 4 + row] * this->ModelView[col * 4 + 3]); } } // Transform all points. for (i = 0, out_p = this->OutPoints; i < num_points; i++, out_p += 3) { in_points->GetTypedTuple(i, in_p); for (row = 0; row < 3; row++) { out_p[row] = (mat[0 * 4 + row] * in_p[0] + mat[1 * 4 + row] * in_p[1] + mat[2 * 4 + row] * in_p[2] + mat[3 * 4 + row]); } } // Check to see if we need to divide by w. if ((mat[0 * 4 + 3] != 0) || (mat[1 * 4 + 3] != 0) || (mat[2 * 4 + 3] != 0) || (mat[3 * 4 + 3] != 1)) { for (i = 0, out_p = this->OutPoints; i < num_points; i++, out_p += 3) { in_points->GetTypedTuple(i, in_p); float w = (mat[0 * 4 + 3] * in_p[0] + mat[1 * 4 + 3] * in_p[1] + mat[2 * 4 + 3] * in_p[2] + mat[3 * 4 + 3]); if (w > 0.0) { out_p[0] /= w; out_p[1] /= w; out_p[2] /= w; } else { // A negative w probably means the point is behind the viewer. Things // can get screwy if we try to inverse-project that. Instead, just // set the position somewhere very far behind us. out_p[2] = -VTK_FLOAT_MAX; } } } } }; } // end anon namespace //------------------------------------------------------------------------------ void vtkProjectedTetrahedraMapper::TransformPoints(vtkPoints* inPoints, const float projection_mat[16], const float modelview_mat[16], vtkFloatArray* outPoints) { if (!inPoints) { return; } outPoints->SetNumberOfComponents(3); outPoints->SetNumberOfTuples(inPoints->GetNumberOfPoints()); TransformPointsWorker worker(projection_mat, modelview_mat, outPoints->GetPointer(0)); vtkArrayDispatch::Dispatch::Execute(inPoints->GetData(), worker); } //------------------------------------------------------------------------------ namespace vtkProjectedTetrahedraMapperNamespace { template void MapScalarsToColorsImpl( ColorArrayT* colors, vtkVolumeProperty* property, ScalarArrayT* scalars); template void MapIndependentComponents( ColorArrayT* colors, vtkVolumeProperty* property, ScalarArrayT* scalars); template void Map2DependentComponents( ColorArrayT* colors, vtkVolumeProperty* property, ScalarArrayT* scalars); template void Map4DependentComponents(ColorArrayT* colors, ScalarArrayT* scalars); struct Worker { vtkVolumeProperty* Property; Worker(vtkVolumeProperty* property) : Property(property) { } template void operator()(ColorArrayT* colors, ScalarArrayT* scalars) { MapScalarsToColorsImpl(colors, this->Property, scalars); } }; } void vtkProjectedTetrahedraMapper::MapScalarsToColors( vtkDataArray* colors, vtkVolumeProperty* property, vtkDataArray* scalars) { using namespace vtkProjectedTetrahedraMapperNamespace; vtkDataArray* tmpColors; int castColors; if ((colors->GetDataType() == VTK_UNSIGNED_CHAR) && (((scalars->GetDataType() != VTK_UNSIGNED_CHAR) || (property->GetIndependentComponents())) || ((!property->GetIndependentComponents()) && (scalars->GetNumberOfComponents() == 2)))) { // Special case. Need to convert from range [0,1] to [0,255]. tmpColors = vtkDoubleArray::New(); castColors = 1; } else { tmpColors = colors; castColors = 0; } vtkIdType numscalars = scalars->GetNumberOfTuples(); tmpColors->Initialize(); tmpColors->SetNumberOfComponents(4); tmpColors->SetNumberOfTuples(numscalars); Worker worker(property); if (!vtkArrayDispatch::Dispatch2::Execute(tmpColors, scalars, worker)) { vtkGenericWarningMacro("Dispatch failed for scalar array " << scalars->GetName()); } if (castColors) { // Special case. Need to convert from range [0,1] to [0,255]. colors->Initialize(); colors->SetNumberOfComponents(4); colors->SetNumberOfTuples(scalars->GetNumberOfTuples()); unsigned char* c = static_cast(colors)->GetPointer(0); for (vtkIdType i = 0; i < numscalars; i++, c += 4) { double* dc = tmpColors->GetTuple(i); c[0] = static_cast(dc[0] * 255.9999); c[1] = static_cast(dc[1] * 255.9999); c[2] = static_cast(dc[2] * 255.9999); c[3] = static_cast(dc[3] * 255.9999); } tmpColors->Delete(); } } //------------------------------------------------------------------------------ namespace vtkProjectedTetrahedraMapperNamespace { template void MapScalarsToColorsImpl(ColorArrayT* colors, vtkVolumeProperty* property, ScalarArrayT* scalars) { if (property->GetIndependentComponents()) { MapIndependentComponents(colors, property, scalars); } else { switch (scalars->GetNumberOfComponents()) { case 2: Map2DependentComponents(colors, property, scalars); break; case 4: Map4DependentComponents(colors, scalars); break; default: vtkGenericWarningMacro("Attempted to map scalar with " << scalars->GetNumberOfComponents() << " with dependent components"); break; } } } template void MapIndependentComponents( ColorArrayT* colors, vtkVolumeProperty* property, ScalarArrayT* scalars) { // I don't really know what to do if there is more than one component. // How am I supposed to mix the resulting colors? Since I don't know // what to do, and the whole thing seems kinda pointless anyway, I'm just // going to punt and copy over the first scalar. vtkIdType i; vtkIdType num_scalars = scalars->GetNumberOfTuples(); typedef typename ScalarArrayT::ValueType ScalarType; typedef typename ColorArrayT::ValueType ColorType; ColorType c[4]; if (property->GetColorChannels() == 1) { vtkPiecewiseFunction* gray = property->GetGrayTransferFunction(); vtkPiecewiseFunction* alpha = property->GetScalarOpacity(); for (i = 0; i < num_scalars; i++) { ScalarType s = scalars->GetTypedComponent(i, 0); c[0] = c[1] = c[2] = static_cast(gray->GetValue(s)); c[3] = static_cast(alpha->GetValue(s)); colors->SetTypedTuple(i, c); } } else { vtkColorTransferFunction* rgb = property->GetRGBTransferFunction(); vtkPiecewiseFunction* alpha = property->GetScalarOpacity(); int vectorMode = rgb->GetVectorMode(); int vectorComponent = rgb->GetVectorComponent(); for (i = 0; i < num_scalars; i++) { ScalarType s = 0.0; if (scalars->GetNumberOfComponents() == 1) { s = scalars->GetValue(i); } else if (vectorMode == vtkScalarsToColors::COMPONENT) { s = scalars->GetTypedComponent(i, vectorComponent); } else { ScalarType sum = 0.0; for (int comp = 0; comp < scalars->GetNumberOfComponents(); ++comp) { ScalarType t = scalars->GetTypedComponent(i, comp); sum += t * t; } s = sqrt(sum); } double trgb[3]; rgb->GetColor(s, trgb); c[0] = static_cast(trgb[0]); c[1] = static_cast(trgb[1]); c[2] = static_cast(trgb[2]); c[3] = static_cast(alpha->GetValue(s)); colors->SetTypedTuple(i, c); } } } template void Map2DependentComponents( ColorArrayT* colors, vtkVolumeProperty* property, ScalarArrayT* scalars) { typedef typename ScalarArrayT::ValueType ScalarType; vtkColorTransferFunction* rgb = property->GetRGBTransferFunction(); vtkPiecewiseFunction* alpha = property->GetScalarOpacity(); vtkIdType num_scalars = scalars->GetNumberOfTuples(); double rgbColor[4]; ScalarType scalar[2]; for (vtkIdType i = 0; i < num_scalars; i++) { scalars->GetTypedTuple(i, scalar); rgb->GetColor(scalar[0], rgbColor); rgbColor[3] = alpha->GetValue(scalar[1]); colors->SetTuple(i, rgbColor); } } template void Map4DependentComponents(ColorArrayT* colors, ScalarArrayT* scalars) { double val[4]; vtkIdType num_scalars = scalars->GetNumberOfTuples(); for (vtkIdType i = 0; i < num_scalars; i++) { scalars->GetTuple(i, val); colors->SetTuple(i, val); } } }