// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkDataArray.h" #include "vtkArrayDispatch.h" #include "vtkDataArrayAccessor.h" namespace { struct InterpolateTupleWorker { vtkIdType SrcTuple1; vtkIdType SrcTuple2; vtkIdType DstTuple; double Weight; InterpolateTupleWorker( vtkIdType srcTuple1, vtkIdType srcTuple2, vtkIdType dstTuple, double weight) : SrcTuple1(srcTuple1) , SrcTuple2(srcTuple2) , DstTuple(dstTuple) , Weight(weight) { } template void operator()(Array1T* src1, Array2T* src2, Array3T* dst) const { // Use accessor here instead of ranges since we need to use Insert for // legacy compat vtkDataArrayAccessor s1(src1); vtkDataArrayAccessor s2(src2); vtkDataArrayAccessor d(dst); typedef typename vtkDataArrayAccessor::APIType DestType; const int numComps = dst->GetNumberOfComponents(); const double oneMinusT = 1. - this->Weight; double val; DestType valT; for (int c = 0; c < numComps; ++c) { val = s1.Get(this->SrcTuple1, c) * oneMinusT + s2.Get(this->SrcTuple2, c) * this->Weight; vtkMath::RoundDoubleToIntegralIfNecessary(val, &valT); d.Insert(this->DstTuple, c, valT); } } }; } // end anon namespace VTK_ABI_NAMESPACE_BEGIN //------------------------------------------------------------------------------ // Interpolate value from the two values, p1 and p2, and an // interpolation factor, t. The interpolation factor ranges from (0,1), // with t=0 located at p1. This method assumes that the three arrays are of // the same type. p1 is value at index id1 in fromArray1, while, p2 is // value at index id2 in fromArray2. void vtkDataArray::InterpolateTuple(vtkIdType dstTuple, vtkIdType srcTuple1, vtkAbstractArray* source1, vtkIdType srcTuple2, vtkAbstractArray* source2, double t) { int type = this->GetDataType(); if (!vtkDataTypesCompare(type, source1->GetDataType()) || !vtkDataTypesCompare(type, source2->GetDataType())) { vtkErrorMacro("All arrays to InterpolateValue must be of same type."); return; } if (srcTuple1 >= source1->GetNumberOfTuples()) { vtkErrorMacro("Tuple 1 out of range for provided array. " "Requested tuple: " << srcTuple1 << " " "Tuples: " << source1->GetNumberOfTuples()); return; } if (srcTuple2 >= source2->GetNumberOfTuples()) { vtkErrorMacro("Tuple 2 out of range for provided array. " "Requested tuple: " << srcTuple2 << " " "Tuples: " << source2->GetNumberOfTuples()); return; } vtkDataArray* src1DA = vtkDataArray::FastDownCast(source1); vtkDataArray* src2DA = vtkDataArray::FastDownCast(source2); if (!src1DA || !src2DA) { vtkErrorMacro("Both arrays must be vtkDataArray subclasses."); return; } bool fallback = type == VTK_BIT; if (!fallback) { InterpolateTupleWorker worker(srcTuple1, srcTuple2, dstTuple, t); // Use fallback if dispatch fails: fallback = !vtkArrayDispatch::Dispatch3SameValueType::Execute(src1DA, src2DA, this, worker); } // Fallback to a separate implementation that checks vtkDataArray::GetDataType // rather than relying on API types, since we'll need to round differently // depending on type, and the API type for vtkDataArray is always double. if (fallback) { bool doRound = !(this->GetDataType() == VTK_FLOAT || this->GetDataType() == VTK_DOUBLE); double typeMin = this->GetDataTypeMin(); double typeMax = this->GetDataTypeMax(); int numComp = source1->GetNumberOfComponents(); double in1; double in2; double out; for (int c = 0; c < numComp; c++) { in1 = src1DA->GetComponent(srcTuple1, c); in2 = src2DA->GetComponent(srcTuple2, c); out = in1 + t * (in2 - in1); // Clamp to datatype range: out = std::max(out, typeMin); out = std::min(out, typeMax); // Round if needed: if (doRound) { out = std::floor((out >= 0.) ? (out + 0.5) : (out - 0.5)); } this->InsertComponent(dstTuple, c, out); } } } VTK_ABI_NAMESPACE_END