pyside6学习专栏(八):在PySide6中使用matplotlib库绘制三维图形

本代码原来是PySide6官网的一个示例程序,我对其进行的详细的注释,同时增加了一个功能:加载显示cass的地形图坐标数据示例,示例可显示以下几种三维图形

程序运行界面如下:

代码如下:

# -*- coding: utf-8 -*-
from __future__ import annotations

import sys,time,copy,os,random
import numpy as np
from matplotlib.backends.backend_qtagg import FigureCanvas
from matplotlib.figure import Figure
from mpl_toolkits.mplot3d import axes3d
from PySide6.QtCore import Qt, Slot
from PySide6.QtGui import QAction, QKeySequence
from PySide6.QtWidgets import (QApplication, QComboBox, QHBoxLayout,
                               QHeaderView, QLabel, QMainWindow, QSlider,
                               QTableWidget, QTableWidgetItem, QVBoxLayout,
                               QWidget)

"""这是一个使用3Dmatplotlib plot 在Qt Widgets上显示三维图形的示例
原版为PySide6官网上的一示例代码,对其进行了详细注解,同时扩展增加了以下一组示例代码
1、从外部导入地形图数据(cass地形测绘数据格式)并进行显示地形三角网

"""
class ApplicationWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        
        self.column_names = ["X向", "Y向", "Z向"]

        #定义中心窗口,并居中显示
        self._main = QWidget()
        self.setCentralWidget(self._main)
        self.setWindowTitle('PySide6+matplotlib绘制三维图示例')
        #定义菜单栏
        self.menu = self.menuBar()
        self.menu_file = self.menu.addMenu("文件")
        exit = QAction("离开", self, triggered=qApp.quit)  # noqa: F821
        self.menu_file.addAction(exit)

        self.menu_about = self.menu.addMenu("关于")
        about = QAction("关于Qt", self, shortcut=QKeySequence(QKeySequence.HelpContents),
                        triggered=QApplication.aboutQt)  # noqa: F821
        self.menu_about.addAction(about)

        #窗体左侧轮廓:为一视图和标签及滑条
        self.fig = Figure(figsize=(5, 3))
        self.canvas = FigureCanvas(self.fig)

        #左侧滑条控件
        min = 0
        max = 360
        self.slider_azim = QSlider(minimum=min, maximum=max, orientation=Qt.Orientation.Horizontal)
        self.slider_elev = QSlider(minimum=min, maximum=max, orientation=Qt.Orientation.Horizontal)

        self.slider_azim_layout = QHBoxLayout()
        self.slider_azim_layout.addWidget(QLabel(f"{min}"))
        self.slider_azim_layout.addWidget(self.slider_azim)
        self.slider_azim_layout.addWidget(QLabel(f"{max}"))

        self.slider_elev_layout = QHBoxLayout()
        self.slider_elev_layout.addWidget(QLabel(f"{min}"))
        self.slider_elev_layout.addWidget(self.slider_elev)
        self.slider_elev_layout.addWidget(QLabel(f"{max}"))

        #窗体右侧为一表格控件
        self.table = QTableWidget()
        header = self.table.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.Stretch)

        #窗体右侧顶部为一组合框控件
        self.combo = QComboBox()
        self.combo.addItems(["网格", "表面", "三角网表面", "球面","导入cass地形图","导入散点模型"])

        #设置窗体右侧布局
        rlayout = QVBoxLayout()
        rlayout.setContentsMargins(1, 1, 1, 1)
        rlayout.addWidget(QLabel("Plot类:"))
        rlayout.addWidget(self.combo)
        rlayout.addWidget(self.table)

        #设置窗体左侧布局
        llayout = QVBoxLayout()
        rlayout.setContentsMargins(1, 1, 1, 1)
        llayout.addWidget(self.canvas, 88)
        llayout.addWidget(QLabel("方位角:"), 1)
        llayout.addLayout(self.slider_azim_layout, 5)
        llayout.addWidget(QLabel("高程:"), 1)
        llayout.addLayout(self.slider_elev_layout, 5)

        #窗体总布局采用竖向布局
        layout = QHBoxLayout(self._main)
        layout.addLayout(llayout, 70)   #左侧布局占70%
        layout.addLayout(rlayout, 30)   #右侧布局点30%

        #定义信号槽绑定
        self.combo.currentTextChanged.connect(self.combo_option)  #组合框选择项发生变化时
        self.slider_azim.valueChanged.connect(self.rotate_azim)   #方位角(XY平面)滑条控件值发生变化时
        self.slider_elev.valueChanged.connect(self.rotate_elev)   #方位角(Z向)滑条控件值发生变化时

        #初始化视图显示
        self.plot_wire()    #默认加载
        self._ax.view_init(30, 30)
        self.slider_azim.setValue(30)
        self.slider_elev.setValue(30)
        self.fig.canvas.mpl_connect("button_release_event", self.on_click)   #左侧画布视图单击后鼠标释放时信号

    #槽函数: 单击Matplotlib视时发出的信号
    def on_click(self, event):
        azim, elev = self._ax.azim, self._ax.elev
        self.slider_azim.setValue(azim + 180)
        self.slider_elev.setValue(elev + 180)

    # 设置表格中的数据:传入XYZ数据(数据是一个np一维数组)
    def set_table_dataS(self, xS, yS, zS):
        for i in range(len(xS)):
            self.table.setItem(i, 0, QTableWidgetItem(f"{xS[i]:.2f}"))
            self.table.setItem(i, 1, QTableWidgetItem(f"{yS[i]:.2f}"))
            self.table.setItem(i, 2, QTableWidgetItem(f"{zS[i]:.2f}"))

    #重绘视图和表格时,当前的XYZ数据集
    def set_canvas_table_configuration(self, row_count, dataS):
        self.fig.set_canvas(self.canvas)
        self._ax = self.canvas.figure.add_subplot(projection="3d")
        self._ax.set_xlabel(self.column_names[0])    #表格的0例数据全部导入到视图的的x
        self._ax.set_ylabel(self.column_names[1])    #表格的0例数据全部导入到视图的的y
        self._ax.set_zlabel(self.column_names[2])    #表格的0例数据全部导入到视图的的z

        self.table.setRowCount(row_count)
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(self.column_names)
        self.set_table_dataS(dataS[0], dataS[1], dataS[2])

    # Plot 绘制样式:
    #视图和表格中数据为四边形网(无表面)
    def plot_wire(self):
        #产生示例数据: np二维数组->(200,200)
        self.X, self.Y, self.Z = axes3d.get_test_data(0.03)    #从axes3d类中得到示例数据
        self.set_canvas_table_configuration(len(self.X[0]), (self.X[0], self.Y[0], self.Z[0]))
        self._ax.plot_wireframe(self.X, self.Y, self.Z, rstride=10, cstride=10, cmap="viridis")
        self.canvas.draw()
    #视图和表格中数据为漏斗型表面
    def plot_surface(self):
        #产生示例数据: np二维数组->(30,30)
        self.X, self.Y = np.meshgrid(np.linspace(-6, 6, 30), np.linspace(-6, 6, 30))   
        self.Z = np.sin(np.sqrt(self.X ** 2 + self.Y ** 2))

        self.set_canvas_table_configuration(len(self.X[0]), (self.X[0], self.Y[0], self.Z[0]))
        self._ax.plot_surface(self.X, self.Y, self.Z,
                              rstride=1, cstride=1, cmap="viridis", edgecolor="none")
        self.canvas.draw()
    #视图和表格中数据为三角网表面
    def plot_triangular_surface(self):
        #产生示例数据: np一维数组->(289,)
        radii = np.linspace(0.125, 1.0, 8)
        angles = np.linspace(0, 2 * np.pi, 36, endpoint=False)[..., np.newaxis]
        self.X = np.append(0, (radii * np.cos(angles)).flatten())
        self.Y = np.append(0, (radii * np.sin(angles)).flatten())
        self.Z = np.sin(-self.X * self.Y)

        self.set_canvas_table_configuration(len(self.X), (self.X, self.Y, self.Z))
        self._ax.plot_trisurf(self.X, self.Y, self.Z, linewidth=0.2, antialiased=True)
        self.canvas.draw()

    #视图和表格中数据为球面
    def plot_sphere(self):
        #产生示例数据: np二维数组->(100,100)
        u = np.linspace(0, 2 * np.pi, 100)
        v = np.linspace(0, np.pi, 100)
        self.X = 10 * np.outer(np.cos(u), np.sin(v))
        self.Y = 10 * np.outer(np.sin(u), np.sin(v))
        self.Z = 9 * np.outer(np.ones(np.size(u)), np.cos(v))

        self.set_canvas_table_configuration(len(self.X), (self.X[0], self.Y[0], self.Z[0]))  #按当前球面的数据重新填写表格
        self._ax.plot_surface(self.X, self.Y, self.Z)
        self.canvas.draw()
