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

高德地图轨迹回放/轨迹播放

前言

本篇文章主要介绍高德地图的轨迹回放或播放的实现过程,是基于vue2实现的功能,同时做一些改动也是能够适配vue3的。其中播放条是用的是element UI中的el-slider组件,包括使用到的图标也是element UI自带的。可以实现轨迹的播放、暂停、停止、播放倍数,以及播放拖拽,涉及到的高德地图的相关权限申请,这里就不再赘述,好了,废话不多说,效果图附上。

效果图 


一、地图初始化

首先,需要在组件dom加载完毕后初始化地图,这里小谭直接用的new AMap.Map方法进行初始化,需要在index.html引入高德的服务。

<script src="https://webapi.amap.com/maps?v=2.0&key=你的key"></script>

其次,在引入高德服务之后,需要在单独引入高德AMapUI 组件库,因为轨迹播放是基于该组件库实现的,引入示例:

<!--引入UI组件库(1.1版本) -->
<script src="//webapi.amap.com/ui/1.1/main.js"></script>

最后,就可以进行初始化地图了,注意需要在组件dom加载完毕才能进行初始化!其中this.map是地图实例,附上代码:

 this.map = new AMap.Map('myMap', {zoom: 10, //级别center:[120.209758, 30.246809], //中心点坐标 默认在杭州});

二、轨迹插件初始化

在地图初始化完成之后,可以引入一些需要的插件,这里就不再过多赘述,我们直接引入AMapUI,我们这里用到的是PathSimplifier模块,故只需要引入该模块即可,附上代码:

//加载PathSimplifier,loadUI的路径参数为模块名中 'ui/' 之后的部分
new AMapUI.load(['ui/misc/PathSimplifier'], PathSimplifier => {if (!PathSimplifier.supportCanvas) {alert('当前环境不支持 Canvas!');return;}if (this.pathList?.length) {//启动页面this.initPage(PathSimplifier);}
});

其中,涉及到的this.pathList是我这边后端返回坐标点信息,this.pathList结构如下:

this.pathList = [[120.79580028, // 经度30.03570354 // 纬度],...];

this.initPage方法如下,需要注意的是,方法内声明的content是轨迹播放时展示的车辆图标,如果不需要可以删掉,PathSimplifier中的配置请参照高德地图轨迹展示的开发文档,还有方法最后调用的this.cruiseInit方法已经放到下一部分了。

initPage(PathSimplifier) {let content = PathSimplifier.Render.Canvas.getImageContent('/img/car1.png',() => {//图片加载成功,重新绘制一次this.pathSimplifierIns.renderLater();},function onerror(e) {this.$message({ type: 'error', message: '图片加载失败!' });});this.pathSimplifierIns = new PathSimplifier({zIndex: 100,map: this.map,getPath: function (pathData, pathIndex) {return pathData.path;},renderOptions: {//轨迹线的样式getPathStyle: (pathItem, zoom) => {return {pathLineStyle: {strokeStyle: "red",lineWidth: 6,dirArrowStyle: true,},};},pathNavigatorStyle: {initRotateDegree: 180,width: 20,height: 35,autoRotate: true,content,},},});this.cruiseInit(); //巡航器初始化
}

三、巡航器初始化

巡航器初始化方法this.cruiseInit代码如下:

cruiseInit() {let pathSimplifierIns = [{ path: this.pathList, color: '#28F' }];this.pathSimplifierIns.setData(pathSimplifierIns);this.pointSum = 0;pathSimplifierIns.forEach((item, index) => {this.pointSum += item.path.length;});this.marksIndex = marksIndex;this.cruiseStop();//如果已经存在巡航器,则停止播放
}

其中this.pointSum是为了记录巡航器的最终点数,方便对应到播放条的最大值。


四、巡航器的播放暂停等功能

巡航器的播放、暂停以及倍数的方法如下:

// 创建一个巡航器
createdCruise(index) {// 判断是否传入indexlet cruiseIndex;if (index != undefined) {cruiseIndex = index;this.cruiseIndex = index;} else {cruiseIndex = this.cruiseIndex;}let cruise = this.pathSimplifierIns.createPathNavigator(cruiseIndex, //关联第index条轨迹{loop: false, //循环播放speed: this.speedList[this.speedValue].speed, //速度});if (this.cruise) {// 清空走过的路线this.cruise.destroy();this.cruise = null;}return cruise;
},
// 开始播放
cruiseStart() {this.isPlay = true;if (this.cruise && !this.cruise.isCursorAtPathEnd() && !this.cruise.isCursorAtPathStart() && !this.isComplete) {// 路段未开始并且没有结束的时候 暂停恢复动画 并且动画没有完成的时候this.cruise.resume();return;}this.isComplete = false;if (this.cruiseIndex == 0) {this.cruiseStop();return;}this.cruise = this.createdCruise();// 判断是否传入初始坐标if (this.startPoint) {this.cruise.start(this.startPoint);this.startPoint = 0;} else {this.cruise.start();}this.cruise.on('move', e => {let idx = this.cruise.cursor.idx;let { address, gpsTime, speed } = this.pathList[idx];let trackAddress = {address,gpsTime,speed,};this.$emit('changeData', 'trackAddress', trackAddress);let [min, max] = this.marksIndex[this.cruiseIndex];this.sliderValue = idx + min;});// 巡航完成事触发this.cruise.on('pause', () => {if (this.cruise && this.cruise.isCursorAtPathEnd()) {this.cruiseStart();}});
},// 暂停播放
cruisePause() {this.cruise.pause();this.isPlay = false;
},
// 停止播放
cruiseStop() {if (this.cruise) {// 清空走过的路线this.cruise.destroy();}// 停止播放this.isPlay = false;this.isComplete = true;this.cruiseIndex = -1;// 为重新播放准备this.cruise = this.createdCruise();this.cruiseIndex = -1;this.sliderValue = 0;
},
// 速度改变
speedChange() {if (this.speedValue == this.speedList.length - 1) {this.speedValue = 0;} else {this.speedValue++;}this.cruise.setSpeed(this.speedList[this.speedValue].speed);
},

到这里巡航器的基础功能已经实现,还有一部分关于播放器调整对应轨迹改变,这里我们要用的监听器,即vue的watch属性:


五、变量声明以及HTML结构

其中使用到的变量有这些:

data() {return {    // 地图实例map: null,cruise: null, //巡航器实例cruiseIndex: -1, // 当前播放轨迹下标pathSimplifierIns: null, //轨迹实例isPlay: false, //是否播放isComplete: true, //是否完成pointSum: 0, //播放器总数sliderValue: 0, //播放器当前数startPoint: 0, //下次播放轨迹从当前值开始marksIndex: {}, //每段路的起止坐标pathList: [],// 轨迹坐标speedValue: 3,// 当前播放速度下标// 速度列表,可自定义配置speedList: [{ value: 0.5, speed: 100 },{ value: 1, speed: 200 },{ value: 2, speed: 400 },{ value: 4, speed: 1600 },{ value: 8, speed: 12800 },{ value: 16, speed: 25600 },],};
},

HTML结构:

<template><div class="workTrack"><div id="myMap"></div><div class="sliderBar" v-show="pathList.length"><span @click="cruiseStart()" v-if="!isPlay"><i class="el-icon-video-play"></i></span><span @click="cruisePause" v-else><i class="el-icon-video-pause"></i></span><span @click="cruiseStop"><i class="el-icon-error"></i></span><el-slider :disabled="isPlay" v-model="sliderValue" :max="pointSum" :show-tooltip="false"></el-slider><b @click="speedChange"><i class="el-icon-d-arrow-right"></i><span>×{{ speedList[speedValue].value }}</span></b></div></div>
</template>

css:

.workTrack {width: 100%;position: relative;height: 100%;#myMap {width: 100%;height: 100%;}.sliderBar {position: absolute;bottom: 30px;user-select: none;width: 100%;padding: 10px 2%;background-color: #00000064;border-radius: 400px;backdrop-filter: blur(5px);z-index: 99;width: 80%;right: 0;left: 0;margin: auto;display: flex;justify-content: center;align-items: center;.el-slider {flex: 1;transform: translateY(1px);margin: 0 15px;}::v-deep .el-slider__runway {pointer-events: none;background-color: #00000021;margin: 0;.el-slider__bar {background-color: #1682e6;}.el-slider__stop {background-color: #1682e6;border-radius: 0;width: 2px;}.el-slider__button-wrapper {pointer-events: auto;}.el-slider__marks-text {white-space: nowrap;color: #fff;font-size: 0;}}> span {flex-shrink: 0;transform: translateY(1px);color: #eee;cursor: pointer;margin: 0 5px;transition: 0.3s;font-size: 20px;&:hover {opacity: 0.5;}}> b {flex-shrink: 0;color: #eee;font-weight: normal;margin: 0 5px;cursor: pointer;border-radius: 3px;border: 1px solid #eee;padding: 0px 10px;transition: 0.3s;user-select: none;> span {vertical-align: middle;font-size: 14px;display: inline-block;transform: translateY(-2px);}i {vertical-align: middle;font-size: 16px;display: inline-block;transform: translateY(-1px);}&:hover {opacity: 0.5;}}}}

六:完整代码

完整代码如下:

<!-- * @description 轨迹回放* @fileName: track.vue * @author: tan * @date: 2024-06-17 10:02:28
!-->
<template><div class="workTrack"><div id="myMap"></div><div class="sliderBar" v-show="pathList.length"><span @click="cruiseStart()" v-if="!isPlay"><i class="el-icon-video-play"></i></span><span @click="cruisePause" v-else><i class="el-icon-video-pause"></i></span><span @click="cruiseStop"><i class="el-icon-error"></i></span><el-slider :disabled="isPlay" v-model="sliderValue" :max="pointSum" :show-tooltip="false"></el-slider><b @click="speedChange"><i class="el-icon-d-arrow-right"></i><span>×{{ speedList[speedValue].value }}</span></b></div></div>
</template><script>
export default {data() {return {// 地图实例map: null,cruise: null, //巡航器实例cruiseIndex: -1, // 当前播放轨迹下标pathSimplifierIns: null, //轨迹实例isPlay: false, //是否播放isComplete: true, //是否完成pointSum: 0, //播放器总数sliderValue: 0, //播放器当前数startPoint: 0, //下次播放轨迹从当前值开始marksIndex: {}, //每段路的起止坐标// 轨迹坐标pathList: [// [经度,纬度] 可再次放置测试数据[120.79573938, 30.03576463],],speedValue: 3, // 当前播放速度下标// 速度列表,可自定义配置speedList: [{ value: 0.5, speed: 100 },{ value: 1, speed: 200 },{ value: 2, speed: 400 },{ value: 4, speed: 1600 },{ value: 8, speed: 12800 },{ value: 16, speed: 25600 },],};},mounted() {this.map = new AMap.Map('myMap', {zoom: 10, //级别center: [120.209758, 30.246809], //中心点坐标 默认在杭州});this.$nextTick(() => {this.loadMap();});},methods: {// 加载地图loadMap() {return new Promise((reslove, reject) => {//加载PathSimplifier,loadUI的路径参数为模块名中 'ui/' 之后的部分new AMapUI.load(['ui/misc/PathSimplifier'], PathSimplifier => {if (!PathSimplifier.supportCanvas) {alert('当前环境不支持 Canvas!');return;}if (this.pathList?.length) {//启动页面this.initPage(PathSimplifier);}});reslove();});},initPage(PathSimplifier) {let content = PathSimplifier.Render.Canvas.getImageContent('/img/car1.png',() => {//图片加载成功,重新绘制一次this.pathSimplifierIns.renderLater();},function onerror(e) {this.$message({ type: 'error', message: '图片加载失败!' });});this.pathSimplifierIns = new PathSimplifier({zIndex: 100,map: this.map,getPath: function (pathData, pathIndex) {return pathData.path;},renderOptions: {//轨迹线的样式getPathStyle: (pathItem, zoom) => {return {pathLineStyle: {strokeStyle: 'red',lineWidth: 6,dirArrowStyle: true,},};},pathNavigatorStyle: {initRotateDegree: 180,width: 20,height: 35,autoRotate: true,content,},},});this.cruiseInit();},// 巡航器初始化cruiseInit() {let pathSimplifierIns = [{ path: this.pathList, color: '#28F' }];this.pathSimplifierIns.setData(pathSimplifierIns);this.pointSum = 0;let marksIndex = {};pathSimplifierIns.forEach((item, index) => {this.pointSum += item.path.length;marksIndex[index] = [0, this.pointSum];});this.marksIndex = marksIndex;this.cruiseStop();},// 创建一个巡航器createdCruise(index) {this.cruiseIndex++;// 判断是否传入indexlet cruiseIndex;if (index != undefined) {cruiseIndex = index;this.cruiseIndex = index;} else {cruiseIndex = this.cruiseIndex;}let cruise = this.pathSimplifierIns.createPathNavigator(cruiseIndex, //关联第index条轨迹{loop: false, //循环播放speed: this.speedList[this.speedValue].speed, //速度});if (this.cruise) {// 清空走过的路线this.cruise.destroy();this.cruise = null;}return cruise;},// 开始播放cruiseStart() {this.isPlay = true;if (this.cruise && !this.cruise.isCursorAtPathEnd() && !this.cruise.isCursorAtPathStart() && !this.isComplete) {// 路段未开始并且没有结束的时候 暂停恢复动画 并且动画没有完成的时候this.cruise.resume();return;}this.isComplete = false;if (this.cruiseIndex == 0) {this.cruiseStop();return;}this.cruise = this.createdCruise();// 判断是否传入初始坐标if (this.startPoint) {this.cruise.start(this.startPoint);this.startPoint = 0;} else {this.cruise.start();}this.cruise.on('move', e => {let idx = this.cruise.cursor.idx;let { address, gpsTime, speed } = this.pathList[idx];let trackAddress = {address,gpsTime,speed,};this.$emit('changeData', 'trackAddress', trackAddress);let [min, max] = this.marksIndex[this.cruiseIndex];this.sliderValue = idx + min;});// 巡航完成事触发this.cruise.on('pause', () => {if (this.cruise && this.cruise.isCursorAtPathEnd()) {this.cruiseStart();}});},// 暂停播放cruisePause() {this.cruise.pause();this.isPlay = false;},// 停止cruiseStop() {if (this.cruise) {// 清空走过的路线this.cruise.destroy();}// 停止播放this.isPlay = false;this.isComplete = true;this.cruiseIndex = -1;// 为重新播放准备this.cruise = this.createdCruise();this.cruiseIndex = -1;this.sliderValue = 0;},speedChange() {if (this.speedValue == this.speedList.length - 1) {this.speedValue = 0;} else {this.speedValue++;}this.cruise.setSpeed(this.speedList[this.speedValue].speed);},},watch: {sliderValue(val) {// 正在播放禁止拖拽播放器if (!this.cruise || this.isPlay) return;this.cruise.moveToPoint(val);this.startPoint = val;this.pathSimplifierIns.render();},},beforeDestroy() {if (this.pathSimplifierIns) this.pathSimplifierIns.clearPathNavigators();if (this.pathSimplifierIns) this.pathSimplifierIns.setData([]);if (this.cruise) this.cruise.destroy();if (this.map) this.map.destroy();},
};
</script><style lang="scss" scoped>
.workTrack {width: 100%;position: relative;height: 100%;#myMap {width: 100%;height: 100%;}.sliderBar {position: absolute;bottom: 30px;user-select: none;width: 100%;padding: 10px 2%;background-color: #00000064;border-radius: 400px;backdrop-filter: blur(5px);z-index: 99;width: 80%;right: 0;left: 0;margin: auto;display: flex;justify-content: center;align-items: center;.el-slider {flex: 1;transform: translateY(1px);margin: 0 15px;}::v-deep .el-slider__runway {pointer-events: none;background-color: #00000021;margin: 0;.el-slider__bar {background-color: #1682e6;}.el-slider__stop {background-color: #1682e6;border-radius: 0;width: 2px;}.el-slider__button-wrapper {pointer-events: auto;}.el-slider__marks-text {white-space: nowrap;color: #fff;font-size: 0;}}> span {flex-shrink: 0;transform: translateY(1px);color: #eee;cursor: pointer;margin: 0 5px;transition: 0.3s;font-size: 20px;&:hover {opacity: 0.5;}}> b {flex-shrink: 0;color: #eee;font-weight: normal;margin: 0 5px;cursor: pointer;border-radius: 3px;border: 1px solid #eee;padding: 0px 10px;transition: 0.3s;user-select: none;> span {vertical-align: middle;font-size: 14px;display: inline-block;transform: translateY(-2px);}i {vertical-align: middle;font-size: 16px;display: inline-block;transform: translateY(-1px);}&:hover {opacity: 0.5;}}}
}
</style>

相关文章:

高德地图轨迹回放/轨迹播放

前言 本篇文章主要介绍高德地图的轨迹回放或播放的实现过程&#xff0c;是基于vue2实现的功能&#xff0c;同时做一些改动也是能够适配vue3的。其中播放条是用的是element UI中的el-slider组件&#xff0c;包括使用到的图标也是element UI自带的。可以实现轨迹的播放、暂停、停…...

像素、像素密度、位图和矢量图

像素、像素密度、位图和矢量图 像素 -- 图像元素pt分辨率ppidpi 点阵图 - bitmap常见的类型 矢量图点阵图 vs 矢量图参考小结 像素、矢量图等概念在前端开发中经常遇到&#xff0c;这里做一个简单的梳理。 像素 – 图像元素 做前端开发的经常遇到它。像素是图像的最小单位&am…...

第二证券股市资讯:昨夜!全球新“股王”诞生

昨晚&#xff0c;英伟达成全球市值榜首公司。 当地时间6月18日&#xff0c;美股三大指数小幅收高&#xff0c;标普500指数与纳指再创前史新高。标普500指数涨0.25%&#xff0c;道指涨0.15%&#xff0c;纳指涨0.03%。 AI热潮推动英伟达大涨&#xff0c;市值逾越微软、苹果&…...

自动水位雨量站:用于水库防汛预警

TH-SW2自动水位雨量站是一种现代化的监测设备&#xff0c;主要用于水库等水域的防汛预警系统。它通过集成水位和雨量监测功能&#xff0c;为水库的管理和调度提供实时、准确的数据支持。 工作原理&#xff1a; 自动水位雨量站通过内置的水位计和雨量计实时监测水库的水位变化和…...

苍穹外卖---新增员工(P16-P20)

一、需求分析和设计 &#xff08;1&#xff09;产品原型 一般在做需求分析时&#xff0c;往往都是对照着产品原型进行分析&#xff0c;因为产品原型比较直观&#xff0c;便于我们理解业务。后台系统中可以管理员工信息&#xff0c;通过新增员工来添加后台系统用户。 新增员工…...

Windows10 利用QT搭建SOEM开发环境

文章目录 一. SOEM库简介二. 安装WinPcap三. SOEM(1.4)库安装(1) 编译32位库(2) 编译64位库 四. 运行SOEM示例代码五. WIN10下利用QT构建SOEM开发环境 一. SOEM库简介 SOEM&#xff08;Scalable Open EtherCAT Master 或 Simple Open EtherCAT Master&#xff09;是一个开源的…...

SpringBoot整合H2数据库并将其打包成jar包、转换成exe文件二(补充)

SpringBoot整合H2数据库并将其打包成jar包、转换成exe文件二&#xff08;补充&#xff09; 如果你想在cmd命令窗口内看到程序运行&#xff0c;即点开弹出运行窗口&#xff0c;关闭时exe自动关闭。 需要再launch4j上进行如下操作&#xff1a; 这样转换好的exe就可以有控制台了…...

【kyuubi k8s】kyuubi发布k8s执行spark sql

背景 依据上一篇kyuubi与spark集成&#xff0c;并发布spark sql到k8s集群&#xff0c;上一篇的将kyuubi和spark环境放在本地某台服务器上的&#xff0c;为了高可用&#xff0c;本篇将其打包镜像&#xff0c;并发布到k8s。 其实就是将本地的kyuubi&#xff0c;spark&#xff0…...

机械装配革新者:3D工艺大师智慧赋能,装配无忧

机械装配&#xff0c;简而言之&#xff0c;就是将各个零件和部件按照严格的技术要求组装起来&#xff0c;使之成为完整且符合标准的机械产品。这一过程不仅要求技术操作的精确性&#xff0c;更强调每个零件之间的完美配合&#xff0c;以确保产品的最终质量和性能达到最优。 常规…...

【C++】const和函数参数

一、const 在 C 中&#xff0c;const 关键字用于定义常量。将 const 关键字放在指针的不同位置&#xff0c;其含义也不同。 1、指向常量的指针 const int* ptr; ptr 是一个指向 const int 的指针&#xff0c;ptr 所指向的值不能通过 ptr 修改&#xff0c;但指针本身可以改变…...

2024zjb

单选331/600 下列不属于常用反爬虫手段动是() A访问频度 B验证码校验 C账号权限 D人工筛 题目答案 正确答案:D 330/600 下列不属于聚焦网络爬虫动常用策略动是 A基于深度优先动爬取策略 B基于内容评价动爬取策略 C基于链接结构评价动爬取策略 D基于语境图动爬取策略 题目答案…...

线程池的艺术:深度解析Java多线程并发性能的优化之道

1. 引言 在高并发的Java应用开发中,线程池作为管理和复用线程资源的核心机制,扮演着举足轻重的角色。合理、高效地使用线程池不仅能减少资源消耗、提高系统响应速度,还能有效控制并发线程数量,保证系统的稳定性和性能。 2. 线程池的基本概念与优势 线程池是一种管理和复用…...

Ubuntu server 24 (Linux) 新增磁盘 lvm 动态扩容磁盘空间

1 新增一块硬盘 #查看 sudo fdisk -l #重新分区&#xff0c;转换成lvm类型 sudo fdisk /dev/sdb 2 查看磁盘 df -h3 lvm 配置 #查看lvm逻辑卷 sudo lvdisplay #创建物理卷 sudo pvcreate /dev/sdb1 #扩展卷组 sudo vgextend ubuntu-vg /dev/sdb1 #扩展逻辑卷 sudo lvexte…...

Linux C编译器从零开发三

AST语法树 BNF抽象 expr equality equality relational ("" relational | "!" relational)* relational add ("<" add | "<" add | ">" add | ">" add)* add mul ("" …...

02-ES6新语法

1. ES6 Proxy与Reflect 1.1 概述 Proxy 与 Reflect 是 ES6 为了操作对象引入的 API 。 Proxy 可以对目标对象的读取、函数调用等操作进行拦截&#xff0c;然后进行操作处理。它不直接操作对象&#xff0c;而是像代理模式&#xff0c;通过对象的代理对象进行操作&#xff0c;…...

Vue3中VueRouter基本用法及与Vue2中路由使用差异解析

Vue Router 在 Vue3 中被重写&#xff0c;使用了 Vue3 的 Composition API。使用上跟Vue2 相比有些不同&#xff0c;需要注意。 首先&#xff0c;让我们来看一下 Vue3 中 VueRouter 的基本使用方法&#xff1a; 安装 Vue Router&#xff1a; npm install vue-routernext创建…...

10.Docker Compose容器编排

文章目录 Compose简介安装和卸载步骤核心概念compose文件两要素 使用步骤Compose常用命令微服务测试本地编码打包编写Dockerfile文件构建镜像 不使用Compose调试使用Compose调试WordPress测试验证增量更新 Compose简介 ​ docker建议我们每一个容器中只运行一个服务,因为docke…...

【算法——动态规划(从dfs回溯开始推导dp)】

基础理论 递归&#xff1a; 递&#xff1a;大问题分解子问题的过程 &#xff1b; 归&#xff1a;产生答案 dp&#xff1a;只进行归&#xff1b;用已知的最底层的&#xff08;递归的边界&#xff0c;搜索树的底&#xff09;&#xff0c;推出未知 《视频索引》 一句话&…...

不是所有洗碗机都能空气除菌 友嘉灵晶空气除菌洗碗机评测

精致的三餐让你以为生活是“享受”&#xff0c;可饭后那些油腻的锅碗瓢盆却成了你我美好生活的最大障碍。想要只吃美食不洗碗&#xff0c;那一台优秀的洗碗机就必不可少了&#xff01;今天&#xff0c;ZOL中关村在线要评测的就是这样一台不光洗得干净更能有效除菌抑菌的洗碗机—…...

【Linux】如何创建yum 组(yum groups)

如何创建yum 组(yum groups) 在 yum 中创建组信息需要手动编辑并创建一个组文件&#xff0c;然后使用 createrepo 工具生成组信息。以下是一个详细的步骤指南&#xff1a; 1. 创建组信息文件 首先&#xff0c;创建一个 XML 文件来定义组信息。例如&#xff0c;创建一个名为 …...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...

ThreadLocal 源码

ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物&#xff0c;因为每个访问一个线程局部变量的线程&#xff08;通过其 get 或 set 方法&#xff09;都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段&#xff0c;这些类希望将…...

算法—栈系列

一&#xff1a;删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...

2025-05-08-deepseek本地化部署

title: 2025-05-08-deepseek 本地化部署 tags: 深度学习 程序开发 2025-05-08-deepseek 本地化部署 参考博客 本地部署 DeepSeek&#xff1a;小白也能轻松搞定&#xff01; 如何给本地部署的 DeepSeek 投喂数据&#xff0c;让他更懂你 [实验目的]&#xff1a;理解系统架构与原…...

【版本控制】GitHub Desktop 入门教程与开源协作全流程解析

目录 0 引言1 GitHub Desktop 入门教程1.1 安装与基础配置1.2 核心功能使用指南仓库管理日常开发流程分支管理 2 GitHub 开源协作流程详解2.1 Fork & Pull Request 模型2.2 完整协作流程步骤步骤 1: Fork&#xff08;创建个人副本&#xff09;步骤 2: Clone&#xff08;克隆…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...