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

关于QGroundControl的软件架构的理解

首先QGC是基于QT平台开发,个人理解软件架构即为项目前后端结构,以及前后端数据交互的逻辑。下面是对QGroundControl源码的一些个人理解,写这个博客只是为了记录下来,防止时间久了忘记,过程中看了一些大佬的博客来帮助理解,感谢一下大佬:

火山上的企鹅

阿木实验室

望天边星宿

前言

  • 前端qml结构

QGC的前端主要为五个主要页面和一个顶栏:

MainToolBar(顶栏)

AppSetting.qml

SetupView.qml

PlanView.qml

FlightDispalyView.qml

AnalyzeView.qml

  • 后端类结构

 前端显示与后端逻辑进行数据交互,即实现了QGC地面站功能。

架构理解

架构理解可以从QGC的运行main函数开始逐步理解。

  • main.cc

在main.cc中有几个关键程序

创建QGCApplication实例,QGCApplication是QGroundControl中的核心类,提供了应用程序的生命周期管理、连接管理、飞行日志管理、地图和任务管理、设置和配置管理,以及警报和通知管理等功能。它扮演着关键角色。这个类只提供了唯一的实例,另外提供了一个访问它的全局函数QGCApplication* qgcApp(void){}

QGCApplication* app = new QGCApplication(argc, argv, runUnitTests);

在_initCommon()中将C++类注册,在前端qml中可以调用,实现前后端数据交互。在