#--------------------------------------------------------------------------------------------------------------------------------------------------------------
    #自定义数据1:视图和表格中数据为从外部文件导入地形图数据: 本例导入CASS的抄测地形坐标文件
    def plot_loadMapDatas(self):
        #导入的示例数据: np二维数组->(526,5)
        self.loadMapData('cass格式地形95个点.DAT')
        self.cassXyz=self.cass_Datas[:,2:5]
        self.X = self.cass_Datas[:,2:3].reshape(int(self.cass_Datas[:,2:3].size))  
        self.Y = self.cass_Datas[:,3:4].reshape(int(self.cass_Datas[:,3:4].size)) 
        self.Z = self.cass_Datas[:,4:5].reshape(int(self.cass_Datas[:,4:5].size)) 
        self.set_canvas_table_configuration(len(self.X), (self.X, self.Y, self.Z))
        self._ax.plot_trisurf(self.X, self.Y, self.Z, linewidth=0.2, antialiased=True)
        self.canvas.draw()
    #自定义数据2:视图和表格中数据为从外部文件导入散点模形
    def plot_load3DSapeDatas(self):
        #产生示例数据: np二维数组->(n,8)
        pass
        self.canvas.draw()

    #从外部地形数据文件导入全部点的坐标数据,示例采用CASS的dat格式数据 二维数组(n,5):如:1,,86240.8790,87568.3282,252.6600
    #导入cass软件用的dat测绘数据
    def loadMapData(self,mapDataFile,type=0):
        s=''
        lstRowData=[]
        lstData=[]
        index=0
        #以下四个变量用于测试坐标点文件中是否存在差距较大的数,以提醒修改,如不修改,可能偏差点会对计算结果影响较大
        minXYZ=[1000000,1000000,1000000]
        maxXYZ=[0,0,0]
        self.minXYZid=[0,0,0]
        self.maxXYZid=[0,0,0]
        if(os.path.exists(mapDataFile)):
            rf = open(mapDataFile,'r',encoding='utf-8')
            lindS=''
            for lineS in rf.readlines():
                lstRowData.clear()
                s=lineS.strip()
                s=s.replace("\n","")  #将从文件中读出的\n删除,此语句可能会报异常
                s=s.replace("\r","")  #将从文件中读出的\r删除,此语句可能会报异常
                if(s==''):continue  #去空行
                lstRowData = s.split(',')
                if(len(lstRowData)!=5):continue  #去格式不对的行(要求每行5个数据,4个逗号)
                lstRowData[0]=index  #重新为数据编号
                if(len(str(lstRowData[1]))!=0): 
                    lstRowData[1]=1                  #对第二个参数不为空时,改其值为1,否则为0
                else:
                    lstRowData[1]=0
                lstRowData[2]=float(lstRowData[2])   #dat文件中的坐标x坐标
                lstRowData[3]=float(lstRowData[3])   #dat文件中的坐标y坐标
                lstRowData[4]=float(lstRowData[4])   #dat文件中的坐标z坐标
                lstData.append(copy.deepcopy(lstRowData))

                #以下对导入的点作最大最小值记录
                if(minXYZ[0]>lstRowData[2]):
                    minXYZ[0]=lstRowData[2]
                    self.minXYZid[0]=index
                if(minXYZ[1]>lstRowData[3]):
                    minXYZ[1]=lstRowData[3]
                    self.minXYZid[1]=index
                if(minXYZ[2]>lstRowData[4]):
                    minXYZ[2]=lstRowData[4]
                    self.minXYZid[2]=index
                if(maxXYZ[0]<lstRowData[2]):
                    maxXYZ[0]=lstRowData[2]
                    self.maxXYZid[0]=index
                if(maxXYZ[1]<lstRowData[3]):
                    maxXYZ[1]=lstRowData[3]
                    self.maxXYZid[1]=index
                if(maxXYZ[2]<lstRowData[4]):
                    maxXYZ[2]=lstRowData[4]
                    self.maxXYZid[2]=index
                index+=1
            rf.close
            print(f'\n minXYZid={self.minXYZid}\n maxXYZid={self.maxXYZid}\n')
            self.pointCount=len(lstData)          #记录本数据文件的总坐标点数
            self.cass_Datas=np.array(lstData)      #保存全部的np原始数据
            #开始处理原始数据
            print(f'导入cass测绘数据文件"{mapDataFile}"成功!')  
            return True
        return False

    #-------------------------------------------------------------------------------------------------------------------------------------------------------------
    #槽函数:组合框选择项发生变化时
    @Slot()
    def combo_option(self, text):
        if text == "网格":
            self.plot_wire()
        elif text == "表面":
            self.plot_surface()
        elif text == "三角网表面":
            self.plot_triangular_surface()
        elif text == "球面":
            self.plot_sphere()
        elif text == "导入cass地形图":
            self.plot_loadMapDatas()
        elif text == "导入散点模型":
            pass     #暂未扩展

    #方位角(XY平面)滑条控件值发生变化时槽函数
    @Slot()
    def rotate_azim(self, value):
        self._ax.view_init(self._ax.elev, value)
        self.fig.set_canvas(self.canvas)
        self.canvas.draw()

    #方位角(Z向)滑条控件值发生变化时槽函数
    @Slot()
    def rotate_elev(self, value):
        self._ax.view_init(value, self._ax.azim)
        self.fig.set_canvas(self.canvas)
        self.canvas.draw()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = ApplicationWindow()
    w.setFixedSize(1280, 720)
    w.show()
    app.exec()

