当前位置: 首页 > news >正文

osg实现鼠标框选

目录

1. 需求的提出

2. 具体实现

     2.1. 禁止场景跟随鼠标转动

     2.2. 矩形框前置绘制

3. 附加说明

        3.1. 颜色设置说明

        3.2.矩形框显示和隐藏的另一种实现


1. 需求的提出

       有时需要在屏幕通过按住键盘上的某个键如Ctrl键且按住鼠标左键,拖出一个矩形,实现框选三维物体,如下效果:

现在的问题是:

  1. 在osg中,拖动鼠标时,物体会随鼠标一起转动,这样框选是不行的,至少是不友好的,我们需要的是,按住鼠标框选时,物体不能随鼠标一起转动。
  2. 如何根据鼠标拖动的起始点和终止点,绘制出这个矩形框?矩形框要在所有三维物体的前面而不能被三维物体遮挡且要是透明的,能透过它看到背后的三维物体,否则框选就失去了意义。
  3. 按住鼠标右键,矩形框消失。

2. 具体实现

     2.1. 禁止场景跟随鼠标转动

        对第1节中提到的第1个问题,默认情况下osgViewer::Viewer事件处理器在鼠标左键按下并拖动时,整个场景会随鼠标一起转动。为了不让转动,可以通过改写osgViewer::Viewer osgGA::GUIEventHandler事件处理器,重载如下方法:

 virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, osg::Object* obj, osg::NodeVisitor*nv)

当按住键盘上的某个键如Ctrl键且按住鼠标左键,让该函数返回true,这样后续的流程就不会处理鼠标拖动事件,三维物体也就不会跟随鼠标旋转了。

     2.2. 矩形框前置绘制

         矩形框要绘制在所有三维物体的前面而不能被三维物体遮挡,这就要用到三维中的HUD技术(Head Up Display)。所谓HUD节点,说白了就是无论三维场景中的内容怎么改变,它都能在屏幕上固定位置显示的节点。实现要点:

  • 关闭光照,不受场景光照影响,所有内容以同一亮度显示。
  • 关闭深度测试。
  • 调整渲染顺序,使它的内容最后绘制。
  • 设定参考贴为绝对型:setReferenceFrame(osg::Transform:ABSOLUTE_RF)。
  • 使其不受父节点变换的影响:setMatrix(osg::Matrix::identity())。
  • 使用平行投影,设定虚拟投影窗口的大小,这个窗口的大小决定了后面绘制的图形和文字的尺度比例。

  实现代码如下:

