【算法记录/六边形网格】(五)直线绘制

说在前面

在这里插入图片描述

步骤

  • 怎样在两个正六边形格点间绘制一条直线呢?通常,我们可以使用线性插值方法来绘制直线。首先均匀地在直线上采样 N + 1 N+1 N+1个点,然后计算这些点在哪个六边形格点中。

    1. 计算两个六边形格点之间的距离,见【算法记录/六边形网格】(四)距离。假设距离为 N N N,起点为 A A A,终点为 B B B
    2. 然后均匀地在 A A A B B B之间选择 N + 1 N+1 N+1个点。在使用线性插值的情况下,每个点为 A + ( B − A ) ∗ 1.0 / N ∗ i A+(B-A)*1.0/N*i A+(BA)1.0/Ni i ∈ [ 0 , N ] i\in[0,N] i[0,N]。整个运算结果为浮点数。
    3. 将每个采样点(浮点数)转换为对应的六边形格点坐标(整型)。
  • 伪代码

    // 浮点坐标转为整型坐标
    function cube_round(cube):
        // 四舍五入取整
        var rx = round(cube.x)
        var ry = round(cube.y)
        var rz = round(cube.z)
    
        // 小数位
        var x_diff = abs(rx - cube.x)
        var y_diff = abs(ry - cube.y)
        var z_diff = abs(rz - cube.z)
    
    	// 小数位最大的重新进行计算
    	// 例如 (2.5 -1.2 -1.3) 
    	// 四舍五入 (3, -1, -1) 但是这个坐标不满足x+y+z=0
    	// 由于0.5 > 0.2、0.3 所以重新计算x 
    	// 最终结果应该是(2, -1, -1)
        if x_diff > y_diff and x_diff > z_diff:
            rx = -ry-rz
        else if y_diff > z_diff:
            ry = -rx-rz
        else:
            rz = -rx-ry
    
        return Cube(rx, ry, rz)
        
    // 浮点插值函数
    function lerp(a, b, t): # for floats
        return a + (b - a) * t
    
    // 立方体坐标插值,此时返回的立方体坐标为浮点数
    function cube_lerp(a, b, t): # for hexes
        return Cube(lerp(a.x, b.x, t), 
                    lerp(a.y, b.y, t),
                    lerp(a.z, b.z, t))
    
    function cube_linedraw(a, b):
        // 计算两个格点之间的六边形距离
        var N = cube_distance(a, b)
        var results = []
        // 计算采样点
        for each 0 ≤ i ≤ N:
            // 采样点转换为六边形坐标(整型)
            results.append(cube_round(cube_lerp(a, b, 1.0/N * i)))
        return results
    

补充说明

  • 有时候,在计算后得到的点有可能刚好在六边形的边上。但是cube_round的结果会比较随机,如下图,有时候会是1,有时候会是2。如果我们将其放在同一边,那么绘制的线会好看一点。
    在这里插入图片描述
    我们可以通过在循环开始前给其中一端(起点或终点)增加一丢丢偏移(或者两端同时), C u b e ( 1 e − 6 , 2 e − 6 , − 3 e − 6 ) Cube(1e-6, 2e-6, -3e-6) Cube(1e6,2e6,3e6)。这样可以将线稍稍偏移,避免点在边上。

  • 在方形网格DDA算法中,我们将 N N N设置为两点之间各方向轴上的最大距离。在六边形网格中也是如此。

  • cube_lerp算法需要返回浮点数据。如果使用的是静态类型语言,我们可以自己定义一个FloatCube结构/方法来代替上面的Cube,或者直接将cube_lerp函数去掉,将其内置到cube_linedraw函数中。

    function cube_round(x, y, z):
        // 四舍五入取整
    	var rx = round(x)
    	var ry = round(y)
    	var rz = round(z)
    	// ......
    	
    function cube_linedraw(a, b):
    	// 计算两个格点之间的六边形距离
    	var N = cube_distance(a, b)
        var results = []
        // 计算采样点
        for each 0 ≤ i ≤ N:
            // 采样点转换为六边形坐标(整型)
            results.append(cube_round(lerp(a.x, b.x, 1.0/N * i), 
    	                lerp(a.y, b.y, 1.0/N * i),
    	                lerp(a.z, b.z, 1.0/N * i)))
        return results
    
    
  • 若想要在偏移坐标下绘制直线,可以参考这个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值