osg实现鼠标框选

news2024/12/23 8:51:22

目录

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 swith
   
        return  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_BOX

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_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 swith

        return  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(); // 告知底层,外层顶点数据更改了,否则不会用新的坐标绘制矩形

如果以为只把顶点数据改了就能重新绘制新的矩形是错误的,不调用上述代码中的某一种,新矩形不会绘制。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1054695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MongoDB 2023年度纽约 MongoDB 年度大会话题 -- 企业级从传统数据库到NOSQL,你会更好...

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&…

Android学习之路(17) Android Adapter详解

Adapter基础讲解 本节引言 从本节开始我们要讲的UI控件都是跟Adapter(适配器)打交道的&#xff0c;了解并学会使用这个Adapter很重要&#xff0c; Adapter是用来帮助填充数据的中间桥梁&#xff0c;简单点说就是&#xff1a;将各种数据以合适的形式显示到view上,提供 给用户看…

读取一张图片各种颜色占比

提问之初 <small> 读取一张图片各种颜色占比 /storage/emulated/0/Pictures/Screenshots/Screenshot_20230725_195440.jpg有趣优雅热情沉着的代码与注释/每行每行 from PIL import Image # 导入PIL大法&#xff0c;这是处理图像的必备神器# 图片路径&#xff0c;此处为…

2023年哪款PDF虚拟打印机好用?

PDF文档想必大家都不陌生&#xff0c;在工作中经常会用到该格式的文档&#xff0c;那么有哪些方法能制作PDF文档呢&#xff1f;一般都是借助PDF虚拟打印机的&#xff0c;那么有哪些好用的软件呢&#xff1f; pdfFactory不仅为用户提供了丰富的PDF文档生成、打印功能&#xff0…

蓝桥杯每日一题2023.10.1

路径 - 蓝桥云课 (lanqiao.cn) 题目分析 求最短路问题&#xff0c;有多种解法&#xff0c;下面介绍两种蓝桥杯最常用到的两种解法 方法一 Floyd&#xff08;求任意两点之间的最短路&#xff09;注&#xff1a;不能有负权回路 初始化每个点到每个点的距离都为0x3f这样才能对…

00后老程序员不讲武德 偷袭 猿人学第二题解题记录 match/2

我是一个00后的老程序员&#xff0c;半夜00点有个Python群友发来一个题目&#xff0c;我以为是leetcode算法题呢&#xff0c;这不轻而易举、手到擒来、简简单单、有手就行&#xff0c;哪怕是博利叶排序我也能招架得住啊&#xff0c;结果发来一个链接。 题发出来了&#xff0…

GD32F10X ----RTC

1. RTC的简介 STM32 的实时时钟&#xff08;RTC&#xff09;是一个独立的定时器。STM32 的 RTC 模块拥有一组连续计数的计数器&#xff0c;在相应软件配置下&#xff0c;可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC 模块和时钟配置…

BUUCTF-WEB-刷题记录

题目地址 https://buuoj.cn/challenges[HITCON 2017]SSRFme 代码理解 进入主页后发现是代码审计/ escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数— 抑制错误输出 mkdir — 创建目录 chdir 更改目录 shell_exec — 通过 shell 环境执行命令&#x…

第5章-宏观业务分析方法-5.3-主成分分析法

5.3.1 主成分分析简介 主成分分析是以最少的信息丢失为前提,将原有变量通过线性组合的方式综合成少数几个新变量;用新变量代替原有变量参与数据建模,这样可以大大减少分析过程中的计算工作量;主成分对新变量的选取不是对原有变量的简单取舍,而是原有变量重组后的结果,因此…

Spring注册Bean系列--方法1:@Component

原文网址&#xff1a;Spring注册Bean系列--方法1&#xff1a;Component_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Spring注册Bean的方法&#xff1a;Component。 注册Bean的方法我写了一个系列&#xff0c;见&#xff1a;Spring注册Bean(提供Bean)系列--方法大全_IT利刃出鞘…

C++代码示例:排列数简单生成工具

文章目录 前言代码仓库内容代码&#xff08;有详细注释&#xff09;编译和运行命令结果总结参考资料作者的话 前言 C代码示例&#xff1a;排列数简单生成工具。 代码仓库 yezhening/Programming-examples: 编程实例 (github.com)Programming-examples: 编程实例 (gitee.com) …

PHP 数码公司运营管理系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 数码公司运营管理系统系统是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 php 数码公司运营管理系统 代码 https://download.csdn.net/download/qq_41…

实战教程:如何在API监控中实现高效报警和通知

问题 因一业务需要&#xff0c;想要对API服务接口添加一些监控&#xff0c;以帮助跟踪应用程序的性能、问题和用户活动等。实现监控的方式有多种多样的方式&#xff0c;以下是一些常用的方法&#xff1a; 日志记录&#xff1a; 在应用程序中添加详细的日志记录&#xff0c;包括…

如何开发一个微信小程序

微信小程序是微信公众平台推出的一种全新的应用形态&#xff0c;它具有跨平台、小巧、高效等特点&#xff0c;深受用户喜爱。 一直想学习开发小程序&#xff0c;最近找了一个教程来看&#xff0c;发现原生小程序写起来还是挺简单的&#xff0c;主要分为以下几步。 准备开发环境…

SpringCloud Alibaba - Sentinel 限流规则(案例 + JMeter 测试分析)

目录 一、Sentinel 限流规则 1.1、簇点链路 1.2、流控模式 1.2.1、直接流控模式 1.2.2、关联流控模式 a&#xff09;在 OrderController 中新建两个端点. b&#xff09;在 Sentinel 控制台中对订单查询端点进行流控 c&#xff09;使用 JMeter 进行测试 d&#xff09;分…

C语言 Cortex-A7核 PWM实验

1 实验目的 驱动开发板蜂鸣器风扇、马达进行工作 2 代码 pwm.h #ifndef __PWM_H__ #define __PWM_H__ #include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_ti…

网页一直跳转到国家反诈中心页面

很明显&#xff0c;我进入的是vscode的官方下载地址。 但是一直会出现反诈中心的拦截 我们需要在控制面板中&#xff0c;找到网络&#xff0c; 将Internet 协议版本 4 (TCP/IPv4)的属性改成 使用下面的DNS 服务地址(E)&#xff1a;8.8.8.8 这样就可以正常访问相关的页面了

【day10.01】使用select实现服务器并发

用select实现服务器并发&#xff1a; linuxlinux:~/study/1001$ cat server.c #include <myhead.h>#define ERR_MSG(msg) do{\printf("%d\n",__LINE__);\perror(msg);\ }while(0)#define PORT 8880#define IP "192.168.31.38"int main(int argc, c…

动态规划算法(1)--矩阵连乘和凸多边形剖分

目录 一、动态数组 1、创建动态数组 2、添加元素 3、删除修改元素 4、访问元素 5、返回数组长度 6、for each遍历数组 二、输入多个数字 1、正则表达式 2、has.next()方法 三、矩阵连乘 1、什么是矩阵连乘&#xff1f; 2、动态规划思路 3、手推m和s矩阵 4、完…

Vue封装全局SVG组件

1.SVG图标配置 1.安装插件 npm install vite-plugin-svg-icons -D 2.Vite.config.ts中配置 import { createSvgIconsPlugin } from vite-plugin-svg-icons import path from path export default () > {return {plugins: [createSvgIconsPlugin({// Specify the icon fo…