Vue2+OpenLayers实现车辆开始、暂停、重置行驶轨迹动画(提供Gitee源码)

news2025/1/21 1:08:33

前言:根据经纬度信息绘制一个完整的行驶路线,车辆根据绘制好的路线从开始点位行驶到结束点位,可以通过开始、暂停、重置按钮控制车辆状态。 

目录

一、案例截图

二、安装OpenLayers库

三、​安装Element-UI ​

四、代码实现

4.1、初始化变量

4.2、创建起始点位

4.3、根据经纬度计算车辆旋转角度

4.4、创建车辆图标

4.5、绘制路线

4.6、车辆行驶动画

4.7、开始事件

4.8、暂停事件

4.9、重置事件

4.10、完整代码 

五、Gitee源码


一、案例截图

二、安装OpenLayers库

npm install ol

三、​安装Element-UI ​

没安装的看官方文档:Element - The world's most popular Vue UI framework

四、代码实现

4.1、初始化变量

关键代码:

data() {
  return {
    map:null,
    //点位信息
    pointList: [
      [120.430070,31.938140],
      [120.428570,31.939100],
      [120.429530,31.941680],
      [120.431240,31.943580],
      [120.432410,31.944820],
      [120.433600,31.943970],
    ],
    //用于存放车辆、起始点位和折线的图层
    vectorLayer: new VectorLayer({
      source: new VectorSource(),
      zIndex: 2,
    }),
    //车辆
    carFeature:null,
    //动画开始标记
    isAnimating: false,
    //动画开始时间/动画暂停时间
    animationStartTime:0,
    //索引
    currentIndex:0,
    // 每个点之间的移动时间(毫秒)
    speed: 1000,
    //记录上一个动画的运行时间
    lastAnimationTime: 0,
  }
},

4.2、创建起始点位

/**
 * 创建开始点位
 */
createStartPoint(){
  // 创建feature要素,一个feature就是一个点坐标信息
  let feature = new Feature({
    geometry: new Point(this.pointList[0]),
  });
  // 设置要素的图标
  feature.setStyle(
      new Style({
        // 设置图片效果
        image: new Icon({
          src: 'http://lbs.tianditu.gov.cn/images/bus/start.png',
          // anchor: [0.5, 0.5],
          scale: 1,
        }),
        zIndex: 10,
      }),

  );
  this.vectorLayer.getSource().addFeature(feature);
},

//创建结束点位
createEndPoint(){
  // 创建feature要素,一个feature就是一个点坐标信息
  let feature = new Feature({
    geometry: new Point(this.pointList[this.pointList.length-1]),
  });
  // 设置要素的图标
  feature.setStyle(
      new Style({
        // 设置图片效果
        image: new Icon({
          src: 'http://lbs.tianditu.gov.cn/images/bus/end.png',
          // anchor: [0.5, 0.5],
          scale: 1,
        }),
        zIndex: 10
      }),

  );
  this.vectorLayer.getSource().addFeature(feature);
},

4.3、根据经纬度计算车辆旋转角度

关键代码:

//计算旋转角度
calculateRotation(currentPoint,nextPoint){
  const dx = nextPoint[0] - currentPoint[0];
  const dy = nextPoint[1] - currentPoint[1];
  return Math.atan2(dy,dx);
},

4.4、创建车辆图标

先封装一个获取车辆样式的方法,后续都会用到。

关键代码:

//获取车辆的样式
getVehicleStyle(rotation) {
  return new Style({
    // 设置图片效果
    image: new Icon({
      src: 'http://lbs.tianditu.gov.cn/images/openlibrary/car.png',
      // anchor: [0.5, 0.5],
      scale: 1,
      rotation: -rotation,
    }),
    zIndex: 5,
  })
},

创建完整的车辆图标。

关键代码:

createCar(){
  // 创建feature要素,一个feature就是一个点坐标信息
  this.carFeature = new Feature({
    geometry: new Point(this.pointList[0]),
  });
  const currentPoint = fromLonLat(this.pointList[0]);
  const nextPoint = fromLonLat(this.pointList[1]);
  let rotation = this.calculateRotation(currentPoint,nextPoint);
  this.carFeature.setStyle(this.getVehicleStyle(rotation));
  this.vectorLayer.getSource().addFeature(this.carFeature);
},