扩展导入的示例cass地形坐标文件内容如下,copy出来后粘贴到记事本另存文件为“cass格式地形95个点.DAT”,将此文件同代码模块文件放在一个目录里即可

1,,8535.0620,20831.2885,384.9640
2,,8564.7031,20818.7979,386.8800
3,,8566.4578,20824.8254,386.8800
4,,8580.2215,20819.2465,388.0300
5,,8590.5382,20815.9465,388.7660
6,,8525.9910,20830.1208,377.0900
7,,8502.7606,20839.6356,383.2100
8,,8537.2997,20855.6420,385.0000
9,,8537.6544,20857.5221,385.0000
10,,8531.2665,20856.1611,385.3500
11,,8534.0532,20857.8461,385.3500
12,,8533.6219,20853.4993,385.3500
13,,8595.2543,20819.8627,391.3100
14,,8558.8369,20813.6480,387.1910
15,,8576.1126,20813.9809,388.4000
16,,8582.0086,20813.3326,388.7660
17,,8574.6472,20807.6877,388.2800
18,,8578.2663,20799.6209,387.8800
19,,8581.3061,20806.9918,388.7000
20,,8544.7344,20858.6430,384.0600
21,,8546.2683,20821.1758,385.8000
22,,8550.3724,20833.8913,385.5660
23,,8544.0034,20833.0925,385.4460
24,,8597.5370,20808.7561,390.1870
25,,8588.3263,20809.5540,389.2140
26,,8581.5961,20810.1927,388.7600
27,,8575.4039,20810.7972,388.3400
28,,8569.2116,20813.0327,387.9020
29,,8560.1202,20816.6382,387.2510
30,,8548.2657,20828.3883,385.8600
31,,8547.2163,20833.4220,385.5060
32,,8546.3340,20840.2102,385.0240
33,,8545.5363,20848.8394,384.7000
34,,8553.8038,20819.7866,386.7750
35,,8550.7684,20823.7166,386.2300
36,,8544.1572,20863.7326,383.6830
37,,8543.6784,20868.8701,383.3000
38,,8529.1556,20863.1078,383.3000
39,,8533.9251,20864.9365,383.3000
40,,8538.7670,20866.7411,383.3000
41,,8548.0837,20870.6865,383.3000
42,,8540.6612,20862.3642,383.6830
43,,8536.5205,20861.3426,383.6830
44,,8531.3321,20860.6948,383.6830
45,,8541.7397,20859.0886,384.0600
46,,8538.8243,20859.4973,384.0600
47,,8528.7124,20850.9021,384.1650
48,,8521.5594,20849.2209,384.1650
49,,8511.9518,20846.3489,384.1650
50,,8531.5137,20846.2046,384.6400
51,,8537.3263,20847.9737,384.6400
52,,8533.9232,20839.3649,384.9640
53,,8540.2409,20839.6848,384.9640
54,,8540.3997,20832.9546,385.4460
55,,8526.7023,20856.3875,384.0600
56,,8520.6090,20855.1941,384.0600
57,,8512.6042,20852.9863,384.0600
58,,8503.9422,20850.4801,384.0600
59,,8499.1817,20849.5675,384.0600
60,,8527.0635,20859.6211,383.6830
61,,8520.2142,20858.3600,383.6830
62,,8511.2339,20856.1466,383.6830
63,,8503.0271,20854.0863,383.6830
64,,8495.8691,20853.3912,383.6830
65,,8585.2618,20790.1975,391.2700
66,,8583.4519,20792.3716,389.6900
67,,8526.2071,20833.0721,377.0900
68,,8511.7583,20834.1661,377.2200
69,,8501.9803,20833.0331,377.2200
70,,8485.7633,20837.8191,377.2800
71,,8480.4063,20841.6261,377.4100
72,,8483.0683,20846.3021,378.1000
73,,8596.9664,20786.3285,391.8000
74,,8587.9307,20791.0655,390.0370
75,,8586.8727,20802.9864,389.1540
76,,8596.9759,20800.4602,390.0300
77,,8565.5924,20800.8019,386.6600
78,,8521.5125,20838.1220,380.1400
79,,8487.6261,20847.4016,378.7800
80,,8497.7541,20845.0826,378.7100
81,,8494.2471,20850.5446,381.6400
82,,8514.0502,20841.4980,383.2100
83,,8524.2421,20843.4686,384.2000
84,,8541.1481,20826.6746,384.7300
85,,8561.0611,20806.2766,386.6300
86,,8547.6462,20816.0442,386.0600
87,,8557.0848,20809.5790,387.1910
88,,8566.6440,20805.8867,387.8420
89,,8580.9124,20803.9858,388.7000
90,,8558.3059,20823.0354,386.8800
91,,8570.3499,20819.9284,388.0300
92,,8587.7689,20820.1814,389.6800
93,,8571.6399,20826.1884,388.0000
94,,8556.9299,20831.2744,386.4100
95,,8550.9689,20844.2314,385.2700

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【多模态大模型论文精读】MOSHI:双工实时语音对话大模型