qgroundcontrolQmlGlobalSingletonFactory中将QGroundControlQmlGlobal类实例化为单例工厂QGroundControl。
app->_initCommon()
{static const char* kRefOnly         = "Reference only";static const char* kQGroundControl  = "QGroundControl";static const char* kQGCControllers  = "QGroundControl.Controllers";static const char* kQGCVehicle      = "QGroundControl.Vehicle";QSettings settings;// Register our Qml objectsqmlRegisterType<QGCPalette>     ("QGroundControl.Palette", 1, 0, "QGCPalette");qmlRegisterType<QGCMapPalette>  ("QGroundControl.Palette", 1, 0, "QGCMapPalette");qmlRegisterUncreatableType<Vehicle>                 (kQGCVehicle,                       1, 0, "Vehicle",                    kRefOnly);qmlRegisterUncreatableType<MissionManager>          (kQGCVehicle,                       1, 0, "MissionManager",             kRefOnly);qmlRegisterUncreatableType<ParameterManager>        (kQGCVehicle,                       1, 0, "ParameterManager",           kRefOnly);qmlRegisterUncreatableType<VehicleObjectAvoidance>  (kQGCVehicle,                       1, 0, "VehicleObjectAvoidance",     kRefOnly);qmlRegisterUncreatableType<QGCCameraManager>        (kQGCVehicle,                       1, 0, "QGCCameraManager",           kRefOnly);qmlRegisterUncreatableType<QGCCameraControl>        (kQGCVehicle,                       1, 0, "QGCCameraControl",           kRefOnly);qmlRegisterUncreatableType<QGCVideoStreamInfo>      (kQGCVehicle,                       1, 0, "QGCVideoStreamInfo",         kRefOnly);qmlRegisterUncreatableType<LinkInterface>           (kQGCVehicle,                       1, 0, "LinkInterface",              kRefOnly);qmlRegisterUncreatableType<MissionController>       (kQGCControllers,                   1, 0, "MissionController",          kRefOnly);qmlRegisterUncreatableType<GeoFenceController>      (kQGCControllers,                   1, 0, "GeoFenceController",         kRefOnly);qmlRegisterUncreatableType<RallyPointController>    (kQGCControllers,                   1, 0, "RallyPointController",       kRefOnly);qmlRegisterUncreatableType<MissionItem>         (kQGroundControl,                       1, 0, "MissionItem",                kRefOnly);qmlRegisterUncreatableType<VisualMissionItem>   (kQGroundControl,                       1, 0, "VisualMissionItem",          kRefOnly);qmlRegisterUncreatableType<CoordinateVector>    (kQGroundControl,                       1, 0, "CoordinateVector",           kRefOnly);qmlRegisterUncreatableType<QmlObjectListModel>  (kQGroundControl,                       1, 0, "QmlObjectListModel",         kRefOnly);qmlRegisterUncreatableType<MissionCommandTree>  (kQGroundControl,                       1, 0, "MissionCommandTree",         kRefOnly);qmlRegisterUncreatableType<CameraCalc>          (kQGroundControl,                       1, 0, "CameraCalc",                 kRefOnly);qmlRegisterUncreatableType<LogReplayLink>       (kQGroundControl,                       1, 0, "LogReplayLink",              kRefOnly);qmlRegisterType<LogReplayLinkController>        (kQGroundControl,                       1, 0, "LogReplayLinkController");
#if defined(QGC_ENABLE_MAVLINK_INSPECTOR)qmlRegisterUncreatableType<MAVLinkChartController> (kQGroundControl,                    1, 0, "MAVLinkChart",               kRefOnly);
#endif
#if defined(QGC_ENABLE_PAIRING)qmlRegisterUncreatableType<PairingManager>      (kQGroundControl,                       1, 0, "PairingManager",             kRefOnly);
#endifqmlRegisterUncreatableType<AutoPilotPlugin>     ("QGroundControl.AutoPilotPlugin",      1, 0, "AutoPilotPlugin",            kRefOnly);qmlRegisterUncreatableType<VehicleComponent>    ("QGroundControl.AutoPilotPlugin",      1, 0, "VehicleComponent",           kRefOnly);qmlRegisterUncreatableType<JoystickManager>     ("QGroundControl.JoystickManager",      1, 0, "JoystickManager",            kRefOnly);qmlRegisterUncreatableType<Joystick>            ("QGroundControl.JoystickManager",      1, 0, "Joystick",                   kRefOnly);qmlRegisterUncreatableType<QGCPositionManager>  ("QGroundControl.QGCPositionManager",   1, 0, "QGCPositionManager",         kRefOnly);qmlRegisterUncreatableType<FactValueSliderListModel>("QGroundControl.FactControls",     1, 0, "FactValueSliderListModel",   kRefOnly);qmlRegisterUncreatableType<QGCMapPolygon>       ("QGroundControl.FlightMap",            1, 0, "QGCMapPolygon",              kRefOnly);qmlRegisterUncreatableType<QGCGeoBoundingCube>  ("QGroundControl.FlightMap",            1, 0, "QGCGeoBoundingCube",         kRefOnly);qmlRegisterUncreatableType<TrajectoryPoints>    ("QGroundControl.FlightMap",            1, 0, "TrajectoryPoints",           kRefOnly);qmlRegisterType<QGCMapCircle>                   ("QGroundControl.FlightMap",            1, 0, "QGCMapCircle");qmlRegisterType<ParameterEditorController>      (kQGCControllers,                       1, 0, "ParameterEditorController");qmlRegisterType<ESP8266ComponentController>     (kQGCControllers,                       1, 0, "ESP8266ComponentController");qmlRegisterType<ScreenToolsController>          (kQGCControllers,                       1, 0, "ScreenToolsController");qmlRegisterType<PlanMasterController>           (kQGCControllers,                       1, 0, "PlanMasterController");qmlRegisterType<ValuesWidgetController>         (kQGCControllers,                       1, 0, "ValuesWidgetController");qmlRegisterType<QGCFileDialogController>        (kQGCControllers,                       1, 0, "QGCFileDialogController");qmlRegisterType<RCChannelMonitorController>     (kQGCControllers,                       1, 0, "RCChannelMonitorController");qmlRegisterType<JoystickConfigController>       (kQGCControllers,                       1, 0, "JoystickConfigController");qmlRegisterType<LogDownloadController>          (kQGCControllers,                       1, 0, "LogDownloadController");qmlRegisterType<SyslinkComponentController>     (kQGCControllers,                       1, 0, "SyslinkComponentController");qmlRegisterType<EditPositionDialogController>   (kQGCControllers,                       1, 0, "EditPositionDialogController");#ifndef __mobile__
#ifndef NO_SERIAL_LINKqmlRegisterType<FirmwareUpgradeController>      (kQGCControllers,                       1, 0, "FirmwareUpgradeController");
#endif
#endifqmlRegisterType<GeoTagController>               (kQGCControllers,                       1, 0, "GeoTagController");qmlRegisterType<MavlinkConsoleController>       (kQGCControllers,                       1, 0, "MavlinkConsoleController");
#if defined(QGC_ENABLE_MAVLINK_INSPECTOR)qmlRegisterType<MAVLinkInspectorController>     (kQGCControllers,                       1, 0, "MAVLinkInspectorController");
#endif// Register Qml SingletonsqmlRegisterSingletonType<QGroundControlQmlGlobal>   ("QGroundControl",                          1, 0, "QGroundControl",         qgroundcontrolQmlGlobalSingletonFactory);qmlRegisterSingletonType<ScreenToolsController>     ("QGroundControl.ScreenToolsController",    1, 0, "ScreenToolsController",  screenToolsControllerSingletonFactory);qmlRegisterSingletonType<ShapeFileHelper>           ("QGroundControl.ShapeFileHelper",          1, 0, "ShapeFileHelper",        shapeFileHelperSingletonFactory);
}

