Skip to content

vtkBrokenLineWidget

1 vtkBrokenLineWidget介绍

vtkBrokenLineWidget**定义了一个用于操纵折线的**Widget
该**Widget**定义了可以交互地放置在场景中的虚线。虚线具有手柄,可以更改其数量,还可以在虚线本身上拾取它以在场景中平移或旋转它。该对象的一个​​不错的功能是vtkBrokenLineWidget像任何**Widget**一样,都可以使用当前的交互器样式。也就是说,如果vtkBrokenLineWidget不处理事件,则所有其他已注册观察者(包括交互器样式)都有机会处理事件。否则,vtkBrokenLineWidget将终止其处理的事件的处理。
默认交互:
1)向下按住鼠标左键并拖动球形手柄之一以更改虚线的形状:这些手柄充当“控制点”。
2)在线段上按下左键可以移动widget。
3)ctrl+鼠标中键实现围绕它本身旋转
4)鼠标右键按下后上下移动启用自身缩放(滚轮则是全局整体缩放)。
5)ctrl+鼠标右键删除点(最少保留两个)
6)增加控制点 sheft+鼠标右键

2 vtkBrokenLineWidget官方案例

绑定了下**vtkBrokenLineWidget**的回调函数。移动点后,在右侧画出几个点以及检测线上穿过的 mesh 一并画出来。可以作为一个选择器。

#include "vtkSmartPointer.h"
#include "vtkActor.h"
#include "vtkBrokenLineWidget.h"
#include "vtkCamera.h"
#include "vtkCommand.h"
#include "vtkDataSetMapper.h"
#include "vtkExtractSelection.h"
#include "vtkInformation.h"
#include "vtkLinearSelector.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProgrammableFilter.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkTextActor.h"
#include "vtkTextProperty.h"
#include "vtkUnstructuredGrid.h"
#include "vtkUnstructuredGridReader.h"
#include <vtkSTLReader.h>
#include <sstream>

// Callback for the broken line widget interaction
class vtkBLWCallback : public vtkCommand {
  public:
    static vtkBLWCallback *New() {
        return new vtkBLWCallback;
    }
    void Execute(vtkObject *caller, unsigned long, void *) override {
        // Retrieve polydata line
        vtkBrokenLineWidget *line = reinterpret_cast<vtkBrokenLineWidget *>(caller);
        line->GetPolyData(Poly);
        // Update linear extractor with current points
        this->Selector->SetPoints(Poly->GetPoints());
        // Update selection from mesh
        this->Extractor->Update();
        vtkMultiBlockDataSet *outMB = vtkMultiBlockDataSet::SafeDownCast(this->Extractor->GetOutput());
        vtkUnstructuredGrid *selection = vtkUnstructuredGrid::SafeDownCast(outMB->GetBlock(0));
        this->Mapper->SetInputData(selection);
        // Update cardinality of selection
        std::ostringstream txt;
        txt << "Number of selected elements: " << (selection ? selection->GetNumberOfCells() : 0);
        this->Text->SetInput(txt.str().c_str());
    }
    vtkBLWCallback()
        : Poly(nullptr)
        , Selector(nullptr)
        , Extractor(nullptr)
        , Mapper(nullptr)
        , Text(nullptr) {
    }
    vtkPolyData *Poly;
    vtkLinearSelector *Selector;
    vtkExtractSelection *Extractor;
    vtkDataSetMapper *Mapper;
    vtkTextActor *Text;
};