4.5、绘制路线

关键代码:

drawLine(){
  // 创建线特征
  const lineFeature = new Feature({
    geometry: new LineString(this.pointList),
  });

  // 设置线样式
  const lineStyle = new Style({
    stroke: new Stroke({
      color: '#25C2F2',
      width: 4,
      lineDash: [10, 8], // 使用点划线 数组的值来控制虚线的长度和间距
    }),

  });
  lineFeature.setStyle(lineStyle);

  // 创建矢量层并添加特征
  const vectorSource = new VectorSource({
    features: [lineFeature],
  });
  const vectorLayer = new VectorLayer({
    source: vectorSource,
    zIndex: 1
  });

  // 将矢量层添加到地图
  this.map.addLayer(vectorLayer);
  // 设置地图视图以适应路径
  this.map.getView().fit(lineFeature.getGeometry().getExtent(), {
    padding: [20, 20, 20, 20],
    maxZoom: 18,
  });
},

4.6、车辆行驶动画

实现思路:

1.动画启动条件

检查动画状态:首先,代码检查this.isAnimating是否为true,以及this.currentIndex是否已经到达pointList的最后一个点。如果满足任一条件,则函数返回,停止动画。

2.获取当前和下一个点

获取当前点和下一个点:通过this.currentIndex获取当前点currentPoint和下一个点nextPoint。

3.计算经过的时间

计算经过的时间:使用timestamp参数(通常由requestAnimationFrame传递)减去this.animationStartTime来计算动画已经经过的时间。

4.计算当前位置

插值计算:根据经过的时间和速度(this.speed),计算进度progress,并使用这个进度来插值计算当前车辆的位置coordinates。这通过线性插值实现,即根据当前点和下一个点的坐标计算出车辆的当前位置。

5.更新车辆位置

更新车辆坐标:通过this.carFeature.getGeometry().setCoordinates(coordinates)更新车辆的实际位置。

6.更新动画状态

检查进度是否完成:如果progress等于1,表示车辆已经到达下一个点。此时,更新currentIndex以指向下一个点,并重置animationStartTime为当前时间。

7.计算并更新车辆朝向

计算角度:调用this.calculateRotation(currentPoint, nextPoint)计算车辆应朝向的角度。 更新样式:通过this.carFeature.setStyle(this.getVehicleStyle(angle))更新车辆的样式,以反映新的朝向。

8.继续动画

请求下一帧:如果currentIndex仍然小于pointList的长度,调用requestAnimationFrame(this.animateVehicle)继续动画;否则,将this.isAnimating设为false,表示动画结束。

关键代码:

//车辆行驶动画
animateVehicle(timestamp) {
  if (!this.isAnimating || this.currentIndex >= this.pointList.length - 1) return;

  const currentPoint = this.pointList[this.currentIndex];
  const nextPoint = this.pointList[this.currentIndex + 1];

  // 计算经过的时间
  const elapsed = timestamp - this.animationStartTime;
  const progress = Math.min(elapsed / this.speed, 1);

  // 计算当前位置的坐标
  const coordinates = [
    currentPoint[0] + (nextPoint[0] - currentPoint[0]) * progress,
    currentPoint[1] + (nextPoint[1] - currentPoint[1]) * progress,
  ];

  // 更新车辆位置
  this.carFeature.getGeometry().setCoordinates(coordinates);

  if (progress === 1) {
    this.currentIndex++;
    this.animationStartTime = timestamp; // 重置动画开始时间
    this.lastAnimationTime = 0; // 移动到下一个点时重置
  }

  // 计算下一个点的角度
  const angle = this.calculateRotation(currentPoint, nextPoint);
  this.carFeature.setStyle(this.getVehicleStyle(angle)); // 更新样式以反映新的朝向

  // 继续动画
  if (this.currentIndex < this.pointList.length - 1) {
    requestAnimationFrame(this.animateVehicle);
  } else {
    this.isAnimating = false; // 动画结束
  }
},