在_initForNormalAppBoot()中进行启动初始化,加载qml文件。

app->_initForNormalAppBoot()QQmlApplicationEngine* QGCCorePlugin::createRootWindow(QObject *parent)
{QQmlApplicationEngine* pEngine = new QQmlApplicationEngine(parent);pEngine->addImportPath("qrc:/qml");// 注册为对象在qml中直接使用,不需要importpEngine->rootContext()->setContextProperty("joystickManager", qgcApp()->toolbox()->joystickManager());pEngine->rootContext()->setContextProperty("debugMessageModel", AppMessages::getModel());pEngine->load(QUrl(QStringLiteral("qrc:/qml/MainRootWindow.qml")));return pEngine;
}
  • 整体架构

想要搞明白整体架构就需要理解QGCApplication类、QGCToolBox类、QGroundControlQmlGlobal类和QGCtool类。

QGCApplication类中新建了QGCToolbox类,在QGCToolbox类初始化时需要传入QGCApplication类,这样通过qgcAPP()->toolBox()就可以获取到功能类的所有属性。

QGCToolBox类是一个大的工具类,QGC的所有功能类都在这个toolBox中进行实例化,使用toolBox提供的接口即可调用类的属性和方法。

在QGroundControlQmlGlobal中通过Q_PROPERTY将功能类的属性和方法共前端可以调用,setToolbox()方法将所有功能类使用指针地址连接到QGCToolBox定义的功能类,所以QGroundControlQmlGlobal是前端获取后端数据的总接口。上边的单例工厂实例化将QGroundControlQmlGlobal实例化为QGroundControl,则前端qml通过import 即可实现调用C++类。

还有一个QGCTool类,所有的功能类都继承了QGCTool。在QGCTool类型定义了QGCApplication* _app;和QGCToolbox* _toolbox;和(QGCApplication* app, QGCToolbox* toolbox)方法,即每个功能类都都有QGCApplication和QGCToolbox,并且都指向同一个QGCApplication和QGCToolbox,即QGCApplication中的_app和_toolBox.这样实现了各个功能类的互通。

