VTK——angleWidget的3D转换

文章目录

3D空间坐标转换

在冠状图、矢状面、横截面等创建的角度组件的三个端点坐标,不能直接用在3D视图中。这是因为2D切片的坐标是基于像素的,而3D空间的坐标可能是基于实际物理尺寸的。
解决方案是使用2D点的坐标、切片的物理位置和方向以及可能的其他参数(例如切片厚度或间距),来计算空间坐标。将计算好的空间坐标p1、p2、p3传入下面的函数中,就可以在3D视图中画出角度组件。

例程

cpp 复制代码
get3DViewAngle(double* p1, double* p2, double* mid, int* indexVal) {
    double modifiedPoints[3][3]; 
    int currentAngleIndex = *indexVal;
    auto iter = threeDActors.find(currentAngleIndex);
    if (iter != threeDActors.end()) {
        for (auto act : iter->second) {
            threeDRenderer->RemoveActor(act);
        }
        threeDActors.erase(iter);
    }

    double* pts[] = {p1, p2, mid};

    for(int i = 0; i < 3; i++) {
        modifiedPoints[i][0] = pts[i][0] * xRange[1] / imageDims[0];
        modifiedPoints[i][1] = pts[i][1] * yRange[1] / imageDims[1];
        modifiedPoints[i][2] = pts[i][2] * zRange[1] / imageDims[2];
    }

    vtkSmartPointer<vtkSphereSource> src1 = vtkSmartPointer<vtkSphereSource>::New();
    src1->SetCenter(modifiedPoints[0]);
    src1->SetRadius(2);
    vtkSmartPointer<vtkPolyDataMapper> map1 = vtkSmartPointer<vtkPolyDataMapper>::New();
    map1->SetInputConnection(src1->GetOutputPort());
    vtkSmartPointer<vtkActor> act1 = vtkSmartPointer<vtkActor>::New();
    act1->SetMapper(map1);

    vtkSmartPointer<vtkSphereSource> src2 = vtkSmartPointer<vtkSphereSource>::New();
    src2->SetCenter(modifiedPoints[1]);
    src2->SetRadius(2);
    vtkSmartPointer<vtkPolyDataMapper> map2 = vtkSmartPointer<vtkPolyDataMapper>::New();
    map2->SetInputConnection(src2->GetOutputPort());
    vtkSmartPointer<vtkActor> act2 = vtkSmartPointer<vtkActor>::New();
    act2->SetMapper(map2);

    vtkSmartPointer<vtkSphereSource> src3 = vtkSmartPointer<vtkSphereSource>::New();
    src3->SetCenter(modifiedPoints[2]);
    src3->SetRadius(2);
    vtkSmartPointer<vtkPolyDataMapper> map3 = vtkSmartPointer<vtkPolyDataMapper>::New();
    map3->SetInputConnection(src3->GetOutputPort());
    vtkSmartPointer<vtkActor> act3 = vtkSmartPointer<vtkActor>::New();
    act3->SetMapper(map3);

    vtkSmartPointer<vtkLineSource> lnSrc1 = vtkSmartPointer<vtkLineSource>::New();
    lnSrc1->SetPoint1(modifiedPoints[0]);
    lnSrc1->SetPoint2(modifiedPoints[2]);
    vtkSmartPointer<vtkPolyDataMapper> lnMap1 = vtkSmartPointer<vtkPolyDataMapper>::New();
    lnMap1->SetInputConnection(lnSrc1->GetOutputPort());
    vtkSmartPointer<vtkActor> lnAct1 = vtkSmartPointer<vtkActor>::New();
    lnAct1->SetMapper(lnMap1);

    vtkSmartPointer<vtkLineSource> lnSrc2 = vtkSmartPointer<vtkLineSource>::New();
    lnSrc2->SetPoint1(modifiedPoints[1]);
    lnSrc2->SetPoint2(modifiedPoints[2]);
    vtkSmartPointer<vtkPolyDataMapper> lnMap2 = vtkSmartPointer<vtkPolyDataMapper>::New();
    lnMap2->SetInputConnection(lnSrc2->GetOutputPort());
    vtkSmartPointer<vtkActor> lnAct2 = vtkSmartPointer<vtkActor>::New();
    lnAct2->SetMapper(lnMap2);

    threeDRenderer->AddActor(act1);
    threeDRenderer->AddActor(act2);
    threeDRenderer->AddActor(act3);
    threeDRenderer->AddActor(lnAct1);
    threeDRenderer->AddActor(lnAct2);
    std::vector<vtkSmartPointer<vtkActor>> acts = {act1, act2, act3, lnAct1, lnAct2};
    threeDActors[currentAngleIndex] = acts;

    for (auto act : acts) {
        threeDRenderer->AddActor(act);
    }
    renderWidget[3]->interactor()->Render();
}


}

心得

  1. 在创建角度组件后,不能直接读取组件的端点坐标来用于计算空间坐标,因为此时的端点坐标还是空。需要等到鼠标左键点击三次后,才会得到完整的端点坐标。这个时候可以写在角度组件的回调函数中,然后使用成员变量来获取创建好的端点坐标。
  2. 在角度组件的回调函数中,可以使用信号槽机制来保证拖动组件后能够实时更新角度组件位置。
  3. 如果是创建线条组件,需要手动触发一次回调函数,因为线条组件的端点位置是可以直接读取的。
cpp 复制代码
                lineCallback->Execute(lineWidget, vtkCommand::EndInteractionEvent, nullptr);         //手动触发回调

4.如果想要保证实时删除2D和3D视图中的角度组件,可以使用map,只需要记住创建的索引就能直接删除组件。这样可以与页面上的组件数量和组件索引独立开来.

cpp 复制代码
std::map<int,vtkSmartPointer<vtkAngleWidget>> ngleWidgets;
相关推荐
布莱克60538 分钟前
C/C++ 中变量的声明与定义:区别、联系与常见误区
c语言·开发语言·c++·声明·定义
沫璃染墨5 小时前
从零入门计算机网络系列(十二):HTTP长连接与会话管理详解——从Connection到Cookie与Session
linux·服务器·c++·tcp/ip·ubuntu·http·交互
xiaoye-duck6 小时前
《C++ 项目:手写大模型接入 SDK》DeepSeek接口设计(下):流式响应实现和测试
开发语言·网络·c++·语言模型
旖旎夜光7 小时前
【C++ 基础入门】类和对象(上):封装、对象模型与 this 指针
开发语言·c++·笔记·学习
小超人诞生日记8 小时前
C++ 智能指针的使用及其原理详解
c++·算法
akinggw9 小时前
libagentcore - 一个基于c++的AI多agent系统升级到2.0版本
开发语言·jvm·c++
繁星蓝雨10 小时前
C++设计原理———多重继承(虚基类、菱形继承、委托、重命名、基类和成员初始化)
c++·委托·多重继承·mi·显式初始化列·虚基类·对象布局
旖旎夜光10 小时前
【C++ 基础入门】命名空间、输入输出、缺省参数与函数重载
开发语言·c++·笔记·学习
扶尔魔ocy11 小时前
【QT入门到晋级】用开源的自定义控件开发
c++·qt·自定义控件
akinggw13 小时前
libsherpacore - 基于 sherpa-onnx 的 C++ 语音交互静态库
c++·交互·语音识别