int main(int argc, char *argv[]) {
    // Create render window and interactor
    vtkSmartPointer<vtkRenderWindow> win = vtkSmartPointer<vtkRenderWindow>::New();
    win->SetMultiSamples(0);
    win->SetSize(600, 300);
    vtkSmartPointer<vtkRenderWindowInteractor> iren =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    iren->SetRenderWindow(win);
    iren->Initialize();
    // Create 2 viewports in window
    vtkSmartPointer<vtkRenderer> ren1 = vtkSmartPointer<vtkRenderer>::New();
    ren1->SetBackground(.4, .4, .4);
    ren1->SetBackground2(.8, .8, .8);
    ren1->GradientBackgroundOn();
    ren1->SetViewport(0., 0., .5, 1.);
    win->AddRenderer(ren1);
    vtkSmartPointer<vtkRenderer> ren2 = vtkSmartPointer<vtkRenderer>::New();
    ren2->SetBackground(1., 1., 1.);
    ren2->SetViewport(.5, 0., 1., 1.);
    win->AddRenderer(ren2);
    // Create a good view angle
    vtkCamera *camera = ren1->GetActiveCamera();
    camera->SetFocalPoint(.12, 0., 0.);
    camera->SetPosition(.38, .3, .15);
    camera->SetViewUp(0., 0., 1.);
    ren2->SetActiveCamera(camera);
    // Read 3D unstructured input mesh
    // char *fileName = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/AngularSector.vtk");
    vtkSmartPointer<vtkUnstructuredGridReader> reader =
        vtkSmartPointer<vtkUnstructuredGridReader>::New();
    reader->SetFileName("tmp.vtk");
//    delete[] fileName;
    reader->Update();
    // Create mesh actor to be rendered in viewport 1
    vtkSmartPointer<vtkDataSetMapper> meshMapper = vtkSmartPointer<vtkDataSetMapper>::New();
    meshMapper->SetInputConnection(reader->GetOutputPort());
    vtkSmartPointer<vtkActor> meshActor = vtkSmartPointer<vtkActor>::New();
    meshActor->SetMapper(meshMapper);
    meshActor->GetProperty()->SetColor(.23, .37, .17);
    meshActor->GetProperty()->SetRepresentationToWireframe();
    ren1->AddActor(meshActor);
    // Create multi-block mesh for linear extractor
    reader->Update();
    vtkUnstructuredGrid *mesh = reader->GetOutput();
    vtkSmartPointer<vtkMultiBlockDataSet> meshMB = vtkSmartPointer<vtkMultiBlockDataSet>::New();
    meshMB->SetNumberOfBlocks(1);
    meshMB->GetMetaData(static_cast<unsigned>(0))->Set(vtkCompositeDataSet::NAME(), "Mesh");
    meshMB->SetBlock(0, mesh);
    // Create broken line widget, attach it to input mesh
    vtkSmartPointer<vtkBrokenLineWidget> line = vtkSmartPointer<vtkBrokenLineWidget>::New();
    line->SetInteractor(iren);
    line->SetInputData(mesh);
    line->SetPriority(1.);
    line->KeyPressActivationOff();
    line->PlaceWidget();
    line->ProjectToPlaneOff();
    line->On();
    line->SetHandleSizeFactor(1.2);
    // Create list of points to define broken line
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    points->InsertNextPoint(.23, .0, .0);
    points->InsertNextPoint(.0, .0, .0);
    points->InsertNextPoint(.23, .04, .04);
    line->InitializeHandles(points);
    // Extract polygonal line and then its points
    vtkSmartPointer<vtkPolyData> linePD = vtkSmartPointer<vtkPolyData>::New();
    line->GetPolyData(linePD);
    vtkSmartPointer<vtkPolyDataMapper> lineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    lineMapper->SetInputData(linePD);
    vtkSmartPointer<vtkActor> lineActor = vtkSmartPointer<vtkActor>::New();
    lineActor->SetMapper(lineMapper);
    lineActor->GetProperty()->SetColor(1., 0., 0.);
    lineActor->GetProperty()->SetLineWidth(2.);
    ren2->AddActor(lineActor);
    // Create selection along broken line defined by list of points
    vtkSmartPointer<vtkLinearSelector> selector = vtkSmartPointer<vtkLinearSelector>::New();
    selector->SetInputData(meshMB);
    selector->SetPoints(points);
    selector->IncludeVerticesOff();
    selector->SetVertexEliminationTolerance(1.e-12);
    // Extract selection from mesh
    vtkSmartPointer<vtkExtractSelection> extractor = vtkSmartPointer<vtkExtractSelection>::New();
    extractor->SetInputData(0, meshMB);
    extractor->SetInputConnection(1, selector->GetOutputPort());
    extractor->Update();
    vtkMultiBlockDataSet *outMB = vtkMultiBlockDataSet::SafeDownCast(extractor->GetOutput());
    vtkUnstructuredGrid *selection = vtkUnstructuredGrid::SafeDownCast(outMB->GetBlock(0));
    // Create selection actor
    vtkSmartPointer<vtkDataSetMapper> selMapper = vtkSmartPointer<vtkDataSetMapper>::New();
    selMapper->SetInputData(selection);
    vtkSmartPointer<vtkActor> selActor = vtkSmartPointer<vtkActor>::New();
    selActor->SetMapper(selMapper);
    selActor->GetProperty()->SetColor(0., 0., 0.);
    selActor->GetProperty()->SetRepresentationToWireframe();
    ren2->AddActor(selActor);
    // Annotate with number of elements
    vtkSmartPointer<vtkTextActor> txtActor = vtkSmartPointer<vtkTextActor>::New();
    std::ostringstream txt;
    txt << "Number of selected elements: " << (selection ? selection->GetNumberOfCells() : 0);
    txtActor->SetInput(txt.str().c_str());
    txtActor->SetTextScaleModeToViewport();
    txtActor->SetNonLinearFontScale(.2, 18);
    txtActor->GetTextProperty()->SetColor(0., 0., 1.);
    txtActor->GetTextProperty()->SetFontSize(18);
    ren2->AddActor(txtActor);
    // Invoke callback on polygonal line to interactively select elements
    vtkSmartPointer<vtkBLWCallback> cb = vtkSmartPointer<vtkBLWCallback>::New();
    cb->Poly = linePD;
    cb->Selector = selector;
    cb->Extractor = extractor;
    cb->Mapper = selMapper;
    cb->Text = txtActor;
    line->AddObserver(vtkCommand::InteractionEvent, cb);
    // Render and test
    win->Render();
    iren->Start();
    return 0;
}