QGCToolbox::QGCToolbox(QGCApplication* app)
{// SettingsManager must be first so settings are available to any subsequent tools_settingsManager        = new SettingsManager           (app, this);//-- Scan and load plugins_scanAndLoadPlugins(app);_audioOutput            = new AudioOutput               (app, this);_factSystem             = new FactSystem                (app, this);_firmwarePluginManager  = new FirmwarePluginManager     (app, this);
#ifndef __mobile___gpsManager             = new GPSManager                (app, this);
#endif_imageProvider          = new QGCImageProvider          (app, this);_joystickManager        = new JoystickManager           (app, this);_linkManager            = new LinkManager               (app, this);_mavlinkProtocol        = new MAVLinkProtocol           (app, this);_missionCommandTree     = new MissionCommandTree        (app, this);_multiVehicleManager    = new MultiVehicleManager       (app, this);_mapEngineManager       = new QGCMapEngineManager       (app, this);_uasMessageHandler      = new UASMessageHandler         (app, this);_qgcPositionManager     = new QGCPositionManager        (app, this);_followMe               = new FollowMe                  (app, this);_videoManager           = new VideoManager              (app, this);_mavlinkLogManager      = new MAVLinkLogManager         (app, this);_adsbVehicleManager     = new ADSBVehicleManager        (app, this);
#if defined(QGC_ENABLE_PAIRING)_pairingManager         = new PairingManager            (app, this);
#endif//-- Airmap Manager//-- This should be "pluggable" so an arbitrary AirSpace manager can be used//-- For now, we instantiate the one and only AirMap provider
#if defined(QGC_AIRMAP_ENABLED)_airspaceManager        = new AirMapManager             (app, this);
#else_airspaceManager        = new AirspaceManager           (app, this);
#endif
#if defined(QGC_GST_TAISYNC_ENABLED)_taisyncManager         = new TaisyncManager            (app, this);
#endif
#if defined(QGC_GST_MICROHARD_ENABLED)_microhardManager       = new MicrohardManager          (app, this);
#endif
}void QGCToolbox::setChildToolboxes(void)
{// SettingsManager must be first so settings are available to any subsequent tools_settingsManager->setToolbox(this);_corePlugin->setToolbox(this);_audioOutput->setToolbox(this);_factSystem->setToolbox(this);_firmwarePluginManager->setToolbox(this);
#ifndef __mobile___gpsManager->setToolbox(this);
#endif_imageProvider->setToolbox(this);_joystickManager->setToolbox(this);_linkManager->setToolbox(this);_mavlinkProtocol->setToolbox(this);_missionCommandTree->setToolbox(this);_multiVehicleManager->setToolbox(this);_mapEngineManager->setToolbox(this);_uasMessageHandler->setToolbox(this);_followMe->setToolbox(this);_qgcPositionManager->setToolbox(this);_videoManager->setToolbox(this);_mavlinkLogManager->setToolbox(this);_airspaceManager->setToolbox(this);_adsbVehicleManager->setToolbox(this);
#if defined(QGC_GST_TAISYNC_ENABLED)_taisyncManager->setToolbox(this);
#endif
#if defined(QGC_GST_MICROHARD_ENABLED)_microhardManager->setToolbox(this);
#endif
#if defined(QGC_ENABLE_PAIRING)_pairingManager->setToolbox(this);
#endif
}void QGCToolbox::_scanAndLoadPlugins(QGCApplication* app)
{
#if defined (QGC_CUSTOM_BUILD)//-- Create custom plugin (Static)_corePlugin = (QGCCorePlugin*) new CUSTOMCLASS(app, app->toolbox());if(_corePlugin) {return;}
#endif//-- No plugins found, use default instance_corePlugin = new QGCCorePlugin(app, app->toolbox());
}

在前端获取后端类的属性的总借口即为QGroundControl,例如

property var   _vehicle:          QGroundControl.multiVehicleManager.getVehicleById(1)

在功能类中向获取其他功能类的属性即使用qgcApp()->toolbox(),如果功能类继承了QGCTool则直接可以使用_toolbox->...即可。

_mavlink = qgcApp()->toolbox()->mavlinkProtocol();
_mavlinkProtocol =           _toolbox->mavlinkProtocol();

其实只要理解这几个总文件之间的关系后,就理解了QGC的整体结构。_app和_toolbox是QGC整个软件的总接口,_app和_toolbox都在QGCApplication类中,然后所有功能类都在QGCToolBox类中新建,想要获取功能类的属性就需要通过_toolbox。然后QGroundControlQmlGlobal中通过指针地址获取到了所有功能类,然后又通过Q_PROPERTY将类以属性的形式开放给前端,再加上单例模式直接在前端import QGroundControl即可获取到后端属性。这样即完成了前后端数据连通,也解决了各个功能类之间的属性获取。

以上是个人理解,很多地理解的不是太透彻,等有新的理解再更新。有错误的地方也望大佬指正,共同进步。

