You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmRender/nmVTKPlanarPolygonLayer.cpp

180 lines
5.6 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmVTKPlanarPolygonLayer.h"
#include <QCoreApplication>
#include <QThread>
#include <vtkActor.h>
#include <vtkCellArray.h>
#include <vtkMath.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkSmartPointer.h>
namespace {
bool isPlanarPolygonLayerGuiThread()
{
// VTK Prop 和 Qt 视图的生命周期都由 GUI 线程统一管理。
QCoreApplication* pApplication = QCoreApplication::instance();
return pApplication == nullptr ||
pApplication->thread() == QThread::currentThread();
}
bool isFinitePoint(const QPointF& oPoint)
{
return vtkMath::IsFinite(oPoint.x()) &&
vtkMath::IsFinite(oPoint.y());
}
}
class nmVTKPlanarPolygonLayerPrivate
{
public:
nmVTKPlanarPolygonLayerPrivate()
: m_pPoints(vtkSmartPointer<vtkPoints>::New()),
m_pVertices(vtkSmartPointer<vtkCellArray>::New()),
m_pLines(vtkSmartPointer<vtkCellArray>::New()),
m_pPolyData(vtkSmartPointer<vtkPolyData>::New()),
m_pMapper(vtkSmartPointer<vtkPolyDataMapper>::New()),
m_pActor(vtkSmartPointer<vtkActor>::New()),
m_bClosed(false)
{
m_pPoints->SetDataTypeToDouble();
m_pPolyData->SetPoints(m_pPoints);
m_pPolyData->SetVerts(m_pVertices);
m_pPolyData->SetLines(m_pLines);
m_pMapper->SetInputData(m_pPolyData);
// 黄色点线只是业务覆盖层:不参与拾取,也不扩大相机自适应范围。
m_pActor->SetMapper(m_pMapper);
m_pActor->GetProperty()->SetColor(1.0, 1.0, 0.0);
m_pActor->GetProperty()->SetLineWidth(2.0f);
m_pActor->GetProperty()->SetPointSize(7.0f);
m_pActor->GetProperty()->LightingOff();
m_pActor->PickableOff();
m_pActor->UseBoundsOff();
}
vtkActor* getActor() const
{
return m_pActor;
}
bool setPolygon(const QVector<QPointF>& vecPoints, bool bClosed)
{
for(int nIndex = 0; nIndex < vecPoints.size(); ++nIndex) {
if(!isFinitePoint(vecPoints[nIndex])) {
return false;
}
}
// 先构建完整候选 PolyData,成功后再一次替换,避免视图看到半更新状态。
vtkSmartPointer<vtkPoints> pCandidatePoints =
vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkCellArray> pCandidateVertices =
vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkCellArray> pCandidateLines =
vtkSmartPointer<vtkCellArray>::New();
pCandidatePoints->SetDataTypeToDouble();
const vtkIdType nPointCount =
static_cast<vtkIdType>(vecPoints.size());
pCandidatePoints->SetNumberOfPoints(nPointCount);
for(vtkIdType nPointId = 0; nPointId < nPointCount; ++nPointId) {
const QPointF& oPoint = vecPoints[static_cast<int>(nPointId)];
pCandidatePoints->SetPoint(nPointId, oPoint.x(), oPoint.y(), 0.0);
pCandidateVertices->InsertNextCell(1, &nPointId);
}
const bool bCandidateClosed = bClosed && nPointCount >= 3;
if(nPointCount >= 2) {
// VTK 折线不会自动闭合,完成后需在索引尾部再写入首点。
const vtkIdType nLinePointCount =
nPointCount + (bCandidateClosed ? 1 : 0);
pCandidateLines->InsertNextCell(nLinePointCount);
for(vtkIdType nPointId = 0;
nPointId < nPointCount; ++nPointId) {
pCandidateLines->InsertCellPoint(nPointId);
}
if(bCandidateClosed) {
pCandidateLines->InsertCellPoint(0);
}
}
m_vecPoints = vecPoints;
m_bClosed = bCandidateClosed;
m_pPoints = pCandidatePoints;
m_pVertices = pCandidateVertices;
m_pLines = pCandidateLines;
m_pPolyData->SetPoints(m_pPoints);
m_pPolyData->SetVerts(m_pVertices);
m_pPolyData->SetLines(m_pLines);
m_pPolyData->Modified();
return true;
}
void clear()
{
setPolygon(QVector<QPointF>(), false);
}
vtkSmartPointer<vtkPoints> m_pPoints;
vtkSmartPointer<vtkCellArray> m_pVertices;
vtkSmartPointer<vtkCellArray> m_pLines;
vtkSmartPointer<vtkPolyData> m_pPolyData;
vtkSmartPointer<vtkPolyDataMapper> m_pMapper;
vtkSmartPointer<vtkActor> m_pActor;
QVector<QPointF> m_vecPoints;
bool m_bClosed;
};
nmVTKPlanarPolygonLayer::nmVTKPlanarPolygonLayer(
const QString& sLayerId)
: nmVTKRenderLayer(sLayerId),
m_pPrivate(new nmVTKPlanarPolygonLayerPrivate)
{
Q_ASSERT(isPlanarPolygonLayerGuiThread());
setRenderProp(m_pPrivate->getActor());
}
nmVTKPlanarPolygonLayer::~nmVTKPlanarPolygonLayer()
{
Q_ASSERT(isPlanarPolygonLayerGuiThread());
if(m_pPrivate != nullptr) {
detach();
delete m_pPrivate;
m_pPrivate = nullptr;
}
}
bool nmVTKPlanarPolygonLayer::setPolygon(
const QVector<QPointF>& vecPoints,
bool bClosed)
{
Q_ASSERT(isPlanarPolygonLayerGuiThread());
return isPlanarPolygonLayerGuiThread() && m_pPrivate != nullptr &&
m_pPrivate->setPolygon(vecPoints, bClosed);
}
void nmVTKPlanarPolygonLayer::clear()
{
Q_ASSERT(isPlanarPolygonLayerGuiThread());
if(isPlanarPolygonLayerGuiThread() && m_pPrivate != nullptr) {
m_pPrivate->clear();
}
}
QVector<QPointF> nmVTKPlanarPolygonLayer::getPoints() const
{
return m_pPrivate != nullptr
? m_pPrivate->m_vecPoints : QVector<QPointF>();
}
bool nmVTKPlanarPolygonLayer::isClosed() const
{
return m_pPrivate != nullptr && m_pPrivate->m_bClosed;
}