3 vtkBrokenLineWidget 常用函数

// 初始位置 
// 第一种根据vtkBrokenLineWidget 放置的actor来确定、第二三种根据自己定义两个对角来确定
 void PlaceWidget() override
    {this->Superclass::PlaceWidget();}
 void PlaceWidget(double bounds[6]) override;
 void PlaceWidget(double xmin, double xmax, double ymin, double ymax,double zmin, double zmax) override

// 把widget投影到正交平面上,这类widget使用方式基本都一样。就一个投影到某一平面,搞了这么多接口,方便使用。下边这个分不清无所谓,使用前测试下那个合适就可以了,其实就是x、y、z、正交、任意。
virtual void vtkBrokenLineWidget::SetProjectToPlane(vtkTypeBool)    
virtual vtkTypeBool vtkBrokenLineWidget::GetProjectToPlane()    
virtual void vtkBrokenLineWidget::ProjectToPlaneOn()    
virtual void vtkBrokenLineWidget::ProjectToPlaneOff()   
void vtkBrokenLineWidget::SetPlaneSource(vtkPlaneSource*plane)  
virtual void vtkBrokenLineWidget::SetProjectionNormal(int)  
virtual int vtkBrokenLineWidget::GetProjectionNormal()  
void vtkBrokenLineWidget::SetProjectionNormalToXAxes()  
void vtkBrokenLineWidget::SetProjectionNormalToYAxes()
void vtkBrokenLineWidget::SetProjectionNormalToZAxes()  
void vtkBrokenLineWidget::SetProjectionNormalToOblique()
void vtkBrokenLineWidget::SetProjectionPosition(double position)    
virtual double vtkBrokenLineWidget::GetProjectionPosition() 

// 获取直线(几个点的坐标)
void vtkBrokenLineWidget::GetPolyData(vtkPolyData*pd)   

// 设置手柄属性 前两个是未选择属性、后两个是选择属性
virtual void vtkBrokenLineWidget::SetHandleProperty(vtkProperty * ) 
virtual vtkProperty* vtkBrokenLineWidget::GetHandleProperty()   
virtual void vtkBrokenLineWidget::SetSelectedHandleProperty(vtkProperty *)  
virtual vtkProperty* vtkBrokenLineWidget::GetSelectedHandleProperty()   