相关文章:

关于QGroundControl的软件架构的理解

首先QGC是基于QT平台开发&#xff0c;个人理解软件架构即为项目前后端结构&#xff0c;以及前后端数据交互的逻辑。下面是对QGroundControl源码的一些个人理解&#xff0c;写这个博客只是为了记录下来&#xff0c;防止时间久了忘记&#xff0c;过程中看了一些大佬的博客来帮助理…...

Android 文本识别:MLKIT + PreviewView

随着移动设备的普及和摄像头的高像素化&#xff0c;利用相机进行文本识别成为了一种流行的方式。MLKit 是 Google 提供的一款机器学习工具包&#xff0c;其中包含了丰富的图像和语言处理功能&#xff0c;包括文本识别。PreviewView 是 Android Jetpack 的一部分&#xff0c;它提…...

刮泥机的分类有哪些及组成部分

刮泥机的分类有哪些及组成部分 刮泥机的分类&#xff1a; 刮泥机主要包括&#xff1a;周边传动刮泥机、中心传动浓缩刮泥机。 1、中心传动浓缩刮泥机&#xff1a;主要由溢流装置、大梁及拦杆、进口管、传动装置、电器箱、稳流筒、主轴、浮渣耙板、刮集装置、水下轴承、小刮刀、…...

Qt编程基础 | 第六章-窗体 | 6.2、VS导入资源文件

一、VS导入资源文件 1.1、导入资源文件 步骤一&#xff1a; 将所有图片放到各自文件夹下&#xff0c;并将文件夹拷贝到资源文件&#xff08;.qrc文件&#xff09;的同级目录下&#xff0c;如下&#xff1a; 步骤二&#xff1a; 新建VS项目的时候&#xff0c;系统会自动建好一…...

NET框架程序设计-第4章类型基础

4.1 所有类型的基类型&#xff1a;System.Object CLR 要求每个类型最终都要继承自 System.Object 类型。 两种类型定义&#xff1a; 1&#xff09;隐式继承 //隐式继承 Object class Employee{}2&#xff09;显式继承 class Employee:System.Object{}System.Object 主要的公…...

Java设计模式-备忘录模式

简介 在软件开发中&#xff0c;设计模式是为了解决常见问题而提出的一种经过验证的解决方案。备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许我们在不破坏封装性的前提下&#xff0c;捕获和恢复对象的内部状态。 备忘录模式是一种…...

Zookeeper集群 + Kafka集群

Zookeeper 概述 Zookeeper 定义 Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目。 Zookeeper 工作机制 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数…...

“邮件营销新趋势,这个平台让你收获颇丰!

随着各媒体平台的迅速发展&#xff0c;2023年大家更专注于视频营销、网红营销、直播营销等营销方式。可以见得&#xff0c;数字媒介手段的发展&#xff0c;对于营销方式也产生了巨大的影响。但是&#xff0c;企业在拥抱新兴的营销方式的同时&#xff0c;也不要忽视传统的营销方…...

Python列表推导

列表推导式 列表推导式创建列表的方式更简洁。常见的用法为&#xff0c;对序列或可迭代对象中的每个元素应用某种操作&#xff0c;用生成的结果创建新的列表&#xff1b;或用满足特定条件的元素创建子序列。 例如&#xff0c;创建平方值的列表&#xff1a; squares [] for …...

git使用查看分支、创建分支、合并分支

一、查看分支 查看的git命令如下&#xff1a; git branch 列出本地已经存在的分支&#xff0c;并且当前分支会用*标记 git branch -r 查看远程版本库的分支列表 git branch -a 查看所有分支列表&#xff08;包括本地和远程&#xff0c;remotes/开头的表示远程分支&#xff09;…...

vue3.0与vue2.0

一、生命周期的变化 1.vue2.响应式架构 2.vue3.0 响应式架构图 Vue3.0响应式框架在设计上&#xff0c;将视图渲染和数据响应式完全分离开来。将响应式核心方法effect从原有的Watcher中抽离。这样&#xff0c;当我们只需要监听数据响应某种逻辑回调(例如监听某个text属性的变化…...