4.7、开始事件

关键代码:

startAnimation() {
  // 如果没有开始动画,则开始动画
  if (!this.isAnimating) {
    this.isAnimating = true;
    //这里存放的是暂停动画的时间,下面启动动画后,会将当前时间减去暂停动画的时间就是动画已运行的时间,这样就不会从头开始了
    //当前时间比如为900ms,用900ms减去500ms,可以计算出当前暂停了400ms
    this.animationStartTime = performance.now() - (this.lastAnimationTime || 0);
    // 继续或者启动动画
    // 计算经过时间:elapsed = timestamp - this.animationStartTime; 900ms减去400ms 可以算出已经运行了500ms 也就是上次动画所运行的时间了
    this.animateVehicle();
  }
},

4.8、暂停事件

关键代码:

// 暂停动画
pauseAnimation() {
  if (this.isAnimating) {
    this.isAnimating = false;
    // 保存当前动画运行的时间 比如已经运行了500ms
    this.lastAnimationTime = performance.now() - this.animationStartTime;
  }
},

4.9、重置事件

关键代码:

// 重置动画
resetAnimation() {
  // 停止动画
  this.isAnimating = false;
  // 重置索引
  this.currentIndex = 0;
  // 将车辆位置重置到起始点
  this.carFeature.getGeometry().setCoordinates(this.pointList[0]);
  const currentPoint = fromLonLat(this.pointList[0]);
  const nextPoint = fromLonLat(this.pointList[1]);
  let rotation = this.calculateRotation(currentPoint,nextPoint);
  // 重置车辆样式
  this.carFeature.setStyle(this.getVehicleStyle(rotation));
},

4.10、完整代码 

<template>
  <div>
    <el-button type="primary" @click="startAnimation">开始</el-button>
    <el-button type="warning" @click="pauseAnimation">暂停</el-button>
    <el-button type="info" @click="resetAnimation">重置</el-button>
    <div id="map-container"></div>
  </div>
</template>
<script>
import { Map, View } from 'ol'
import { Tile as TileLayer } from 'ol/layer'
import {fromLonLat, get} from 'ol/proj';
import { getWidth, getTopLeft } from 'ol/extent'
import { WMTS } from 'ol/source'
import WMTSTileGrid from 'ol/tilegrid/WMTS'
import { defaults as defaultControls} from 'ol/control';
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import Feature from "ol/Feature";
import {LineString, Point} from "ol/geom";
import {Icon, Stroke, Style} from "ol/style";

export const projection = get("EPSG:4326");
const projectionExtent = projection.getExtent();
const size = getWidth(projectionExtent) / 256;
const resolutions = [];
for (let z = 0; z < 19; ++z) {
  resolutions[z] = size / Math.pow(2, z);
}