写在前面 大型语言模型&#xff08;LLM&#xff09;的飞速发展&#xff0c;让人机对话变得越来越自然流畅。从 Alexa、Siri 到 Google Assistant&#xff0c;语音助手已经成为我们生活中不可或缺的一部分。然而&#xff0c;这些看似智能的对话系统&#xff0c;背后却隐藏着一个…

Elasticsearch --- 相关基础知识整理

目录 1、核心功能2、主要用途3、数据模型4、优势5、映射5.1 映射的作用5.2 字段数据类型5.3 动态映射与显式映射5.4 映射设置5.5 多字段与元字段5.6 映射的创建与管理5.7 映射优化建议 6、 倒排索引6.1 **倒排索引的基本概念**6.2 **倒排索引的工作原理**6.3 **倒排索引的优势*…

lqb官方题单-速成刷题清单(上) - python版

预计3月5日 Wednesday 前完成 【2025年3月1日&#xff0c;记】题目太简单了&#xff0c;3月3日前完成 蓝桥杯速成刷题清单&#xff08;上&#xff09; https://www.lanqiao.cn/problems/1216/learning/?problem_list_id30&page1 替换题号1216 目录 进度题解和碎碎念1. 排…

计算机网络——详解TCP三握四挥

文章目录 前言一、三次握手1.1 三次握手流程1.2 tcp为什么需要三次握手建立连接&#xff1f; 二、四次挥手2.1 四次挥手流程2.2 为什么是四次&#xff0c;不是三次&#xff1f;2.3 为什么要等待2msl&#xff1f;2.4 TCP的保活计时器 前言 TCP和UDP是计算机网络结构中运输层的两…