HTML 中的常用标签用法

HTML是构建Web页面的基础语言&#xff0c;其中包含许多不同类型的标签。这些标签由尖括号包围&#xff0c;以指示浏览器如何呈现文本。下面是HTML中的一些常用标签以及它们的使用方法&#xff1a; 标题标签&#xff08;h1-h6&#xff09; 标题标签用于标识页面内容的标题&…...

【C++】指针 - 定义和使用,所占内存空间,空指针,野指针,const 修饰指针,指针和数组,指针和函数

文章目录 1. 定义和使用2. 所占内存空间3. 空指针4. 野指针5. const 修饰指针6. 指针和数组7. 指针和函数 1. 定义和使用 数据类型 * 变量名; 指针的作用是&#xff0c;可以通过指针间接访问内存。 内存编号是从 0 开始记录的&#xff0c;一般用十六进制数字表示。可以利用指…...

新规之下产业园区如何合理收费水电费用

一、政策背景 2018年3月30日&#xff0c;国家发改委发布《国家发展改革委关于降低一般工商业电价有关事项的通知》。明确提出进一步规范和降低电网环节收费&#xff0c;一是提高两部制电价的灵活性&#xff1b;二是全面清理规范电网企业在输配电价之外的收费项目&#xff0c;重…...

1011. 在 D 天内送达包裹的能力

传送带上的包裹必须在 days 天内从一个港口运送到另一个港口。 传送带上的第 i 个包裹的重量为 weights[i]。每一天&#xff0c;我们都会按给出重量&#xff08;weights&#xff09;的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。 返回能在 days 天内将…...

基于SpringBoot养老院管理系统

目录 一、项目介绍 二. 运行环境 三、项目技术 四、部署项目 五、项目运行 六、项目展示 五、项目下载 一、项目介绍 基于springboot的养老院管理系统拥有多种角色账号&#xff1a;管理员和用户 管理员&#xff1a;管理员管理、用户管理、健康管理、病例方案管理、药品…...

1.3 eBPF的工作原理初探

写在前面 上一节提到过,eBPF程序是面向BPF体系结构指令集编写的,它并不直接运行在Linux内核中,我们可以理解为它是运行在eBPF虚拟机,由eBPF虚拟机来执行eBPF字节码,就像java运行在jvm一样。 我们用一张原理图来看下eBPF程序的编译,加载,验证,钩子,映射等结点。 如上是…...

【CH32】| 02——常用外设 | GPIO

系列文章目录 【CH32】| 00——开发环境搭建 【CH32】| 01——新建工程 | 下载 | 运行 |调试 【CH32】| 02——常用外设 | GPIO 失败了也挺可爱&#xff0c;成功了就超帅。 文章目录 前言1. GPIO简介2. IO口的内部结构框图保护二极管上下拉电阻施密特触发器两个MOS管输出寄存器…...

第四章 测试用例编

本科程目标 1.什么是测试用例 2.测试用例的重要性 3.测试用例的八大要素&#xff08;重点&#xff09; 4.测试用例的评审 一、什么叫软件测试用例 测试用例&#xff08;TestCase&#xff09;是为项目需求而编制的一组测试输入、执行条件以及预期结果&#xff0c;以便测试…...

解决dpdk reserve的内存返回的虚拟地址和iova地址一样的问题

1. 背景: 在ubuntu20.04上用dpdk API: rte_memzone_reserve_aligned("L1L2_PCIE_MEMORY", 1.5*1024*1024*1024, rte_socket_id(), RTE_MEMZONE_1GB|RTE_MEMZONE_IOVA_CONTIG, RTE_CACHE_LINE_SIZE); 分配1.5…...

全方位防护矿山开采三维透明化智能安全防控整体方案

依托黎阳之光核心技术矿山开采三维透明化智能安全防控整体方案一、方案前言1.建设背景矿山开采井下巷道错综复杂、采掘工作面地质隐蔽&#xff0c;顶板、透水、瓦斯、边坡失稳、三违作业、设备故障为高发安全风险。传统二维监控、分散监测系统存在场景碎片化、地质不可视、风险…...

