You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效获取两个六边形网格范围的相交六边形?

嘿,我太懂你这种痛点了——生成两个全量坐标列表再暴力匹配找交集,等范围半径稍微大一点,那效率简直低到让人抓狂😅。之前我在做六边形网格的地图系统时,也踩过一模一样的坑,刚好对Red Blob Games里的范围交集方法有实操经验,给你梳理下核心思路、实操步骤,还有容易踩的坑:

为什么原来的方法效率拉胯?

先掰扯清楚根源:单个六边形范围的坐标数量是O(r²)级别的(r是半径),两个范围就是O(r1² + r2²)的存储量,再加上遍历匹配的O(r1²*r2²)时间复杂度,数据量上去后完全是灾难级的。而Red Blob Games的思路核心就是跳过全量生成,直接通过数学约束找到交集区域。

核心思路(对应原指南的核心逻辑)

不管用哪种六边形坐标系统(轴向、立方体、偏移),两个范围的交集都是「同时满足两个范围约束的所有六边形坐标」。我们不需要生成所有点再筛选,而是:

  1. 先判断两个范围是否存在交集(或者是否完全包含)
  2. 只在可能重叠的区域内遍历,同时验证是否满足两个范围的约束

下面以最常用的**轴向坐标(q, r)**为例,给你拆解实操步骤:

第一步:先搞定「点是否在范围内」的判断函数

这是基础,轴向坐标下的距离公式是:两个点(q1, r1)和(q2, r2)的距离为(abs(q1-q2) + abs(q1+r1 - q2 - r2) + abs(r1-r2)) // 2。基于这个,判断点是否在范围内的函数可以写成:

def is_in_hex_range(q, r, center_q, center_r, radius):
    dq = abs(q - center_q)
    dr = abs(r - center_r)
    ds = abs(-q - r + center_q + center_r)  # 轴向坐标中s = -q - r,这里计算s方向的差值
    return (dq + dr + ds) // 2 <= radius

第二步:高效计算交集的流程

  1. 快速判断特殊情况:
    • 如果两个中心的距离 > 两个半径之和:完全无交集,直接返回空列表
    • 如果两个中心的距离 + 较小半径 ≤ 较大半径:小范围完全被包含在大范围里,直接返回小范围的所有坐标(用你原来的生成函数就行)
  2. 遍历重叠区域并筛选:
    对于部分重叠的情况,我们不需要遍历整个小范围,而是先算出两个范围在q、r轴上的重叠区间,再在这个区间内遍历,同时验证是否满足两个范围的约束:
    def get_hex_range_intersection(center1, radius1, center2, radius2):
        q1, r1 = center1
        q2, r2 = center2
        
        # 计算两个中心的距离
        dq = abs(q1 - q2)
        dr = abs(r1 - r2)
        ds = abs(-q1 - r1 + q2 + r2)
        center_distance = (dq + dr + ds) // 2
        
        # 情况1:无交集
        if center_distance > radius1 + radius2:
            return []
        # 情况2:一个范围完全包含另一个
        if center_distance + min(radius1, radius2) <= max(radius1, radius2):
            if radius1 <= radius2:
                return your_existing_generate_range_function(center1, radius1)
            else:
                return your_existing_generate_range_function(center2, radius2)
        
        # 情况3:部分重叠,遍历重叠区间
        # 先确定q的遍历范围(取两个范围q区间的交集)
        q_min = max(q1 - radius1, q2 - radius2)
        q_max = min(q1 + radius1, q2 + radius2)
        
        intersection = []
        for q in range(q_min, q_max + 1):
            # 计算当前q下,在两个范围内的r的有效区间
            # 第一个范围的r约束
            r_low1 = max(r1 - (radius1 - abs(q - q1)), r1 - radius1)
            r_high1 = min(r1 + (radius1 - abs(q - q1)), r1 + radius1)
            # 第二个范围的r约束
            r_low2 = max(r2 - (radius2 - abs(q - q2)), r2 - radius2)
            r_high2 = min(r2 + (radius2 - abs(q - q2)), r2 + radius2)
            
            # 取两个r区间的交集
            current_r_min = max(r_low1, r_low2)
            current_r_max = min(r_high1, r_high2)
            
            # 遍历r并验证
            for r in range(current_r_min, current_r_max + 1):
                if is_in_hex_range(q, r, q1, r1, radius1) and is_in_hex_range(q, r, q2, r2, radius2):
                    intersection.append((q, r))
        return intersection
    

容易踩的坑(我之前掉过的坑)

  1. 坐标系统搞混:如果你用的是偏移坐标(比如行偏移、列偏移),一定要先转成轴向/立方体坐标再处理,不然距离和范围约束的公式完全不对。
  2. 边界条件写错:比如把<=写成<,导致边缘的六边形被漏掉;或者计算中心距离时忘了除以2,导致判断交集的逻辑出错。
  3. 遍历范围没优化:如果直接遍历整个小范围而不是重叠区间,虽然结果对,但效率还是会打折扣,尤其是两个范围重叠部分很小的时候。

额外优化建议

  • 如果用立方体坐标(x, y, z,满足x+y+z=0),距离计算会更直观,约束条件也更容易推导,你可以试试转成立方体坐标来处理。
  • 如果你需要频繁计算交集,可以把每个范围的q、r边界预存起来,避免重复计算。

内容的提问来源于stack exchange,提问作者WDUK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:22:36