# Error area picking with vtk and qt

**URL:** https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842
**Category:** Support
**Created:** [November 9, 2024, 2:32pm UTC](https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842 "2024-11-09T14:32:58Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![hjxy2012](https://discourse.vtk.org/user_avatar/discourse.vtk.org/hjxy2012/32/9334_2.png) [@hjxy2012](https://discourse.vtk.org/u/hjxy2012)
#### Post date: [November 9, 2024, 2:32pm UTC](https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842/1 "2024-11-09T14:32:58Z")

</div>

I am using Qt and VTK to select cells in my VTU file. However, the highlighted cells do not match the cells in the area picker. I tried converting the world coordinates of the selected cells to screen coordinates, but the bounding box of these screen coordinates differs from the bounding box of my area picker. My code is as follows.

```auto
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QVTKOpenGLNativeWidget.h>
#include <QFileDialog>
#include <vtkActor.h>
#include <vtkDataSetMapper.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkInteractorStyleRubberBand3D.h>
#include <vtkNew.h>
#include <vtkPolyData.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkUnstructuredGrid.h>
#include <vtkXMLUnstructuredGridReader.h>
#include <vtkHardwareSelector.h>
#include <vtkSelection.h>
#include <vtkExtractSelection.h>
#include <vtkCallbackCommand.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <qdebug.h>
#include <qpainter.h>
#include <qpen.h>
#include <vtkCamera.h>
#include <vtkCell.h>
#include <vtkCoordinate.h>
#include <vtkMath.h>

class CustomInteractorStyle : public vtkInteractorStyleRubberBand3D
{
public:
    static CustomInteractorStyle* New();
    vtkTypeMacro(CustomInteractorStyle, vtkInteractorStyleRubberBand3D);

    virtual void OnLeftButtonDown() override
    {
        // 记录起始点
        StartPosition[0] = this->Interactor->GetEventPosition()[0];
        StartPosition[1] = this->Interactor->GetEventPosition()[1];
        vtkInteractorStyleRubberBand3D::OnLeftButtonDown();
    }

    virtual void OnMouseMove() override
    {
        if (this->State == VTKIS_ROTATE)
        {
            // 更新选择框
            EndPosition[0] = this->Interactor->GetEventPosition()[0];
            EndPosition[1] = this->Interactor->GetEventPosition()[1];
        }
        vtkInteractorStyleRubberBand3D::OnMouseMove();
    }
};
vtkStandardNewMacro(CustomInteractorStyle);

class MainWindow : public QWidget
{
    Q_OBJECT

private:
    QRect lastSelectionRect;
    bool showDebugInfo = true;
public:
    MainWindow(QWidget* parent = nullptr) : QWidget(parent)
    {
        QVBoxLayout* layout = new QVBoxLayout(this);
        renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
        renderer = vtkSmartPointer<vtkRenderer>::New();
        renderWindow->AddRenderer(renderer);

        vtkWidget = new QVTKOpenGLNativeWidget(this);
        vtkWidget->setRenderWindow(renderWindow);

        selectButton = new QPushButton("Enter Selection Mode", this);

        layout->addWidget(vtkWidget);
        layout->addWidget(selectButton);
        setLayout(layout);
        resize(800, 600);

        interactor = vtkWidget->interactor();
        defaultStyle = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
        selectionStyle = vtkSmartPointer<CustomInteractorStyle>::New();
        selectionStyle->SetCurrentRenderer(renderer);
        interactor->SetInteractorStyle(defaultStyle);

        loadVTUFile();

        connect(selectButton, &QPushButton::clicked, this, &MainWindow::toggleSelectionMode);

        vtkNew<vtkCallbackCommand> selectionCallback;
        selectionCallback->SetCallback(
            [](vtkObject* caller, long unsigned int eventId, void* clientData, void* callData)
            {
                MainWindow* self = static_cast<MainWindow*>(clientData);
                self->processSelection();
            }
        );
        selectionCallback->SetClientData(this);
        selectionStyle->AddObserver(vtkCommand::SelectionChangedEvent, selectionCallback);
    }

private slots:
    void toggleSelectionMode()
    {
        if (interactor->GetInteractorStyle() == defaultStyle)
        {
            selectButton->setText("Exit Selection Mode");
            interactor->SetInteractorStyle(selectionStyle);
        }
        else
        {
            selectButton->setText("Enter Selection Mode");
            interactor->SetInteractorStyle(defaultStyle);
        }
    }

private:
    void loadVTUFile()
{
    reader = vtkSmartPointer<vtkXMLUnstructuredGridReader>::New();

    QString fileName =
        "path of my vtu.vtu";

    reader->SetFileName(fileName.toStdString().c_str());
    reader->Update();

    vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
    mapper->SetInputConnection(reader->GetOutputPort());

    mainActor = vtkSmartPointer<vtkActor>::New();
    mainActor->SetMapper(mapper);

    renderer->AddActor(mainActor);
    renderer->ResetCamera();

    renderer->SetBackground(0.2, 0.3, 0.4);
    renderWindow->Render();

    double bounds[6];
    reader->GetOutput()->GetBounds(bounds);

    qDebug() << "Model World Bounds:" << bounds[0] << bounds[1] << bounds[2] << bounds[3] << bounds[4] << bounds[5];

    vtkSmartPointer<vtkCoordinate> coordinate = vtkSmartPointer<vtkCoordinate>::New();
    coordinate->SetCoordinateSystemToWorld();

    int* winSize = renderWindow->GetSize();

    int minX = winSize[0], minY = winSize[1], maxX = 0, maxY = 0;
    for (int i = 0; i < 8; ++i)
    {
        double worldPos[3] = {
            bounds[i % 2],
            bounds[2 + (i / 2) % 2],
            bounds[4 + (i / 4) % 2]
        };
        coordinate->SetValue(worldPos);
        int* displayPos = coordinate->GetComputedDisplayValue(renderer);

        qDebug() << "World Pos:" << worldPos[0] << worldPos[1] << worldPos[2] << " -> Screen Pos:" << displayPos[0] << displayPos[1];

        if (displayPos[0] < minX) minX = displayPos[0];
        if (displayPos[0] > maxX) maxX = displayPos[0];
        if (displayPos[1] < minY) minY = displayPos[1];
        if (displayPos[1] > maxY) maxY = displayPos[1];
    }

    QRect modelBoundingBox(QPoint(minX, minY), QPoint(maxX, maxY));
    qDebug() << "Model Bounding Box on Screen:" << modelBoundingBox;
}

void processSelection()
{
    CustomInteractorStyle* style = CustomInteractorStyle::SafeDownCast(interactor->GetInteractorStyle());
    if (!style) return;

    int* startPos = style->GetStartPosition();
    int* endPos = style->GetEndPosition();
    int* winSize = renderWindow->GetSize();

    lastSelectionRect = QRect(QPoint(std::min(startPos[0], endPos[0]),
                                     std::min(startPos[1], endPos[1])),
                              QPoint(std::max(startPos[0], endPos[0]),
                                     std::max(startPos[1], endPos[1])));

    int x1 = std::min(startPos[0], endPos[0]);
    int x2 = std::max(startPos[0], endPos[0]);
    int y1 = winSize[1] - std::max(startPos[1], endPos[1]);
    int y2 = winSize[1] - std::min(startPos[1], endPos[1]);

    qDebug() << "Selection Process:";
    qDebug() << " Window Size:" << winSize[0] << winSize[1];
    qDebug() << " Original Selection:" << QPoint(startPos[0], startPos[1]) << QPoint(endPos[0], endPos[1]);
    qDebug() << " VTK Selection:" << QRect(x1, y1, x2 - x1, y2 - y1);

    vtkCamera* camera = renderer->GetActiveCamera();
    double viewAngle = camera->GetViewAngle();
    double* position = camera->GetPosition();
    double* focalPoint = camera->GetFocalPoint();
    double* viewUp = camera->GetViewUp();

    double viewDir[3] = {
        focalPoint[0] - position[0],
        focalPoint[1] - position[1],
        focalPoint[2] - position[2]
    };
    vtkMath::Normalize(viewDir);

    qDebug() << "Camera Information:";
    qDebug() << " Position:" << position[0] << position[1] << position[2];
    qDebug() << " View Direction:" << viewDir[0] << viewDir[1] << viewDir[2];
    qDebug() << " View Up:" << viewUp[0] << viewUp[1] << viewUp[2];

    vtkSmartPointer<vtkHardwareSelector> selector = vtkSmartPointer<vtkHardwareSelector>::New();
    selector->SetRenderer(renderer);
    selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_CELLS);
    selector->SetArea(x1, y1, x2, y2);

    vtkSmartPointer<vtkSelection> selection;
    try
    {
        renderWindow->Render();
        selection = selector->Select();
    }
    catch (const std::exception& e)
    {
        qDebug() << "Selection failed:" << e.what();
        return;
    }

    if (!selection || selection->GetNumberOfNodes() == 0)
    {
        qDebug() << "No elements selected";
        return;
    }

    vtkSmartPointer<vtkExtractSelection> extractSelection = vtkSmartPointer<vtkExtractSelection>::New();
    extractSelection->SetInputData(0, reader->GetOutput());
    extractSelection->SetInputData(1, selection);
    extractSelection->Update();

    vtkDataSet* selectedData = vtkDataSet::SafeDownCast(extractSelection->GetOutput());
    if (!selectedData || selectedData->GetNumberOfCells() == 0)
    {
        qDebug() << "No valid cells in selection";
        return;
    }

    vtkSmartPointer<vtkCoordinate> coordinate = vtkSmartPointer<vtkCoordinate>::New();
    coordinate->SetCoordinateSystemToWorld();

    int minX = winSize[0], minY = winSize[1], maxX = 0, maxY = 0;
    for (vtkIdType i = 0; i < selectedData->GetNumberOfCells(); ++i)
    {
        vtkCell* cell = selectedData->GetCell(i);
        for (vtkIdType j = 0; j < cell->GetNumberOfPoints(); ++j)
        {
            double worldPos[3];
            cell->GetPoints()->GetPoint(j, worldPos);
            coordinate->SetValue(worldPos);
            int* displayPos = coordinate->GetComputedDisplayValue(renderer);

            if (displayPos[0] < minX) minX = displayPos[0];
            if (displayPos[0] > maxX) maxX = displayPos[0];
            if (displayPos[1] < minY) minY = displayPos[1];
            if (displayPos[1] > maxY) maxY = displayPos[1];
        }
    }

    QRect selectedBoundingBox(QPoint(minX, minY), QPoint(maxX, maxY));
    qDebug() << "Selected Bounding Box:" << selectedBoundingBox;

    QRect adjustedSelectionRect = QRect(QPoint(x1, y1), QPoint(x2, y2));
    qDebug() << "Adjusted Selection Rect:" << adjustedSelectionRect;

    if (adjustedSelectionRect.contains(selectedBoundingBox))
    {
        qDebug() << "Selection is correct.";
    }
    else
    {
        qDebug() << "Selection is incorrect.";
    }

    vtkSmartPointer<vtkDataSetMapper> selectedMapper = vtkSmartPointer<vtkDataSetMapper>::New();
    selectedMapper->SetInputData(selectedData);

    vtkSmartPointer<vtkActor> selectedActor = vtkSmartPointer<vtkActor>::New();
    selectedActor->SetMapper(selectedMapper);
    selectedActor->GetProperty()->SetColor(1.0, 0.0, 0.0);
    selectedActor->GetProperty()->SetOpacity(0.7);
 
    renderer->RemoveActor(selectedActor);
    renderer->AddActor(selectedActor);
    renderWindow->Render();
}

    void paintEvent(QPaintEvent* event) override
    {
        QWidget::paintEvent(event);

        if (!showDebugInfo || lastSelectionRect.isNull())
            return;

        QPainter painter(this);
        painter.setPen(QPen(Qt::green, 2));

        QRect adjustedRect = QRect(lastSelectionRect.topLeft() + vtkWidget->pos(),
                                   lastSelectionRect.size());
        painter.drawRect(adjustedRect);
        painter.setPen(Qt::white);
        painter.drawText(10, 20, QString("Selection: (%1,%2) to (%3,%4)")
                                 .arg(lastSelectionRect.left())
                                 .arg(lastSelectionRect.top())
                                 .arg(lastSelectionRect.right())
                                 .arg(lastSelectionRect.bottom()));
    }

private:
    QVTKOpenGLNativeWidget* vtkWidget;
    QPushButton* selectButton;
    vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow;
    vtkSmartPointer<vtkRenderer> renderer;
    vtkSmartPointer<vtkRenderWindowInteractor> interactor;
    vtkSmartPointer<vtkInteractorStyleTrackballCamera> defaultStyle;
    vtkSmartPointer<CustomInteractorStyle> selectionStyle;
    vtkSmartPointer<vtkXMLUnstructuredGridReader> reader;
    vtkSmartPointer<vtkActor> mainActor;
};

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.show();
    return app.exec();
}

#include "testRectSelect.moc"

```

---

<div class="post-metadata">

### Author: ![Paulo\_Carvalho](https://discourse.vtk.org/user_avatar/discourse.vtk.org/paulo_carvalho/32/370_2.png) [@Paulo\_Carvalho](https://discourse.vtk.org/u/Paulo_Carvalho)
#### Post date: [November 19, 2024, 12:03pm UTC](https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842/2 "2024-11-19T12:03:06Z")

</div>

Hello,

Can you, please, post a screen cap to illustrate the issue?

best,

PC

---

<div class="post-metadata">

### Author: ![hjxy2012](https://discourse.vtk.org/user_avatar/discourse.vtk.org/hjxy2012/32/9334_2.png) [@hjxy2012](https://discourse.vtk.org/u/hjxy2012)
#### Post date: [November 20, 2024, 12:58am UTC](https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842/3 "2024-11-20T00:58:15Z")

</div>

> [@hjxy2012](#):
>
> ```auto
> QVTKOpenGLNativeWidget* vtkWidget;
> QPushButton* selectButton;
> vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow;
> vtkSmartPointer<vtkRenderer> renderer;
> vtkSmartPointer<vtkRenderWindowInteractor> interactor;
> vtkSmartPointer<vtkInteractorStyleTrackballCamera> defaultStyle;
> vtkSmartPointer<CustomInteractorStyle> selectionStyle;
> vtkSmartPointer<vtkXMLUnstructuredGridReader> reader;
> vtkSmartPointer<vtkActor> mainActor;
> 
> ```

Thank you for your reply. Just like this

---

<div class="post-metadata">

### Author: ![hjxy2012](https://discourse.vtk.org/user_avatar/discourse.vtk.org/hjxy2012/32/9334_2.png) [@hjxy2012](https://discourse.vtk.org/u/hjxy2012)
#### Post date: [November 20, 2024, 1:22am UTC](https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842/4 "2024-11-20T01:22:22Z")

</div>

Thank you. The video added.

---

<div class="post-metadata">

### Author: ![Paulo\_Carvalho](https://discourse.vtk.org/user_avatar/discourse.vtk.org/paulo_carvalho/32/370_2.png) [@Paulo\_Carvalho](https://discourse.vtk.org/u/Paulo_Carvalho)
#### Post date: [November 21, 2024, 1:53pm UTC](https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842/5 "2024-11-21T13:53:17Z")

</div>

Hello,

You’re creating a second actor with coincident geometry to render the selection. So, there is likely z-fighting or depth-fighting going on between the model and the selection actors. Please, take a look at this: [Visualization failed when display two polygon in the same time - Support - VTK](https://discourse.vtk.org/t/visualization-failed-when-display-two-polygon-in-the-same-time/10397) . Particularly, see this post: [Visualization failed when display two polygon in the same time - #9 by zhang-qiang-github](https://discourse.vtk.org/t/visualization-failed-when-display-two-polygon-in-the-same-time/10397/9) (`map2` in that post is a `vtkMapper`).

best,

PC

---

<div class="post-metadata">

### Author: ![hjxy2012](https://discourse.vtk.org/user_avatar/discourse.vtk.org/hjxy2012/32/9334_2.png) [@hjxy2012](https://discourse.vtk.org/u/hjxy2012)
#### Post date: [November 26, 2024, 1:51am UTC](https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842/6 "2024-11-26T01:51:22Z")

</div>

Thank you for your reply. I tried using the `SetResolveCoincidentTopologyPolygonOffsetParameters` method, which only improved the display effect, but the selected cells are still not the ones I boxed. I tried writing these selected cells to a VTU file and found that these cells are consistent with the highlighted cells above. So, the current problem is that the boxed cells are not within the box, rather than a display issue.

---

<div class="post-metadata">

### Author: ![hjxy2012](https://discourse.vtk.org/user_avatar/discourse.vtk.org/hjxy2012/32/9334_2.png) [@hjxy2012](https://discourse.vtk.org/u/hjxy2012)
#### Post date: [November 26, 2024, 3:22am UTC](https://discourse.vtk.org/t/error-area-picking-with-vtk-and-qt/14842/7 "2024-11-26T03:22:36Z")

</div>

If I use a 3D plane, the selection and highlighting of cells are normal. But if I use other complex 3D models, the selection and highlighting of cells are incorrect. Below is the operation video and my code.

```auto
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QVTKOpenGLNativeWidget.h>
#include <QFileDialog>
#include <vtkActor.h>
#include <vtkDataSetMapper.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkInteractorStyleRubberBand3D.h>
#include <vtkNew.h>
#include <vtkPolyData.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkUnstructuredGrid.h>
#include <vtkXMLUnstructuredGridReader.h>
#include <vtkXMLUnstructuredGridWriter.h>
#include <vtkHardwareSelector.h>
#include <vtkSelection.h>
#include <vtkExtractSelection.h>
#include <vtkCallbackCommand.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <qdebug.h>
#include <qpainter.h>
#include <vtkCamera.h>
#include <vtkMath.h>

class CustomInteractorStyle : public vtkInteractorStyleRubberBand3D
{
public:
    static CustomInteractorStyle *New();
    vtkTypeMacro(CustomInteractorStyle, vtkInteractorStyleRubberBand3D);

    virtual void OnLeftButtonDown() override
    {
        StartPosition[0] = this->Interactor->GetEventPosition()[0];
        StartPosition[1] = this->Interactor->GetEventPosition()[1];
        vtkInteractorStyleRubberBand3D::OnLeftButtonDown();
    }

    virtual void OnMouseMove() override
    {
        EndPosition[0] = this->Interactor->GetEventPosition()[0];
        EndPosition[1] = this->Interactor->GetEventPosition()[1];
        vtkInteractorStyleRubberBand3D::OnMouseMove();
    }
};
vtkStandardNewMacro(CustomInteractorStyle);

class MainWindow : public QWidget
{
    Q_OBJECT

private:
    QRect lastSelectionRect;
    bool showDebugInfo = true;
    vtkSmartPointer<vtkActor> previousSelectedActor;
    bool isSelecting = false;

public:
    MainWindow(QWidget *parent = nullptr) : QWidget(parent)
    {
        QVBoxLayout *layout = new QVBoxLayout(this);
        renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
        renderer = vtkSmartPointer<vtkRenderer>::New();
        renderWindow->AddRenderer(renderer);

        vtkWidget = new QVTKOpenGLNativeWidget(this);
        vtkWidget->setRenderWindow(renderWindow);

        selectButton = new QPushButton("Enter Selection Mode", this);

        layout->addWidget(vtkWidget);
        layout->addWidget(selectButton);
        setLayout(layout);
        resize(800, 600);

        interactor = vtkWidget->interactor();
        defaultStyle = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
        selectionStyle = vtkSmartPointer<CustomInteractorStyle>::New();
        selectionStyle->SetCurrentRenderer(renderer);
        interactor->SetInteractorStyle(defaultStyle);

        loadVTUFile();

        connect(selectButton, &QPushButton::clicked, this, &MainWindow::toggleSelectionMode);

        vtkNew<vtkCallbackCommand> selectionCallback;
        selectionCallback->SetCallback(
            [](vtkObject *caller, long unsigned int eventId, void *clientData, void *callData)
            {
                MainWindow *self = static_cast<MainWindow *>(clientData);
                self->processSelection();
            });
        selectionCallback->SetClientData(this);
        selectionStyle->AddObserver(vtkCommand::SelectionChangedEvent, selectionCallback);
    }

private slots:
    void toggleSelectionMode()
    {
        if (interactor->GetInteractorStyle() == defaultStyle)
        {
            selectButton->setText("Exit Selection Mode");
            interactor->SetInteractorStyle(selectionStyle);
            isSelecting = true;
        }
        else
        {
            selectButton->setText("Enter Selection Mode");
            interactor->SetInteractorStyle(defaultStyle);
            isSelecting = false;
        }
    }

private:
    void loadVTUFile()
    {
        reader = vtkSmartPointer<vtkXMLUnstructuredGridReader>::New();
        QString fileName =
            "path to my vtu file";
        
        reader->SetFileName(fileName.toStdString().c_str());
        reader->Update();

        vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
        mapper->SetInputConnection(reader->GetOutputPort());
        mapper->SetResolveCoincidentTopologyToPolygonOffset();
        mapper->SetResolveCoincidentTopologyPolygonOffsetParameters(0, 0);

        mainActor = vtkSmartPointer<vtkActor>::New();
        mainActor->SetMapper(mapper);

        renderer->AddActor(mainActor);

        vtkCamera *camera = renderer->GetActiveCamera();
        camera->SetViewUp(0, 1, 0);
        camera->SetPosition(2344.01, -740.319, 1496.1);
        camera->SetFocalPoint(2344.01, -740.319, 0);

        renderer->ResetCamera();
        renderer->ResetCameraClippingRange();
        renderer->SetBackground(0.2, 0.3, 0.4);

        renderWindow->Render();

        double bounds[6];
        reader->GetOutput()->GetBounds(bounds);
        qDebug() << "Model World Bounds:" << bounds[0] << bounds[1] << bounds[2] << bounds[3] << bounds[4] << bounds[5];
    }

    QList<vtkSmartPointer<vtkActor>> selectedActors;

    void clearSelectedActors()
    {
        for (auto actor : selectedActors)
        {
            renderer->RemoveActor(actor);
        }
        selectedActors.clear();
        if (previousSelectedActor)
        {
            renderer->RemoveActor(previousSelectedActor);
            previousSelectedActor = nullptr;
        }
        renderWindow->Render();
    }

    void processSelection()
    {
        clearSelectedActors();

        CustomInteractorStyle *style = CustomInteractorStyle::SafeDownCast(interactor->GetInteractorStyle());
        if (!style)
            return;

        int *startPos = style->GetStartPosition();
        int *endPos = style->GetEndPosition();

        int x1 = std::min(startPos[0], endPos[0]);
        int x2 = std::max(startPos[0], endPos[0]);
        int y1 = std::min(startPos[1], endPos[1]);
        int y2 = std::max(startPos[1], endPos[1]);

        vtkSmartPointer<vtkHardwareSelector> selector = vtkSmartPointer<vtkHardwareSelector>::New();
        selector->SetRenderer(renderer);
        selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_CELLS);
        selector->SetArea(x1, y1, x2, y2);

        renderWindow->SwapBuffersOff();
        renderWindow->Render();

        vtkSmartPointer<vtkSelection> selection;
        try
        {
            selection = selector->Select();
        }
        catch (const std::exception &e)
        {
            qDebug() << "Selection failed:" << e.what();
            renderWindow->SwapBuffersOn();
            return;
        }
        renderWindow->SwapBuffersOn();

        if (!selection || selection->GetNumberOfNodes() == 0)
        {
            qDebug() << "No elements selected";
            return;
        }

        vtkSmartPointer<vtkExtractSelection> extractSelection = vtkSmartPointer<vtkExtractSelection>::New();
        extractSelection->SetInputData(0, reader->GetOutput());
        extractSelection->SetInputData(1, selection);
        extractSelection->Update();

        vtkUnstructuredGrid *selectedData = vtkUnstructuredGrid::SafeDownCast(extractSelection->GetOutput());
        if (!selectedData || selectedData->GetNumberOfCells() == 0)
        {
            qDebug() << "No valid cells in selection";
            return;
        }

        vtkSmartPointer<vtkDataSetMapper> selectedMapper = vtkSmartPointer<vtkDataSetMapper>::New();
        selectedMapper->SetInputData(selectedData);
        selectedMapper->SetResolveCoincidentTopologyToPolygonOffset();
        selectedMapper->SetResolveCoincidentTopologyPolygonOffsetParameters(1, 1);

        vtkSmartPointer<vtkActor> selectedActor = vtkSmartPointer<vtkActor>::New();
        selectedActor->SetMapper(selectedMapper);
        selectedActor->GetProperty()->SetColor(1.0, 0.0, 0.0);
        selectedActor->GetProperty()->SetRepresentationToWireframe();
        selectedActor->GetProperty()->SetLineWidth(2);
        selectedActor->GetProperty()->SetOpacity(0.7);

        selectedActors.append(selectedActor);
        renderer->AddActor(selectedActor);
        renderWindow->Render();
    }

private:
    QVTKOpenGLNativeWidget *vtkWidget;
    QPushButton *selectButton;
    vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow;
    vtkSmartPointer<vtkRenderer> renderer;
    vtkSmartPointer<vtkRenderWindowInteractor> interactor;
    vtkSmartPointer<vtkInteractorStyleTrackballCamera> defaultStyle;
    vtkSmartPointer<CustomInteractorStyle> selectionStyle;
    vtkSmartPointer<vtkXMLUnstructuredGridReader> reader;
    vtkSmartPointer<vtkActor> mainActor;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.show();
    return app.exec();
}

#include "testRectSelect.moc"

```