【AD】3-6 层次原理图

自上而下 1.放置-页面符号&#xff0c;并设置属性 2.放置-端口 可通过如下设置将自动生成关掉 3.放置-添加图纸入口&#xff0c;并创建图纸 自下而上 1.子图的原理图页设计 设计资原理图&#xff0c;复制网络标签&#xff0c;智能粘贴未PORT 2.新建主图原理图 创建框…

C语言【指针篇】(四)

前言&#xff1a;正文1. 字符指针变量2. 数组指针变量2.1 数组指针变量是什么?2.2 数组指针变量怎么初始化 3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用4.3 两段有趣的代码4.3.1 typedef关键字 5. 函数指针数组6. 转移表 总结 前言&am…

认识苹果SWIFT语言

Swift 是苹果公司于 2014 年在 WWDC&#xff08;苹果全球开发者大会&#xff09;上发布的一种编程语言&#xff0c;旨在替代 Objective-C&#xff0c;用于开发 iOS、macOS、watchOS 和 tvOS 等苹果平台的应用程序。Swift 的设计目标是结合 C 和 Objective-C 的优点&#xff0c;…

python集合set的常用方法

目录 集合的定义 集合的基础操作 多个集合之间的操作 集合的for循环 集合的定义 集合的基础操作 集合.add(元素) 添加新元素 集合.pop() 从集合中随机取出一个元素 集合.clear() 清空集合 集合.remove(元素) 移除元素 #定义集合,集合自动去重了 set1{"春"…

