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++

#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;
}