zoukankan      html  css  js  c++  java
  • [VTK]vtkAngleWidget角度测量设置point位置

    一.楔子

    这段时间一直有个问题没有解决就是在使用vtkAngleWidget的时候,想要在程序里面设置三个点的位置。

    因为测量角度时候一直需要手动去选择三个点然后触发事件,但在三维空间中想要在二维屏幕上设置准确三个

    点着实有点小蛋疼--!但是每次调用widget的setPosition时候发现会报错:null point 1 representation.

    然后...

    我果断忽略了,直接就百度、Google、bing各种但都没有找到合适的解答,在vtk user上找到有类似案例,

    http://vtk.1045678.n5.nabble.com/Re-How-to-initialize-vtkAngleWidget-with-three-points-specified-td3281326.html

    不过解决方案不明朗没有说清楚,否则如果照他们所说的我就都尝试过,且败了.

    后来终于百度了这个报错,当然百度是百不到的,于是google之,go到了vtk的源代码。

    http://stuff.mit.edu/afs/athena/course/16/16.225/dv/VTK/Widgets/vtkAngleRepresentation3D.cxx

    里面提到:

    void vtkAngleRepresentation3D::SetCenterWorldPosition(double x[3])
    {
       if (!this->CenterRepresentation)
        {
        vtkErrorMacro("SetCenterWorldPosition: null center representation");
        return;
        }
      this->CenterRepresentation->SetWorldPosition(x);
    }

    从代码里面可以看出在设置时候会先判断本身的成员CenterRepresentation是否为空,那么CenterRepresentation又是何方高人呢?

    继续Follow之,发现在vtkAngleRepresentation(抽象类)里面定义了四个成员变量:

    (注:源代码可以通过修改后缀在网上查看:如这里与上面的链接就只有后面的文件名不同的

    http://stuff.mit.edu/afs/athena/course/16/16.225/dv/VTK/Widgets/vtkAngleRepresentation3D.h

    // The handle and the rep used to close the handles
    vtkHandleRepresentation *HandleRepresentation;
    vtkHandleRepresentation *Point1Representation;
    vtkHandleRepresentation *CenterRepresentation;
    vtkHandleRepresentation *Point2Representation;

    但是在vtkAngleRepresentation3D.的构造函数里面只有:

      // By default, use one of these handles
      this->HandleRepresentation  = vtkPointHandleRepresentation3D::New();

    难怪会报那样的错呢--!

    (这里就不对以前自己完全忽略错误提示的行为...)

    2.解决方案

    我的粗劣的解决方案是自己继承一个vtkAngleRepresentation3D类,然后对其余的三个representation进行初始化,再在后面对他们进行修改即可。

    // GitPro.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <vtkCommand.h>
    #include <vtkRenderer.h>
    #include <vtkRenderWindow.h>
    #include <vtkSphereSource.h>
    #include <vtkRenderWindowInteractor.h>
    #include <vtkPolyData.h>
    #include <vtkPolyDataMapper.h>
    #include <vtkClipPolyData.h>
    #include <vtkActor.h>
    #include <vtkConeSource.h>
    #include <vtkPlane.h>
    #include <vtkImageActor.h>
    #include <vtkImplicitPlaneWidget2.h>
    #include <vtkAngleWidget.h>
    #include <vtkPlaneWidget.h>
    #include <vtkSmartPointer.h>
    #include <vtkImplicitPlaneRepresentation.h>
    #include <vtkAngleRepresentation3D.h>
    #include <vtkPointHandleRepresentation3D.h>
    #include <vtkInteractorStyleTrackballCamera.h>
    
    #define PLANE_LEFT
    
    class vtkAngleRepresentation3DWithPointRepresentation: public vtkAngleRepresentation3D
    {
        public:
         static vtkAngleRepresentation3DWithPointRepresentation *New()
         {
              return new vtkAngleRepresentation3DWithPointRepresentation;
         }
         void initialPointRepresentation()
         {
             this->Point1Representation = vtkPointHandleRepresentation3D::New();
             this->Point2Representation = vtkPointHandleRepresentation3D::New();
             this->CenterRepresentation = vtkPointHandleRepresentation3D::New();
         }
    };
    
    
    class VTKWidgetCall : public vtkCommand
    {
    public:
    
        static VTKWidgetCall *New()
        {
        return new VTKWidgetCall;
        }
    public:
        virtual void Execute(vtkObject *caller, unsigned long eventId, void *callData)
        {
            vtkImplicitPlaneWidget2 *pWidget = reinterpret_cast<vtkImplicitPlaneWidget2*>(caller);
            if (pWidget)
            {
                // update the clip plane and the second renderer
                 vtkImplicitPlaneRepresentation *rep = 
                 reinterpret_cast<vtkImplicitPlaneRepresentation*>(pWidget->GetRepresentation());
    
                vtkSmartPointer<vtkPlane> planeNew = vtkPlane::New();
                rep->GetPlane(planeNew);
            
                cliper->SetClipFunction(planeNew);
                cliper->Update();
    
                vtkSmartPointer<vtkPolyData> clipedData = vtkPolyData::New();
                clipedData->DeepCopy(cliper->GetOutput());
    
                vtkSmartPointer<vtkPolyDataMapper> coneMapper = vtkPolyDataMapper::New();
                coneMapper->SetInput(clipedData);
                actor->SetMapper(coneMapper);
    
                // calculate three point to place the angleWidget
                double* position1 = planeNew->GetOrigin();
                double  position2[3] = {position1[0], position1[1], position1[2] + 1};
                double  position3[3] = {position1[0], position1[1] + 1, position1[2]};
                // you can modify the 3 points like this(Notice:you need to use SetWorldPosition not SetDisplayPosition you could try and look)
                angleWidget->GetAngleRepresentation()->GetPoint1Representation()->SetWorldPosition(position1);
                angleWidget->GetAngleRepresentation()->GetPoint2Representation()->SetWorldPosition(position2);
                angleWidget->GetAngleRepresentation()->GetCenterRepresentation()->SetWorldPosition(position3);
                // There is a bug here, that the angle did not calculated or updated. But in my other 
                // test it act well. I don't know why...
            }
        }
        void setCliper(vtkSmartPointer<vtkClipPolyData> other){cliper = other;}
        void setPlane(vtkSmartPointer<vtkPlane> other){pPlane = other;}
        void setActor(vtkSmartPointer<vtkActor> other){actor = other;}
        void setAngleWidget(vtkSmartPointer<vtkAngleWidget> other){angleWidget = other;}
    private:
        vtkSmartPointer<vtkPlane> pPlane;
        vtkSmartPointer<vtkActor> actor;
        vtkSmartPointer<vtkClipPolyData> cliper;
        vtkSmartPointer<vtkAngleWidget> angleWidget;
    };
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        vtkSmartPointer<vtkSphereSource> sphereSource = 
        vtkSmartPointer<vtkSphereSource>::New();
        sphereSource->Update();
     
        // Create a mapper and actor
        vtkSmartPointer<vtkPolyDataMapper> mapper = 
        vtkSmartPointer<vtkPolyDataMapper>::New();
        mapper->SetInputConnection(sphereSource->GetOutputPort());
        vtkSmartPointer<vtkActor> actor = 
        vtkSmartPointer<vtkActor>::New();
     
        // A renderer and render window
        vtkSmartPointer<vtkRenderer> renderer = 
        vtkSmartPointer<vtkRenderer>::New();
        vtkSmartPointer<vtkRenderWindow> renderWindow = 
        vtkSmartPointer<vtkRenderWindow>::New();
        renderWindow->AddRenderer(renderer);
        renderer->SetBackground( 0.1, 0.2, 0.4 );
        renderer->SetViewport(0.0, 0.0, 0.5, 1.0);
        actor->SetMapper(mapper);
        renderer->AddActor(actor);
     
        // An interactor
        vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = 
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
        renderWindowInteractor->SetRenderWindow(renderWindow);
     
        vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = 
        vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
     
        renderWindowInteractor->SetInteractorStyle( style );
        double origin[3] = {0, 100, 0};
    
          vtkSmartPointer<vtkImplicitPlaneRepresentation> rep = 
        vtkSmartPointer<vtkImplicitPlaneRepresentation>::New();
        rep->SetPlaceFactor(1.25); // This must be set prior to placing the widget
        rep->PlaceWidget(actor->GetBounds());
        
        vtkSmartPointer<vtkImplicitPlaneWidget2> implicitPlaneWidget = vtkImplicitPlaneWidget2::New();
        implicitPlaneWidget->SetInteractor(renderWindowInteractor);
        implicitPlaneWidget->SetRepresentation(rep);
        /*this code set the default render of the planeWidget*/
        //implicitPlaneWidget->SetCurrentRenderer(renderer);
        vtkSmartPointer<vtkPlane> planeNew = vtkPlane::New();
        vtkSmartPointer<vtkClipPolyData> cliper = vtkClipPolyData::New();
        cliper->SetInput(sphereSource->GetOutput());
        cliper->SetClipFunction(planeNew);
        cliper->Update();
    
        vtkSmartPointer<vtkPolyData> clipedData = vtkPolyData::New();
        clipedData->DeepCopy(cliper->GetOutput());
    
        /*Codes below set the second renderer*/
        vtkSmartPointer<vtkConeSource> cone = vtkConeSource::New();
        cone->SetHeight( 3.0 );
        cone->SetRadius( 1.0 );
        cone->SetResolution( 10 );
        vtkSmartPointer<vtkPolyDataMapper> coneMapper = vtkPolyDataMapper::New();
        coneMapper->SetInput(clipedData);
        vtkSmartPointer<vtkActor> coneActor = vtkActor::New();
        coneActor->SetMapper( mapper );
    
        vtkSmartPointer<vtkRenderer> rRenderer = 
        vtkSmartPointer<vtkRenderer>::New();
        rRenderer->SetBackground( 0.2, 0.3, 0.5 );
        rRenderer->SetViewport(0.5, 0.0, 1.0, 1.0);
        rRenderer->AddActor(coneActor);
    
        renderWindow->AddRenderer(rRenderer);
        
    #ifdef PLANE_LEFT
        /*if you did not use implicitPlaneWidget->SetCurrentRenderer(renderer)
          then the default render of the plane is different with the loaction of this sentence。
          You could try and see. 
        */
        renderWindow->Render();
    #endif
        vtkSmartPointer<VTKWidgetCall> pCall = VTKWidgetCall::New();
        pCall->setPlane(planeNew);
        pCall->setActor(coneActor);
        pCall->setCliper(cliper);
        implicitPlaneWidget->AddObserver(vtkCommand::EndInteractionEvent, pCall);
        implicitPlaneWidget->On();
    
          vtkSmartPointer<vtkAngleRepresentation3DWithPointRepresentation> rep3D = vtkSmartPointer<vtkAngleRepresentation3DWithPointRepresentation>::New();
        vtkSmartPointer<vtkAngleWidget> angleWidget = vtkSmartPointer<vtkAngleWidget>::New();
        rep3D->initialPointRepresentation();
        angleWidget->SetRepresentation(rep3D);
        angleWidget->SetInteractor(renderWindowInteractor);
        //angleWidget->SetCurrentRenderer(rRenderer);
        angleWidget->On();
        pCall->setAngleWidget(angleWidget);
    
    #ifndef PLANE_LEFT
        renderWindow->Render();
    #endif
        renderWindowInteractor->Initialize();
        // Begin mouse interaction
        renderWindowInteractor->Start();
        return EXIT_SUCCESS;
    }

    上面代码做的有这样几件事:

    一:使用默认的model进行了显示

    二:设置了切割平面进行切割

    三:切割后结果显示在右边的第二个renderer里面

    四:添加了角度测量的widget进行测量

    五:当移动切割平面时候widget每次都会自动设置到与平面相关的一个位置(这个就是我这里想说明的东东)

    六:有个bug,就是在这个例子里面每次设置了位置后角度值并没有更新,而我另外一个例子(太乱的一个原始例子里面)其值是得到了更新的

          而在这里需要再对几个点移动一点点才会更新

    三:The end

    下面是结果图,第一组是初始化的手动设置的三个点;第二组是移动了切割平面后;第三组是手动再挪动了一下angleWidget的顶点更新角度值效果图



  • 相关阅读:
    基于《Hadoop权威指南 第三版》在Windows搭建Hadoop环境及运行第一个例子
    使用java发送HTTP请求
    关于centOS7的一些笔记
    关于netty的多个handler链式模式
    关于netty的简单实现
    EF---延迟加载技术
    Restful Api 最佳实践
    FlaskWeb开发
    python多线程/多进程
    Python网络编程
  • 原文地址:https://www.cnblogs.com/dawnWind/p/3D_10.html
Copyright © 2011-2022 走看看