LidarView源码分析(十五)lqLidarCoreManager类

本文介绍了lqLidarCoreManager类,它是LidarView的基础控制类,包含了初始化Python解析器、渲染视图管理、相机设置、数据保存以及与Paraview交互等功能。文章详细描述了类的构造、析构、单例模式实现以及与PythonShell的相关操作。
摘要由CSDN通过智能技术生成

简介

lqLidarCoreManager类是LidarView的基本控制类,其基类是QObject。功能由:初始化并启动python解析器、创建渲染视图、显示隐藏距离网格、camera(视角)设置、保存数据(调用对应的保存类)、获取paraview服务指针、获取主窗口、恢复默认设置。‘

该类是lqLidarViewManager的基类。lqLidarViewManager中只实现了部分python启动的功能,然后调用lqLidarCoreManager中的pythonStartup进行完整初始化。

lqLidarViewManager类在vvMainWindow构造函数中创建,并传入vvMainWindow的this指针,由vvMainWindow进行内存管理。在vvMainWindow类中,多次调用了lqLidarViewManager单例模式进行LidarView的基本控制。

头文件

头文件比较简单,根据功能的不同,声明了不同类型的函数种函。具体函数在源文件代码中进行注释。

/**
 * @class lqLidarCoreManager
 * @brief Base Class for LidarView-based app singleton manager.
 *
 */
class LQAPPLICATIONCOMPONENTS_EXPORT lqLidarCoreManager : public QObject
{

  Q_OBJECT

public:
  lqLidarCoreManager(QObject* parent = nullptr);
  virtual ~lqLidarCoreManager();

  // Return the singleton instance, Derived class should return the same and cast it.
  static lqLidarCoreManager* instance();

  // Python Shell related
  void schedulePythonStartup();
  void setPythonShell(pqPythonShell* pythonShell);
  pqPythonShell* getPythonShell();
  void runPython(const QString& statements);
  void forceShowShell();

  // Main render view Creation
  void createMainRenderView();

  // Convenience methods
  static pqServer* getActiveServer();
  static QWidget* getMainWindow();

  // WIP Those are common to all ParaView-based Apps, it may change in the future
  static void saveFramesToPCAP(vtkSMSourceProxy* proxy,
    int startFrame,
    int endFrame,
    const QString& filename);

  static void saveFramesToLAS(vtkLidarReader* reader,
    vtkPolyData* position,
    int startFrame,
    int endFrame,
    const QString& filename,
    int positionMode);

public Q_SLOTS:
  // Perform delayed python shell startup
  virtual void pythonStartup();

  void onEnableCrashAnalysis(bool crashAnalysisEnabled);

  void onCloseAllData();
  void onResetDefaultSettings();

  void onMeasurementGrid(bool gridVisible);

  void onResetCameraLidar();
  void onResetCameraToForwardView();
  void onResetCenterToLidarCenter();

private:
  Q_DISABLE_COPY(lqLidarCoreManager)
  static QPointer<lqLidarCoreManager> Instance;

  class pqInternal;
  pqInternal* Internal;

  pqPythonShell* pythonShell;
};

#endif // LQLIDARCOREMANAGER_H

源文件

instance

单例模式调用接口,Instance指针会在lqLidarCoreManager构造函数中进行赋值。并通过Instance指针是否为nullptr进行单例模式判断,当创建多个lqLidarCoreManager时会触发Q_ASSERT断言,退出程序。

QPointer<lqLidarCoreManager> lqLidarCoreManager::Instance = nullptr; // 单例模式

//-----------------------------------------------------------------------------
lqLidarCoreManager* lqLidarCoreManager::instance() // 单例模式
{
  return lqLidarCoreManager::Instance;
}

构造函数

在构造函数中,进行单例模式判断。

创建lqSensorListWidget类,该类时LidarView的一个重要部分,用于控制显示隐藏。