export default {
  data() {
    return {
      map:null,
      //点位信息
      pointList: [
        [120.430070,31.938140],
        [120.428570,31.939100],
        [120.429530,31.941680],
        [120.431240,31.943580],
        [120.432410,31.944820],
        [120.433600,31.943970],
      ],
      //用于存放车辆、起始点位和折线的图层
      vectorLayer: new VectorLayer({
        source: new VectorSource(),
        zIndex: 2,
      }),
      //车辆
      carFeature:null,
      //动画开始标记
      isAnimating: false,
      //动画开始事件
      animationStartTime:0,
      //索引
      currentIndex:0,
      // 每个点之间的移动时间(毫秒)
      speed: 1000,
      //记录上一个动画的运行时间
      lastAnimationTime: 0,
    }
  },
  mounted(){
    this.initMap() // 加载矢量底图
  },
  methods:{
    initMap() {
      const KEY = '你申请的KEY'

      this.map = new Map({
        target: 'map-container',
        layers: [
          // 底图
          new TileLayer({
            source: new WMTS({
              url: `http://t{0-6}.tianditu.com/vec_c/wmts?tk=${KEY}`,
              layer: 'vec', // 矢量底图
              matrixSet: 'c', // c: 经纬度投影 w: 球面墨卡托投影
              style: "default",
              crossOrigin: 'anonymous', // 解决跨域问题 如无该需求可不添加
              format: "tiles", //请求的图层格式,这里指定为瓦片格式
              wrapX: true, // 允许地图在 X 方向重复(环绕)
              tileGrid: new WMTSTileGrid({
                origin: getTopLeft(projectionExtent),
                resolutions: resolutions,
                matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15','16','17','18']
              })
            })
          }),
          // 标注
          new TileLayer({
            source: new WMTS({
              url: `http://t{0-6}.tianditu.com/cva_c/wmts?tk=${KEY}`,
              layer: 'cva', //矢量注记
              matrixSet: 'c',
              style: "default",
              crossOrigin: 'anonymous',
              format: "tiles",
              wrapX: true,
              tileGrid: new WMTSTileGrid({
                origin: getTopLeft(projectionExtent),
                resolutions: resolutions,
                matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15','16','17','18']
              })
            })
          })
        ],
        view: new View({
          center: [120.430070,31.938140],
          projection: projection,
          zoom: 16,
          maxZoom: 17,
          minZoom: 1
        }),
        //加载控件到地图容器中
        controls: defaultControls({
          zoom: false,
          rotate: false,
          attribution: false
        })
      });
      // 将矢量层添加到地图
      this.map.addLayer(this.vectorLayer);
      this.createStartPoint();
      this.createEndPoint();
      this.createCar();
      this.drawLine();
    },
    /**
     * 创建开始点位
     */
    createStartPoint(){
      // 创建feature要素,一个feature就是一个点坐标信息
      let feature = new Feature({
        geometry: new Point(this.pointList[0]),
      });
      // 设置要素的图标
      feature.setStyle(
          new Style({
            // 设置图片效果
            image: new Icon({
              src: 'http://lbs.tianditu.gov.cn/images/bus/start.png',
              // anchor: [0.5, 0.5],
              scale: 1,
            }),
            zIndex: 10,
          }),

      );
      this.vectorLayer.getSource().addFeature(feature);
    },

    //创建结束点位
    createEndPoint(){
      // 创建feature要素,一个feature就是一个点坐标信息
      let feature = new Feature({
        geometry: new Point(this.pointList[this.pointList.length-1]),
      });
      // 设置要素的图标
      feature.setStyle(
          new Style({
            // 设置图片效果
            image: new Icon({
              src: 'http://lbs.tianditu.gov.cn/images/bus/end.png',
              // anchor: [0.5, 0.5],
              scale: 1,
            }),
            zIndex: 10
          }),

      );
      this.vectorLayer.getSource().addFeature(feature);
    },

    createCar(){
      // 创建feature要素,一个feature就是一个点坐标信息
      this.carFeature = new Feature({
        geometry: new Point(this.pointList[0]),
      });
      const currentPoint = fromLonLat(this.pointList[0]);
      const nextPoint = fromLonLat(this.pointList[1]);
      let rotation = this.calculateRotation(currentPoint,nextPoint);
      this.carFeature.setStyle(this.getVehicleStyle(rotation));
      this.vectorLayer.getSource().addFeature(this.carFeature);
    },

    //计算旋转角度
    calculateRotation(currentPoint,nextPoint){
      const dx = nextPoint[0] - currentPoint[0];
      const dy = nextPoint[1] - currentPoint[1];
      return Math.atan2(dy,dx);
    },
    //获取车辆的样式
    getVehicleStyle(rotation) {
      return new Style({
        // 设置图片效果
        image: new Icon({
          src: 'http://lbs.tianditu.gov.cn/images/openlibrary/car.png',
          // anchor: [0.5, 0.5],
          scale: 1,
          rotation: -rotation,
        }),
        zIndex: 5,
      })
    },

    drawLine(){
      // 创建线特征
      const lineFeature = new Feature({
        geometry: new LineString(this.pointList),
      });

      // 设置线样式
      const lineStyle = new Style({
        stroke: new Stroke({
          color: '#25C2F2',
          width: 4,
          lineDash: [10, 8], // 使用点划线 数组的值来控制虚线的长度和间距
        }),

      });
      lineFeature.setStyle(lineStyle);

      // 创建矢量层并添加特征
      const vectorSource = new VectorSource({
        features: [lineFeature],
      });
      const vectorLayer = new VectorLayer({
        source: vectorSource,
        zIndex: 1
      });

      // 将矢量层添加到地图
      this.map.addLayer(vectorLayer);
      // 设置地图视图以适应路径
      this.map.getView().fit(lineFeature.getGeometry().getExtent(), {
        padding: [20, 20, 20, 20],
        maxZoom: 18,
      });
    },

    startAnimation() {
      // 如果没有开始动画,则开始动画
      if (!this.isAnimating) {
        this.isAnimating = true;
        //这里存放的是暂停动画的时间,下面启动动画后,会将当前时间减去暂停动画的时间就是动画已运行的时间,这样就不会从头开始了
        //当前时间比如为900ms,用900ms减去500ms,可以计算出当前暂停了400ms
        this.animationStartTime = performance.now() - (this.lastAnimationTime || 0);
        // 继续或者启动动画
        // 计算经过时间:elapsed = timestamp - this.animationStartTime; 900ms减去400ms 可以算出已经运行了500ms 也就是上次动画所运行的时间了
        this.animateVehicle();
      }
    },

    // 暂停动画
    pauseAnimation() {
      if (this.isAnimating) {
        this.isAnimating = false;
        // 保存当前动画运行的时间 比如已经运行了500ms
        this.lastAnimationTime = performance.now() - this.animationStartTime;
      }
    },
    // 重置动画
    resetAnimation() {
      // 停止动画
      this.isAnimating = false;
      // 重置索引
      this.currentIndex = 0;
      // 将车辆位置重置到起始点
      this.carFeature.getGeometry().setCoordinates(this.pointList[0]);
      const currentPoint = fromLonLat(this.pointList[0]);
      const nextPoint = fromLonLat(this.pointList[1]);
      let rotation = this.calculateRotation(currentPoint,nextPoint);
      // 重置车辆样式
      this.carFeature.setStyle(this.getVehicleStyle(rotation));
    },

    //车辆行驶动画
    animateVehicle(timestamp) {
      if (!this.isAnimating || this.currentIndex >= this.pointList.length - 1) return;

      const currentPoint = this.pointList[this.currentIndex];
      const nextPoint = this.pointList[this.currentIndex + 1];

      // 计算经过的时间
      const elapsed = timestamp - this.animationStartTime;
      const progress = Math.min(elapsed / this.speed, 1);

      // 计算当前位置的坐标
      const coordinates = [
        currentPoint[0] + (nextPoint[0] - currentPoint[0]) * progress,
        currentPoint[1] + (nextPoint[1] - currentPoint[1]) * progress,
      ];

      // 更新车辆位置
      this.carFeature.getGeometry().setCoordinates(coordinates);

      if (progress === 1) {
        this.currentIndex++;
        this.animationStartTime = timestamp; // 重置动画开始时间
        this.lastAnimationTime = 0; // 移动到下一个点时重置
      }

      // 计算下一个点的角度
      const angle = this.calculateRotation(currentPoint, nextPoint);
      this.carFeature.setStyle(this.getVehicleStyle(angle)); // 更新样式以反映新的朝向

      // 继续动画
      if (this.currentIndex < this.pointList.length - 1) {
        requestAnimationFrame(this.animateVehicle);
      } else {
        this.isAnimating = false; // 动画结束
      }
    },
  },
}
</script>
<style scoped>
#map-container {
  width: 100%;
  height: 100vh;
}
</style>

