image frame

星际旅行日志

彼汾一曲,言采其藚.彼其之子,美如玉.美如玉,殊异乎公族.

BearPi_hm_nano调试助手一直打印测试信息

# BearPi_hm_nano

前几天华为发布了Harmony 3.0之后,我便把自己的Ubuntu 20.04按照3.0的环境要求配置了一遍HUAWEI DevEco Device Tool

之后依旧按照小熊派的官方教程来下载代码,使用的源码获取方式为:
在这里插入图片描述

VS Code中安装好DevEco Device Tool 3.0 Beta1之后,VS Code就具备了代码的编译、烧录等功能。
使用VS Code中来进行build编译后,再使用upload烧录,功能倒是没什么问题,就是使用monitor或者调试助手来查看打印时,会像下面这样一直打印一些功能测试的信息,容易把自己想要打印的信息给刷掉。
在这里插入图片描述

经过一番研究,在Ubuntu终端对源码进行编译不会出现这种问题。
然后在源代码根目录使用编译命令:hpm dist
注意:使用命令行进行编译之前,先按照 下载代码里的教程(~/Desktop/Code_Space/HarmonyOS/applications/BearPi/BearPi-HM_Nano/docs/board/课程配套PPT/2_开发环境搭建.pdf)或者 官方教程配置linux编译环境

然后回车,等待直到屏幕出现:BUILD SUCCESS字样,说明编译成功。
此时再次使用VS Code 进行烧录,,然后使用Monitor监控,就不会出现一直打印测试信息的情况了。
在这里插入图片描述

  • 还有一种方法,在project setting那把编译类型Debug改为Release ,这些大量打印信息是华为提供的生态认证套件输出的。

win10本地 SSH链接虚拟机Ubuntu出错

HarmonyOS Device 远程开发环境准备

错误一

win10 本地 VSCode 插件Remote-SSH连接远程服务器错误 “could not establish connection *****“

解决办法

1.确定虚拟机Ubuntu的IP地址,$:ifconfig
在这里插入图片描述2.在Windows下确定是否能够链接虚拟机Ubuntu

打开cmd, 执行:ping 192.168.201.144
在这里插入图片描述

3.Ubuntu安装ssh服务

$:  ssh localhost

在这里插入图片描述

如上图则说明未安装成功,ssh包括ssh客户端openssh-client和ssh服务端openssh-server,通过openssh-client我们可以远程登录其他主机,而开放本机的ssh的服务我们需要有openssh-server,ubuntu默认安装了openssh-client,但没有安装openssh-server,因此我们无法在主机上通过ssh访问虚拟机内部的ubuntu。

安装SSH服务: sudo apt-get install openssh-server

查看SSH状态:sudo service ssh status

在这里插入图片描述

如上图Active: active (running) since Mon 2021-10-25 16:08:37 CST; 19s ago 则说明安装成功。

到这里之后,回到Windows中的VS CODE 。
SSH TARGETS中,找到远程计算机,点击右边的,链接到远程计算机。此时应该会弹出输入远程计算机密码,但是不管怎么输入密码,都会反复要求输入密码,最后链接失败,控制台输出MyHarmonyOS@192.168.201.144: Permission denied (publickey,password).
在这里插入图片描述在这里插入图片描述

错误二

SSH 登录 Ubuntu 出现错误,MyHarmonyOS@192.168.201.144: Permission denied (publickey,password)..

回到Windows下,打开cmd, 执行ssh Name@ip_addressNameUbuntu的主机名称,ip_addressUbuntu中的IP地址。
但是不管我怎么输入密码,和在VS CODE中一样,密码错误,反复输入都一样。
在这里插入图片描述

网络上大多数的 Permission denied 解决方案,都是修改sudo gdiet /etc/ssh/sshd_config
加上这一句 :

PermitRootLogin yes

有的还说要去掉PasswordAuthentication yes前的#

保存退出,重启ssh服务:

sudo  /etc/init.d/ssh restart

但是依旧不能解决问题,我这边还是SSH远程访问出现Permission denied(publickey,password)
终于在这一篇文章中找到了答案,SSH远程访问出现Permission denied(publickey,password)解决方法

解决方法

1.Windows上安装SSH服务

设置–》应用–》可选功能–》添加功能–》安装 OpenSSH服务器 和 OpenSSH客户端

在这里插入图片描述

在左下角搜索栏输入服务,将相关SSH服务设置为自动(延迟启动),我的之前一个是禁用,一个是手动。
在这里插入图片描述

在确保ssh服务已开启、管理员密码正确、IP地址正确、网络通畅后,SSH远程访问依旧出现Permission denied(publickey,password),原因在于我的Ubuntu里并没有创建名为MyHarmonyOS的用户,所以在输入
ssh 用户名@目标ip地址 时,输入Ubuntu的管理员密码就不对了。所以这里的 "用户名" 应该是Ubuntu的用户名或管理员名,而不是Ubuntu的主机名,之前Permission denied的原因误以为是这个地方是主机名,然后就一直没改。

现在再次打开cmd,输入: ssh 用户名@目标ip地址就能够链接到Ubuntu了。
在这里插入图片描述

在windows的VS CODE里再次链接Ubuntu, 此时在弹出的SSH连接命令输入框中输入“ssh username@ip_address” ,输入登录远程计算机的密码,就不会报错了,已进入远程计算机的Visual Studio Code 。

之前输错的ssh 链接, 需要在SSH TARGET 中进行删除
点击右边的齿轮
在这里插入图片描述

