Как получить пиксельные координаты в шестнадцатеричных координатах на основе массива на основе массива?

Я пытаюсь сделать пиксель для координации функции для шестнадцатеричной карты, но я не получаю математику правильно, все, что я пытаюсь, кажется, немного не работает, и примеры, которые я нашел, были основаны на центрированном окружении карты.

Под «массивом» я подразумеваю способ упорядочения гексов, см. рис.

Самый точный результат, который я получил, был со следующим кодом, но он все еще выключен и становится хуже, чем больше значения повышаются:

public HexCell<T> coordsToHexCell(float x, float y){
    final float size = this.size; // cell size
    float q = (float) ((1f/3f* Math.sqrt(3) * x - 1f/3f * y) / size);
    float r = 2f/3f * y / size;
    return getHexCell((int) r, (int) q);
}

Hexmap

Экран начинается с 0,0 в левом верхнем углу, каждая ячейка знает свой центр.

Все, что мне нужно, это способ преобразования экранных координат в шестнадцатеричные координаты. Как я могу это сделать?

9 голосов | спросил petervaz 20 PM00000070000000431 2013, 19:40:04

5 ответов


10

Существует много шестнадцатеричных систем координат. Подходы «смещения» хороши для хранения прямоугольной карты, но алгоритмы hex имеют тенденцию быть более сложными.

В моем руководстве по шестигранной сетке (которое, как я считаю, вы уже нашли), ваша система координат называется " even-r ", за исключением того, что вы маркируете их r,q вместо q,r. Вы можете преобразовать местоположения пикселей в шестнадцатеричные координаты с помощью следующих шагов:

  1. Преобразуйте местоположения пикселей в осевые шестнадцатеричные координаты, используя описанный алгоритм в этом раздел . Это то, что делает ваша функция. Однако вам нужно сделать еще один шаг.
  2. Те осевые координаты являются дробными. Их нужно округлить до ближайшего гексагона. В вашем коде вы используете (int)r, (int)q, но это работает только для квадратов; для гексов нам нужен более сложный подход округления. Преобразуйте координаты r, q в cube , используя формулы axial to cube . Затем используйте функцию hex_round здесь .
  3. Теперь у вас есть целочисленный набор координат cube . В вашей карте используется «четный-r», а не куб, поэтому вам нужно преобразовать обратно. Используйте формулы cube to even-r offset из здесь .

Мне нужно переписать пиксель в шестнадцатеричный координатный раздел, чтобы сделать его более понятным. Сожалею!

Я знаю, это кажется запутанным. Я использую этот подход, потому что он является наименее подверженным ошибкам (нет особых случаев!) И позволяет повторно использовать. Эти процедуры преобразования могут быть повторно использованы. Гнездовое округление можно использовать повторно. Если вы когда-нибудь захотите нарисовать линии или повернуть вокруг шестнадцатеричной координаты или поле зрения или другие алгоритмы, некоторые из этих подпрограмм тоже будут полезны.

ответил amitp 21 PM000000100000002831 2013, 22:53:28
9

Есть два способа справиться с этой проблемой, на мой взгляд.

  1. Используйте лучшую систему координат. Вы можете сделать математику намного легче для себя, если вы умны о том, как вы числиваете гексы. Амит Патель имеет окончательную ссылку на гексагональные сетки. Вы захотите найти осевые координаты на этой странице.

  2. Заимствуйте код у кого-то, кто его уже решил. У меня есть некоторый код , который работает, который я снял с Battle for Wesnoth источник. Имейте в виду, что моя версия имеет плоскую часть гексов сверху, поэтому вам придется поменять местами x и y.

ответил Michael Kristofik 20 PM00000080000001831 2013, 20:28:18
6

Я думаю, что ответ Майкла Кристофика правильный, особенно для упоминания сайта Амита Пател, но я хотел поделиться своим начинающий подход к сеткам Hex.

Этот код был взят из проекта, в котором я потерял интерес и отказался , написанного на JavaScript, но положение мыши в гексагоне было большим. Я использовал * эту статью GameDev * для моих ссылок. С этого сайта автор этот образ , который показал как математически представлять все стороны и позиции Hex.