Gofile下载器深度解析:Python自动化文件获取架构设计与性能优化

Gofile下载器深度解析&#xff1a;Python自动化文件获取架构设计与性能优化 【免费下载链接】gofile-downloader Download files from https://gofile.io 项目地址: https://gitcode.com/gh_mirrors/go/gofile-downloader Gofile下载器是一个基于Python的高效自动化文件…...

NGUI性能优化实战:DrawCall控制与内存泄漏治理

1. 为什么今天还要谈NGUI&#xff1f;——一个被低估的“老派”UI系统的现实生命力很多人看到标题里的“NGUI”&#xff0c;第一反应是&#xff1a;“这玩意儿不是早该进博物馆了吗&#xff1f;”Unity官方从4.6版本起力推UGUI&#xff0c;2018年之后新项目几乎清一色UGUI&…...

Get Jobs:你的智能求职导航员,让找工作不再像大海捞针

Get Jobs&#xff1a;你的智能求职导航员&#xff0c;让找工作不再像大海捞针 【免费下载链接】get_jobs &#x1f4bc;【AI找工作助手】全平台自动投简历脚本&#xff1a;(boss、前程无忧、猎聘、智联招聘) 项目地址: https://gitcode.com/gh_mirrors/ge/get_jobs 在求…...

别再死记硬背了!用‘橡皮筋’和‘电线杆’比喻,5分钟彻底搞懂Unity UI锚点(Anchors)

用生活化比喻破解Unity UI锚点&#xff1a;橡皮筋与电线杆的魔法刚接触Unity UI系统时&#xff0c;那个神秘的四三角锚点控件总让人望而生畏。官方文档里冷冰冰的MinX/MaxY参数&#xff0c;就像一道数学题般令人头疼。但当我偶然发现这两个生活比喻后&#xff0c;一切突然变得清…...

量子随机数生成器技术演进与多分布实时生成方案

1. 量子随机数生成器的技术演进与核心挑战量子随机数生成器&#xff08;QRNG&#xff09;作为现代密码学和科学计算的基础工具&#xff0c;其发展历程经历了从单一功能到多用途集成的技术跃迁。传统QRNG通常基于单一量子现象&#xff08;如光子到达时间、真空涨落或激光相位噪声…...

国密滑块登录实战:SM2+SM4密码链路全解析

1. 这不是“加个密”那么简单&#xff1a;滑块登录里藏着的国密链路真相你有没有试过&#xff0c;在某个政务类App或银行类Web端拖动滑块完成登录后&#xff0c;页面瞬间跳转&#xff0c;但控制台Network面板里却找不到任何明文密码字段&#xff1f;甚至抓包发现&#xff0c;提…...

Scalify:基于e-graph的分布式机器学习计算图等价性验证工具

1. 项目概述在分布式机器学习的世界里&#xff0c;我们常常面临一个看似简单实则棘手的问题&#xff1a;我写的这个并行化代码&#xff0c;真的和单机版本在数学上等价吗&#xff1f;这个问题背后&#xff0c;是无数个深夜调试的工程师&#xff0c;是那些在数百个GPU上跑了一周…...

13.解决 99% 刷机故障!小米 / 华为 / OV / 苹果通用救砖与分区修复教程

摘要 本文面向具备基础电子知识的技术人员,系统阐述主流品牌手机(华为、小米、OPPO、vivo、一加、苹果)的刷机与维修全流程。内容涵盖底层引导加载机制、分区表结构、签名验证原理,并提供完整的刷机脚本与维修诊断工具链。所有代码均已测试,可直接在Linux/Windows环境下运…...

告别刻录光盘!用Rufus 4.5快速搞定Win10 U盘安装盘(保姆级图文指南)

用Rufus 4.5打造Win10 U盘安装盘的终极指南在数字时代&#xff0c;光驱已经逐渐退出历史舞台&#xff0c;但系统安装的需求依然存在。传统的光盘安装方式不仅速度慢&#xff0c;而且对硬件有要求。相比之下&#xff0c;U盘安装系统更加高效便捷。本文将详细介绍如何使用Rufus 4…...