我的解决方案基于@Peter-ReinstateMonica 的建议:创建一个包装类,其中两个对象 vtkFloatArray 和 Eigen::MatrixXf 都将驻留,这样可以控制这两个对象的生命周期。
让我们调用包装类vtkEigenFloatArray 并让它从vtkFloatArray 继承。由于我们的包装类隐式继承 vtkObject,我们应该遵循 vtk 的继承结构,使其在 vtk 中可用(例如 vtkNew<vtkEigenFloatArray>),同时保持 pimp 习惯用法(这就是为什么您可以在创建的类中看到许多 vtk 方法和宏,这是与vtkFloatArray源代码类推)。
我们将Eigen::MatrixXf* eigArr 成员变量添加到我们的vtkEigenFloatArray 类中。
我们还添加了返回 Eigen::MatrixXf* eigArr 指针和设置器 void SetEigenArray(Eigen::MatrixXf* arr) 的方法 Eigen::MatrixXf* GetEigenArray() 以使用外部创建的类中的内部 Eigen::MatrixXf 对象。
值得注意的是vtkEigenFloatArray 及其受保护的Eigen::MatrixXf* eigArr 对象共享同一个缓冲区。每次调用void UpdateEigenBuffer() 函数时设置。此外,每当从创建的类外部调整Eigen::MatrixXf* eigArr 的大小时,必须调用函数void UpdateEigenBuffer() 来更新vtkFloatArray-inherited 类的大小。
此外,用户绝不能从外部删除Eigen::MatrixXf* eigArr,因为它在vtkEigenFloatArray 的析构函数中被删除。
建议解决方案的缺点:
当主vtkEigenFloatArray 对象被删除时,指针Eigen::MatrixXf* eigArr 将不等于nullptr。因此,当您没有持有者 vtkEigenFloatArray 对象时,您无法检查 Eigen::MatrixXf* eigArr 是否存在。
#include <vtkNew.h>
#include <vtkFloatArray.h>
#include <Eigen/Dense>
#include <iostream>
class vtkEigenFloatArray : public vtkFloatArray
{
public:
static vtkEigenFloatArray* New();
vtkTypeMacro(vtkEigenFloatArray, vtkFloatArray);
void PrintSelf(ostream& os, vtkIndent indent) override
{
this->RealSuperclass::PrintSelf(os, indent);
}
// This macro expands to the set of method declarations that
// make up the interface of vtkAOSDataArrayTemplate, which is ignored
// by the wrappers.
#if defined(__VTK_WRAP__) || defined(__WRAP_GCCXML__)
vtkCreateWrappedArrayInterface(float);
#endif
/**
* A faster alternative to SafeDownCast for downcasting vtkAbstractArrays.
*/
static vtkEigenFloatArray* FastDownCast(vtkAbstractArray* source)
{
return static_cast<vtkEigenFloatArray*>(Superclass::FastDownCast(source));
}
/**
* Get the minimum data value in its native type.
*/
static float GetDataTypeValueMin() { return VTK_FLOAT_MIN; }
/**
* Get the maximum data value in its native type.
*/
static float GetDataTypeValueMax() { return VTK_FLOAT_MAX; }
/**
* Deletes previous pointer and sets new
*/
void SetEigenArray(Eigen::MatrixXf* arr)
{
delete eigArr;
eigArr = arr;
UpdateEigenBuffer();
}
/**
* Don't delete this pointer!
*/
Eigen::MatrixXf* GetEigenArray()
{
return eigArr;
}
/**
* Must be manually called every time Eigen::MatrixXf resized
*/
void UpdateEigenBuffer()
{
this->SetArray(eigArr->data(), eigArr->size(), 1); // must be set to 1 or in destructor runtime error
}
protected:
vtkEigenFloatArray()
{
eigArr = new Eigen::MatrixXf();
}
~vtkEigenFloatArray() override
{
delete eigArr;
eigArr = nullptr;
}
Eigen::MatrixXf* eigArr;
private:
typedef vtkAOSDataArrayTemplate<float> RealSuperclass;
vtkEigenFloatArray(const vtkEigenFloatArray&) = delete;
void operator=(const vtkEigenFloatArray&) = delete;
friend class vtkNew<vtkEigenFloatArray>;
};
vtkStandardNewMacro(vtkEigenFloatArray);
int main(int argc, char *argv[]) {
/* General usage */
vtkNew<vtkEigenFloatArray> arr;
Eigen::MatrixXf* M = arr->GetEigenArray();
M->resize(2, 2);
*M << 1, 2, 3, 4;
arr->UpdateEigenBuffer();
std::cout << "Eigen M:" << std::endl;
std::cout << *M << std::endl;
std::cout << "VTK array:" << std::endl;
for(int i = 0; i < arr->GetSize(); i++)
std::cout << arr->GetValue(i) << std::endl;
arr->Allocate(5);
std::cout << "Eigen M:" << std::endl;
std::cout << *M << std::endl;
std::cout << "VTK array:" << std::endl;
for(int i = 0; i < arr->GetSize(); i++)
std::cout << arr->GetValue(i) << std::endl;
/* Test `SetEigenArray` */
Eigen::MatrixXf* MM = new Eigen::MatrixXf();
MM->resize(2,2);
*MM << 11, 22, 33, 44;
arr->SetEigenArray(MM);
std::cout << "Eigen MM:" << std::endl;
std::cout << *MM << std::endl;
std::cout << "VTK array:" << std::endl;
for(int i = 0; i < arr->GetSize(); i++)
std::cout << arr->GetValue(i) << std::endl;
return 0;
}