在弹出的选项中选择之前的第一个
在这里插入图片描述

config文件中的每一个这样的段落都对应一个链接,不需要的直接删除后保存即可。
在这里插入图片描述

HUAWEI DevEco Device Tool 3.0 Beta1 Ubuntu20.04安装失败过程记录

10月22日,鸿蒙官网上架了HUAWEI HarmonyOS 3.0的智能硬件开发工具 DevEco Device Tool 3.0 Beta1。
官方文档

Windows开发环境准备

可直接安装官方文档进行,过程中没有遇到过任何问题,链接

Ubuntu开发环境准备

系统要求:

  • Ubuntu18及以上版本。
  • 系统的用户名不能含有中文字符。
  • 只能使用普通用户角色搭建开发环境。

DevEco Device Tool支持一体化安装,即DevEco Device Tool安装向导会检测系统是否安装Visual Studio Code、Python、Node.js、hpm的适配版本,当安装向导未检测到这些软件时,会给出相应的提示,根据提示勾选要自动安装的软件,安装向导会自动下载相应的软件进行安装。

安装DevEco Device Tool,主机的用户名不能包含中文字符,否则在运行DevEco Device Tool时,DevEco Home界面会一直处于Loading状态,导致不能正常使用。

我的开发环境是:Windows10,虚拟机Ubuntu20.04,VMware® Workstation 16 Pro

按照安装教程下载DevEco Device Tool V3.0 Beta1之后,直接在终端赋予安装文件可执行权限,执行./devicetool-linux-tool-3.0.0.200.run后便能一体化安装好各种依赖以及VS CODE

然而在自动安装NodeJS 12.22.5HPM时遇到了以下错误:

Resolving nodejs.org (nodejs.org)... failed: Temporary failure in name resol
Execution failed (Unexpected exit code: 255): "npm install -g @ohos/hpm-cli"

除了python外,Node和HPM自动安装失败, 于是只能按照之前2.0的版本手动安装Node和HPM。

将Ubuntu shell改为bash

打开终端工具,执行如下命令,输入密码,然后选择No,将Ubuntu shell修改为bash。

sudo dpkg-reconfigure dash

安装Node.js

进入Nodejs下载网站下载node-v12.22.5-linux-x64.tar.gz。

1.进入Node.js软件包目录(例如: ~/tools/),执行如下命令,解压已经下载好的安装包,其中node-v1x.xx.x-linux-x64.tar.xz为软件包名称,请根据实际进行修改。

tar -xvf node-v1x.xx.x-linux-x64.tar.xz

2.配置Node.js环境变量

sudo gedit ~/.bashrc

把Node.js的环境变量信息添加到文件末尾:

#nodejs
export NODE_HOME=~/tools/node-v1x.xx.x-linux-x64
export PATH=$NODE_HOME/bin:$PATH

执行source ~/.bashrc 使配置文件立即生效。
执行如下命令,检查Node.js安装结果。

node -v

安装Hpm

安装HPM之前需要确保Node.js安装成功。在安装hpm前,请检查网络连接状态,如果网络不能直接访问Internet,则需要通过代理服务器才可以访问。这种情况下,需要先设置npm代理,才能安装hpm。如果已安装hpm,可以执行npm update -g @ohos/hpm-cli命令升级hpm至最新版本。

建议将npm源配置为国内镜像,例如设置为华为云镜像源。

npm config set registry https://repo.huaweicloud.com/repository/npm/

执行如下命令安装HPM

npm install -g @ohos/hpm-cli

执行如下命令(V为大写字母)查看HPM安装结果

hpm -V

执行如下命令,安装curl工具,用于通过hpm下载源码时拉取对应的工具链。

sudo apt-get install curl

继续安装DevEco Device Tool

执行如下命令,安装DevEco Device Tool。

./devicetool-linux-tool-3.0.0.200.run

把所有需要安装的软件都勾选上,点击next,输入sudo密码,等待DevEco Device Tool 安装向导自动下载和安装软件,点击Next,直到安装完成,点击Finish。

检查Visual Studio Code

终端输入:code ,即可打开VS code.

点击左侧的Extensions ,检查是否成功安装C/C++、CodeLLDB和DevEco Device Tool。
在这里插入图片描述
但是左下角会一直显示CodeLLDB插件未安装成功,C/C++ language components一直正在安装:
在这里插入图片描述
如果C/C++CodeLLDB插件安装不成功,则DevEco Device Tool不能正常运行,VS code左侧也不会出现DevEco的三角图标和DevEco Home界面。
在这里插入图片描述

解决办法:离线安装C/C++CodeLLDB插件
运行DevEco Device Tool,在Visual Studio Code左侧的Extensions中,选择Views and More Actions > install from VSIX,分别安装C/C++和CodeLLDB插件。
这里需要注意不能下载最新的C/C++CodeLLDB插件,不然可能会遇到插件版本与自动安装的VS code 1.59版本不兼容的问题。
我下载的版本是(如果不行的话,再下更老一点点的版本来试试):
1.6.0版本的cpptools-linux.vsix

1.6.6版本的codelldb-x86_64-linux.vsix

在这里插入图片描述

如果遇到VS CODE插件安装失败的情况,EACCES: permission denied, open '/home/lk/.vscode/extensions/.obsolete' ,由报错信息可以看出,错误原因是义务VS code没有权限打开这个目录。
解决方法:

