十六进制网格的计算

时间:2014-06-25 04:17:14

标签: delphi delphi-xe2 hexagonal-tiles

我想做的是创建一个如下所示的十六进制网格。

Hex grid

我可以绘制十六进制但不确定如何让它们错开。所以第一行应该是 图中的(0,0)(0,1)(0,2)(0,3)和第二行应为(1,0)(1,1)(1,2)(1,3)等行中的偶数十六进制总是错开。

目前我知道要使用的行/列数 hexRows hexColumns

以及我如何绘制十六进制是这样的,i就是在绘制十六进制数时对其进行编号。 DrawSolidHex(x,y,i);

当前代码如下所示

 begin
 hexcolumns := c;
 hexrows := r;
 i:=1;             //first cube
 x := 1;           //default x,y,z values
 y := 1;
 z := 0;
   while hexrows>0 do
    begin
      columnssave := hexcolumns ;
      while hexcolumns >0 do
        begin
          DrawSoildHex(X,Y,i);
          i:=i+1;
          x := x + 1; 
          hexcolumns := hexcolumns -1;
        end;
      y:=y+1;
      x:= 1;
      z:=0;
      hexcolumns := columnssave;
      hexrows:= hexrows-1;
    end;
    totalhex := i;

目前使用此代码,它只会在直线上绘制十六进制x,y,(1,1)(2,1)(3,1)...等我不确定如何添加偏移,计算它们,并对其进行编码,以便错开行。

2 个答案:

答案 0 :(得分:7)

在如下的六边形中,您需要了解构成边的三角形:

    B                   B
    *--*                *
   /|   \              /|
  / |    \            / |
A*--*C    *  ==>   c /  | a
  \      /          /   |
   \    /          /    |
    *--*         A*-----*C
                     b

这些三角形被称为30-60-90三角形,因为它构成了内角的角度:C = 90A = 60B = 30

这些三角形的边长比为c = 2b = 1a = sqrt(3)

所以,假设您知道c(它是六边形之一的长度),您可以计算该三角形的另外两边而不必求助于三角函数:

a = c * sqrt(3) / 2
b = c / 2

一旦我们知道这些值,只需通过观察网格并使用每个六边形的最左角(上图中为A)作为起点和终点,六角形偏移相对容易计算。

(0,0)(0,1)的水平距离为b + c + b - b(向东北,东,东南和西南方向)。这是所有"相邻"之间的水平差异。连续的单元格,如果您只想使用b + c,则会简化为3 * c / 2c

(0,0)(0,1)(半行)的垂直距离只是a(东南方向不相关的东方)。这相当于sqrt(3) * c / 2或者可能接近c * 433 / 500(16,000中的一部分的误差),而不必涉及平方根。

虽然,如果你更喜欢准确性,你可以坚持使用平方根计算 - 只需记住在开始时计算sqrt(3) / 2一次,然后将其用作乘数。

行之间的垂直距离显然是(0,0)(1,0)的两倍。

因此,对于每一整行,您只需向下移动c * 433 / 250单位。对于每一列,您可以移动c * 3 / 2单位和垂直c * 433 / 500单位(如果您从偶数索引移动到奇数索引,则向下移动,否则向上)。

答案 1 :(得分:0)

如果你知道(你应该)六角形单元的大小,你可以通过简单的计算来解决这个问题。

   | small |
   | width |
    _______  ______
   /       \       h
  /         \      e
 /           \     i
 \           /     g
  \         /      h
|  \_______/ _|____t
|             |
|--- width ---|
uses
  System.Types,
  Vcl.Graphics;

type
  THexCellSize = record
    Width : Integer;
    Height : Integer;
    SmallWidth : Integer;
  end;

function GetHexDrawPoint( AHexCellSize : THexCellSize; ACol, ARow : Integer ) : TPoint;
begin
  Result.X := ( ( AHexCellSize.Width - AHexCellSize.SmallWidth ) div 2 + AHexCellSize.SmallWidth ) * ACol;
  Result.Y := AHexCellSize.Height * ARow + ( AHexCellSize.Height div 2 ) * ( ACol mod 2 );
end;

procedure DrawHexCell( ACanvas : TCanvas; AOffSet : TPoint; AHexCellSize : THexCellSize; ACol, ARow : Integer );
var
  LPoint : TPoint;
  LXOffset : Integer;
begin
  { *************
    *   1---2
    *  /     \
    * 6       3
    *  \     /
    *   5---4
    ************* }

  LXOffset := ( AHexCellSize.Width - AHexCellSize.SmallWidth ) div 2;

  // Move to point 1
  LPoint := GetHexDrawPoint( AHexCellSize, ACol, ARow );
  LPoint.Offset( AOffSet );
  ACanvas.MoveTo( LPoint.X, LPoint.Y );
  // Line to point 2
  LPoint.Offset( AHexCellSize.SmallWidth, 0 );
  ACanvas.LineTo( LPoint.X, LPoint.Y );
  // Line to point 3
  LPoint.Offset( LXOffset, AHexCellSize.Height div 2 );
  ACanvas.LineTo( LPoint.X, LPoint.Y );
  // Line to point 4
  LPoint.Offset( -LXOffset, AHexCellSize.Height div 2 );
  ACanvas.LineTo( LPoint.X, LPoint.Y );
  // Line to point 5
  LPoint.Offset( -AHexCellSize.SmallWidth, 0 );
  ACanvas.LineTo( LPoint.X, LPoint.Y );
  // Line to point 6
  LPoint.Offset( -LXOffset, -AHexCellSize.Height div 2 );
  ACanvas.LineTo( LPoint.X, LPoint.Y );
  // Line to point 1
  LPoint.Offset( LXOffset, -AHexCellSize.Height div 2 );
  ACanvas.LineTo( LPoint.X, LPoint.Y );
end;

procedure DrawHexCellGrid( ACanvas : TCanvas; AOffSet : TPoint; AHexCellSize : THexCellSize; ACols, ARows : Integer );
var
  LCol, LRow : Integer;
begin
  for LRow := 0 to ARows - 1 do
    for LCol := 0 to ACols - 1 do
      DrawHexCell( ACanvas, AOffSet, AHexCellSize, LCol, LRow );
end;