I’m learning how to use fast pre-select with VTK. I learned that using the SetSelection method of the Mapper class can effectively use the data in the buffer for fast selection. I wrote a demo, but I met some problems.
The process of this demo is : I showed a PlaneSource in vtkWindow, then I wrote a class inherited from vtkInteractorStyleTrackballCamera. The HardwareSelector’s GenerateSelection method is executed when OnMouseMove event occurs. The vtkSelection object returned is then passed to the mapper of PlaneSource by SetSelection method.
Most of the time, the demo worked fine, but when A cell was already selected, and I moved the mouse over the selected red border, an error occurred. Hardwareselector selects unit 0 in the lower left corner.
Here is my code.
Apologize for my confusing code logic, because I wanted to quickly switch between the two methods of selections using a #define statement.
#include <vtkExtractSelection.h>
#include <vtkNew.h>
#include <vtkPointSource.h>
#include <vtkPolyData.h>
#include <vtkSelectionNode.h> // for POINT and INDICES enum values
#include <vtkSelectionSource.h>
#include <vtkMapper.h>
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkRenderView.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkMapper.h>
#include <vtkInteractorStyle.h>
#include <vtkInteractorStyleRubberBand3D.h>
#include <vtkInteractorObserver.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkAxesActor.h>
#include <vtkLookupTable.h>
#include <vtkScalarBarActor.h>
#include <vtkTextProperty.h>
#include <vtkProperty2D.h>
#include <vtkCaptionActor2D.h>
#include <vtkRendererCollection.h>
#include <vtkWindowToImageFilter.h>
#include <vtkPNGWriter.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QVTKOpenGLNativeWidget.h>
#include <vtkWin32OpenGLRenderWindow.h>
#include <vtkCallbackCommand.h>
#include <vtkTextActor.h>
#include <vtkOutputWindow.h>
#include <vtkDataSetMapper.h>
#include <vtkProperty.h>
#include <vtkPolyDataMapper.h>
#include <vtkHardwareSelector.h>
#include <vtkSphereSource.h>
#include <vtkCellData.h>
#include <vtkPlaneSource.h>
#include <vtkCubeSource.h>
#include <vtkImageProcessingPass.h>
#include <vtkOpenGLHardwareSelector.h>
#include <vtkOpenGLPolyDataMapper.h>
#include <vtkSynchronizedRenderers.h>
#define USEFASTPRESELECT
namespace
{
class customMouseInteractorStyle : public vtkInteractorStyleTrackballCamera
{
public:
static customMouseInteractorStyle* New();
vtkTypeMacro(customMouseInteractorStyle, vtkInteractorStyleTrackballCamera);
vtkRenderer* renderer;
vtkActor* actor;
vtkOpenGLPolyDataMapper* mappeer_;
vtkDataSetMapper* dsmapper_;
vtkExtractSelection* extract_;
std::vector<double> time;
bool MakingSelection = false;
int PreviouseSwapBuffers;
vtkNew<vtkOpenGLHardwareSelector> cell_selector_;
virtual void OnLeftButtonDown() override
{
std::cout << renderer->GetActiveCamera()->GetPosition()[0] <<" " <<renderer->GetActiveCamera()->GetPosition()[1] << " " <<renderer->GetActiveCamera()->GetPosition()[2] << std::endl;
std::cout << renderer->GetActiveCamera()->GetFocalPoint()[0] <<" " <<renderer->GetActiveCamera()->GetFocalPoint()[1] << " " <<renderer->GetActiveCamera()->GetFocalPoint()[2] << std::endl;
// Forward events
// Disable window rotating/ moving
vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
}
virtual void OnMiddleButtonDown() override
{
std::cout << "Pressed middle mouse button." << std::endl;
// Forward events
// // Disable window rotating/ moving
vtkInteractorStyleTrackballCamera::OnMiddleButtonDown();
}
virtual void OnRightButtonDown() override
{
std::cout << "Pressed right mouse button." << std::endl;
// Forward events
// // Disable window rotating/ moving
vtkInteractorStyleTrackballCamera::OnRightButtonDown();
}
bool PrepareSelect(int fieldAssociation)
{
if (this->MakingSelection)
{
//return false;
}
this->MakingSelection = true;
#ifdef USEFASTPRESELECT
this->PreviouseSwapBuffers = this->renderer->GetRenderWindow()->GetSwapBuffers();
this->renderer->GetRenderWindow()->SwapBuffersOff();
//this->mappeer_->SetSelection(nullptr);
//this->mappeer_->Modified();
//this->renderer->GetRenderWindow()->Render();
//this->renderer->Render();
#endif // USEFASTPRESELECT
this->cell_selector_->SetRenderer(renderer);
this->cell_selector_->SetFieldAssociation(fieldAssociation);
return true;
}
virtual void OnMouseMove() override
{
if (!this->PrepareSelect(vtkDataObject::FIELD_ASSOCIATION_CELLS))
{
return;
}
//mappeer_->SetSelection(nullptr);
//Get the time of capturebuffers.
std::clock_t start_select = clock();
unsigned int last_position[2] = { 0,0 };
memcpy(last_position, this->GetInteractor()->GetLastEventPosition(), sizeof(int) * 2);
cell_selector_->SetArea(last_position[0], last_position[1], last_position[0], last_position[1]);
cell_selector_->Modified();
cell_selector_->SetUseProcessIdFromData(true);
//renderer->SetDraw(false);
if (cell_selector_->CaptureBuffers())
{
if (vtkActor::SafeDownCast(cell_selector_->GetPixelInformation(last_position).Prop)) {
int temp_mesh_id = vtkActor::SafeDownCast(cell_selector_->GetPixelInformation(last_position).Prop)->GetMapper()->GetArrayId();
int temp_cell_id = cell_selector_->GetPixelInformation(last_position, 0).AttributeID;
cout << temp_mesh_id << " " << temp_cell_id << endl;
}
std::clock_t mid_select = clock();
//if (cell_selector_->GetPixelInformation(last_position).Valid) {
int cell_id = -1;
int mesh_id = -1;
vtkSmartPointer<vtkSelection> sel;
sel.TakeReference(cell_selector_->GenerateSelection(last_position[0], last_position[1], last_position[0], last_position[1]));
this->renderer->Render();
if (sel->GetNumberOfNodes() != 0)
{
cout << "Get sth." << endl;
#ifdef USEFASTPRESELECT
//renderer->SetDraw(false);
if (mappeer_->GetSelection() == nullptr)
{
mappeer_->SetSelection(sel);
mappeer_->Modified();
}
else
{
mappeer_->GetSelection()->ShallowCopy(sel);
//mappeer_->SetSelection(selectionSource->GetOutput());
//mappeer_->Modified();
}
this->renderer->GetRenderWindow()->SwapBuffersOn();
this->renderer->GetRenderWindow()->Render();
vtkInteractorStyleTrackballCamera::OnMouseMove();
std::clock_t end_select = clock();
if (time.size() < 9)
{
time.push_back((double)(end_select - mid_select) / CLOCKS_PER_SEC);
}
else
{
time.push_back((double)(end_select - mid_select) / CLOCKS_PER_SEC);
double ave_time = 0;
for (auto& pertime : time)
{
ave_time += pertime;
}
ave_time = ave_time / 10;
std::cout << (double)(mid_select - start_select) / CLOCKS_PER_SEC << " " << ave_time << endl;
time.clear();
}
//renderer->SetDraw(true);
this->MakingSelection = false;
this->renderer->GetRenderWindow()->SetSwapBuffers(this->PreviouseSwapBuffers);
return;
#else
extract_->SetInputData(1, sel);
extract_->Modified();
extract_->Update();
this->renderer->GetRenderWindow()->SwapBuffersOn();
//dsmapper_->SetInputConnection(extract_->GetOutputPort());
//dsmapper_->Modified();
this->renderer->GetRenderWindow()->Render();
vtkInteractorStyleTrackballCamera::OnMouseMove();
std::clock_t end_select = clock();
if (time.size() < 9)
{
time.push_back((double)(end_select - start_select) / CLOCKS_PER_SEC);
}
else
{
time.push_back((double)(end_select - start_select) / CLOCKS_PER_SEC);
double ave_time = 0;
for (auto& pertime : time)
{
ave_time += pertime;
}
ave_time = ave_time / 10;
std::cout << ave_time << endl;
time.clear();
}
//renderer->SetDraw(true);
return;
#endif
}
//}
}
#ifdef USEFASTPRESELECT
//if (mappeer_->GetSelection() != nullptr)
//{
mappeer_->GetSelection()->RemoveAllNodes();
mappeer_->GetSelection()->Modified();
this->renderer->GetRenderWindow()->Render();
//}
#endif // USEFASTPRESELECT
vtkInteractorStyleTrackballCamera::OnMouseMove();
}
};
vtkStandardNewMacro(customMouseInteractorStyle);
}
int main(int, char*[])
{
// Note - this generates 50 points and a single poly-vertex cell.
//vtkNew<vtkSphereSource> spheresource;
vtkNew<vtkPlaneSource> spheresource;
//vtkNew<vtkCubeSource> spheresource;
spheresource->SetResolution(10, 10);
//spheresource->SetPhiResolution(700);
//spheresource->SetThetaResolution(700);
spheresource->Modified();
spheresource->Update();
cout << spheresource->GetOutput()->GetNumberOfCells() << endl;
/*vtkNew<vtkSelectionSource> selectionSource;
selectionSource->SetFieldType(vtkSelectionNode::POINT);
selectionSource->SetContentType(vtkSelectionNode::INDICES);
// Without this line, all points are passed through because the 11 points
// we will select below are some of the points of the poly-vertex created
// by the PointSource, so the cell (by default) gets passed through since
// it contains some selected points, so therefore all of the points
// (the 50 belonging to the poly-vertex) also get passed through, which
// is not what we are trying to demonstrate.
selectionSource->SetContainingCells(false);
for (vtkIdType i = 10; i <= 20; i++)
{
selectionSource->AddID(0, i);
}
selectionSource->Update();
*/
vtkNew<vtkOpenGLPolyDataMapper> mapper;
mapper->SetInputConnection(spheresource->GetOutputPort());
mapper->SetArrayId(1);
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
//actor->GetProperty()->SetEdgeVisibility(true);
//actor->GetProperty()->SetLineWidth(20);
//actor->GetProperty()->SetSelectionLineWidth(20);
//actor->GetProperty()->EdgeVisibilityOn();
#ifdef USEFASTPRESELECT
actor->GetProperty()->SetSelectionColor(1, 0, 0, 1);
actor->GetProperty()->SetSelectionPointSize(20);
//actor->GetProperty()->SetSelectionLineWidth(80);
actor->GetProperty()->SetPointSize(5);
#endif // USEFASTPRESELECT
//actor->GetProperty()->RenderPointsAsSpheresOn();
vtkNew<vtkRenderer> renderer;
renderer->AddActor(actor);
renderer->SetBackground(0,0,0);
vtkNew<vtkRenderWindow> rwin;
rwin->AddRenderer(renderer);
//mapper->SetSelection(selectionSource->GetOutput());
mapper->Modified();
vtkNew<vtkRenderWindowInteractor> rwinin;
rwin->SetInteractor(rwinin);
//rwin->SetSize(640, 480);
rwin->SetWindowName("UGrid)");
renderer->GetActiveCamera()->SetPosition(0, 0, 0.0603645);
renderer->GetActiveCamera()->SetFocalPoint(0, 0, 0);
rwin->FullScreenOn();
vtkNew<customMouseInteractorStyle> rwinstyle;
rwinstyle->renderer = renderer;
#ifdef USEFASTPRESELECT
rwinstyle->mappeer_ = mapper;
rwinstyle->actor = actor;
#endif
#ifndef USEFASTPRESELECT
vtkNew<vtkExtractSelection> extractselection;
extractselection->SetInputConnection(spheresource->GetOutputPort());
rwinstyle->extract_ = extractselection;
vtkNew<vtkDataSetMapper> selmapper;
selmapper->SetInputConnection(extractselection->GetOutputPort());
rwinstyle->dsmapper_ = selmapper;
vtkNew<vtkActor> selactor;
selactor->SetMapper(selmapper);
selactor->GetProperty()->SetRepresentationToWireframe();
selactor->GetProperty()->SetColor(0,0,1);
selactor->SetPickable(false);
renderer->AddActor(selactor);
#endif // !USEFASTPRESELECT
rwin->Render();
rwinin->SetInteractorStyle(rwinstyle);
vtkNew<vtkHardwareSelector> cell_selector_;
cell_selector_->SetArea(0,0,1920,1080);
cell_selector_->SetRenderer(renderer);
cell_selector_->Modified();
cell_selector_->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_CELLS);
cell_selector_->CaptureBuffers();
//Get the number of visible cells
/*
* std::vector<int> cellids;
for (int i = 0; i < 1920; i++)
{
for (int j = 0; j < 1080; j++)
{
//cout << i << " " << j << endl;
//Get the number of visible cells
unsigned int pos[2] = { i,j };
if (cell_selector_->GetPixelInformation(pos).Valid) {
int cell_id = -1;
int mesh_id = -1;
if (vtkActor::SafeDownCast(cell_selector_->GetPixelInformation(pos).Prop)) {
cell_id = cell_selector_->GetPixelInformation(pos, 0).AttributeID;
mesh_id = cell_selector_->GetPixelInformation(pos, 0).PropID;
}
if (cell_id != -1 && cell_id != 0 && (std::find(cellids.begin(), cellids.end(), cell_id) == cellids.end()))
{
cellids.push_back(cell_id);
}
}
}
}
cout << "There are " << cellids.size() << " Cells " << endl;
*/
if (actor->GetSupportsSelection()) cout << "Support Selection" << endl;
rwinin->Start();
return EXIT_SUCCESS;
}