algorithm(一):直线经过的网格区域计算

1 背景描述

  在一给定画布场景中,判断线段所经过网格。下图所示分别为线性递增和线性递减时,直线经过的网格路径。

octave:1> plot([1.5,8.7],[0.4,9.4]);
octave:2>grid on;

在这里插入图片描述

octave:3> plot([1.5,8.7],[9.4,0.4]);
octave:4>grid on;

在这里插入图片描述

2 方案详解

2.1 前述

  在计算机图形学,生成直线的常见算法包括:数值微分法(DDA)、Bresenham法和中点画线法。乍眼一看,计算直线经过的网格区域类似反向算法实现,通过实验发现,对线段起始点坐标为[(2,4),(8,9)]、[(2.1,4),(8.9,9)]和[(2,0.4),(8,9.4)]进行计算较为有效,但当起始点横纵坐标不为整数,计算网格存在遗漏。

2.2 分析

  回归问题本身,直线经过网格,就必然会与网格线产生交点,因此,可考虑此种策略:①先分别遍历直线与网格横纵交点(需考虑沿X轴和Y轴递增递减性质);②根据直线与网格横纵交点求出交点位置跨越的网格序列号,且存在以下规律:

1)当交点在横轴
{ p 1 u p = { p 1 c o l = c e i l ( p 1 x ) p 1 r o w = p 1 y + 1 上侧网格 p 1 d o w n = { p 1 c o l = c e i l ( p 1 x ) p 1 r o w = p 1 y 下侧网格 \begin{cases} p1_{up} = \begin{cases} p1_{col} = ceil(p1_x) \\ p1_{row} = p1_y + 1 \end{cases} & \quad \text{上侧网格}\\ p1_{down} = \begin{cases} p1_{col} = ceil(p1_x) \\ p1_{row} = p1_y \end{cases} & \quad \text{下侧网格} \end{cases} p1up={p1col=ceil(p1x)p1row=p1y+1p1down={p1col=ceil(p1x)p1row=p1y上侧网格下侧网格

2)当交点在纵轴
{ p 2 l e f t = { p 2 c o l = p 2 x p 2 r o w = c e i l ( p 2 y ) 左侧网格 p 2 r i g h t = { p 2 c o l = p 2 x + 1 p 2 r o w = c e i l ( p 2 y ) 右侧网格 \begin{cases} p2_{left} = \begin{cases} p2_{col} = p2_x \\ p2_{row} = ceil(p2_y) \end{cases} & \quad \text{左侧网格}\\ p2_{right} = \begin{cases} p2_{col} = p2_x + 1 \\ p2_{row} = ceil(p2_y) \end{cases} & \quad \text{右侧网格} \end{cases} p2left={p2col=p2xp2row=ceil(p2y)p2right={p2col=p2x+1p2row=ceil(p2y)左侧网格右侧网格

在这里插入图片描述

3 具体实现

/**
 * @description: 计算线段与网格线的交点
 * @param {type} 
 * @return: 
 */
function intersectionCal(startPoint, endPoint) {
	var dx = endPoint.x - startPoint.x;
   	var dy = endPoint.y - startPoint.y;
   	// 设置数据列表空间
    var temList = new Array();
    var gridList = new Array();
    // 设置增量
    var increX = dx/Math.abs(dx);
    var increY = dy/Math.abs(dy);
    // 直线方程:斜截式
    var k = dy/dx;
    var b = -k * startPoint.x + startPoint.y;
    // 开始计算交点
    for (var m=0; m<=Math.abs(dx)-1; m++) {
     // 沿横轴方向遍历,既查询与网格轴轴的交点
     var temPoint1 = new b2Vec2();
     temPoint1.x = Math.ceil(startPoint.x) + increX * m;
     temPoint1.y = k * temPoint1.x + b;
     temList.push(temPoint1);
 }
   // 沿纵轴方向遍历,既查询与网格横轴的交点
   for (var n=0; n<=Math.abs(dy); n++) {
     var temPoint2 = new b2Vec2();
     temPoint2.y = Math.ceil(startPoint.y) + increY * n;
     temPoint2.x = (temPoint2.y - startPoint.y) / k + startPoint.x;
     temList.push(temPoint2);
   }
	return temList;
}
/**
 * @description: 计算线段经过网格行列号
 * @param {type} 
 * @return: 
 */
function lineGridCal(temList) {
   // 存储网格路径
   for (var j=0; j<(temList.length);j++) {
     var temGridUp = new b2Vec2();
     var temGridDown = new b2Vec2();
     var temGridLeft = new b2Vec2();
     var temGridRight = new b2Vec2();
     // 横轴交点
     if((temList[j].x !=Math.ceil(temList[j].x)) && 
     (temList[j].y ==Math.ceil(temList[j].y))){
       temGridUp.x = Math.ceil(temList[j].x);
       temGridUp.y = Math.ceil(temList[j].y)+1;
       temGridDown.x = Math.ceil(temList[j].x);
       temGridDown.y = Math.ceil(temList[j].y);
       gridList.push(temGridUp, temGridDown);
     } 
     // 纵轴交点
     else if((temList[j].y !=Math.ceil(temList[j].y)) && 
     (temList[j].x ==Math.ceil(temList[j].x))) {
       temGridLeft.x = Math.ceil(temList[j].x);
       temGridLeft.y = Math.ceil(temList[j].y);
       temGridRight.x = Math.ceil(temList[j].x)+1;
       temGridRight.y = Math.ceil(temList[j].y);
       gridList.push(temGridLeft, temGridRight);
     }
   };
   return gridList;
 }
}
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值