2019年01月全国POI数据分享(同源历史POI分享系列)

2019年01月全国范围POI数据 2019年01月份全国范围历史POI数据&#xff0c;全国范围所有类别共59336781个POI 2019年01月全国范围POI数据按大类统计 大类代码大类名称2019年01月该类POI数量010000汽车服务1151164020000汽车销售213647030000汽车维修517367040000摩托车服务1800…

简单介绍JVM

1.什么是JVM&#xff1f; JVM就是Java虚拟机【Java Virtual Machine】&#xff0c;简称JVM。主要部分包括类加载子系统&#xff0c;运行时数据区&#xff0c;执行引擎&#xff0c;本地方法库等&#xff0c;接下来我们一一介绍 2.类加载子系统 JVM中运行的就是我们日常写的JA…

关于流水线的理解

还是不太理解&#xff0c;我之前一直以为&#xff0c;对axis总线&#xff0c;每一级的寄存器就像fifo一样&#xff0c;一级一级的分级存储最后一级需要的数据。 像这张图&#xff0c;一开始是在解析axis流形式的数据包&#xff0c;数据包一直都能输入&#xff0c;所以valid一直…

基于PHP和MySQL的用户登录注册系统实现

系统架构 系统采用前后端分离的架构&#xff0c;使用PHP作为后端语言&#xff0c;MySQL作为数据库。以下是系统的整体架构图&#xff1a; 这个架构图展示了系统的三个主要层次&#xff1a; 前端界面层&#xff1a;包含用户交互的三个页面&#xff08;注册、登录和欢迎页面&am…