sudo chown -R myuser:myuser ~
sudo chmod -R 700 ~

myuser改为你的用户名称。
执行这两条命令后即可继续安装C/C++CodeLLDB这两个插件。

在这里插入图片描述
重新打开VS CODE,此时便已安装成功。
在这里插入图片描述

WIN10 WLAN的适配器驱动程序可能出现问题

WIN10找不到wifi,右下角的无线图标也不见了,诊断显示WLAN的适配器驱动程序可能出现问题,但是系统无法自动修复。

解决办法:

WIN+R后输入services.msc进入服务列表;

分别找到Wired AutoConfig 、WLAN AutoConfig 、 WWAN AutoConfig 双击将其启动类型都改为自动;

在这里插入图片描述

VTK计算PolyData每一个面片的中心坐标

/***********************计算每一个面片的中心坐标***********/
vtkNew<vtkCellCenters> cellCentersFilter;
cellCentersFilter->SetInputData(PolyData);
cellCentersFilter->VertexCellsOn();
cellCentersFilter->Update();
// Access the cell centers
// for (vtkIdType i = 0; i < cellCentersFilter->GetOutput()->GetNumberOfPoints();
//     i++)
// {
//     double p[3];
//     cellCentersFilter->GetOutput()->GetPoint(i, p);
//     cout << "Point " << i << " : " << p[0] << " , " << p[1] << " , " << p[2]
//         << endl;
// }
/******************************************************/

VTK找出Cell的中心点, 并用小球显示中心点

#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCellCenters.h>
#include <vtkGlyph3DMapper.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>

#include <vtkBYUReader.h>
#include <vtkOBJReader.h>
#include <vtkPLYReader.h>
#include <vtkPolyDataReader.h>
#include <vtkSTLReader.h>
#include <vtkSphereSource.h>
#include <vtkXMLPolyDataReader.h>
#include <vtksys/SystemTools.hxx>

#include <vtkColor.h>
#include <vtkNamedColors.h>
#include <vtkSphereSource.h>

#include <algorithm>
#include <vector>

namespace {
vtkSmartPointer<vtkPolyData> ReadPolyData(const char* fileName);
}

int main(int argc, char* argv[])
{
  // Define the colors used in the example
  vtkNew<vtkNamedColors> colors;

  vtkColor3d actorColor = colors->GetColor3d("Banana");
  vtkColor3d pointActorColor = colors->GetColor3d("Peacock");
  vtkColor3d backgroundColor = colors->GetColor3d("Silver");

  // Read the polydata
  auto polyData = ReadPolyData(argc > 1 ? argv[1] : "");

  std::vector<double> bounds(6);
  polyData->GetBounds(&bounds[0]);
  std::vector<double> range(3);
  for (int i = 0; i < 3; ++i)
  {
    range[i] = bounds[2 * i + 1] - bounds[2 * i];
  }
  std::cout << "Range: " << range[0] << ", " << range[1] << ", " << range[2]
            << std::endl;

  vtkNew<vtkCellCenters> centers;
  centers->SetInputData(polyData);

  auto maxRange = std::max_element(range.begin(), range.end());
  double radius = 0;
  if (argc > 1)
  {
    radius = *maxRange * 0.0025;
  }
  else
  {
    radius = *maxRange * 0.01;
  }
  vtkNew<vtkSphereSource> sphere;
  sphere->SetPhiResolution(11);
  sphere->SetThetaResolution(11);
  sphere->SetRadius(radius);

  vtkNew<vtkGlyph3DMapper> pointMapper;
  pointMapper->SetInputConnection(centers->GetOutputPort());
  pointMapper->SetSourceConnection(sphere->GetOutputPort());

  vtkNew<vtkActor> pointActor;
  pointActor->SetMapper(pointMapper);
  pointActor->GetProperty()->SetColor(pointActorColor.GetData());

  vtkNew<vtkPolyDataMapper> mapper;
  mapper->SetInputData(polyData);

  vtkNew<vtkActor> actor;
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(actorColor.GetData());
  actor->GetProperty()->EdgeVisibilityOn();
  actor->GetProperty()->SetInterpolationToFlat();

  // Setup render window, renderer, and interactor
  vtkNew<vtkRenderer> renderer;
  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->AddRenderer(renderer);
  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);
  renderer->AddActor(actor);
  renderer->AddActor(pointActor);

  renderer->ResetCamera();
  renderer->GetActiveCamera()->Azimuth(30);
  renderer->GetActiveCamera()->Elevation(30);
  renderer->GetActiveCamera()->Dolly(1.5);
  renderer->ResetCameraClippingRange();
  renderer->SetBackground(backgroundColor.GetData());

  renderWindow->SetSize(640, 480);
  renderWindow->SetWindowName("CellCentersDemo");
  renderWindow->Render();

  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}