lqLidarCoreManager::lqLidarCoreManager(QObject* parent)
  : QObject(parent)
{
  // Only 1 lqLidarCoreManager instance can be created.
  // 确保单例模式,如果创建两个以上的该类实例,会退出程序。
  Q_ASSERT(lqLidarCoreManager::Instance == nullptr); 
  lqLidarCoreManager::Instance = this;

  this->Internal = new pqInternal;

  // Create lqSensorListWidget, a critical component of LidarView core.
  // App can choose wether or not to show it or not, and how to present it (e.g QWidgetDock)
  new lqSensorListWidget();
}

析构函数

主要用于单例模式的实例,当析构该类时,将单例模式的指针置为nullptr。

lqLidarCoreManager::~lqLidarCoreManager()
{
  if (lqLidarCoreManager::Instance == this)
  { // 只进行置空,有QObject进行内存的析构
    lqLidarCoreManager::Instance = nullptr;
  } // WIP Paraview has similar code but 'else' case should not happend at all

  delete this->Internal; // 该类为空类,因为在构造函数内进行创建,因此需要进行析构
}

schedulePythonStartup

定时启动进行python初始化。使用了QTimer的singleShot,定时器定时为0,即当调用schedulePythonStartup时会直接进行python的初始化。

void lqLidarCoreManager::schedulePythonStartup()
{
  // QTimer::singleShot:0毫秒后调用槽函数pythonStartup。
  QTimer::singleShot(0, this, SLOT(pythonStartup()));
}

setPythonShell

设置python shell

void lqLidarCoreManager::setPythonShell(pqPythonShell* shell)
{
  // pqPythonShell:paraview的python执行器
  // pqPythonShell的基类为QWidget
  this->pythonShell = shell;
}

runPython

运行python代码。

void lqLidarCoreManager::runPython(const QString& statements)
{
  // 执行python代码
  if (this->pythonShell)
  {
    this->pythonShell->executeScript(statements);
  }
  else
  {
    qCritical() << "LidarView python shell has not been set, cannot run:\n" << statements;
  }
}

forceShowShell

显示python解析器界面。

void lqLidarCoreManager::forceShowShell()
{ // 显示运行python的界面
  if (this->pythonShell)
  {
    this->pythonShell->show();
    this->pythonShell->raise();
    this->pythonShell->activateWindow();
  }
}

createMainRenderView

创建渲染视图。使用工厂模式进行创建视图,然后将视图设置到激活窗口中。视图的颜色设置成黑色。

