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