Let’s add three items to the render window. Draw a rectangle and pick all actors in the rectangle. The class vtkAreaPicker can help us to find these picked actors. I will show how to do it in the following code snippet.

area pick

main.cpp

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkHull.h>
#include <vtkProperty.h>
#include <vtkCamera.h>
#include <vtkPlane.h>
#include <vtkSTLReader.h>

#include "Point.hpp"
#include "CustomIteractorStyle.h"

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();

using namespace std;

vtkSmartPointer<vtkRenderer> renderer;
vtkSmartPointer<vtkCamera> camera;

int main()
{
    setbuf( stdout, nullptr );

    // ============ add sphere ==========
    vtkSPtrNew( sphereReader, vtkXMLPolyDataReader );
    sphereReader->SetFileName( "sphere.vtp" );
    sphereReader->Update();

    vtkSPtrNew( sphereMapper, vtkPolyDataMapper );
    sphereMapper->SetInputData( sphereReader->GetOutput() );

    vtkSPtrNew( sphereActor, vtkActor );
    sphereActor->SetMapper( sphereMapper );
    // ============ add cone ============
    vtkSPtrNew( coneReader, vtkXMLPolyDataReader );
    coneReader->SetFileName( "cone.vtp" );
    coneReader->Update();

    vtkSPtrNew( coneMapper, vtkPolyDataMapper );
    coneMapper->SetInputData( coneReader->GetOutput() );

    vtkSPtrNew( coneActor, vtkActor );
    coneActor->SetMapper( coneMapper );
    // ============ add Cylinder ============
    vtkSPtrNew( cylinderReader, vtkXMLPolyDataReader );
    cylinderReader->SetFileName( "cylinder.vtp" );
    cylinderReader->Update();

    vtkSPtrNew( cylinderMapper, vtkPolyDataMapper );
    cylinderMapper->SetInputData( cylinderReader->GetOutput() );

    vtkSPtrNew( cylinderActor, vtkActor );
    cylinderActor->SetMapper( cylinderMapper );

    renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor( sphereActor );
    renderer->AddActor( coneActor );
    renderer->AddActor( cylinderActor );
    renderer->SetBackground( 0, 0, 0 );

    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( renderer );
    renderWindow->SetSize( 600, 400 );

    vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
    renderWindowInteractor->SetRenderWindow( renderWindow );

    vtkSPtrNew( iteractorStyle, CustomIteractorStyle );
    iteractorStyle->Setm_Renderer( renderer );
    iteractorStyle->SetInteractor( renderWindowInteractor );
    iteractorStyle->Setm_RendererWindow( renderWindow );
    iteractorStyle->PushActor( sphereActor );
    iteractorStyle->PushActor( coneActor );
    iteractorStyle->PushActor( cylinderActor );
    iteractorStyle->InitPicker();

    renderWindowInteractor->SetInteractorStyle( iteractorStyle );
    renderer->ResetCamera();
    renderWindow->Render();

    renderWindowInteractor->Start();
    return 0;
}

CustomIteractorStyle.h

#pragma once

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkActor.h>
#include <vtkActor2D.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTransform.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkHull.h>
#include <vtkProperty.h>
#include <vtkCamera.h>
#include <vtkPlane.h>
#include <vtkAreaPicker.h>
#include <vector>

#include "Point.hpp"

#define CPP_SET_MACRO(name,type) \
  void Set##name(type _arg) \
  { \
    if (this->name != _arg) \
    { \
    this->name = _arg; \
    } \
  }

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();

class CustomIteractorStyle: public vtkInteractorStyleTrackballCamera
{
public:
    static CustomIteractorStyle *New(){ return new CustomIteractorStyle(); }
    void OnMouseWheelForward() override;
    void OnMouseWheelBackward() override;
    void OnLeftButtonDown() override;
    void OnLeftButtonUp() override;
    void OnMouseMove() override;
    void PushActor( vtkActor *actor );
    void InitPicker();

    CPP_SET_MACRO( m_Renderer, vtkRenderer* )
    CPP_SET_MACRO( m_RendererWindow, vtkRenderWindow* )

protected:
    void DrawRectangle();

    CustomIteractorStyle();
    ~CustomIteractorStyle() override;
    vtkSmartPointer<vtkActor2D> m_2DRectActor;
    vtkRenderer *m_Renderer;
    vtkRenderWindow *m_RendererWindow;
    vtkSmartPointer<vtkActorCollection> m_Actors;
    vtkSmartPointer<vtkAreaPicker> m_AreaPicker;
    Point m_LastPt;
    bool m_IsDrawing;
};

CustomIteractorStyle.cpp

#include "CustomIteractorStyle.h"
#include <vtkCoordinate.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty2D.h>
#include <vtkFeatureEdges.h>
#include <vtkProp3DCollection.h>
#include <vtkCallbackCommand.h>

