Konva 开源绘图库中碰撞检测的改进(JS)
Konva 是一个开源JavaScript 2d canvas library
项目网址:
这个库方便易用,文档和示例较多,上手容易
里面集成了常用的方放大、缩小、移动、碰撞检测等功能
我们在研的汽车船配载仪就用到了这个库
将各种型号汽车装载到甲板上
汽车装载时,需要检测汽车与汽车之间是否发生碰撞
Konva示例demo中有碰撞检测示例,但是存在以下不足
- 只适用于物体不发生旋转的情况
- 当物体发生旋转时,Konva中给定Demo是根据物体的矩形包围盒做碰撞检测的,所以会存误检测情况,如下图所示
需要在konva基础上手写碰撞检测实现,依赖的碰撞检测开源库有
- Javascript Clipper
参考另一篇文章
步骤1: 实现多边形碰撞检测函数
Clipper主要是多边形布尔运算的开源库,但是他适用于凸多边形和凹多边形,所以我们可以在Clipper的基础上封装一个碰撞检测函数,通用性和实时性较好
- 思路:两个多边形求交,如果存在交集则发生碰撞,否则不碰撞
function isCollision(car_paths, deck_paths) {
var cpr = new ClipperLib.Clipper();
cpr.AddPaths(car_paths, ClipperLib.PolyType.ptSubject, true); // true means closed path
cpr.AddPaths(deck_paths, ClipperLib.PolyType.ptClip, true);
var solution_paths = new ClipperLib.Paths();
var succeeded = cpr.Execute(ClipperLib.ClipType.ctIntersection, solution_paths, ClipperLib.PolyFillType
.pftNonZero, ClipperLib.PolyFillType.pftNonZero);
if (solution_paths.length === 0) return false;
return true;
}
步骤2:计算Konva矩形框旋转后的角度
- Konva的旋转是以矩形是围绕矩形的中心点进行旋转的,旋转过程中中心点坐标不变
function getCenter(shape) {
return {
x: shape.x() +
(shape.width() / 2) * Math.cos(shape.rotation() / 180 *Math.PI) +
(shape.height() / 2) * Math.sin(-shape.rotation() / 180 * Math.PI),
y: shape.y() +
(shape.height() / 2) * Math.cos(shape.rotation() / 180 * Math.PI) +
(shape.width() / 2) * Math.sin(shape.rotation() / 180 * Math.PI)
}
- 计算Rect旋转后的四个点坐标
function GetPtsFromRect(rect)
//矩形的属性
let x=rect.x();
let y=rect.y();
let rotation=rect.rotation()/180*Math.PI;
let width = rect.width();
let height= rect.height();
//如果没有旋转
if(rect.rotation()===0){
let p0={x:rect.x(),y:rect.y()};
let p1={x:p0.x+width,y:p0.y};
let p2={x:p0.x+width,y:p0.y+height};
let p3={x:p0.x,y:p0.y+height};
return [p0,p1,p2,p3]
//计算中心点
let center=getCenter(rect);
let centerX=center.x;
let centerY=center.y;
//四个初始坐标
let p0= RotateAroundCenter(x,y,centerX,centerY,-rotation);
let p1={x:p0.x+width,y:p0.y};
let p2={x:p0.x+width,y:p0.y+height};
let p3={x:p0.x,y:p0.y+height};
//旋转后的坐标
//左上P0 右上P1
//左小P3 右下P2
let p0_new={x:x,y:y};