注册
web

使用pixi.js开发一个智慧路口(车辆轨迹追踪)项目

项目效果


项目功能:



  • 位置更新、航向角计算。
  • debug模式。
  • 位置角度线性补帧。
  • 变道、转弯、碰撞检测。
  • mock轨迹数据

图片效果:


result.gif


视频效果:


eca66db3168173bb581492d1954fb21a.jpg


项目启动


项目地址



(如果觉得项目对你有帮助的话, 可以给我一个star 和 赞,❤️)


启动demo项目



  1. cd car-tracking-2d/demos/react-demo
  2. yarn
  3. yarn start

界面使用


debug 模式


浏览器url ?后面(search部分)加入参数debug=1


例如:http://localhost:3000/home?tunnelNo=tunnel1&debug=1


将会展示调试信息:


image.png


如图:车旁边的白色文字信息为debug模式才会展示的内容(由上到下为:里程、车id、车道id、[x,y]、旋转角度)


实现:


技术栈:


ts+pixi.js+任意前端框架


(前端框架使用vuereact或者其他框架都可以。只需要在mounted阶段,实例化我们暴露出来class即可。然后在destroyed或者unmounted阶段destory示例即可,后面会提到。)


pixi.js


官网介绍:



Create beautiful digital content with the fastest, most flexible 2D WebGL renderer.



pixi.js是一个2D的WebGL的渲染库。但是没有three.js知名度高。一个原因是,我们2D的需求技术路线很多,可以是dom、svg、canvas draw api等,包括本项目也可以使用其他技术方案实现,希望通过本文,大家在实现这种频繁更新元素位置的功能,可以考虑一下pixi.js。



API快速讲解

这里只讲我们项目使用到的


Application

import * as PIXI from 'pixi.js';

const app = new PIXI.Application({
view: canvasDom // canvas dom 对象
});


Container

容器,功能为一个组。
当我们设置容器的scale(缩放)、rotation(旋转)、x、y(位置)时。里面的元素都会收到影响。


(ps:app.stage也是一个Container


每个 Container可以通过addChild(增加子节点)、removeChild(删除子节点),也可以设置子元素的zIndex(和css的功能一致)。子原始的scale(缩放)、rotation(旋转)、x、y(位置)是相对于Container的。


Sprite

精灵,渲染图片对象。


carObj = Sprite.from('/car.svg')

Sprite.from(url),url相同的话,只会加载一次图片。纹理对象也只会创建一次。


anchor属性其他对象也有,设置定位点,类似于csstransform-origin


执行下面代码
carObj.anchor.set(0.5, 0.5)


如果x = 10 y =10,carObj的中心点的坐标就是(10,10),旋转原点也是(10,10),缩放也是如此。


Graphics

绘制几何图形,圆弧,曲线、直线等都可以。也支持fill和stroke,canvas draw api支持的,Graphics都支持。


Text

文本,比较简单。字体、颜色、大小,都支持。



  • 值得注意的是文本内容含有换行符时(\n \r),文本会换行。
  • pixi提供测量文本的width height的方法非常好用。

Tick

this.app.ticker.add(() => {})

类似于requestAnimationFrame


具体实现


分三步,vue/react都一样:


1 获取canvas dom通过ref的方式。


2 创建我们封装Stage Road


3 组件销毁时,执行 stage.destroy(注意stage是我封装的,不是pixi的。使用方不需要使用pixi.js的api)


线性插帧

当有一个对象由坐标 点a(0,0)变换到点b(1000,1000),1秒内完成。
中间的变化值为:
dx =1000 dy=1000
记录每帧的时间差t(当前帧距离第0帧的,单位毫秒)


所以第n帧位置信息为(0+dx / 1000 * t, 0+ dy /1000 *t)


角度变换也是这个道理。


位置坐标获取

如果直线长度为1000px,对应的实际里程为100米。


当跑了50米,当前就是直线的中点坐标。
弯道呢,通过弧度可以推算出坐标。
可以把 Road.ts line 70的注释取消。


 // 方便开发观察 绘制车道线 ---begin----
// this.mount(lane.centerLine.paint())

航向角

直线简单,通过Math.atan2可以求出来。
弯道需要通过解析几何,计算出圆弧切线,然后推测出航向角。


转弯

mark.png
可以查看我们标注的一些点


以1到7的弯道举例,相当于是从新创建一次车道,车道的点是车道1和车道7的组合。
我们通过 circle属性配置,在创建Road


{
uid: '1-2',
x: 1072,
y: 1605,
circle: {
// 编号形式 车道序号-第几个点

linkId: '7-3'
}
},

这条信息表示:车道1的第2个点(uid),有圆弧链接到车道7的第3个点(circle.linkId)


碰撞检测

我们这个项目的特点是,前端展示,实际后端返回什么数据,我们就展示什么数据。(一般不需要前端处理)。
这里我们mock的数据就简单处理一下。判断是否存在相交的线段(当前对象的位置和将要到达的点),如果线段相交,车辆暂停移动。


作者:火锅小王子
来源:juejin.cn/post/7327467832866095130

0 个评论

要回复文章请先登录注册