В моем классе рендеринга я определил это в методе, который позволил мне установить любую длину стороны Hex, которую я хотел. Здесь показано, что некоторые из этих значений были указаны в коде координаты пикселя и шестнадцатеричного кода.

                this.s = Side; //Side length
                this.h = Math.floor(Math.sin(30 * Math.PI / 180) * this.s);
                this.r = Math.floor(Math.cos(30 * Math.PI / 180) * this.s);
                this.HEXWIDTH = 2 * this.r;
                this.HEXHEIGHT = this.h + this.s;
                this.HEXHEIGHT_CENTER = this.h + Math.floor(this.s / 2);

В классе ввода мыши я создал метод, который принял координату x и y экрана и возвратил объект с координатой Hex, в которой находится пиксель. * Обратите внимание, что у меня была фальшивая «камера», поэтому смещения для позиции рендеринга также включены.

    ConvertToHexCoords:function (xpixel, ypixel) {
        var xSection = Math.floor(xpixel / ( this.Renderer.HEXWIDTH )),
            ySection = Math.floor(ypixel / ( this.Renderer.HEXHEIGHT )),
            xSectionPixel = Math.floor(xpixel % ( this.Renderer.HEXWIDTH )),
            ySectionPixel = Math.floor(ypixel % ( this.Renderer.HEXHEIGHT )),
            m = this.Renderer.h / this.Renderer.r, //slope of Hex points
            ArrayX = xSection,
            ArrayY = ySection,
            SectionType = 'A';
        if (ySection % 2 == 0) {
            /******************
             * http://www.gamedev.net/page/resources/_/technical/game-programming/coordinates-in-hexagon-based-tile-maps-r1800
             * Type A Section
             *************
             *     *     *
             *   *   *   *
             * *       * *
             * *       * *
             *************
             * If the pixel position in question lies within the big bottom area the array coordinate of the
             *      tile is the same as the coordinate of our section.
             * If the position lies within the top left edge we have to subtract one from the horizontal (x)
             *      and the vertical (y) component of our section coordinate.
             * If the position lies within the top right edge we reduce only the vertical component.
             ******************/
            if (ySectionPixel < (this.Renderer.h - xSectionPixel * m)) {// left Edge
                ArrayY = ySection - 1;
                ArrayX = xSection - 1;
            } else if (ySectionPixel < (-this.Renderer.h + xSectionPixel * m)) {// right Edge
                ArrayY = ySection - 1;
                ArrayX = xSection;
            }
        } else {
            /******************
             * Type B section
             *********
             * *   * *
             *   *   *
             *   *   *
             *********
             * If the pixel position in question lies within the right area the array coordinate of the
             *      tile is the same as the coordinate of our section.
             * If the position lies within the left area we have to subtract one from the horizontal (x) component
             *      of our section coordinate.
             * If the position lies within the top area we have to subtract one from the vertical (y) component.
             ******************/
            SectionType = 'B';
            if (xSectionPixel >= this.Renderer.r) {//Right side
                if (ySectionPixel < (2 * this.Renderer.h - xSectionPixel * m)) {
                    ArrayY = ySection - 1;
                    ArrayX = xSection;
                } else {
                    ArrayY = ySection;
                    ArrayX = xSection;
                }
            } else {//Left side
                if (ySectionPixel < ( xSectionPixel * m)) {
                    ArrayY = ySection - 1;
                    ArrayX = xSection;
                } else {
                    ArrayY = ySection;
                    ArrayX = xSection - 1;
                }
            }
        }
        return {
            x:ArrayX + this.Main.DrawPosition.x, //Draw position is the "camera" offset
            y:ArrayY + this.Main.DrawPosition.y
        };
    },

Наконец, вот скриншот моего проекта с включенной отладкой рендера. Он показывает красные линии, где код проверяет ячейки TypeA vs TypeB вместе с координатами Hex и контурами ячеек  введите описание изображения здесь
Надеюсь, это поможет некоторым.

ответил user32959 21 AM00000050000000731 2013, 05:32:07
3

Я действительно нашел решение без гексаграммы.
Как я уже упоминал в вопросе, каждая ячейка сохраняет собственные центральные координаты, вычисляя ближайший гексагон до пиксельных коордов, я могу определить соответствующую шестую ячейку с точностью до пикселя (или очень близко к ней).
Я не думаю, что это лучший способ сделать это, так как я должен перебирать каждую ячейку, и я вижу, как это может облагаться налогом, но оставит код в качестве альтернативного решения:

