Calculating grid coordinates for rotated map

I have a game that joins maps with some of the maps being rotated 60 degrees (see image below). I have imposed a Hex Grid with Grid Numbering on top of the tilted map. Obviously, the hex coordinates generated by VASSAL do not match the game map’s actual hex coordinate. I have developed formulas that will take the gridLocation and uses it to calculate the game map’s actual hex coordinate (i.e., from the image, it will convert VASSAL coordinate 2127 to actual map coordinate 2123). Unfortunately, I do not believe you can use Calculated Values in the “Location format” field of the Grid Numbering object. Does anyone have any suggestions? Thanks, Ramon Weston

image

Have you checked if the Location Format field of the Grid Numbering component supports BeanShell? BeanShell support has been added to other Message Format fields (such as Report Action traits), but I have no idea if it works in Grid Numbering. If it is supported, you could theoretically do the necessary math to convert the numbers within a BeanShell expression.

Hi,

First off, it seems that your grid numbering goes the wrong way.

Image VASSAL
2025 1827
2126 1828
2024 1927
2125 2028

However, that’s not the full story. In the top part of your image, you have a grid where the last coordinate is vertical and ascending from top to bottom - that’s pretty standard.

The first coordinate, however, is diagonal and ascending from top-left corner to the bottom right-corner. Other games, most notably older Avalon Hill games such as Afrika Korps, Blitzkrieg, D-Day, etc. uses a similar grid.

There’s really no way that VASSAL can deal with that in any sensible manner.

What you need is a custom grid numbering. I have implemented that in ObliqueHexGridNumbering.java. You need to

  • Optionally, open up ObliqueHexGridNumbering.java in a text editor and change the namespace to something different than dd - e.g., foo

    // package dd;
    package foo;
    
  • Compile the Java code into a .class file. Make sure you have the Java Development Kit installed. Suppose you have VASSAL installed in `/opt/vassal’, then do in a terminal

    > javac -cp /opt/vassal/lib/Vengine.jar ObliqueHexGridNumbering.java
    
    • For less sensible OSs you may have VASSAL installed in C:\Program Files\VASSAL, then do

      > javac -cp "C:\Program Files\VASSAL\lib\Vengine.jar" ObliqueHexGridNumbering.java
      
  • Put the ObliqueHexGridNumbering.class into your module (Add custom class). Make sure that the file goes into a sub-directory that has the same name as the package line above - e.g., dd or foo.

  • In the VASSAL editor, remove your current grid numbering from the problematic zone, and add a ObliqueHexGridNumbering component instead. Adjust the settings on the component to suit your needs.

@VASSAL core: Perhaps this component could make it into the official code base? ObliqueHexGridNumbering is rather small and main override HexGridNumbering.getRow.

Yours,
Christian

1 Like

I’ve raised Vassalengine issue #13135 to capture this suggestion / offer. Hopefully a Vassal dev may consider it for v3.8.

We’ve been here before with Oblique Hex numberings, but it has never made it in because it has always been an incomplete solution that just addresses one type of Oblique grid found in one particular module.

This is a good start, but I would like to see this fleshed out:

  1. Be incorporated into the existing HexGridNumbering, rather than extending it. It is counter-intuitive to have 2 different hex grid numberings and have to know which you need to add in advance.

  2. Add support for ‘Slanted Left’.

  3. Add support for Left and Right slant for sideways grids,

  4. Add (optional) slant support for the Hex Grid drawing to also slant to be along the appropriate hex sides.

Regards.

1 Like

This is a good start, but I would like to see this fleshed out:

  1. Be incorporated into the existing HexGridNumbering, rather than extending it. It is counter-intuitive to > have 2 different hex grid numberings and have to know which you need to add in advance.

That could easily be done - you simply put in a member, say obligue (with appropriate attributes), which for given values does

obligue value Meaning
<1 Slanted left
0 No slant
>1 Slanted right

However, there’s something to be said for keeping this as a separate class. HexGridNumbering is already a bit convoluted with many ifs for different cases. Also, it is highly unlikely that a developer will go from HexGridNumbering to ObligueHexGridNumbering and back again. Once the grid is defined, then there should be little reason to go back. If you want to change to have it in HexGridNumbering, do

  • Add name of attribute

    public static final String OBLIGUE = "obligue"; //NON-NLS
    private char obligue = '\0';
      
    @Override
    public String[] getAttributeDescriptions() {
        return ArrayUtils.add(
            super.getAttributeDescriptions(),
            Resources.getString("Editor.HexGridNumbering.stagger"),
            Resources.getString("Editor.HexGridNumbering.obligue")
            );
    }
    
    @Override
    public String[] getAttributeNames() {
        return ArrayUtils.add(
            super.getAttributeNames(),
            STAGGER,
            OBLIGUE
            );
    }
    
    @Override
    public Class<?>[] getAttributeTypes() {
        return ArrayUtils.add(
            super.getAttributeTypes(),
            Boolean.class,
            Char.class
            );
    }
    
    @Override
    public void setAttribute(String key, Object value) {
        if (STAGGER.equals(key)) {
            if (value instanceof String) {
                value = Boolean.valueOf((String) value);
            }
            stagger = (Boolean) value;
        }
        else if (OBLIGUE.equals(key)) {
            if (value instanceof String) {
                value = Char.valueOf((String) value);
            }
            obligue = (Char) value;
        }
        else {
            super.setAttribute(key, value);
        }
    }
    
    @Override
    public String getAttributeValueString(String key) {
        if (STAGGER.equals(key)) {
            return String.valueOf(stagger);
        }
        else if (OBLIGUE.equals(key)) {
            return String.valueOf(obligue);
        }
        else {
            return super.getAttributeValueString(key);
        }
    }
    
  • Override getName

    @Override
    protected String getName(int row, int column)
    {
       int orow = row;
       if (obligue == 'R') // Check this
           orow = row - (int)Math.floor(column/2)+1;
       else if (obligue == 'L') // Check this 
           orow = (int)Math.floor(column/2) + row;
       
       final String rowName = getName(orow   + vOff, vType, vLeading);
       final String colName = getName(column + hOff, hType, hLeading);
       if (first == 'H') {
           return colName + sep + rowName;
       }
       return rowName + sep + colName;
    }
    
  • Add the appropriate string resource and perhaps

  1. Add support for ‘Slanted Left’.

Oh, that’s there already - just set direction = true.

  1. Add support for Left and Right slant for sideways grids,

Should work as far as I can tell. Take Africa Korps for example

  1. Add (optional) slant support for the Hex Grid drawing to also slant to be along the appropriate hex sides.

Not sure what you mean.

I’m sure that OblliqueexNumbering.java could do with some improvements, but as a starting point?

Yours,
Christian

Hi Christian (cholmcc),

Is there currently a module using ObliqueHexGridNumbering that I could look at to see the implementation?

Thanks,
Ramon Weston

Hi Ramon,

Yes, there’s Afrika Korps and D-Day - in both cases the version that end in -ch (here and here).

Yours,
Christian