#include<osgViewer/Viewer>
#include<osg/ShapeDrawable>
#include<osgDB/readFile>
#include<osg/BlendFunc>
class selectBoxEventHandler: public osgGA::GUIEventHandler
{
public:selectBoxEventHandler(osg::ref_ptr<osg::Camera> spHudCamera){m_spHudCamera = spHudCamera;}
private:virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, osg::Object* obj, osg::NodeVisitor*nv){m_pViewer = (osgViewer::Viewer*)(&aa);if (m_pViewer == nullptr){return false;}auto width = m_pViewer->getCamera()->getViewport()->width();auto height = m_pViewer->getCamera()->getViewport()->height();/* 设置HUD相机为正投影,这样绘制的矩形框和鼠标拖动的框选框大小就一样了且要设置正投影的区域和视图窗体一样大小,因为鼠标可以在窗体任何位置进行框选*/m_spHudCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, width, 0, height));auto eventType = ea.getEventType();switch (eventType){case osgGA::GUIEventAdapter::KEYDOWN:{if ((osgGA::GUIEventAdapter::KEY_Control_L == ea.getKey()) || (osgGA::GUIEventAdapter::KEY_Control_R == ea.getKey())) // Ctrl键被按下{m_ctrlKeyPressed = true;}}break;case osgGA::GUIEventAdapter::KEYUP:{if ((osgGA::GUIEventAdapter::KEY_Control_L == ea.getKey())|| (osgGA::GUIEventAdapter::KEY_Control_R == ea.getKey())) // Ctrl键被释放{m_ctrlKeyPressed = false;}}break;case osgGA::GUIEventAdapter::PUSH:  // 鼠标左键按下{auto buttonMask = ea.getButtonMask();auto bIsMouseBtn = buttonMask & osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON;if (bIsMouseBtn){m_fStartPosX = ea.getX();m_fStartPosY = ea.getY();m_bPush = true;}else if (buttonMask & osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) // 鼠标右键按下,则删除选择框{if (m_spOldNode != nullptr){m_spHudCamera->removeChild(m_spOldNode);}}}break;case osgGA::GUIEventAdapter::RELEASE:  // 释放鼠标左键{m_bPush = false;}break;case osgGA::GUIEventAdapter::DRAG:    // 拖动鼠标{auto buttonMask = ea.getButtonMask();auto bIsMouseBtn = buttonMask & osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON;if (bIsMouseBtn && m_ctrlKeyPressed && m_bPush){m_fEndPosX = ea.getX();m_fEndPosY = ea.getY();auto pSelectBox = createSelectBox(m_fStartPosX, m_fStartPosY, m_fEndPosX, m_fEndPosY);if (m_spOldNode != nullptr){m_spHudCamera->removeChild(m_spOldNode);}m_spHudCamera->addChild(pSelectBox);m_spOldNode = pSelectBox;return true;}}} // end swithreturn  false;}osg::Geode* createSelectBox(float fStartPosX, float fStartPosY, float fEndPosX, float fEndPosY){osg::Geode* pGeode = new osg::Geode();auto pQuardGeomerty = new osg::Geometry();pGeode->addChild(pQuardGeomerty);osg::Vec3Array* pVertArray = new osg::Vec3Array;pVertArray->push_back(osg::Vec3(fStartPosX, fStartPosY, 0.0));pVertArray->push_back(osg::Vec3(fStartPosX, fEndPosY, 0.0));pVertArray->push_back(osg::Vec3(fEndPosX, fEndPosY, 0.0));pVertArray->push_back(osg::Vec3(fEndPosX, fStartPosY, 0.0));pQuardGeomerty->setVertexArray(pVertArray);osg::Vec4Array* pColorArray = new osg::Vec4Array;pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.4));/*  pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));*/pQuardGeomerty->setColorArray(pColorArray);//pQuardGeomerty->setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX);pQuardGeomerty->setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_PRIMITIVE_SET);pQuardGeomerty->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));pGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); // 关闭光照pGeode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); // 开启透明,否则就不能透过选择框看到后面的牛pGeode->addDrawable(pQuardGeomerty);return pGeode;}private:/* 鼠标按下的起始坐标点 */float m_fStartPosX{0.0};float m_fStartPosY{ 0.0 };float m_fEndPosX{ 0.0 };float m_fEndPosY{ 0.0 };bool m_ctrlKeyPressed{false};             // Ctrl键被按下bool m_bPush{false};                      // 鼠标左键是否被按下osgViewer::Viewer* m_pViewer{nullptr};osg::ref_ptr<osg::Camera> m_spHudCamera;  // 用于HUD的相机osg::ref_ptr<osg::Node> m_spOldNode;      // 上次鼠标框选绘制出的矩形框};
int main(int argc, char *argv[])
{osgViewer::Viewer viewer;auto cowNode = osgDB::readNodeFile(R"(E:\osg\OpenSceneGraph-Data\cow.osg)");if (nullptr == cowNode){OSG_WARN << "node is null!";return 1;}auto spRoot = new osg::Group();osg::ref_ptr<osg::Camera> spHudCamera = new osg::Camera;spHudCamera->setClearMask(GL_DEPTH_BUFFER_BIT);  // 关闭深度缓冲// 设置渲染顺序为后渲染,即始终在其它绘制物体的上面,防止被其它绘制的物体遮挡spHudCamera->setRenderOrder(osg::Camera::RenderOrder::POST_RENDER); spHudCamera->setAllowEventFocus(false);  // 不接受任何焦点事件,即不响应键盘、鼠标事件spHudCamera->setReferenceFrame(osg::Transform::ReferenceFrame::ABSOLUTE_RF); // 设置参考帧为绝对帧spHudCamera->setViewMatrix(osg::Matrix::identity()); // 设置相机视图矩阵为单位矩阵,这样就矩形框选框就不受相机旋转等变换影响spRoot->addChild(cowNode);spRoot->addChild(spHudCamera);viewer.setSceneData(spRoot);viewer.addEventHandler(new selectBoxEventHandler(spHudCamera));return viewer.run();
}

3. 附加说明

        3.1. 颜色设置说明

              2.2节代码对颜色的设置,也可以按如下代码一样达到同样的效果:

 osg::Vec4Array* pColorArray = new osg::Vec4Array;pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.4));pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pQuardGeomerty->setColorArray(pColorArray);pQuardGeomerty->setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX);