// 创建渲染视图
void lqLidarCoreManager::createMainRenderView()
{
  vtkSMSessionProxyManager* pxm =
    vtkSMProxyManager::GetProxyManager()->GetActiveSessionProxyManager();
  vtkSMProxy* renderviewsettings = pxm->GetProxy("RenderViewSettings");
  assert(renderviewsettings);
  vtkSMPropertyHelper(renderviewsettings, "ResolveCoincidentTopology")
    .Set(0); // WIP Is This necessary

  // 创建视图
  pqRenderView* view =
    qobject_cast<pqRenderView*>(pqApplicationCore::instance()->getObjectBuilder()->createView(
      pqRenderView::renderViewType(), pqActiveObjects::instance().activeServer()));
  assert(view);
  pqActiveObjects::instance().setActiveView(view); 
  pqApplicationCore::instance()->getObjectBuilder()->addToLayout(view);

  double bgcolor[3] = { 0, 0, 0 };
  vtkSMPropertyHelper(view->getProxy(), "Background").Set(bgcolor, 3); // 设置背景颜色
  vtkSMPropertyHelper(view->getProxy(), "CenterAxesVisibility").Set(0); // 显示坐标轴
  // vtkSMPropertyHelper(view->getProxy(),"MultiSamples").Set(4); //WIP set to 0 1, 4 ?
  vi

pythonStartup

python启动函数,设置python搜多路径,然后引入一些python模块。

void lqLidarCoreManager::pythonStartup()
{
  // 获取全局ProcessModule
  vtkProcessModule* pm = vtkProcessModule::GetProcessModule();
  // PrependPythonPath will complete automatically path to right python lib path depending os.
  vtkPythonInterpreter::PrependPythonPath(pm->GetSelfDir().c_str(), "lidarview/__init__.py");

  // Python Decorators
  PythonQt::self()->addDecorators(new lqPythonQtDecorators(this));

  // Start applogic
  this->runPython(QString("import PythonQt\n"
                          "QtGui = PythonQt.QtGui\n"
                          "QtCore = PythonQt.QtCore\n"
                          "import lidarview.applogic as lv\n"
                          "lv.start()\n"));
}

onMeasurementGrid

控制三维视图中的网格的显示和隐藏,并将其状态保存到默认设置中。

void lqLidarCoreManager::onMeasurementGrid(bool gridVisible)
{
  pqSettings* settings = pqApplicationCore::instance()->settings();
  settings->setValue("LidarPlugin/MeasurementGrid/Visibility", gridVisible);

  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;

  pqServerManagerModel* smmodel = pqApplicationCore::instance()->getServerManagerModel();

  // pqPipelineSource的基类是pqProxy,最终基类是QObject。
  // pqProxy的基类是pqServerManagerModelItem。
  // smmodel->findItems返回一个pqServerManagerModelItem列表。
  // pqPipelineSource是paraview qt中对vtkSMProxy的封装。
  Q_FOREACH (pqPipelineSource* src, smmodel->findItems<pqPipelineSource*>())
  {
    if (IsProxy<vtkGridSource>(src->getProxy()))
    {  // 控制显示和隐藏
      controller->SetVisibility(vtkSMSourceProxy::SafeDownCast(src->getProxy()),
        0,
        pqActiveObjects::instance().activeView()->getViewProxy(),
        gridVisible);
    }
  }
  // 进行渲染
  pqApplicationCore::instance()->render();
}

onResetCameraLidar

重置观察视角,通过对camera进行操作实现。

设置CameraPosition, CameraFocalPoint 和 CameraViewUp为默认参数,将观察视角重置。

void lqLidarCoreManager::onResetCameraLidar()
{
  pqRenderView* view = qobject_cast<pqRenderView*>(pqActiveObjects::instance().activeView());
  if (!view)
  {
    return;
  }

  // See pqRenderView::resetViewDirection
  // Position at 30 degrees [0, -(squareRoot(3)/2)*dist, (1/2)*dist]
  vtkSMProxy* proxy = view->getProxy();
  constexpr double dist = 100;
  double pos[3] = { 0, -0.866025 * dist, (1.0 / 2.0) * dist };
  double focal_point[3] = { 0, 0, 0 };
  double view_up[3] = { 0, 0, 1 };
  vtkSMPropertyHelper(proxy, "CameraPosition").Set(pos, 3);
  vtkSMPropertyHelper(proxy, "CameraFocalPoint").Set(focal_point, 3);
  vtkSMPropertyHelper(proxy, "CameraViewUp").Set(view_up, 3);
  proxy->UpdateVTKObjects();
  view->resetCamera();
  view->render();
}

onResetCameraToForwardView

前视图观察,观察位置为(0, -72, 18),即位于y轴-72,高度为18出进行观察。此视角默认y轴为前向方向。

// 将观察视角变换为前视图视角
void lqLidarCoreManager::onResetCameraToForwardView()
{
  pqRenderView* view = qobject_cast<pqRenderView*>(pqActiveObjects::instance().activeView());
  if (!view)
  {
    return;
  }

  vtkSMProxy* proxy = view->getProxy();
  double pos[3] = { 0, -72, 18.0 };
  double focal_point[3] = { 0, 0, 0 };
  double view_up[3] = { 0, 0.27, 0.96 };
  vtkSMPropertyHelper(proxy, "CameraPosition").Set(pos, 3);
  vtkSMPropertyHelper(proxy, "CameraFocalPoint").Set(focal_point, 3);
  vtkSMPropertyHelper(proxy, "CameraViewUp").Set(view_up, 3);
  proxy->UpdateVTKObjects();
  view->setCenterOfRotation(0, 0, 0);

  view->render();
}

onResetCenterToLidarCenter

将观察视角旋转中心设置为原定,并设置了两次。

对于setCenterOfRotation,需要有设当的交互方式,比如vtkPVInteractorStyle子类并使用旋转中心的相机操纵器。 默认情况下,它们设置正确。

// 从原点进行观察
void lqLidarCoreManager::onResetCenterToLidarCenter()
{
  pqRenderView* view = qobject_cast<pqRenderView*>(pqActiveObjects::instance().activeView());
  if (!view)
  {
    return;
  }

  // Set Axis Center to 0 0 0
  double center[3] = { 0.0, 0.0, 0.0 };
  view->setCenterOfRotation(center);
  view->render();

  // Set Camera Rotation Focal Point
  view->setCenterOfRotation(0, 0, 0);
  view->render();
}

saveFramesToPCAP

将数据保存为pcap格式。

调用了vtkLidarReader进行操作,vtkLidarReader的SaveFrame函数。SaveFrame函数中使用了vtkPacketFileWriter类,vtkPacketFileWriter类是对pcap库的包装。

// 保存pcap数据包
// 调用vtkLidarReader进行保存
void lqLidarCoreManager::saveFramesToPCAP(vtkSMSourceProxy* proxy,
  int startFrame,
  int endFrame,
  const QString& filename)
{
  if (!proxy)
  {
    return;
  }

  vtkLidarReader* reader = vtkLidarReader::SafeDownCast(proxy->GetClientSideObject());
  if (!reader)
  {
    return;
  }

  reader->Open();
  reader->SaveFrame(startFrame, endFrame, filename.toUtf8().data());
  reader->Close();
}

saveFramesToLAS

将数据保存为LAS格式。使用了LASFileWriter进行保存。

// 保存数据为LAS格式
// 调用LASFileWriter进行保存
void lqLidarCoreManager::saveFramesToLAS(vtkLidarReader* reader,
  vtkPolyData* position,
  int startFrame,
  int endFrame,
  const QString& filename,
  int positionMode)
{
  if (!reader || (positionMode > 0 && !position))
  {
    return;
  }

  // initialize origin point
  double northing, easting, height;
  easting = northing = height = 0;

  // projection transform parameters
  int gcs, in, out, utmZone;
  gcs = in = out = utmZone = 0;

  // data accuracy
  double neTol, hTol;
  hTol = neTol = 1e-3;

  bool isLatLon = false;

  LASFileWriter writer;
  writer.Open(qPrintable(filename));

  // not sensor relative; it can be
  // relative registered data or
  // georeferenced data
  if (positionMode > 0)
  {

    // Georeferenced data
    if (positionMode > 1)
    {
      // Since the data are georeferenced here, we must
      // check that a position reader is provided
      if (position)
      {
        vtkDataArray* const zoneData = position->GetFieldData()->GetArray("zone");
        vtkDataArray* const eastingData = position->GetPointData()->GetArray("easting");
        vtkDataArray* const northingData = position->GetPointData()->GetArray("northing");
        vtkDataArray* const heightData = position->GetPointData()->GetArray("height");

        if (zoneData && zoneData->GetNumberOfTuples() && eastingData &&
          eastingData->GetNumberOfTuples() && northingData && northingData->GetNumberOfTuples() &&
          heightData && heightData->GetNumberOfTuples())
        {
          // We assume that eastingData, norhtingData and heightData are in system reference
          // coordinates (srs) of UTM zoneData
          utmZone = static_cast<int>(zoneData->GetComponent(0, 0));

          // should in some cases use 32700? 32600 is for northern UTM zone, 32700 for southern UTM
          // zone
          gcs = 32600 + utmZone;

          out = gcs;
          if (positionMode == 3) // Absolute lat/lon
          {
            in = gcs;     // ...or 32700?
            out = 4326;   // lat/lon (espg id code for lat-long-alt coordinates)
            neTol = 1e-8; // about 1mm;
            isLatLon = true;
          }

          northing = northingData->GetComponent(0, 0);
          easting = eastingData->GetComponent(0, 0);
          height = heightData->GetComponent(0, 0);
        }
      }
    }
  }

  std::cout << "origin : [" << northing << ";" << easting << ";" << height << "]" << std::endl;
  std::cout << "gcs : " << gcs << std::endl;

  writer.SetPrecision(neTol, hTol);
  writer.SetGeoConversionUTM(utmZone, isLatLon);
  writer.SetOrigin(easting, northing, height);

  QProgressDialog progress("Exporting LAS...",
    "Abort Export",
    startFrame,
    startFrame + (endFrame - startFrame) * 2,
    getMainWindow());
  progress.setWindowModality(Qt::WindowModal);

  reader->Open();
  for (int frame = startFrame; frame <= endFrame; ++frame)
  {
    progress.setValue(frame);

    if (progress.wasCanceled())
    {
      reader->Close();
      return;
    }

    const vtkSmartPointer<vtkPolyData>& data = reader->GetFrame(frame);
    writer.UpdateMetaData(data.GetPointer());
  }

  writer.FlushMetaData();

  for (int frame = startFrame; frame <= endFrame; ++frame)
  {
    progress.setValue(endFrame + (frame - startFrame));

    if (progress.wasCanceled())
    {
      reader->Close();
      return;
    }

    const vtkSmartPointer<vtkPolyData>& data = reader->GetFrame(frame);
    writer.WriteFrame(data.GetPointer());
  }

  reader->Close();
}

getActiveServer

通过单例模式获取激活状态的服务指针。

pqServer* lqLidarCoreManager::getActiveServer()
{
  pqApplicationCore* app = pqApplicationCore::instance();
  pqServerManagerModel* smModel = app->getServerManagerModel();
  pqServer* server = smModel->getItemAtIndex<pqServer*>(0);
  return server;
}

getMainWindow

通过单例模式获取主窗口指针。

QWidget* lqLidarCoreManager::getMainWindow()
{
  Q_FOREACH (QWidget* topWidget, QApplication::topLevelWidgets())
  {
    if (qobject_cast<QMainWindow*>(topWidget))
    {
      return topWidget;
    }
  }
  return nullptr;
}

onEnableCrashAnalysis

开启或关闭崩溃分析。

void lqLidarCoreManager::onEnableCrashAnalysis(bool crashAnalysisEnabled)
{
  pqSettings* const Settings = pqApplicationCore::instance()->settings();
  Settings->setValue("LidarPlugin/MainWindow/EnableCrashAnalysis", crashAnalysisEnabled);
}

onCloseAllData

关闭所有数据,并重置观察视角。

void lqLidarCoreManager::onCloseAllData()
{
  // Remove lidars
  RemoveAllProxyTypeFromPipelineBrowser<vtkLidarReader>();
  RemoveAllProxyTypeFromPipelineBrowser<vtkLidarStream>();
  RemoveAllProxyTypeFromPipelineBrowser<vtkPositionOrientationPacketReader>();

  // Reset Camera
  this->onResetCameraToForwardView();

  // WIP Disable actions
  this->runPython("lv.disableSaveActions()\n");
}

onResetDefaultSettings

恢复默认设置。

void lqLidarCoreManager::onResetDefaultSettings()
{
  QMessageBox messageBox;
  messageBox.setIcon(QMessageBox::Warning);
  std::stringstream ss;
  ss << "This action will reset all settings. "
     << "This action requires " << SOFTWARE_NAME << " to restart to be completly reset. "
     << "Every unsaved changes will be lost. Are you sure you want to reset " << SOFTWARE_NAME
     << " settings?";
  messageBox.setText(ss.str().c_str());
  messageBox.setStandardButtons(QMessageBox::Cancel | QMessageBox::Ok);

  if (messageBox.exec() == QMessageBox::Ok)
  {
    // Clear Settings, sets the no restore flag "pqApplicationCore.DisableSettings"
    pqApplicationCore::instance()->clearSettings();

    // Quit the current application instance and restart a new one.
    qApp->quit();

    QStringList appArguments = qApp->arguments();
    QString appName = appArguments.at(0);
    appArguments.pop_front();
    QProcess::startDetached(appName, appArguments);
  }
}

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值