namespace {
vtkSmartPointer<vtkPolyData> ReadPolyData(const char* fileName)
{
  vtkSmartPointer<vtkPolyData> polyData;
  std::string extension =
      vtksys::SystemTools::GetFilenameExtension(std::string(fileName));
  if (extension == ".ply")
  {
    vtkNew<vtkPLYReader> reader;
    reader->SetFileName(fileName);
    reader->Update();
    polyData = reader->GetOutput();
  }
  else if (extension == ".vtp")
  {
    vtkNew<vtkXMLPolyDataReader> reader;
    reader->SetFileName(fileName);
    reader->Update();
    polyData = reader->GetOutput();
  }
  else if (extension == ".obj")
  {
    vtkNew<vtkOBJReader> reader;
    reader->SetFileName(fileName);
    reader->Update();
    polyData = reader->GetOutput();
  }
  else if (extension == ".stl")
  {
    vtkNew<vtkSTLReader> reader;
    reader->SetFileName(fileName);
    reader->Update();
    polyData = reader->GetOutput();
  }
  else if (extension == ".vtk")
  {
    vtkNew<vtkPolyDataReader> reader;
    reader->SetFileName(fileName);
    reader->Update();
    polyData = reader->GetOutput();
  }
  else if (extension == ".g")
  {
    vtkNew<vtkBYUReader> reader;
    reader->SetGeometryFileName(fileName);
    reader->Update();
    polyData = reader->GetOutput();
  }
  else
  {
    vtkNew<vtkSphereSource> source;
    source->Update();
    polyData = source->GetOutput();
  }
  return polyData;
}
} // namespace

计算并打印每一个表面的中心点,可以使用以下代码:

//计算每一个面片的中心坐标
vtkNew<vtkCellCenters> cellCentersFilter;
cellCentersFilter->SetInputData(wedgePoly2);
cellCentersFilter->VertexCellsOn();
cellCentersFilter->Update();
// Access the cell centers
for (vtkIdType i = 0; i < cellCentersFilter->GetOutput()->GetNumberOfPoints();
    i++)
{
    double p[3];
    cellCentersFilter->GetOutput()->GetPoint(i, p);
    cout << "Point " << i << " : " << p[0] << " , " << p[1] << " , " << p[2]
        << endl;
}

How to compile PUMGen

本文来源于https://github.com/SeisSol/PUMGen/wiki/How-to-compile-PUMGen

开始编译PUMGen之前,需要先按照https://blog.csdn.net/afgqwjgfjqwgfg/article/details/120308484中的步骤安装好HDF5;

HDF5

cd hdf5-1.8.21
CC=mpicc ./configure --enable-parallel --prefix=/path/to/hdf5
make -j $ncpu
make install

Where ncpu can be obtained by:

ncpu=$(lscpu | grep "^CPU(" | awk '{print $2}')

Simmetrix (optional)可选

The Sim Modeling Suite from Simmetrix is optional. To use it, you need a valid Simmetrix license for the Sim Modeling Suite library. If you have the license you should be able to download the library from http://simmetrix.com/index.php/support/support-downloads. See here for the installation process.
这个网站打开就是一个什么登录界面,太麻烦了,反正我没装。

PUMI

https://github.com/SCOREC/core

cd $HOME
git clone git@github.com:SCOREC/core.git
cd core
  • 如果没有安装Simmetrix
mkdir build && cd build
cmake .. \
  -DCMAKE_C_COMPILER="`which mpicc`" \
  -DCMAKE_CXX_COMPILER="`which mpiCC`" \
  -DCMAKE_C_FLAGS="-O2 -g -Wall" \
  -DCMAKE_CXX_FLAGS="-O2 -g -Wall" \
  -DCMAKE_INSTALL_PREFIX=$path_to_pumi
make -j $ncpu
sudo make install

(depending of the mpi environement, you may need to used which mpicxx instead of which mpiCC)对应不同的MPI环境,需要选择使用which mpicxx 还是which mpiCC, 建议是如果不会报错就用原来的which mipCC,报错了再换 which mpicxx 试试。

  • 如果安装了Simmetrix
mkdir build && cd build
cmake .. \
  -DCMAKE_C_COMPILER="`which mpicc`" \
  -DCMAKE_CXX_COMPILER="`which mpiCC`" \
  -DCMAKE_C_FLAGS="-O2 -g -Wall" \
  -DCMAKE_CXX_FLAGS="-O2 -g -Wall" \
  -DCMAKE_INSTALL_PREFIX=$path_to_pumi \
  -DENABLE_SIMMETRIX=ON \
  -DSIM_MPI=$mpi_name \
  -DSIMMETRIX_LIB_DIR=$path_to_SimModeler_lib \
  -DSIMMODSUITE_INCLUDE_DIR=$path_to_SimModeler_include_dir
make -j $ncpu
make install

Where $mpi_name is the mpi implementation (see the name of the preinstalled libSimPartitionedMesh-xxx.a, e.g. mpi, mpich3, openmpi3 or openmpi4. on supermucNG we use mpich3)

As an illustration, the different path could be:

export myLibs=(set your myLibs here)
export path_to_SimModeler=$myLibs/SimModelerLib/15.0-200822/
export mpi_name=mpich3
export path_to_pumi=$myLibs/core/
export path_to_SimModeler_lib=$path_to_SimModeler/lib/x64_rhel7_gcc48
export path_to_SimModeler_include_dir=$path_to_SimModeler/include
export path_to_hdf5=$HDF5_BASE

Where $myLibs point to the folder where user libraries are installed.

netCDF (optional/deprecated)

标题都说不建议了,这一部分可以直接跳过。

NetCDF is required to convert old SeisSol meshes.

http://www.unidata.ucar.edu/downloads/netcdf/index.jsp (NetCDF-C Releases)

CPPFLAGS=-I/path/to/hdf5/include CC=mpicc LDFLAGS=-L/path/to/hdf5/lib LIBS=-ldl ./configure --disable-shared --prefix=/path/to/netcdf
make -j $ncpu
make install

Getting PUMGen