也就是说设置一个顶点的颜色且颜色绑定方式为BIND_PER_PRIMITIVE_SET和分别设置4个顶点颜色,颜色绑定方式为BIND_PER_VERTEX效果相同。关于BIND_PER_PRIMITIVE_SET和BIND_PER_VERTEX的具体含义和不同点,请参考:osg图元绑定方式总结博文。

        3.2.矩形框显示和隐藏的另一种实现

       上面矩形框的显示和隐藏是通过removeChild和addChild函数来实现的,即将新的矩形框节点加入到相机作为其子节点之前,删除上次创建的矩形框节点。也可以通过osg::Node的setNodeMask函数来实现,如下为更改后的代码:

#include<osgViewer/Viewer>
#include<osg/ShapeDrawable>
#include<osgDB/readFile>
#include<osg/BlendFunc>#define HIDE_SELECT_BOX 0X0
#define  SHOW_SELECT_BOX ~HIDE_SELECT_BOXclass selectBoxEventHandler : public osgGA::GUIEventHandler
{
public:selectBoxEventHandler(osg::ref_ptr<osg::Camera> spHudCamera){m_spHudCamera = spHudCamera;}
private:virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, osg::Object* obj, osg::NodeVisitor* nv){m_pViewer = (osgViewer::Viewer*)(&aa);if (m_pViewer == nullptr){return false;}auto width = m_pViewer->getCamera()->getViewport()->width();auto height = m_pViewer->getCamera()->getViewport()->height();/* 设置HuD相机为正投影,这样绘制的矩形框和鼠标拖动的框选框大小就一样了且要设置正投影的区域和视图窗体一样大小,因为鼠标可以在窗体任何位置进行框选*/m_spHudCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, width, 0, height));auto eventType = ea.getEventType();switch (eventType){case osgGA::GUIEventAdapter::KEYDOWN:{if ((osgGA::GUIEventAdapter::KEY_Control_L == ea.getKey())|| (osgGA::GUIEventAdapter::KEY_Control_R == ea.getKey())) // Ctrl键被按下{m_ctrlKeyPressed = true;}}break;case osgGA::GUIEventAdapter::KEYUP:{if ((osgGA::GUIEventAdapter::KEY_Control_L == ea.getKey())|| (osgGA::GUIEventAdapter::KEY_Control_R == ea.getKey())) // Ctrl键被按下{m_ctrlKeyPressed = false;}}break;case osgGA::GUIEventAdapter::PUSH:  // 鼠标左键按下{auto buttonMask = ea.getButtonMask();auto bIsMouseBtn = buttonMask & osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON;if (bIsMouseBtn){m_fStartPosX = ea.getX();m_fStartPosY = ea.getY();m_bPush = true;}else if (buttonMask & osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) // 鼠标右键按下,则删除选择框{if (m_spRectGeometry != nullptr){m_spRectGeometry->setNodeMask(HIDE_SELECT_BOX);}}}break;case osgGA::GUIEventAdapter::RELEASE:  // 释放鼠标左键{m_bPush = false;}break;case osgGA::GUIEventAdapter::DRAG:    // 拖动鼠标{auto buttonMask = ea.getButtonMask();auto bIsMouseBtn = buttonMask & osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON;if (bIsMouseBtn && m_ctrlKeyPressed && m_bPush){m_fEndPosX = ea.getX();m_fEndPosY = ea.getY();if (nullptr != m_spRectGeometry){auto pVertArray = (osg::Vec3Array*)m_spRectGeometry->getVertexArray();(*pVertArray)[0].set(m_fStartPosX, m_fStartPosY, 0.0);(*pVertArray)[1].set(m_fStartPosX, m_fEndPosY, 0.0);(*pVertArray)[2].set(m_fEndPosX, m_fEndPosY, 0.0);(*pVertArray)[3].set(m_fEndPosX, m_fStartPosY, 0.0);// m_spRectGeometry->setVertexArray(pVertArray);m_spRectGeometry->dirtyDisplayList(); // 告知底层,外层顶点数据更改了,否则不会用新的坐标绘制矩形m_spRectGeometry->setNodeMask(SHOW_SELECT_BOX);}else{auto spSelectBox = createSelectBox(m_fStartPosX, m_fStartPosY, m_fEndPosX, m_fEndPosY);m_spRectGeometry = spSelectBox->asGeode()->getChild(0)->asGeometry();m_spHudCamera->addChild(spSelectBox);}return true;}}} // end swithreturn  false;}osg::Geode* createSelectBox(float fStartPosX, float fStartPosY, float fEndPosX, float fEndPosY){osg::Geode* pGeode = new osg::Geode();auto pQuardGeomerty = new osg::Geometry();pGeode->addChild(pQuardGeomerty);osg::Vec3Array* pVertArray = new osg::Vec3Array;pVertArray->push_back(osg::Vec3(fStartPosX, fStartPosY, 0.0));pVertArray->push_back(osg::Vec3(fStartPosX, fEndPosY, 0.0));pVertArray->push_back(osg::Vec3(fEndPosX, fEndPosY, 0.0));pVertArray->push_back(osg::Vec3(fEndPosX, fStartPosY, 0.0));pQuardGeomerty->setVertexArray(pVertArray);osg::Vec4Array* pColorArray = new osg::Vec4Array;pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.4));/*  pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));*/pQuardGeomerty->setColorArray(pColorArray);//pQuardGeomerty->setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX);pQuardGeomerty->setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_PRIMITIVE_SET);pQuardGeomerty->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));pGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); // 关闭光照pGeode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); // 开启透明,否则就不能透过选择框看到后面的牛pGeode->addDrawable(pQuardGeomerty);return pGeode;}private:/* 鼠标按下的起始坐标点 */float m_fStartPosX{ 0.0 };float m_fStartPosY{ 0.0 };float m_fEndPosX{ 0.0 };float m_fEndPosY{ 0.0 };bool m_ctrlKeyPressed{ false };             // Ctrl键被按下bool m_bPush{ false };                      // 鼠标左键是否被按下osgViewer::Viewer* m_pViewer{ nullptr };osg::ref_ptr<osg::Camera> m_spHudCamera;  // 用于HUD的相机osg::ref_ptr<osg::Geometry> m_spRectGeometry;      // 矩形框};int main(int argc, char *argv[])
{osgViewer::Viewer viewer;auto cowNode = osgDB::readNodeFile(R"(E:\osg\OpenSceneGraph-Data\cow.osg)");if (nullptr == cowNode){OSG_WARN << "node is null!";return 1;}auto spRoot = new osg::Group();osg::ref_ptr<osg::Camera> spHudCamera = new osg::Camera;spHudCamera->setClearMask(GL_DEPTH_BUFFER_BIT);  // 开启深度缓冲// 设置渲染顺序为后渲染,即始终在其它绘制物体的上面,防止被其它绘制的物体遮挡spHudCamera->setRenderOrder(osg::Camera::RenderOrder::POST_RENDER); spHudCamera->setAllowEventFocus(false);  // 不接受任何焦点事件,即不响应键盘、鼠标事件spHudCamera->setReferenceFrame(osg::Transform::ReferenceFrame::ABSOLUTE_RF); // 设置参考帧为绝对帧spHudCamera->setViewMatrix(osg::Matrix::identity()); // 设置相机视图矩阵为单位矩阵,这样就矩形框选框就不受相机旋转等变换影响spRoot->addChild(cowNode);spRoot->addChild(spHudCamera);viewer.setSceneData(spRoot);viewer.addEventHandler(new selectBoxEventHandler(spHudCamera));return viewer.run();
}

说明

  • 在鼠标拖动坐标改变重新设置矩形框坐标时,记得调用:           
// 告知底层,外层顶点数据更改了,否则不会用新的坐标绘制矩形 
m_spRectGeometry->setVertexArray(pVertArray);

或调用:

 m_spRectGeometry->dirtyDisplayList(); // 告知底层,外层顶点数据更改了,否则不会用新的坐标绘制矩形

在C++中,只要把指针指向的内容改了,也就是立马改了,但在上述代码中如果以为只把顶点数据改了,新矩形就会呈现出来是错误的,不调用上述代码中的某一种,新矩形不会绘制,因为只改了顶点数据,但osg还没执行重绘。

  • 上述采用节点的setNodeMask函数,通过设置节点掩码来实现矩形框的显示或隐藏,其实最好的方法是采用osg::Switch来控制矩形框的显示和隐藏,在此不再详述列出代码,关于这两者的详述,参见:osg利用setNodeMask和Switch隐藏节点用法说明博文。

相关文章:

osg实现鼠标框选

目录 1. 需求的提出 2. 具体实现 2.1. 禁止场景跟随鼠标转动 2.2. 矩形框前置绘制 3. 附加说明 3.1. 颜色设置说明 3.2.矩形框显示和隐藏的另一种实现 1. 需求的提出 有时需要在屏幕通过按住键盘上的某个键如Ctrl键且按住鼠标左键&#xff0c;拖出一个矩形&#xff0c;实现框…...

电路原理解题笔记(一)

文章目录 贼基础的知识等效电阻基尔霍夫电流定律电阻电路的一般分析支路电流法节点电压法回路电流法 电路定理叠加定理戴维宁等效电路诺顿等效电路求某电阻值为多少可吸收最大功率。吸收、释放功率 第一个月&#xff0c;对应猴博士的一到五课时。 贼基础的知识电阻电路的等效变…...

分享几个优秀开源免费管理后台模版,建议收藏!

大家好&#xff0c;我是 jonssonyan 今天和大家分享一些免费开源的后台管理页面&#xff0c;帮助大家快速搭建前端页面。为什么要用模板&#xff1f;道理很简单&#xff0c;原因是方便我们快速开发。我们不应该花太多的时间在页面调整上&#xff0c;而应该把精力放在核心逻辑和…...

BFS模板:844. 走迷宫

给定一个 nmnm 的二维整数数组&#xff0c;用来表示一个迷宫&#xff0c;数组中只包含 00 或 11&#xff0c;其中 00 表示可以走的路&#xff0c;11 表示不可通过的墙壁。 最初&#xff0c;有一个人位于左上角 (1,1)(1,1) 处&#xff0c;已知该人每次可以向上、下、左、右任意…...

re学习(37)DASCTF 2023 0X401七月暑期挑战赛 controflow

程序通过改变栈里面的返回地址来控制程序的控制流 从而达到混淆的效果 左侧有许多被hook的函数 在每个函数开头设置断点 然后观察程序的运行流程 会发现输入的数据会进行 异或 相加 异或 相减 相乘 异或等操作 要注意部分运算的索引是 从[10]开始的 具体思路参考&#xf…...

数字IC前端学习笔记:数字乘法器的优化设计(进位保留乘法器)

相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 阵列乘法器设计中限制乘法器速度的是随着数据位宽而迅速增大的串行进位链&#xff0c;如果使用进位保留加法器&#xff0c;则可以避免在设计中引入较长时间的等待&…...

prority_queue的学习

优先级队列&#xff08;Priority Queue&#xff09;是一种抽象数据类型&#xff0c;它类似于普通的队列或堆栈&#xff0c;但每个元素都有一个关联的优先级&#xff0c;这个优先级决定了元素在队列中的位置和被访问的顺序。在优先级队列中&#xff0c;具有最高优先级的元素通常…...

【vue3】toRef与toRefs的使用,toRef与ref的区别

假期第四篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 1、toRef与toRefs 创建一个ref对象&#xff0c;其value值指向另一个对象中的某个属性 语法&#xff1a;const name toRef&#xff08;person,‘name’&#xf…...

信息论基础第二章部分习题

2.5 证明若H(Y|X)0&#xff0c;则Y是X的函数 若 H ( Y ∣ X ) 0 H(Y|X) 0 H(Y∣X)0&#xff0c;意味着在已知 X X X 的条件下&#xff0c; Y Y Y 的不确定性为零&#xff0c;即给定 X X X 的值&#xff0c;我们完全确定了 Y Y Y 的值。这表明 Y Y Y 的取值完全由 X X…...

信息化发展73

数字经济 数字经济是继农业经济、工业经济之后的更高级经济形态。从本质上看&#xff0c;数字经济是一种新的技术经济范式&#xff0c;它建立在信息与通信技术的重大突破的基础上&#xff0c;以数字技术与实体经济融合驱动的产业梯次转型和经济创新发展的主引擎&#xff0c;在…...

560. 和为 K 的子数组

题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的连续子数组的个数 。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2示例 2&#xff1a; 输入&#xff1a;nums [1,2,3], k 3 输出&#xff1a;2…...

24 mysql all 查询

前言 这里主要是 探究一下 explain $sql 中各个 type 诸如 const, ref, range, index, all 的查询的影响, 以及一个初步的效率的判断 这里会调试源码来看一下 各个类型的查询 需要 lookUp 的记录 以及 相关的差异 此系列文章建议从 mysql const 查询 开始看 测试表结构…...

【Excel单元格数值统计】python实现-附ChatGPT解析

1.题目 Excel单元格数值统计 知识点: 递归、循环数组 时间限制:2s 空间限制:256MB 限定语言:不限 题目描述: Excel工作表中对选定区域的数值进行统计的功能非常实用。仿照Excel的这个功能,请对给定表格中选中区域中的单元格进行求和统计,并输出统计结果。 为简化计算,假设当…...

爬虫项目实战——爬取B站视频

目标&#xff1a;对B站视频详情页url进行视频的爬取。 注&#xff1a;由于B站的音频和视频的链接是分开的&#xff0c;所以在提取是需要分别提取&#xff0c;然后进行合成。 这里只管提取&#xff0c;合成的工作以后再说。 具体步骤 发送请求 对于视频详情页url地址发送请求 …...

关掉在vscode使用copilot时的提示音

1. 按照图示的操作File --> Preferences --> Settings 2. 搜索框输入关键字Sound&#xff0c;因为是要关掉声音&#xff0c;所以找有关声音的设置 3. 找到如下图所示的选项 Audio Cues:Line Has Inline Suggetion,将其设置为Off 这样&#xff0c;就可以关掉suggest code时…...

【有限域除法】二元多项式除法电路原理及C语言实现

二元多项式除法电路原理 例: g ( x ) = x 4 + x 2 + x + 1 g(x)=x^4 + x^2+x+1...

RabbitMQ核心总结

AMQP协议核心概念 RabbitMQ是基于AMQP协议的&#xff0c;通过使用通用协议就可以做到在不同语言之间传递。 server&#xff1a;又称broker&#xff0c;接受客户端连接&#xff0c;实现AMQP实体服务。 connection&#xff1a;连接和具体broker网络连接。 channel&#xff1a…...

Unicode与UTF-8

软件开发中乱码问题经常遇到&#xff0c;Unicode&#xff0c;UTF-8, ASCII等都是高频词语&#xff0c;不过具体是啥意思其实都不清楚。这个周末研究了一下&#xff0c;略有了解&#xff0c;记录一下。 Unicode Unicode本身是纯理论的东西&#xff0c;和具体计算机实现无关。它…...

A : DS单链表--类实现

Description 用C语言和类实现单链表&#xff0c;含头结点 属性包括&#xff1a;data数据域、next指针域 操作包括&#xff1a;插入、删除、查找 注意&#xff1a;单链表不是数组&#xff0c;所以位置从1开始对应首结点&#xff0c;头结点不放数据 类定义参考 #include<…...

React Hooks —— ref hooks

什么是Hooks Hooks从语法上来说是一些函数。这些函数可以用于在函数组件中引入状态管理和生命周期方法。 React Hooks的优点 简洁 从语法上来说&#xff0c;写的代码少了上手非常简单 基于函数式编程理念&#xff0c;只需要掌握一些JavaScript基础知识与生命周期相关的知识不…...

泛型与Gson解析

/*** 回调接口的一种实现* 用于把网络返回的json字符串转换成参数化类型* 泛型 T 就是用户输入的javaBean的类型*/ public abstract class HttpCallback<T> implements ICallback {Overridepublic void onSuccess (String result) {// result就是网络回来的数据// 把这个…...

c++使用ifstream和ofstream报错:不允许使用不完整的类型

学习《C Primer》关于IO库的部分&#xff0c;输入284页的的代码&#xff0c;出现了报错&#xff1a; 不允许使用不完整的类型 原来的代码&#xff1a; #include <iostream> #include <vector> using namespace std;int main(int argc, char **argv) {ifstream in…...

调试器通用波形显示工具

前言&#xff1a;事情起因是我们实验室买了个无线调试器是CMSIS-DAP的&#xff0c;无法使用J-SCOPE显示波形来方便调PID&#xff0c;所以我就在网上找到了个开源工具链接&#xff1a;http://t.csdnimg.cn/ZqZPY使用方法&#xff1a;工具是好工具&#xff0c;就是没有使用手册&a…...

Linux中getopt函数、optind等变量使用详解

getopt函数、optind等变量使用详解 最近在学习《Unix网络编程》vol2时&#xff0c;发现书中例子经常使用一个命令行解析getopt函数&#xff0c;因为函数声明比较特别&#xff0c;根据自己摸索&#xff0c;遂总结出使用方法。 1. getopt函数的声明 该函数是由Unix标准库提供的…...

RDP协议流程详解(二)Basic Settings Exchange 阶段

RDP连接建立过程&#xff0c;在Connection Initiation后&#xff0c;RDP客户端和服务端将进行双方基础配置信息交换&#xff0c;也就是basic settings exchange阶段。在此阶段&#xff0c;将包含两条消息Client MCS Connect Initial PDU和Server MCS Connect Response PDU&…...

实时人脸五观检测:基于libfacedetection(CNN模型)

一、前言 随着人工智能技术的不断发展,人脸检测已成为计算机视觉领域的重要应用之一。人脸检测是一种将输入图像中的人脸位置和轮廓提取出来的技术,广泛应用于人脸识别、智能监控、人机交互等领域。利用libfacedetection开源的人脸检测库,实现人脸检测。 libfacedetection…...

图像和视频上传平台Share Me

本文完成于 6 月&#xff0c;所以反代中&#xff0c;域名演示还是使用的 laosu.ml&#xff0c;不过版本并没有什么变化&#xff1b; 什么是 Share Me &#xff1f; Share Me 是使用 Next.js 和 PocketBase 的自托管图像和视频上传平台&#xff0c;具有丰富的嵌入支持和 API&…...

JavaScript 在前端开发中有什么应用?

JavaScript&#xff08;简称JS&#xff09;是一种脚本语言&#xff0c;广泛应用于前端开发中。作为Web前端三大基石之一&#xff08;HTML、CSS、JS&#xff09;&#xff0c;它可以使网页具备交互性、动态性和实时性&#xff0c;提高用户体验。在本文中&#xff0c;我将详细论述…...

【沐风老师】推荐2023年3DMAX的10个最佳插件!

推荐2023年3DMAX的10个最佳插件 3dMax是一款专业的三维建模、动画和渲染软件&#xff0c;供建筑师、工程师、游戏开发商和视觉效果艺术家使用。它提供了一系列用于建模、纹理、装配、动画和渲染3D对象和场景的工具。3ds Max包括粒子和流体模拟的高级功能&#xff0c;以及对各种…...

【visual studio 小技巧】项目属性->生成->事件

需求 我们有时会用到一些dll&#xff0c;需要把这些dll和我们生成的exe放到一起&#xff0c;一般我们是手动自己copy&#xff0c; 这样发布的时候&#xff0c;有时会忘记拷贝这个dll&#xff0c;导致程序运行出错。学会这个小技巧&#xff0c;就能实现自动copy&#xff0c;非…...

嵊州市住房和建设局网站/如何实施网站推广

众所周知&#xff0c;QQ上面是可以设置自动回复的&#xff0c;但是微信上面并不可以。最近在学习Python,发现Python的适用范围是真的很广,这里使用itchat组件实现微信的自动回复。1&#xff1a;安装itchatpip install itchat2&#xff1a;简单实例(1):发送信息import itchatitc…...

重庆搭建工厂/seo算法培训

Android开发平台中&#xff0c;可通过TelephonyManager 获取本机号码。 TelephonyManager phoneMgr(TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE); txtPhoneNumber.setText(phoneMgr.getLine1Number()); //txtPhoneNumber是一个EditText 用于显示手机号…...

建设装修网站/百度推广后台登录

一、前述 反向自动求导是 TensorFlow 实现的方案&#xff0c;首先&#xff0c;它执行图的前向阶段&#xff0c;从输入到输出&#xff0c;去计算节点值&#xff0c;然后是反向阶段&#xff0c;从输出到输入去计算所有的偏导。 二、具体 1、举例 图是第二个阶段&#xff0c;在第一…...

网站建设公司的业务范围/百度获客平台怎么收费的

ts_15_0001.html。官网上提供了一个基于pycharmmodelarts的示例&#xff0c;链接如下https://support.huaweicloud.com/bestpractice-modelarts/modelarts_10_0021.html&#xff0c;但里面的步骤3和步骤4ts_15_0001.html。官网上提供了一个基于pycharmmodelarts的示例&#xff…...

北京市住房城乡建设厅网站首页/免费推广网站大全集合

HDFS采用Master/Slave架构。NameNode就是HDFS的Master架构。HDFS系统包括一个NameNode组件&#xff0c;主要负责HDFS文件系统的管理工作&#xff0c;具体包括名称空间(namespace)管理&#xff0c;文件Block管理。 NameNode提供的是始终被动接收服务的server。 NameNode主要有三…...

洛阳做网站的公司哪家好/最好用的搜索引擎排名

substring 方法用于提取字符串中介于两个指定下标之间的字符 substring(start,end) 开始和结束的位置&#xff0c;从零 开始的索引 参数 描述 start 必需。一个非负的整数&#xff0c;规定要提取的子串的第一个字符在 stringObject 中的位置。 stop 可选。一个…...