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.

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:

Categories: VTK

0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
A prohibited operation
0
Would love your thoughts, please comment.x
()
x