void PickCallbackFunction(vtkObject* caller,
                          long unsigned int vtkNotUsed(eventId),
                          void* vtkNotUsed(clientData),
                          void* vtkNotUsed(callData))
{
    std::cout << "Pick." << std::endl;
    vtkAreaPicker* areaPicker = static_cast<vtkAreaPicker*>(caller);
    vtkProp3DCollection* props = areaPicker->GetProp3Ds();
    props->InitTraversal();
    for (vtkIdType i = 0; i < props->GetNumberOfItems(); i++)
    {
        vtkProp3D* prop = props->GetNextProp3D();
        std::cout << "Picked prop: " << prop << std::endl;
    }
}

void CustomIteractorStyle::OnMouseWheelForward()
{
    vtkInteractorStyleTrackballCamera::OnMouseWheelForward();
}

void CustomIteractorStyle::OnMouseWheelBackward()
{
    vtkInteractorStyleTrackballCamera::OnMouseWheelBackward();
}

void CustomIteractorStyle::OnLeftButtonDown()
{
    int *eventPos = this->Interactor->GetEventPosition();
    m_LastPt = Point( eventPos[0], eventPos[1], 0 );
    m_IsDrawing = true;

    m_Actors->InitTraversal();
    m_AreaPicker->InitializePickList();
    vtkActor *actor = m_Actors->GetNextItem();
    while( nullptr != actor )
    {
        m_AreaPicker->AddPickList( actor );
        actor = m_Actors->GetNextItem();
    }
    m_AreaPicker->PickFromListOn();
}

/*
*   The interface contains four cornor points.
*   0   3
*   1   2
*/
void CustomIteractorStyle::OnLeftButtonUp()
{
    DrawRectangle();
    m_IsDrawing = false;

    int *eventPos = this->Interactor->GetEventPosition();
    Point pt0 = m_LastPt;
    Point pt1( eventPos[0], eventPos[1], 0 );
    double bds[4] = { min(pt0[0], pt1[0]), max(pt0[0], pt1[0]), min(pt0[1], pt1[1]), max(pt0[1], pt1[1]) };

    this->Interactor->StartPickCallback();
    m_AreaPicker->AreaPick( bds[0], bds[2], bds[1], bds[3], m_Renderer );
    this->Interactor->EndPickCallback();
}

void CustomIteractorStyle::OnMouseMove()
{
    vtkInteractorStyleTrackballCamera::OnMouseMove();
    DrawRectangle();
}

void CustomIteractorStyle::PushActor(vtkActor *actor)
{
    m_Actors->AddItem( actor );
}

void CustomIteractorStyle::DrawRectangle()
{
    if( !m_IsDrawing )
    {
        return ;
    }

    int *eventPos = this->Interactor->GetEventPosition();
    Point pt0 = m_LastPt;
    Point pt1( eventPos[0], eventPos[1], 0 );

    std::vector<Point> displayPoints{ pt0, pt1 };
    if( displayPoints[0][0] > displayPoints[1][0] )
    {
        swap( displayPoints[0], displayPoints[1] );
    }

    Point points[4];
    points[0] = displayPoints[0];
    points[1] = Point(displayPoints[0][0], displayPoints[1][1], displayPoints[0][2]);
    points[2] = displayPoints[1];
    points[3] = Point(displayPoints[1][0], displayPoints[0][1], displayPoints[0][2]);

    vtkSPtrNew(pdPoints, vtkPoints);
    for (int i = 0; i < 4; ++i)
    {
        pdPoints->InsertNextPoint(points[i].point);
    }
    vtkSPtrNew(pdCells, vtkCellArray);
    for (int i = 0; i < 4; ++i)
    {
        vtkIdType line[2] = { i, (i + 1) % 4 };
        pdCells->InsertNextCell(2, line);
    }
    vtkSPtrNew(polydata, vtkPolyData);
    polydata->SetPoints(pdPoints);
    polydata->SetLines(pdCells);
    polydata->Modified();

    m_2DRectActor->GetMapper()->SetInputDataObject( polydata );
    m_Renderer->AddActor2D( m_2DRectActor );

    m_RendererWindow->Render();
}

void CustomIteractorStyle::InitPicker()
{
    this->Interactor->SetPicker( m_AreaPicker );
    vtkSmartPointer<vtkCallbackCommand> pickCallback = vtkSmartPointer<vtkCallbackCommand>::New();
    pickCallback->SetCallback( PickCallbackFunction );
    m_AreaPicker->AddObserver( vtkCommand::EndPickEvent, pickCallback );
}