// 设置折线属性 前两个是未选择属性、后两个是选择属性
virtual void vtkBrokenLineWidget::SetLineProperty(vtkProperty *)    
virtual vtkProperty* vtkBrokenLineWidget::GetLineProperty() 
virtual void vtkBrokenLineWidget::SetSelectedLineProperty(vtkProperty *)    
virtual vtkProperty* vtkBrokenLineWidget::GetSelectedLineProperty() 

// 设置控制点  数量和位置
virtual void vtkBrokenLineWidget::SetNumberOfHandles(int npts)
virtual int vtkBrokenLineWidget::GetNumberOfHandles(
void vtkBrokenLineWidget::SetHandlePosition(int handle,double x,double y,double z)  
void vtkBrokenLineWidget::SetHandlePosition(int handle,double xyz[3])   
void vtkBrokenLineWidget::GetHandlePosition(int handle,double xyz[3])   
double* vtkBrokenLineWidget::GetHandlePosition(int handle)  
// 直接用 vtkPoints初始化点数量
void vtkBrokenLineWidget::InitializeHandles(vtkPoints *points)  

// 各个折线长度总和
double vtkBrokenLineWidget::GetSummedLength()   

// 开启关闭 widget选择功能  关闭后点和折线都显示,只是无法调整位置
virtual void vtkBrokenLineWidget::SetProcessEvents(vtkTypeBool) 
virtual vtkTypeBool vtkBrokenLineWidget::GetProcessEvents() 
virtual void vtkBrokenLineWidget::ProcessEventsOn() 
virtual void vtkBrokenLineWidget::ProcessEventsOff()    

// 控制点尺寸(默认值1.0)
virtual void vtkBrokenLineWidget::SetHandleSizeFactor(double)   
virtual double vtkBrokenLineWidget::GetHandleSizeFactor()   

4 vtkBrokenLineWidget 使用技巧

4.1 vtkBrokenLineWidget 绑定回调函数

class vtkBLWCallback : public vtkCommand {
  public:
    static vtkBLWCallback *New() {
        return new vtkBLWCallback;
    }
    void Execute(vtkObject *caller, unsigned long, void *) override {
        // Retrieve polydata line
        vtkBrokenLineWidget *line = reinterpret_cast<vtkBrokenLineWidget *>(caller);
        line->GetPolyData(Poly);
        // Update linear extractor with current points
        this->Selector->SetPoints(Poly->GetPoints());
        // Update selection from mesh
        this->Extractor->Update();
        vtkMultiBlockDataSet *outMB = vtkMultiBlockDataSet::SafeDownCast(this->Extractor->GetOutput());
        vtkUnstructuredGrid *selection = vtkUnstructuredGrid::SafeDownCast(outMB->GetBlock(0));
        this->Mapper->SetInputData(selection);
        // Update cardinality of selection
        std::ostringstream txt;
        txt << "Number of selected elements: " << (selection ? selection->GetNumberOfCells() : 0);
        this->Text->SetInput(txt.str().c_str());
    }
    vtkBLWCallback()
        : Poly(nullptr)
        , Selector(nullptr)
        , Extractor(nullptr)
        , Mapper(nullptr)
        , Text(nullptr) {
    }
    vtkPolyData *Poly;
    vtkLinearSelector *Selector;
    vtkExtractSelection *Extractor;
    vtkDataSetMapper *Mapper;
    vtkTextActor *Text;
};
    vtkSmartPointer<vtkBLWCallback> cb = vtkSmartPointer<vtkBLWCallback>::New();
    line->AddObserver(vtkCommand::InteractionEvent, cb);

4.2 vtkBrokenLineWidget 投影到某一个平面

这个比较实用,就是每次需要的投影平面比较难找,自己测试下就可以。

virtual void vtkBrokenLineWidget::SetProjectToPlane(vtkTypeBool)    
virtual vtkTypeBool vtkBrokenLineWidget::GetProjectToPlane()    
virtual void vtkBrokenLineWidget::ProjectToPlaneOn()    
virtual void vtkBrokenLineWidget::ProjectToPlaneOff()   
void vtkBrokenLineWidget::SetPlaneSource(vtkPlaneSource*plane)  
virtual void vtkBrokenLineWidget::SetProjectionNormal(int)  
virtual int vtkBrokenLineWidget::GetProjectionNormal()  
void vtkBrokenLineWidget::SetProjectionNormalToXAxes()  
void vtkBrokenLineWidget::SetProjectionNormalToYAxes()
void vtkBrokenLineWidget::SetProjectionNormalToZAxes()  
void vtkBrokenLineWidget::SetProjectionNormalToOblique()
void vtkBrokenLineWidget::SetProjectionPosition(double position)    
virtual double vtkBrokenLineWidget::GetProjectionPosition() 

4.3 设置控制点 数量和位置

可以逐个设置,如果设置了数量,为初始化则那几个点会重叠放在(0,0,0)

// 设置控制点  数量和位置
virtual void vtkBrokenLineWidget::SetNumberOfHandles(int npts)
virtual int vtkBrokenLineWidget::GetNumberOfHandles(
void vtkBrokenLineWidget::SetHandlePosition(int handle,double x,double y,double z)  
void vtkBrokenLineWidget::SetHandlePosition(int handle,double xyz[3])   
void vtkBrokenLineWidget::GetHandlePosition(int handle,double xyz[3])   
double* vtkBrokenLineWidget::GetHandlePosition(int handle)  
// 直接用 vtkPoints初始化点数量
void vtkBrokenLineWidget::InitializeHandles(vtkPoints *points)
    vtkNew<vtkBrokenLineWidget> line;
    line->SetInteractor(iren);
    line->SetInputData(mesh);
    line->SetPriority(1.);
    line->KeyPressActivationOff();
    line->PlaceWidget();
    line->ProjectToPlaneOff();
    line->On();
    line->SetHandleSizeFactor(1.2);
    // Create list of points to define broken line
    vtkNew<vtkPoints> points ;
    points->InsertNextPoint(.23, .0, .0);
    points->InsertNextPoint(.0, .0, .0);
    points->InsertNextPoint(.23, .04, .04);
    line->InitializeHandles(points);

4.4 修改控制点尺寸

默认控制点尺寸为1.0

    vtkNew<vtkBrokenLineWidget> line;
    line->SetHandleSizeFactor(1.2);

4.5 vtkBrokenLineWidget 修改交互属性(顶点、折线)

    vtkNew<vtkBrokenLineWidget> line;
    vtkProperty *pr = line->GetHandleProperty();
    vtkProperty *spr = line->GetSelectedHandleProperty();
    pr->SetColor(1, 0, 0);
    spr->SetColor(0, 0, 1);

// 设置手柄属性 前两个是未选择属性、后两个是选择属性
virtual void vtkBrokenLineWidget::SetHandleProperty(vtkProperty * ) 
virtual vtkProperty* vtkBrokenLineWidget::GetHandleProperty()   
virtual void vtkBrokenLineWidget::SetSelectedHandleProperty(vtkProperty *)  
virtual vtkProperty* vtkBrokenLineWidget::GetSelectedHandleProperty()   
// 设置折线属性 前两个是未选择属性、后两个是选择属性
virtual void vtkBrokenLineWidget::SetLineProperty(vtkProperty *)    
virtual vtkProperty* vtkBrokenLineWidget::GetLineProperty() 
virtual void vtkBrokenLineWidget::SetSelectedLineProperty(vtkProperty *)    
virtual vtkProperty* vtkBrokenLineWidget::GetSelectedLineProperty()

4.6 vtkBrokenLineWidget 当前折线长度 当前点坐标

放在回调函数里或者触发获取槽函数。

void vtkBrokenLineWidget::GetPolyData(vtkPolyData*pd)
double vtkBrokenLineWidget::GetSummedLength()