git clone https://github.com/SeisSol/PUMGen.git
cd PUMGen
git submodule update --init

Compiling PUMGen

mkdir build
cd build
cmake .. -DCMAKE_PREFIX_PATH=$path_to_pumi -DSIMMETRIX=ON \
    -DSIMMETRIX_ROOT=$path_to_SimModeler -DSIM_MPI=$mpi_name \
    -DCMAKE_BUILD_TYPE=Release\
    -DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc 
make -j $ncpu

pumgen can be compiled with simmetrix using -DSIMMETRIX=OFF.
The argument of -DCMAKE_C_COMPILER and -DCMAKE_CXX_COMPILER should match the compiler used for pumi.

如果没有安装Simmetrix的话,直接使用上面的

cmake .. -DCMAKE_PREFIX_PATH=$path_to_pumi -DSIMMETRIX=ON \
    -DSIMMETRIX_ROOT=$path_to_SimModeler -DSIM_MPI=$mpi_name \
    -DCMAKE_BUILD_TYPE=Release\
    -DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc 

会出错,需要将其改为:

cmake .. -DCMAKE_PREFIX_PATH=$path_to_pumi -DSIMMETRIX=OFF -DSIM_MPI=$mpi_name     -DCMAKE_BUILD_TYPE=Release    -DCMAKE_C_COMPILER="`which mpicc`" -DCMAKE_CXX_COMPILER="`which mpiCC`"

make -j $ncpu

其中The argument of -DCMAKE_C_COMPILER and -DCMAKE_CXX_COMPILER should match the compiler used for pumi.

如果执行 make -j $ncpu 后出现 undefined reference to ompi_mpi_comm_world之类的错误,最好回到安装OPENMPImpich 那一步,重新编译,安装一遍,确保过程中没有问题,都正确安装了。
MPI环境: Ubuntu 20.04下安装和配置MPI - 知乎

OpenMPI : openmpi入门1-安装与测试 - 灰信网(软件开发博客聚合),

或者:OpenMPI的下载和安装

编译和安装最好分别进行:

make
make install    #权限不够加 sudo

成功执行make -j $ncpu之后:
在这里插入图片描述
安装:sudo make install
在这里插入图片描述

此时在命令行输入pumgen ,就会出现pumgen命令的参数介绍了。
在这里插入图片描述
到这里应该就成功安装好PUMGen了。

Ubuntu20.04下QT5.15.2配置QVTKOpenGLNativeWidget控件并在QT中显示VTK窗口

操作系统:Ubuntu 20.04
QT: 5.15.2
VTK : 9.0.1

一、QT5.15.2配置QVTKOpenGLNativeWidget控件

1.1 下载安装VTK9.0.1

具体方法和配置按照我之前的文章进行,使用CMKE进行编译VTK,且要编译release版本,否则不会生成QVTKOpenGLNativeWidget所需要的动态库libQVTKWidgetPlugin.so

1.2 在QT中显示VTK渲染窗口

网上有很多方法很多案例使用qt+vtk的时候用QVTKWidget、QVTKWidget2、QVTKOpenGLWidget、QVTKOpenGLNativeWidget,容易把人弄混。我也是看了这篇文章之后才弄清楚https://blog.csdn.net/a15005784320/article/details/99460999

QVTKWidget、QVTKOpenGLWidget、QVTKOpenGLNativeWidget、QVTKWidget2 区别

这几个控件名指的都是VTK在QT中的控件类型
在这里插入图片描述

这几个widget怎么使用:
每个widget都提供了不同的功能以及不同的API,但是widget的创建以及使用基本一样。
    1)实例化widget
    2)指定渲染窗口交互器
    3)创建回调函数(qt里就直接绑定信号和槽)
    4)创建模型,并与widget关联
    5)激活widget
    6)反激活widget

这几个widget的关系:
在这里插入图片描述
到底应该用那个widget:

  放弃使用QVTKWidget。
  包含QVTKOpenGLWidget的VTK的第一个版本是VTK 8.0.0!
  如果你是Qt5.4以前,请使用QVTKWidget2。
  如果你是Qt5.4以后,vtk8.1X及以前 请使用QVTKOpenGLWidget。
  如果你是Qt5.4以后,vtk8.2X 请使用QVTKOpenGLNativeWidget。

比如你有QVTKWidget的程序,直接替换成QVTKWidget2(根据版本定),以此向后类推。

为什么自己用时候还要保留vtk8.1X:

  为什么自己用时候还要保留vtk8.1X,因为vmtk官方说明仅支持vtk8.1X及以前,vtk8.2X不确定。虽然vtk8.2X+vmtk可以使用,但可能有隐藏bug。
————————————————
原文链接:https://blog.csdn.net/a15005784320/article/details/99460999

1.3 在QT中配置VTK控件

安裝完VTK之后使用sudo find / -name libQVTKWidgetPlugin.so找到动态链接库的路径;

把ibQVTKWidgetPlugin.so复制到QT的安装目录下:

/home/username/Qt/5.15.2/gcc_64/plugins/designer
/home/username/Qt/Tools/QtCreator/lib/Qt/plugins/designer

在这里插入图片描述
在这里插入图片描述

然后独立的QT Designer和QT creator 中包含的Designer左侧栏目下方就有了QVTKWidget,这里叫是叫QVTKWidget,后面需要根据自己使用的VTK版本和QT版本来修改为QVTKWidget、QVTKOpenGLWidget、QVTKOpenGLNativeWidget、QVTKWidget2 ,不然的话直接拖入到designer界面中后会报错;
在这里插入图片描述

