添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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};