Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/403.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何为凸包算法的中间步骤设置动画?_Javascript_Animation_Canvas_Geometry_Convex Hull - Fatal编程技术网

Javascript 如何为凸包算法的中间步骤设置动画?

Javascript 如何为凸包算法的中间步骤设置动画?,javascript,animation,canvas,geometry,convex-hull,Javascript,Animation,Canvas,Geometry,Convex Hull,我正在尝试制作某种动画,以便用户能够理解或看到查找点集的凸包所采取的步骤。例如,假设我在Graham Scan中使用下面的代码,有哪些方法可以设置线条添加和删除的动画?即使对很多点来说,处理它们需要时间,然后几乎立即绘制它们,我不确定如何帮助用户体验正在发生的事情 function GrahamScan(points) { points.sort(function(a, b){return a.x - b.x}) var stack1 = []; var stack2 = [];

我正在尝试制作某种动画,以便用户能够理解或看到查找点集的凸包所采取的步骤。例如,假设我在Graham Scan中使用下面的代码,有哪些方法可以设置线条添加和删除的动画?即使对很多点来说,处理它们需要时间,然后几乎立即绘制它们,我不确定如何帮助用户体验正在发生的事情

function GrahamScan(points) {
  points.sort(function(a, b){return a.x - b.x})

  var stack1 = [];
  var stack2 = [];

  stack1.push(points[0])
  stack1.push(points[1])

  for (i=2; i < points.length; i++) {
     len = stack1.length > 1;
     turn = RTT(stack1[stack1.length-2], stack1[stack1.length-1], points[i]) === 1;
     ctx.beginPath();
     ctx.moveTo(stack1[stack1.length-2].x,stack1[stack1.length-2].y);
     ctx.lineTo(stack1[stack1.length-1].x,stack1[stack1.length-1].y);
     ctx.stroke();
     while (len && !turn) {
           stack1.pop();
           reDraw(points, stack1, stack2);
           len = stack1.length > 1;
           if (!len) {
              break
           }
           turn = RTT(stack1[stack1.length-2], stack1[stack1.length-1], points[i]) === 1;
     }
     stack1.push(points[i]);

  }
  ctx.beginPath();
  ctx.moveTo(stack1[stack1.length-2].x,stack1[stack1.length-2].y);
  ctx.lineTo(stack1[stack1.length-1].x,stack1[stack1.length-1].y);
  ctx.stroke();

  stack2 = [];
  stack2.push(points[points.length-1])
  stack2.push(points[points.length-2])

  for (i=2; i < points.length; i++) {
     len = stack2.length > 1;
     turn = RTT(stack2[stack2.length-2], stack2[stack2.length-1], points[points.length-i-1]) === 1;
     ctx.beginPath();
     ctx.moveTo(stack2[stack2.length-2].x,stack2[stack2.length-2].y);
     ctx.lineTo(stack2[stack2.length-1].x,stack2[stack2.length-1].y);
     ctx.stroke();
     while (len && !turn) {
           stack2.pop();
           reDraw(points, stack1, stack2);
           len = stack2.length > 1;
           if (!len) {
              break
           }
           turn = RTT(stack2[stack2.length-2], stack2[stack2.length-1], points[points.length-i-1]) === 1;
     }
     stack2.push(points[points.length-i-1]);

  }
  ctx.beginPath();
  ctx.moveTo(stack2[stack2.length-2].x,stack2[stack2.length-2].y);
  ctx.lineTo(stack2[stack2.length-1].x,stack2[stack2.length-1].y);
  ctx.stroke();

}
   function reDraw(points,stack1,stack2) {
      ctx.clearRect(0, 0, w, h);
      document.getElementById("canvasimg").style.display = "none";
      for (j = 0; j < points.length; j++) {
         ctx.beginPath();
         ctx.fillStyle = x;
         ctx.fillRect(points[j].x-1, points[j].y-1, 3, 3);
         ctx.closePath();
      }
      for (k = 1; k < stack1.length; k++) {
         ctx.beginPath();
         ctx.moveTo(stack1[k-1].x-1,stack1[k-1].y-1);
         ctx.lineTo(stack1[k].x-1,stack1[k].y-1);
         ctx.stroke();
      }
      for (l = 1; l < stack2.length; l++) {
         ctx.beginPath();
         ctx.moveTo(stack2[l-1].x-1,stack2[l-1].y-1);
         ctx.lineTo(stack2[l].x-1,stack2[l].y-1);
         ctx.stroke();
      }
   }

   function RTT(a, b, c) {
      return Math.sign((b.x - a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
   }
函数GrahamScan(点){
sort(函数(a,b){返回a.x-b.x})
var stack1=[];
var stack2=[];
堆栈1.推送(点[0])
堆栈1.推送(点[1])
对于(i=2;i1;
回合=RTT(stack1[stack1.length-2],stack1[stack1.length-1],点[i])==1;
ctx.beginPath();
ctx.moveTo(stack1[stack1.length-2].x,stack1[stack1.length-2].y);
ctx.lineTo(stack1[stack1.length-1].x,stack1[stack1.length-1].y);
ctx.stroke();
while(len&!turn){
stack1.pop();
重新绘制(点、堆栈1、堆栈2);
len=stack1.length>1;
如果(!len){
打破
}
回合=RTT(stack1[stack1.length-2],stack1[stack1.length-1],点[i])==1;
}
堆栈1.推送(点[i]);
}
ctx.beginPath();
ctx.moveTo(stack1[stack1.length-2].x,stack1[stack1.length-2].y);
ctx.lineTo(stack1[stack1.length-1].x,stack1[stack1.length-1].y);
ctx.stroke();
stack2=[];
堆栈2.推送(点[点.长度-1])
堆栈2.推送(点[点.长度-2])
对于(i=2;i1;
回合=RTT(stack2[stack2.length-2],stack2[stack2.length-1],points[points.length-i-1])==1;
ctx.beginPath();
ctx.moveTo(stack2[stack2.length-2].x,stack2[stack2.length-2].y);
ctx.lineTo(stack2[stack2.length-1].x,stack2[stack2.length-1].y);
ctx.stroke();
while(len&!turn){
stack2.pop();
重新绘制(点、堆栈1、堆栈2);
len=stack2.length>1;
如果(!len){
打破
}
回合=RTT(stack2[stack2.length-2],stack2[stack2.length-1],points[points.length-i-1])==1;
}
堆栈2.推送(点[点.长度-i-1]);
}
ctx.beginPath();
ctx.moveTo(stack2[stack2.length-2].x,stack2[stack2.length-2].y);
ctx.lineTo(stack2[stack2.length-1].x,stack2[stack2.length-1].y);
ctx.stroke();
}
函数重绘(点、堆栈1、堆栈2){
ctx.clearRect(0,0,w,h);
document.getElementById(“canvasimg”).style.display=“无”;
对于(j=0;j
使用生成器函数设置算法动画。 最简单的方法是使用生成器函数创建可以停止算法执行的位置,并允许动画循环显示和控制执行速度。它不会干扰算法的功能。看

正常生成器函数用于生成数据,但在这种情况下,我们对数据不感兴趣,而是对算法中内置的可视化过程感兴趣

要设置动画,只需创建一个标准动画循环。创建背景画布,以便在每次更新/步进算法时保存不希望绘制的任何图形。为可视化设置帧速率,然后每帧清除画布,绘制背景,从生成器函数调用下一个值(该函数将渲染算法的下一部分),然后等待下一帧

当算法完成时,生成器将返回undefined作为值,您知道它已完成

一个简单的例子

我已将您的
grahamScan
函数转换为生成器函数。然后用vis=grahamScan(points)
创建一个生成器,然后每4帧渲染一次步骤,即~15fps。我不确定你想在哪里进行视觉打断,我还添加了一些额外的渲染,因为找到的线在闪烁(在内部循环中,而外部线没有被绘制)

我随机生成点阵列,并在完成后大约2秒重新启动动画

主动画循环在底部,我添加了一些代码来创建随机点并将它们渲染到背景画布上。唯一的限制是船体垂直计数,如果非常高,将减慢速度。这些点是预渲染的,因此不会影响帧速率,您可以有10万到100万个(虽然预渲染时间需要一点时间。我测试了50万个点,渲染背景大约需要4秒,但可视化以全帧速率运行

“使用严格的”
var canvas=document.createElement(“canvas”);
canvas.width=innerWidth-20;
canvas.height=内部高度-20;
var ctx=canvas.getContext(“2d”);
document.body.appendChild(画布)
var w=画布宽度;
var h=画布高度;
var点;
var background=document.createElement(“画布”);
背景宽度=w;
背景高度=h;
background.ctx=background.getContext(“2d”);
const frameRate=4;//渲染之间有多少帧(正常更新每1/60秒渲染一次,因此1的值是每秒60次)
var frameCount=0;
var restartIn=120;//重新启动前的帧数
var restarcount=120;
var restart=true