1.4 配置VTK控件

1.4.1 创建一个新的项目
在这里插入图片描述

构建系统选择CMake;
在这里插入图片描述在这里插入图片描述

然后一直点点点直到完成,打开widget.ui文件;

从左侧栏目中拖入QVTKWidget到widget.ui 的界面中,即设置用于渲染VTK模型的窗口;
在这里插入图片描述

此时可以看到该控件类的类类型为QVTKWidget;
在这里插入图片描述

保存,回到左侧的的编辑代码界面,此时widget.cpp文件中会出现报错;
在这里插入图片描述
error :'QVTKWidget.h' file ot found 因为我的vtk版本是VTK9.0.1,是找不到QVTKWidget.h这个文件的;

1.4.2 修改CMakeLists.txt 配置VTK相关头文件 以及 动态链接库篇;

cmake_minimum_required(VERSION 3.5)

project(LastTest LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check https://doc.qt.io/qt/deployment-android.html for more information.
# They need to be set before the find_package( ...) calls below.

#if(ANDROID)
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
#    if (ANDROID_ABI STREQUAL "armeabi-v7a")
#        set(ANDROID_EXTRA_LIBS
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
#    endif()
#endif()

find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
FIND_PACKAGE(VTK REQUIRED)
set(PROJECT_SOURCES
        main.cpp
        widget.cpp
        widget.h
        widget.ui
)

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(LastTest
        ${PROJECT_SOURCES}
    )
else()
    if(ANDROID)
        add_library(LastTest SHARED
            ${PROJECT_SOURCES}
        )
    else()
        add_executable(LastTest
            ${PROJECT_SOURCES}
        )
    endif()
endif()

target_link_libraries(LastTest PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${VTK_LIBRARIES})

实际上就改了两个地方:

FIND_PACKAGE(VTK REQUIRED)

target_link_libraries(LastTest PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${VTK_LIBRARIES})

1.4.3 点击左侧的widget.ui,然后右键选择用文本编辑器打开;此时可以直接修改widget.ui的内容;
widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QVTKWidget" name="qvtkWidget">
   <property name="geometry">
    <rect>
     <x>210</x>
     <y>110</y>
     <width>401</width>
     <height>341</height>
    </rect>
   </property>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>QVTKWidget</class>
   <extends>QWidget</extends>
   <header>QVTKWidget.h</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

把其中的QVTKWidget修改为QVTKOpenGLNativeWidget

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QVTKOpenGLNativeWidget" name="qvtkWidget">
   <property name="geometry">
    <rect>
     <x>210</x>
     <y>110</y>
     <width>401</width>
     <height>341</height>
    </rect>
   </property>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>QVTKOpenGLNativeWidget</class>
   <extends>QWidget</extends>
   <header>QVTKOpenGLNativeWidget.h</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

此时界面中的VTK控件类型就变成了QVTKOpenGLNativeWidget;
在这里插入图片描述

保存;
此时再点击左下角的运行,即可
在这里插入图片描述

二、在QT UI界面中使用VTK窗口进行渲染

2.1 使用pushButton控制VTK窗口的显示

在widget.ui 中拖入左侧的PushButton;
在这里插入图片描述
点击PushButton右键选择转到槽 ,选择clicked() ,即点击之后显示画面;
然后widget.h中便会出现槽函数的函数声明;

private slots:
    void on_pushButton_clicked();

widget.cpp 中生成槽函数的定义;

void Widget::on_pushButton_clicked()
{

}

继续沿用一中的代码:
其中:
widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <QWidget>
#include <vtkSmartPointer.h>
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkConeSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include <vtkNew.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    vtkSmartPointer<vtkRenderer> renderer;//这个渲染器其实也可以放在OnOpenSlot()中
    void OnOpenSlot();//负责生成模型和添加渲染窗口画面
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "./ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    renderer = vtkSmartPointer<vtkRenderer>::New();//在构造函数中进行初始化
}

Widget::~Widget()
{
    delete ui;
}

void Widget::OnOpenSlot()
{
    vtkSmartPointer<vtkConeSource> cone=vtkSmartPointer<vtkConeSource>::New();//生成一个圆锥,用于展示
    cone->SetHeight(3.0);
    cone->SetRadius(1);
    cone->SetResolution(10);

    vtkSmartPointer<vtkPolyDataMapper> coneMapper=vtkSmartPointer<vtkPolyDataMapper>::New();
    coneMapper->SetInputConnection(cone->GetOutputPort());
    vtkSmartPointer<vtkActor> coneActor=vtkSmartPointer<vtkActor>::New();
    coneActor->SetMapper(coneMapper);
    renderer->AddActor(coneActor);
    vtkNew<vtkGenericOpenGLRenderWindow> renwindow;
    renwindow->AddRenderer(renderer);
    renwindow->Render();
    ui->qvtkWidget->SetRenderWindow(renwindow.Get());
    ui->qvtkWidget->update();
}

void Widget::on_pushButton_clicked()
{
    qDebug()<<"Show Renderer Windows!!\n";
    OnOpenSlot();
}

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    qDebug()<<"RUN MAIN";
    return a.exec();
}

2.2 运行

点击左下角的运行;
在这里插入图片描述
点击PushButton, VTK控件窗口中显示模型渲染画面;
在这里插入图片描述

2.3 不使用PushButton