public HexCell<T> coordsToHexCell(float x, float y){
    HexCell<T> cell;
    HexCell<T> result = null;
    float distance = Float.MAX_VALUE;
    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
            cell = getHexCell(r, c);

            final float dx = x - cell.getX();
            final float dy = y - cell.getY();
            final float newdistance = (float) Math.sqrt(dx*dx + dy*dy);

            if (newdistance < distance) {
                distance = newdistance;
                result = cell;
            }           
        }
    }
    return result;
}
ответил petervaz 21 PM00000080000000431 2013, 20:00:04
2

Вот мужество реализации C # одного из методов, размещенных на веб-сайте Amit Patel (я уверен, что перевод на Java не будет проблемой):

public class Hexgrid : IHexgrid {
  /// <summary>Return a new instance of <c>Hexgrid</c>.</summary>
  public Hexgrid(IHexgridHost host) { Host = host; }

  /// <inheritdoc/>
  public virtual Point ScrollPosition { get { return Host.ScrollPosition; } }

/// <inheritdoc/>
public virtual Size  Size           { get { return Size.Ceiling(Host.MapSizePixels.Scale(Host.MapScale)); } }

/// <inheritdoc/>
public virtual HexCoords GetHexCoords(Point point, Size autoScroll) {
  if( Host == null ) return HexCoords.EmptyCanon;

  // Adjust for origin not as assumed by GetCoordinate().
  var grid    = new Size((int)(Host.GridSizeF.Width*2F/3F), (int)Host.GridSizeF.Height);
  var margin  = new Size((int)(Host.MapMargin.Width  * Host.MapScale), 
                         (int)(Host.MapMargin.Height * Host.MapScale));
  point      -= autoScroll + margin + grid;

  return HexCoords.NewCanonCoords( GetCoordinate(matrixX, point), 
                                   GetCoordinate(matrixY, point) );
}

/// <inheritdoc/>
public virtual Point   ScrollPositionToCenterOnHex(HexCoords coordsNewCenterHex) {
  return HexCenterPoint(HexCoords.NewUserCoords(
          coordsNewCenterHex.User - ( new IntVector2D(Host.VisibleRectangle.Size.User) / 2 )
  ));
}

/// <summary>Scrolling control hosting this HexGrid.</summary>
protected IHexgridHost Host { get; private set; }

/// <summary>Matrix2D for 'picking' the <B>X</B> hex coordinate</summary>
Matrix matrixX { 
  get { return new Matrix(
      (3.0F/2.0F)/Host.GridSizeF.Width,  (3.0F/2.0F)/Host.GridSizeF.Width,
             1.0F/Host.GridSizeF.Height,       -1.0F/Host.GridSizeF.Height,  -0.5F,-0.5F); } 
}
/// <summary>Matrix2D for 'picking' the <B>Y</B> hex coordinate</summary>
Matrix matrixY { 
  get { return new Matrix(
            0.0F,                        (3.0F/2.0F)/Host.GridSizeF.Width,
            2.0F/Host.GridSizeF.Height,         1.0F/Host.GridSizeF.Height,  -0.5F,-0.5F); } 
}

/// <summary>Calculates a (canonical X or Y) grid-coordinate for a point, from the supplied 'picking' matrix.</summary>
/// <param name="matrix">The 'picking' matrix</param>
/// <param name="point">The screen point identifying the hex to be 'picked'.</param>
/// <returns>A (canonical X or Y) grid coordinate of the 'picked' hex.</returns>
  static int GetCoordinate (Matrix matrix, Point point){
  var pts = new Point[] {point};
  matrix.TransformPoints(pts);
      return (int) Math.Floor( (pts[0].X + pts[0].Y + 2F) / 3F );
  }

Остальная часть проекта доступна здесь как Open Source, включая классы MatrixInt2D и VectorInt2D, на которые ссылаются выше:
http : //hexgridutilities.codeplex.com/

Несмотря на то, что реализация выше для гекса с плоскими вершинами, библиотека HexgridUtilities включает в себя возможность переноса сетки.

ответил Pieter Geerkens 21 AM000000100000004231 2013, 10:02:42

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132