【湖北省计算机信息系统集成协会主办,多高校支持 | ACM出版,EI检索,往届已见刊检索】第二届边缘计算与并行、分布式计算国际学术会议(ECPDC 2025)

第二届边缘计算与并行、分布式计算国际学术会议&#xff08;ECPDC 2025&#xff09;将于2025年4月11日至13日在中国武汉盛大召开。本次会议旨在为边缘计算、并行计算及分布式计算领域的研究人员、学者和行业专家提供一个高水平的学术交流平台。 随着物联网、云计算和大数据技术…

从零开始用react + tailwindcss + express + mongodb实现一个聊天程序(七) 主题设置

1. 引入daisyUi 我们用的是^4.12.23版本 daisyUI介绍 Install daisyUI as a Tailwind CSS plugin — Tailwind CSS Components ( version 4 update is here ) 切换主题功能我们仿照daisyUI themes — Tailwind CSS Components ( version 5 update is here ) 1.在tailwind.co…

EGO-Planner的无人机视觉选择(yolov5和yolov8)

EGO-Planner的无人机视觉选择&#xff08;yolov5和yolov8&#xff09; 效果 yolov5检测效果 yolov8检测效果 一、YOLOv8 vs YOLOv5&#xff1a;关键差异解析 1. 训练效率&#xff1a;为何YOLOv8更快&#xff1f; 架构轻量化 YOLOv8采用C2f模块&#xff08;Cross Stage Partia…

.net8 使用 license 证书授权案例解析

创建 webapi 项目 使用 .NET CLI 创建一个 ASP.NET Core Web API 应用&#xff0c;并添加指定的 NuGet 包&#xff0c;可以按照以下步骤操作&#xff1a; 创建 ASP.NET Core Web API 项目&#xff1a; dotnet new webapi -n WebAppLicense cd WebAppLicense添加 Standard.Li…

uniapp中使用leaferui使用Canvas绘制复杂异形表格的实现方法

需求&#xff1a; 如下图&#xff0c;要实现左图的样式&#xff0c;先实现框架&#xff0c;文字到时候 往里填就行了&#xff0c;原来的解决方案是想用css,html来实现&#xff0c;发现实现起来蛮麻烦的。我也没找到合适的实现方法&#xff0c;最后换使用canvas来实现&#xff…

支付宝 IoT 设备入门宝典(下)设备经营篇

上篇介绍了支付宝 IoT 设备管理&#xff0c;但除了这些基础功能外&#xff0c;商户还可以利用设备进行一些运营动作&#xff0c;让设备更好的帮助自己&#xff0c;本篇就会以设备经营为中心&#xff0c;介绍常见的设备相关能力和问题解决方案。如果对上篇感兴趣&#xff0c;可以…

Vue学习教程-18Vue单文件组件

文章目录 前言一、单文件组件的构成二、组件引用三、组件的应用举例1.组件实例2.显示结果 前言 Vue 单文件组件&#xff08;又名 *.vue 文件&#xff0c;缩写为 SFC&#xff09;是一种特殊的文件格式&#xff0c;它允许将 Vue 组件的模板、逻辑 与 样式封装在单个文件中。组件…

games101 作业5

题目 光线追踪的核心算法: 1.光线的生成 2.光线与三角的相交 题解 1.光线的生成 如课件中的图所示&#xff1a; image plane 就是 代码中的scene的FrameBuffer。 但是&#xff0c;FrameBuffer 是窗口坐标系中&#xff0c;而光线是世界坐标系中的。所以我们需要将scene中的屏…