OnOpenSlot() 函数直接放在Widget的构造函数中,在QT界面初始化之后就可以显示VTK的模型渲染界面;

ubuntu 20.04与华为matepadPro实现文件互相访问【其他华为机型可参考】

## 一.ubuntu电脑访问matepadPro

我的设备:
电脑系统:Ubuntu20.04
平板matepadPro: 系统HarmonyOS 2.0.0

参考博客:https://blog.csdn.net/WMX843230304WMX/article/details/104526991/

1.首先确保平板和电脑在同一局域网下,即连接同一wifi;
2.平板开启 huawei share,并在下拉栏中长按huawei share,打开“共享至电脑”,配置“电脑端访问验证”,设置用户名和密码。
在这里插入图片描述在这里插入图片描述在这里插入图片描述

3.Ubuntu电脑连接平板
在下方的连接到服务器,点击输入服务器地址
在这里插入图片描述
服务器地址填写 smb://手机的IP地址
IP地址在-设置-关于平板电脑-状态信息 中;
在这里插入图片描述

然后会出现输入用户名和密码的界面,把之前设置的输入后,便可打开平板的存储空间:
在这里插入图片描述
在这里插入图片描述遇到的问题

输入smb://手机的IP地址 之后,可能会出现各种访问失败或者无法访问的问题,这些报错百度一下基本都有解决方案。
我遇到的是“共享失败:由软件导致的连接断开”;
参考解决方案:
https://forum.ubuntu.org.cn/viewtopic.php?t=491129
https://zhidao.baidu.com/question/318712314.html

打开/etc/samba/smb.conf 后应该就能看到
[global] 在下面添加应该就行 client min protocol = NT1
由于20.04把smb协议升级了,造成旧协议无法使用,我猜应该是重新启用smb1.0就行,如果是服务端就把client改称server

二. 平板通过网络邻居访问Ubuntu电脑文件

参考博客:
https://blog.csdn.net/qq_40511918/article/details/105663279
https://blog.csdn.net/weixin_43863426/article/details/114012541

  1. Ubuntu下载samba开启文件共享
sudo apt-get install samba
sudo apt-get install smbclient

2.创建需要共享的文件夹

例如:

mkdir /home/username/samba

然后给权限:

chmod 777 /home/username/samba

3.配置文件

sudo gedit  /etc/samba/smb.conf

在文件末尾添加:
在最后添加

 [samba]
comment = smb share
path = /home/username/samba
public = yes
guest ok = yes
writable = yes
available = yes
browseable = yes
create mask=0775
directory mask=0775

在配置文件中找到usershare allow guests = yes,在后面一行添加 usershare owner only = false
在这里插入图片描述

  1. 添加用户
    sudo smbpasswd -a xxx
    我这里写的是ubuntu的用户名。

  2. 重新运行服务
    sudo service smbd restart

6.在平板上 打开 文件管理- 网络邻居
在这里插入图片描述
这里如果看不到电脑设备名字的话,右上角点击扫描试试;
在这里插入图片描述

然后点击设备名,会弹出窗口,填上ubuntu系统的用户名和密码,便可显示连接成功:
这里如果显示无法打开,或者没有权限的话,回去检查一下前面的共享文件路径是否有错。如果还是无法解决的话,建议百度一下对应的错误提示。
在这里插入图片描述

然后打开samba文件夹就可以访问电脑上的对应共享文件夹了。
共享文件夹可以是上面这样新建的,也可以是已经存在的文件夹,只需要在设置共享文件夹路径的时候修改为需要共享的文件夹就可以了。

c++11并发与多线程【第十二节】windows临界区、其他各种mutex互斥量

【第十二节】windows临界区、其他各种mutex互斥量

一、windows临界区

#include<iostream>
#include<vector>
#include<thread>
#include<string>
#include<list>
#include<mutex>
#include<windows.h>
using namespace std;
#define _WINDOWSJQ_

class A{
public:
    //把收到的消息(玩家命令)放入到一个队列的线程入口函数
    void inMsgRecvQueue(){
        for(int i=0;i<10000;i++){//用数字模拟玩家发送来的命令
            cout<<"inMsgRecvQueue()执行,插入一个元素 "<<i<<endl;
#ifdef _WINDOWSJQ_
            EnterCriticalSection(&my_winsec);
            msgRecvQueue.push_back(i);
            LeaveCriticalSection(&my_winsec);
#else
            //
            my_mutex.lock();//加锁
            msgRecvQueue.push_back(i);//把命令放入队列当中
            my_mutex.unlock();//解锁
            //
#endif
        }
    }

    bool MsgProcess(int &command){
#ifdef _WINDOWSJQ_
        EnterCriticalSection(&my_winsec);//进入临界区
        if(!msgRecvQueue.empty()){
            command=msgRecvQueue.front();//返回第一个元素
            msgRecvQueue.pop_front();//取出后移除该元素
            LeaveCriticalSection(&my_winsec);
            //然后处理数据
            return true;
        }
        LeaveCriticalSection(&my_winsec);//离开临界区
#else
        my_mutex.lock();//加锁
        if(!msgRecvQueue.empty()){
            command=msgRecvQueue.front();//返回第一个元素
            msgRecvQueue.pop_front();//取出后移除该元素
            my_mutex.unlock();//解锁
            //然后处理数据
            return true;
        }
        my_mutex.unlock();//解锁
#endif
        return false;
    }
    //从消息队列list中读取玩家命令的线程入口函数
    void outMsgRecvQueue(){
        int command=0;
        for(int i=0;i<10000;i++){
            //
            bool result=MsgProcess(command);
            if(result){
                cout<<"outMsgRecvQueue执行,取出一个元素 "<<command<<endl;
                //然后对数据进行处理
            }
            else
                cout<<"outMsgRecvQueue执行,但是list已经空了 : "<<i<<endl;
        }
        cout<<"end "<<endl;
    }
A()
{
#ifdef _WINDOWSJQ_
    IntialiseCriticalSection(&my_winsec);//初始化临界区
#endif
}
private:
    std::list<int> msgRecvQueue;//在list中存放玩家发来的命令
    std::mutex my_mutex;

#ifdef _WINDOWSJQ_
    CRITICAL_SECTION my_winsec;//windows中的临界区,类似与c++11中的mutex

#endif
};

