VTK9.2.0+QT5.14.0 实现三维点拾取并显示标签

效果

点云拾取并显示标签

背景

通过鼠标交互,显示当前选取点的坐标值

基本原理

在主程序中添加鼠标响应的回调函数,该函数中,首先获取鼠标在窗口中点下的屏幕坐标,有一点和垂直屏幕方向产生射线,若射线与着色器中的点云有满足邻近距离小于容差值的,则返回当前点的id,由此获得它的坐标。

实现方式

首先,在主程序中添加vtkCallbackCommand

// 创建vtkCallbackCommand指针对象
vtkNew<vtkCallbackCommand> pickCallback;
// 设置该响应命令的客户数据入口为主程序的类,此处的this在我的代码中指的是QMainWindow
pickCallback->SetClientData(this);
// 设置该响应命令的具体实现函数为handle_point_picker
pickCallback->SetCallback(handle_point_picker);
	
// 定义一个与vtk窗口交互的点拾取器 vtkPointPicker
vtkNew<vtkPointPicker> picker;
// 设置拾取器的容差为0.005
picker->SetTolerance(0.005);
// 将该拾取器添加到vtk窗口交互中
ui.openGLWidget->renderWindow()->GetInteractor()->SetPicker(picker);
// 定义右键按下鼠标事件的响应为前面创建的pickCallback
ui.openGLWidget->renderWindow()->GetInteractor()->AddObserver(vtkCommand::RightButtonPressEvent, pickCallback);

由此,当我们在vtk窗口中按下鼠标右键时,就会进入pickCallback,进一步的进入它的具体实现方式,也就是handle_point_picker函数中,下面是该函数具体实现

void handle_point_picker(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata)
{
    // 将clientdata转换为QVtkDemo2类型的指针,这是一个自定义的类。
    QVtkDemo2* demo = (QVtkDemo2*)clientdata;
    
    // 获取当前窗口的渲染窗口。
    vtkRenderWindow *window = demo->ui.openGLWidget->renderWindow();
    
    // 获取渲染窗口的第一个渲染器。
    vtkRenderer* renderer = window->GetRenderers()->GetFirstRenderer();
    
    // 获取渲染窗口的交互器。
    vtkRenderWindowInteractor* interactor = window->GetInteractor();
    
    // 创建一个整型数组来存储交互器事件的位置。
    int pos[2];
    
    // 获取鼠标按下的屏幕坐标,单位是像素
    interactor->GetEventPosition(pos);
    
    // 输出事件位置到控制台。
    std::cout << "pos: " << pos[0] << " " << pos[1] << std::endl;

    // 根据鼠标选取点和容差,判断是否有三维点被选中
    int picresult = interactor->GetPicker()->Pick(pos[0], pos[1], 0, renderer);
    
    // 输出拾取结果到控制台。
    std::cout << "picresult: " << picresult << std::endl;
    
    // 如果拾取成功(picresult非零)。
    if (picresult)
    {
        // 存储拾取点的世界坐标。
        double world[3];
        
        // 获取拾取点的世界坐标。
        interactor->GetPicker()->GetPickPosition(world);
        
        // 输出拾取点的世界坐标到控制台。
        std::cout << "world: " << world[0] << " " << world[1] << " " << world[2] << std::endl;
        
        // 创建一个缓冲区来格式化拾取点的世界坐标。
        char buffer[20];
        sprintf_s(buffer, 20, "%0.2f, %0.2f, %0.2f", world[0], world[1], world[2]);
        
        // 获取openGLWidget的宽度和高度。
        int width = demo->ui.openGLWidget->width();
        int height = demo->ui.openGLWidget->height();
        
        // 计算拾取点在窗口中的归一化位置。
        double ratiox = (double)pos[0] / width + 0.05;
        double ratioy = (double)pos[1] / height + 0.05;
        
        // 输出归一化位置到控制台。
        std::cout << "ratiox: " << ratiox << " ratioy: " << ratioy << std::endl;
        
        // 设置标题表示的文本。
        demo->captionRepresentation->GetCaptionActor2D()->SetCaption("VTK caption!");
        
        // 设置标题表示的锚点位置为拾取点的世界坐标。
        demo->captionRepresentation->SetAnchorPosition(world);
        
        // 设置标题控件的交互器、表示、选择性和可调整性。
        demo->captionWidget->SetInteractor(interactor);
        demo->captionWidget->SetRepresentation(demo->captionRepresentation);
        demo->captionWidget->SetSelectable(0);
        demo->captionWidget->SetResizable(0);
        demo->captionWidget->PickingManagedOff();
        demo->captionWidget->SetEnabled(1);
        
        // 设置标题控件的边框和文本属性。
        demo->captionWidget->GetCaptionActor2D()->SetBorder(1);
        demo->captionWidget->GetCaptionActor2D()->SetCaption(buffer);
        
        // 设置标题文本的垂直和水平对齐方式。
        demo->captionWidget->GetCaptionActor2D()->GetCaptionTextProperty()->SetVerticalJustificationToCentered();
        demo->captionWidget->GetCaptionActor2D()->GetCaptionTextProperty()->SetJustificationToCentered();
        
        // 设置标题控件边框的位置。
        demo->captionWidget->GetBorderRepresentation()->SetPosition(ratiox, ratioy);
        demo->captionWidget->GetBorderRepresentation()->SetPosition2(0.1, 0.05);
        
        // 设置标题控件的引导符号大小。
        demo->captionWidget->GetCaptionActor2D()->SetLeaderGlyphSize(0.01);
        
        // 输出引导符号大小到控制台。
        std::cout << "size: " << demo->captionWidget->GetCaptionActor2D()->GetLeaderGlyphSize() << std::endl;
    }
}

需要特别注意的是: vtkNew captionWidget; vtkNew captionRepresentation;定义这两个变量必须是全局的,否则无法显示。这个和之前博客中,显示坐标系是一样的,在头文件中定义全局变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leaf_csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值