五、Gitee源码

地址:Vue2+OpenLayers实现车辆开始.暂停.重置行驶轨迹动画 

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

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

相关文章

使用傅里叶变换进行图像边缘检测

使用傅里叶变换进行图像边缘检测 今天我们介绍通过傅里叶变换求得图像的边缘 什么是傅立叶变换&#xff1f; 简单来说&#xff0c;傅里叶变换是将输入的信号分解成指定样式的构造块。例如&#xff0c;首先通过叠加具有不同频率的两个或更多个正弦函数而生成信号f&#xff08;x…

基础vue3前端登陆注册界面以及主页面设计

1.下载依赖 "element-plus/icons": "^0.0.11", "element-plus/icons-vue": "^2.3.1", "fortawesome/fontawesome-svg-core": "^6.7.2", "fortawesome/free-solid-svg-icons": "^6.7.2", &quo…

中国数字安全产业年度报告(2024)

数字安全是指&#xff0c;在全球数字化背景下&#xff0c;合理控制个人、组织、国家在各种活动中面临的数字风险&#xff0c;保障数字社会可持续发展的政策法规、管理措施、技术方法等安全手段的总和。 数字安全领域可从三个方面对应新质生产力的三大内涵:一是基于大型语言模型…

从CRUD到高级功能:EF Core在.NET Core中全面应用(三)

