当前位置: 首页 > 知识库问答 >
问题:

在六边形网格上:在选定点的给定半径内选择瓷砖。

钱俊楚
2023-03-14
(0,0) (0,1) (0,2) (0,3) (0,4)    
   (1,0) (1,1) (1,2) (1,3) (1,4)   
(2,0) (2,1) (2,2) (2,3) (2,4)  
   (3,0) (3,1) (3,2) (3,3) (3,4) etc...

我正在努力解决的问题是,我不能通过使用for(x-range;x+range;x++)来“选择”相邻的瓷砖;对于(y-range;y+range;y++);,因为它选择了不需要的平铺(在我给出的示例中,选择(1,1)平铺并给出1的范围也会给出(3,0)平铺(我实际上需要的平铺是(0,1)(0,2)(1,0)(1,2)(2,1)(2,2)),它有点靠近平铺(因为数组的结构方式),但这并不是我真正想要选择的东西。

有人能在这里给我指个正确的方向吗?

共有1个答案

章琛
2023-03-14

上面你可以看到的是两个网格。这一切都取决于你给瓷砖编号的方式,以及你理解什么是六边形网格的方式。在我看来,六边形网格只不过是一个变形的正交网格。

我用紫色圈出的两个十六进制块理论上仍然与0,0相邻。然而,由于我们从正交网格中获得十六进制网格的变形,这两个网格在视觉上不再相邻。

我们需要理解的是在某个方向上发生的变形,在我的例子中沿着[(-1,1)(1,-1)]假想线。更准确地说,这就好像网格沿着那条线被拉长了,而沿着垂直于那条线被压扁了。因此,这条线上的两块瓷砖自然地展开了,在视觉上不再相邻。相反,与(0,0)对角线的tiles(1,1)(-1,-1)现在异常地靠近(0,0),实际上它们现在在视觉上与(0,0)相邻。然而,在数学上,它们仍然是对角线,在代码中这样处理它们是有帮助的。

我所展示的图像说明了半径为1。对于半径为2时,您会注意到(2,-2)(-2,2)是不应该包含在选定内容中的块。诸如此类。因此,对于半径r的任何选择,都不应选择(r,-r)(-r,r)点。除此之外,您的选择算法应该与平铺网格相同。

只要确保你的轴正确地设置在六边形网格上,并相应地为你的瓷砖编号。

让我们进一步讨论一下这个问题。我们现在知道沿着网格中的任何方向移动花费我们1。沿着伸展的方向移动要花费我们2。例如,请参见(0,0)(-1,1)

Normal distance = (1, 1) - (-2, 5) = (3, -4)
(3, -4) = (3, -3) + (0, -1)

所以重述一下。(1,1)(-2,5)之间的距离是(3,-3)的长度加上(0,-1)的长度。也就是说距离=3*2+1=7

下面是我上面解释的算法在C++中的实现:

int ComputeDistanceHexGrid(const Point & A, const Point & B)
{
  // compute distance as we would on a normal grid
  Point distance;
  distance.x = A.x - B.x;
  distance.y = A.y - B.y;

  // compensate for grid deformation
  // grid is stretched along (-n, n) line so points along that line have
  // a distance of 2 between them instead of 1

  // to calculate the shortest path, we decompose it into one diagonal movement(shortcut)
  // and one straight movement along an axis
  Point diagonalMovement;
  int lesserCoord = abs(distance.x) < abs(distance.y) ? abs(distance.x) : abs(distance.y);
  diagonalMovement.x = (distance.x < 0) ? -lesserCoord : lesserCoord; // keep the sign 
  diagonalMovement.y = (distance.y < 0) ? -lesserCoord : lesserCoord; // keep the sign

  Point straightMovement;

  // one of x or y should always be 0 because we are calculating a straight
  // line along one of the axis
  straightMovement.x = distance.x - diagonalMovement.x;
  straightMovement.y = distance.y - diagonalMovement.y;

  // calculate distance
  size_t straightDistance = abs(straightMovement.x) + abs(straightMovement.y);
  size_t diagonalDistance = abs(diagonalMovement.x);

  // if we are traveling diagonally along the stretch deformation we double
  // the diagonal distance
  if ( (diagonalMovement.x < 0 && diagonalMovement.y > 0) || 
       (diagonalMovement.x > 0 && diagonalMovement.y < 0) )
  {
    diagonalDistance *= 2;
  }

  return straightDistance + diagonalDistance;
}

现在,给定上面实现的ComputeDistanceHexGrid函数,您现在可以使用一个简单的、未优化的选择算法实现,该算法将忽略任何超出指定选择范围的瓷砖:

int _tmain(int argc, _TCHAR* argv[])
{
  // your radius selection now becomes your usual orthogonal algorithm
  // except you eliminate hex tiles too far away from your selection center
  // for(x-range;x+range;x++); for(y-range;y+range;y++);
  Point selectionCenter = {1, 1};
  int range = 1;

  for ( int x = selectionCenter.x - range;
            x <= selectionCenter.x + range;
            ++x )
  {
    for ( int y = selectionCenter.y - range;
              y <= selectionCenter.y + range;
              ++y )
    {
      Point p = {x, y};
      if ( ComputeDistanceHexGrid(selectionCenter, p) <= range )
        cout << "(" << x << ", " << y << ")" << endl;
      else
      {
        // do nothing, skip this tile since it is out of selection range
      }
    }
  }

    return 0;
}
(0, 0)
(0, 1)
(1, 0)
(1, 1)
(1, 2)
(2, 1)
(2, 2)
 类似资料:
  • 我正在使用meanstack应用程序。所以我有mongodb系列,其中包含全球各地的位置。模式loook如下所示。 选择圆内所有点(预定义点和预定义半径)的有效方法是什么。。?? 使用SQL查询也可以做到这一点。但我想要一种有效的方法,不需要逐个迭代,检查它是否在该半径内。

  • 问题内容: 目前,我正在使用此: 它将我重定向到选项值内的位置。但这不能按预期工作。..这意味着如果我单击select的第一个选项,则onChange操作不会运行。我正在考虑使用javascript,但我想您会收到一些更好的建议。因此,如果我单击每个选项将其重定向到它的值,该如何使其起作用? 问题答案: 因为已经选择了第一个选项,所以永远不会触发change事件。添加一个空值作为第一个值,并检查位

  • 我正在尝试创建az xpath,我想在其中获取一个节点,其中存在一个具有属性的子节点。我的问题是,这个结构中唯一的区别是子属性。这里有一个例子来告诉你我的意思: 例如,给定UniqueName3,我想获取包含它的记录。到目前为止,我尝试了以下操作: 然而,有了这个,我得到了所有具有field_name属性的值节点。

  • 我已经10年没做过这样的数学了...我正在编程一个2D游戏和移动一个球员周围。当我移动播放器时,我试图计算离播放器位置200像素的圆上的点,给定-360到360之间的正或负角度(度)。屏幕是1280x720,0,0是屏幕的中心点。玩家在整个笛卡尔坐标系中移动。我试图找到的点可以不在屏幕上。 我尝试了文章中用半径和角度找到点的公式,但我不相信我理解了什么是“角度”,因为当我把角度作为-360到360

  • 我查阅了多个用不同形式的数学(微积分、几何、三角学等)编写的示例,但无法将其中任何一个转换为代码。我的理解是,给出的值产生两个不同的中心/交点。这些就是我需要弄清楚的。 这个解释器是在Arduino上运行的,用C语言编写的,如果有人能用伪代码来指导我,我会非常感激的。 谢了!

  • 在给定JWS(JWT)头的JWKS密钥存储中,是否有选择签名验证密钥的标准方法? 我的目标是实现OpenID连接ID令牌验证库,我尝试灵活地预测不同的配置,但如果密钥选择是特定于IdP的,我不确定这样做是否有意义。 我当前的算法遍历JWKS并过滤掉: 如果JWK有“使用”字段,如果“使用”不等于“sig”,则拒绝 如果JWK有“密钥操作”字段,如果“密钥操作”不包含“验证”,则拒绝该字段。 如果J