CustomIteractorStyle::CustomIteractorStyle()
{
    m_Renderer = nullptr;
    m_2DRectActor = vtkSmartPointer<vtkActor2D>::New();

    vtkSmartPointer<vtkCoordinate> coordinateIns =
       vtkSmartPointer<vtkCoordinate>::New();
    coordinateIns->SetCoordinateSystemToDisplay();

    vtkSmartPointer<vtkPolyDataMapper2D> mapper2D =
       vtkSmartPointer<vtkPolyDataMapper2D>::New();
    mapper2D->SetTransformCoordinate(coordinateIns);
    m_2DRectActor->GetProperty()->SetColor( 1, 0, 0 );
    m_2DRectActor->SetMapper( mapper2D );

    m_Actors = vtkSmartPointer<vtkActorCollection>::New();
    m_AreaPicker = vtkSmartPointer<vtkAreaPicker>::New();
    m_IsDrawing = false;
}

CustomIteractorStyle::~CustomIteractorStyle()
{
}

But how to find the actors in the rectangle, I mean the actors that the whole body is in the picking rectangle.

Here is my solution. Expand the rectangle a little, and regard the point on the new boundary as pick position to try to find the picked actor. If the model being tested can be picked by the point on the new boundary, it indicates that the actor is out from the original rectangle.

CustomIteractorStyle *g_StylePtr = nullptr;

void PickCallbackFunction(vtkObject* caller,
                          long unsigned int vtkNotUsed(eventId),
                          void* vtkNotUsed(clientData),
                          void* vtkNotUsed(callData))
{
    std::cout << "Pick: " << std::endl;
    vtkAreaPicker* areaPicker = static_cast<vtkAreaPicker*>(caller);
    vtkProp3DCollection* props = areaPicker->GetProp3Ds();
    props->InitTraversal();
    for (vtkIdType i = 0; i < props->GetNumberOfItems(); i++)
    {
        vtkProp3D* prop = props->GetNextProp3D();
        if( g_StylePtr->TestInRectangle( (vtkActor *)prop ) )
        {
            g_StylePtr->PrintActorName( prop );
            //std::cout << "Picked prop: " << prop << std::endl;
        }
    }
}

bool CustomIteractorStyle::TestInRectangle(vtkActor *actor)
{
    vtkPoints *pts = ((vtkPolyDataMapper2D *)m_2DRectActor->GetMapper())->GetInput()->GetPoints();
    Point leftTop( pts->GetPoint( 0 ) );
    Point rightBottom( pts->GetPoint( 2 ) );
    if( (rightBottom - leftTop).Length() < 1e-6 )
    {
        return false;
    }

    int offset = 1;
    leftTop[0] -= offset;
    leftTop[1] += offset;
    rightBottom[0] += offset;
    rightBottom[1] -= offset;
    Point leftBottom( leftTop[0], rightBottom[1], 0 );
    Point rightTop( rightBottom[0], leftTop[1], 0 );
    vtkSmartPointer<vtkPoints> testPts =
            vtkSmartPointer<vtkPoints>::New();
    testPts->InsertNextPoint( leftTop.point );
    Point vec = leftBottom - leftTop;
    for( int i = 1; i <= 99; ++i )
    {
        Point newPt = leftTop + vec*i/100.0;
        testPts->InsertNextPoint( newPt.point );
    }
    testPts->InsertNextPoint( leftBottom.point );
    vec = rightBottom - leftBottom;
    for( int i = 1; i <= 99; ++i )
    {
        Point newPt = leftBottom + vec*i/100.0;
        testPts->InsertNextPoint( newPt.point );
    }
    testPts->InsertNextPoint( rightBottom.point );
    vec = rightTop - rightBottom;
    for( int i = 1; i <= 99; ++i )
    {
        Point newPt = rightBottom + vec*i/100.0;
        testPts->InsertNextPoint( newPt.point );
    }
    testPts->InsertNextPoint( rightTop.point );
    vec = leftTop - rightTop;
    for( int i = 1; i <= 99; ++i )
    {
        Point newPt = rightTop + vec*i/100.0;
        testPts->InsertNextPoint( newPt.point );
    }

    vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();
    picker->AddPickList( actor );
    picker->PickFromListOn();

    bool result = true;
    for( int i = 0; i < testPts->GetNumberOfPoints(); ++i )
    {
        double *pt = testPts->GetPoint( i );
        picker->Pick( pt[0], pt[1], 0, m_Renderer );
        if( nullptr != picker->GetActor() )
        {
            result = false;
            break;
        }
    }

    return result;
}

void CustomIteractorStyle::PrintActorName(vtkProp3D *actor)
{
    m_Actors->InitTraversal();
    if( m_Actors->GetItemAsObject( 0 ) == actor )
    {
        cout << "sphere\n";
    }
    if( m_Actors->GetItemAsObject( 1 ) == actor )
    {
        cout << "cone\n";
    }
    if( m_Actors->GetItemAsObject( 2 ) == actor )
    {
        cout << "cylinder\n";
    }
}

result:

in pick
Categories: VTK

0 0 votes
Article Rating
Subscribe
Notify of
guest

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Charles
Charles
2 years ago

Hi,but where is the Point.hpp ?

XML To JSON
: Input your strings, the tool can convert XML to JSON for you.

X
2
0
Would love your thoughts, please comment.x
()
x