目录 IQueryable使用 原生SQL使用 实体状态跟踪 全局查询筛选器 并发控制使用 IQueryable使用 在EFCore中IQueryable是一个接口用于表示可查询的集合&#xff0c;它继承自IEnumerable但具有一些关键的区别&#xff0c;使得它在处理数据库查询时非常有用&#xff0c;普通集…

【VRChat · 改模】Unity2019、2022的版本选择哪个如何决策,功能有何区别;

总览 1.Unity2019、2022的版本的选择 2.Unity添加着色器教程 一、Unity2019、2022的版本的选择 1.Unity2019 和 Unity2022 的区别&#xff0c;VRChat SDK 为何要区分两个版本 我是外行&#xff0c;最开始以为的是&#xff0c;2019 和 2022 的变化是基于这个模型本身的。 也…

人工智能之深度学习-[1]-了解深度学习

文章目录 深度学习1. 神经网络的基础2. 深度学习中的重要概念3. 深度学习的工作流程4. 深度学习的应用5. 深度学习的挑战6. 深度学习与传统机器学习的比较7.深度学习的特点 8. 常见的深度学习模型9.深度学习发展史[了解] 深度学习 深度学习&#xff08;Deep Learning&#xff…

彻底理解JVM类加载机制

文章目录 一、类加载器和双亲委派机制1.1、类加载器1.2、双亲委派机制1.3、自定义类加载器1.4、打破双亲委派机制 二、类的加载 图片来源&#xff1a;图灵学院   由上图可知&#xff0c;创建对象&#xff0c;执行其中的方法&#xff0c;在java层面&#xff0c;最重要的有获取…

第148场双周赛:循环数组中相邻元素的最大差值、将数组变相同的最小代价、最长特殊路径、所有安放棋子方案的曼哈顿距离

Q1、循环数组中相邻元素的最大差值 1、题目描述 给你一个 循环 数组 nums &#xff0c;请你找出相邻元素之间的 最大 绝对差值。 **注意&#xff1a;**一个循环数组中&#xff0c;第一个元素和最后一个元素是相邻的。 2、解题思路 这个问题的核心是遍历循环数组并计算相邻…

电脑换固态硬盘

参考&#xff1a; https://baijiahao.baidu.com/s?id1724377623311611247 一、根据尺寸和缺口可以分为以下几种&#xff1a; 1、M.2 NVME协议的固态 大部分笔记本是22x42MM和22x80MM nvme固态。 在京东直接搜&#xff1a; M.2 2242 M.2 2280 2、msata接口固态 3、NGFF M.…

opengrok_windows_环境搭建

软件列表 软件名下载地址用途JDKhttps://download.java.net/openjdk/jdk16/ri/openjdk-1636_windows-x64_bin.zipindex 使用java工具tomcathttps://dlcdn.apache.org/tomcat/tomcat-9/v9.0.98/bin/apache-tomcat-9.0.98-windows-x64.zipweb服务器opengrokhttps://github.com/o…

《offer 来了:Java 面试核心知识点精讲 -- 原理篇》