int main(){
    A myobj;
    std::thread myInMsgObj(&A::outMsgRecvQueue,&myobj);//第二个参数是引用,作用与std::ref相同,保证是子线程中使用的是主线程中的同一个对象,但是主线程后面必须等待子线程完成
    std::thread myOutMsgObj(&A::inMsgRecvQueue,&myobj);
    myInMsgObj.join();
    myOutMsgObj.join();

    cout<<"主线程结束"<<endl;
    return 0;
}

上面的代码在windows环境下与使用mutex来加锁解锁完成的功能相同。

二、多次进入临界区实验

在同一个线程中,多次进入临界区是允许的,windows中的“”相同临界区变量“”代表的临界区的进入(EnterCriticalSection(&my_winsec);)可以被多次调用,但是调用了多少次,就得调用多少次LeaveCriticalSection(&my_winsec); 但是mutex类的lock是不允许在unlock之前多次执行的。

#ifdef _WINDOWSJQ_
            EnterCriticalSection(&my_winsec);//进入临界区(加锁)
            EnterCriticalSection(&my_winsec);//两次进入
            msgRecvQueue.push_back(i);
            LeaveCriticalSection(&my_winsec);//离开临界区(解锁)
            LeaveCriticalSection(&my_winsec);//再次离开
#else

三、自动析构技术

#include<windows.h>
using namespace std;
#define _WINDOWSJQ_
//本类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection,导致死锁,类似于C++11中的lock_guard
class CWinLock //RAII类(Resource Acquisition Is Initialization)中文“资源获取即初始化”
{              //容器、智能指针都属于RAII类
public:
    CWinLock(CRITICAL_SECTION *pCritmp)//构造函数
    {
        m_pCritical=pCritmp;
        EnterCriticalSection(m_pCritical);
    }
    ~CWinLock()//析构函数
    {
        EnterCriticalSection(m_pCritical);
    }
private:
    CRITICAL_SECTION *m_pCritical;
};

    //把收到的消息(玩家命令)放入到一个队列的线程入口函数
void inMsgRecvQueue(){
        for(int i=0;i<10000;i++){//用数字模拟玩家发送来的命令
            cout<<"inMsgRecvQueue()执行,插入一个元素 "<<i<<endl;
#ifdef _WINDOWSJQ_
            //EnterCriticalSection(&my_winsec);//进入临界区(加锁)
            //EnterCriticalSection(&my_winsec);//两次进入
            CWinLock wlcok(&my_winsec);
            CWinLock wlcok2(&my_winsec);//进入临界区多次也没问题
            msgRecvQueue.push_back(i);
            //LeaveCriticalSection(&my_winsec);//离开临界区(解锁)
            //LeaveCriticalSection(&my_winsec);//再次离开
#else
            //
            //my_mutex.lock();//加锁
            std::lock_guard<std::mutex> sbguard(my_mutex);
            msgRecvQueue.push_back(i);//把命令放入队列当中
            //my_mutex.unlock();//解锁
            //
#endif
        }
    }

四、recursive_mutex递归的独占互斥量

std::mutex 独占互斥量,一次只有一个线程拿到锁;
recursive_mutex 递归的独占互斥量,允许同一个线程,同一个互斥量多次被lock;

//std::mutex my_mutex;
std::recursive_mutex my_mutex;//递归独占互斥量

使用了这种多次lock的互斥量,要考虑代码是否有优化空间,递归太多可能报异常;

五、带超时的互斥量std::timed_mutex和std::recursive_timed_mutex

5.1 std::timed_mutex:是带超时功能的独占互斥量

try_lock_for():参数是一段时间,等待一段时间,如果拿到了锁或者等待超过时间没拿到锁,就往下走,不会一直阻塞;

std::timed_mutex my_mutex;
std::chrono::milliseconds timeout(100);//100毫秒
if(my_mutex.try_lock_for(timeout))//等待100毫秒来尝试获取锁
{
    //在这100毫秒之内拿到了锁
    //操作
    my_mutex.unlock();//用完了要解锁
}
else
{
}

try_lock_until() :参数是一个未来的时间点,在这个未来的时间没有到达的时间内,如果拿到了锁或者超时,就往下走;

if(my_mutex.try_lock_until(std::chrono::steady_lock::now()*timeout))//从当前时间算起的100毫秒
{
    //在这100毫秒之内拿到了锁
    //操作
    my_mutex.unlock();//用完了要解锁
}

5.2 std::recursive_timed_mutex 带超时功能的递归独占互斥量

文章内容来源《C++并发与多线程视频课程》

  • Copyrights © 2022-2024 lk
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信