在 Java 面试的战场上,只知皮毛可不行,面试官们越来越看重对原理的理解。今天就给大家分享一本能让你在面试中脱颖而出的 “武林秘籍”——《offer 来了:Java 面试核心知识点精讲 -- 原理篇》。 本书详细介绍了Java架构师在BAT和移动互联网公司面试中常被问及的核心知识,内…

Linux之网络套接字

Linux之网络套接字 一.IP地址和端口号二.TCP和UDP协议2.1网络字节序 三.socket编程的常见API四.模拟实现UDP服务器和客户端五.模拟实现TCP服务器和客户端 一.IP地址和端口号 在了解了网络相关的基础知识之后我们知道了数据在计算机中传输的流程并且发现IP地址在其中占据了确定…

迈向 “全能管家” 之路:机器人距离终极蜕变还需几步?

【图片来源于网络&#xff0c;侵删】 这是2024年初Figure公司展示的人形机器人Figure 01&#xff0c;他可以通过观看人类的示范视频&#xff0c;在10小时内经过训练学会煮咖啡&#xff0c;并且这个过程是完全自主没有人为干涉的&#xff01; 【图片来源于网络&#xff0c;侵删】…

几何数据结构之四叉树与八叉树

几何数据结构之四叉树与八叉树 四叉树的定义四叉树深度的计算公式推导假设&#xff1a;计算过程&#xff1a;1. 划分空间&#xff1a;2. 节点容纳的最小距离&#xff1a;3. 解出深度&#xff1a;4. 考虑常数项&#xff1a; 总结&#xff1a; 八叉树 四叉树的定义 四叉树&#…

(一)相机标定——四大坐标系的介绍、对应转换、畸变原理以及OpenCV完整代码实战(C++版)

一、四大坐标系介绍 1&#xff0c;世界坐标系 从这个世界&#xff08;world&#xff09;的视角来看物体 世界坐标系是3D空间坐标&#xff0c;每个点的位置用 ( X w , Y w , Z w ) (X_w,Y_w,Z_w) (Xw​,Yw​,Zw​)表示 2&#xff0c;相机坐标系 相机本身具有一个坐标系&…

嵌入式知识点总结 C/C++ 专题提升(一)-关键字

针对于嵌入式软件杂乱的知识点总结起来&#xff0c;提供给读者学习复习对下述内容的强化。 目录 1.C语言宏中"#“和"##"的用法 1.1.(#)字符串化操作符 1.2.(##)符号连接操作符 2.关键字volatile有什么含意?并举出三个不同的例子? 2.1.并行设备的硬件寄存…

重塑商业智能:大数据改变商业的十种方式

在过去几年间&#xff0c;大数据一直在改变许多公司的运营方式。大数据指的是大量且多样的数据集&#xff0c;当这些数据被妥善收集和分析时&#xff0c;人们能够从中获取有价值的洞察信息。随着大数据逐渐应用于中小型企业&#xff0c;它有望彻底变革企业运营模式。以下将介绍…

基于Spring Boot的车间调度管理系统

基于 Spring Boot 的车间调度管理系统 一、系统概述 基于 Spring Boot 的车间调度管理系统是一个为制造企业车间生产活动提供智能化调度和管理解决方案的软件系统。它利用 Spring Boot 框架的便捷性和高效性&#xff0c;整合车间内的人员、设备、物料、任务等资源&#xff0c…

Ubuntu 24.04 LTS 安装 tailscale 并访问 SMB共享文件夹

Ubuntu 24.04 LTS 安装 tailscale 安装 Tailscale 官方仓库 首先&#xff0c;确保系统包列表是最新的&#xff1a; sudo apt update接下来&#xff0c;安装 Tailscale 所需的仓库和密钥&#xff1a; curl -fsSL https://tailscale.com/install.sh | sh这会自动下载并安装 …

Ubuntu 22.04 TLS 忘记root密码,重启修改的解决办法

1.想办法进入这个界面&#xff0c;我这里是BIOS引导的是按Esc按一下就行&#xff0c;UEFI的貌似是按Shift不得而知&#xff0c;没操作过。下移到Advanced options for Ubuntu&#xff0c;按enter 2.根据使用的内核版本&#xff0c;选择带「recovery mode」字样的内核版本&#…