# Truly Hexagonal Cells Example

### 1 collaborator

Ian Heath (Author)

### Tags

geometry

Tagged by Ian Heath about 10 years ago

grid

Tagged by Ian Heath about 10 years ago

hexagon

Tagged by Ian Heath about 10 years ago

Visible to everyone | Changeable by the author
Model was written in NetLogo 6.0.2 • Viewed 1149 times • Downloaded 163 times • Run 0 times

## WHAT IS IT?

This demonstrates how to make a model that uses an undistorted hexagonal grid of cells.

## HOW IT WORKS

To achieve an undistorted hexagonal grid, the grid is not based on patches the same height as the cells (as in Uri Wilensky's "Hex Cells Example") because such a grid must be squashed vertically by a factor of 0.866 . Instead we use pixel patches that are pixels (with `patch size = 1`) and create truly hexagonal cells (a breed of turtles) to form the grid.

`setup` resizes the World (according to the user parameters) and creates the hex grid. The user parameters are constained so that the hex grid wraps exactly, and the World origin is set to the bottom-left corner as there must be an even number of patches on each axis.

After `setup`, cells are used instead of patches (with the sole exception of inside the `xNeighbor-reporter`). For example, `selected-cell-reporter` reports the cell under the mouse, with no reference to patches. In order to conform with this avoidance of using patches, navigation around the grid uses `xNeighbor-reporter` which reports the neighboring cell in the specified direction. Use of this navigation is exemplified by the `walk` procedure in which walkers are centred on cells and navigate the grid by stepping to an immediate neighbor cell. They do a (mostly straight) random walk, bouncing off any non-wrapping boundary. The model allows for the World to have none-wrapping boundaries, and even for the grid to have holes in it (provided 'no cell is an island').

To demonstrate the use of manipilation of hexes, we define hex turtles to fit into cells exactly. The Interface tab has mouse and "Action key" combinations to create them, select them, recolor them, drag and drop them between cells, and delete them. Multiple hexes can be created on the same cell. Each new hex is created on top of the others and hides those below (until it is deleted or dragged away).

Only the `setup-hex-grid` procedure is dependent upon whether the grid geometry is truly hexagonal. To demonstrate this the `TrueHex` switch allows the use of either undistorted or distorted hexagonal grids.

## RELATED MODELS

Uri Wilensky's "Hex Cells Example". This uses the distorted hexagonal grid, also modeled here for comparison purposes.

## CREDITS AND REFERENCES

Partly based on Uri Wilensky's "Hex Cells Example" in the Models Library.

## Excellent

I grew up with paper hexagon maps for games. Great to see this code.

## Posted almost 8 years ago

Click to Run Model

```;;Assumptions:
;;
;;  - All turtles are centered on a cell, otherwise it won't work
;;  - worldWidth is even, so that the cells wraps properly         (imposed by slider)
;;  - xHeight    is even, so that cell centres are integral pixels (imposed by slider)
;;
;; PROCEDURE and VARIABLE USAGE
;;
;; setup                     <<< User
;; setup-hex-grid            <<< setup
;; drag                      <<< User
;; drag-hex                  <<< drag
;; selected-hex-reporter     <<< drag-hex, delete-hex-atMouse, recolor-hex-atMouse
;; recolor-hex-atMouse       <<< User
;; delete-hex-atMouse        <<< User
;; xNeighborsInGrid-reporter <<< add-walker, walk, test-xNeighbors
;; xNeighbor-reporter        <<< walk, xNeighborsInGrid-reporter
;; test-xNeighbors           <<< User

globals [xDx xDy cell-size hex-size xNeighbors-xDx xNeighbors-xDy]
breed [cells   cell  ]
breed [hexs    hex   ]
breed [walkers walker]

to setup
clear-all

setup-hex-grid                                            ;; create a hex grid of cells

;; setup walkers
set-default-shape walkers "arrow half"

reset-ticks
end

to setup-hex-grid                                           ;; set up a grid of hexagonal cells
ifelse TrueHex [
set-default-shape cells   "truhex-outline"
set-default-shape hexs    "truhex"
set xDx round(xHeight / 2 * sqrt 3)                     ;; pxcor displacement of xNeighbors
set xDy       xHeight                                   ;; pycor displacement of xNeighbors
set-patch-size 1
set cell-size round(2 * xDy / sqrt 3)
set hex-size cell-size - 2                              ;; so that it just fits within the outine.     Used in add-hex
][
set-default-shape cells   "hex-outline"
set-default-shape hexs    "hex"
set xDx 1                                               ;; pxcor displacement of xNeighbors
set xDy 1                                               ;; pycor displacement of xNeighbors
set-patch-size xHeight
set cell-size 4 / 3                                     ;; Make cells fit fully by expanding beyond patch .
set hex-size cell-size - .04
]

set xNeighbors-xDx map [ ?1 -> xDx * ?1 ] [0  1    1    0  -1   -1  ]  ;; xDx of xNeighbors, listed by xHeading.  Used in xNeighbor-reporter
set xNeighbors-xDy map [ ?1 -> xDy * ?1 ] [1  0.5 -0.5 -1  -0.5  0.5]  ;; xDy of xNeighbors, listed by xHeading.  Used in xNeighbor-reporter

;; resize the world
no-display
let pixels worldWidth * xDx * worldHeight * xDy
if pixels > 999999 [error (word "World too big! It has " pixels " pixels.  You should adjust its parameters.")]
resize-world 0 (worldWidth * xDx - 1) 0 (worldHeight * xDy   - 1)  ;;subtract 1 is in order to wrap exactly

;;create cells to form a hex grid
foreach   n-values worldWidth  [ ?1 -> ?1 ] [ ?1 -> let cellX ?1
foreach n-values worldHeight [ ??1 -> ??1 ] [ ??1 -> let cellY ??1
;; sprout cell(cellX,cellY) at its central patch. Shift even columns half a cell up/down, so that the cells fit together.
ask patch (cellX * xDx) (cellY * xDy) [
sprout-cells 1[
set size cell-size                                ;; Make cells fit fully by expanding beyond patch
set color gray
;; In order to stay within the World (if bounded). Shift up if TrueHex, else shift down.
if (xcor / xDx) mod 2 = 0 [set ycor ycor + (ifelse-value TrueHex [1][-1]) * (xDy / 2)]
]
]
]
]
display
end

to drag                                                     ;; User method
if mouse-down? [drag-hex]
end

to drag-hex
ask selected-hex-reporter [hatch 1  die]                  ;; re-incarnate moused-hex so that it will be on top of any cell it is dragged over

ask selected-hex-reporter [                               ;; selected-hex is now the re-incarnated moused-hex
while [mouse-down?] [
setxy mouse-xcor mouse-ycor
display                                               ;; force the display to update, to see the turtle moving around
]

move-to min-one-of cells [distance myself]              ;; snap to nearest cell at end of drag
display                                                 ;; force the display to update, to see the snap
]
end

to-report selected-hex-reporter                             ;; set of the top (newest added) hex that the mouse is over ('empty' if none)
report turtle-set [top-hex-reporter] of selected-cell-reporter
end

to-report top-hex-reporter                                  ;; cell reporter: top-hex on this cell ('nobody' if none)
report max-one-of (hexs-on self) [who]
end

to-report selected-cell-reporter                            ;; set of the cell the mouse is over ('empty' if outside world)
report ifelse-value mouse-inside? [turtle-set min-one-of cells [distancexy mouse-xcor mouse-ycor]]
[no-turtles]
end

to add-hex-atMouse                                          ;; User method: add a hex on selected cell (on top of any others; no action if mouse outside world)
end

to add-hex                                                  ;; cell method: add a hex on top, with the next color after the previous top hex (or red, if none)
;; First, get the current-color of the top hex on this cell, or "none"
let top-hex top-hex-reporter
let current-color ifelse-value (is-turtle? top-hex) [ [color] of top-hex ] ["none"]

;; Now, add a hex with the next color
hatch-hexs 1 [
set size hex-size                                       ;; shrink hex to fit just inside the grid lines
set color next-color-reporter current-color
]
end

to-report next-color-reporter [current-color]               ;; color after current-color (or red, if not in swatch)
let swatch [red sky yellow lime red]
let next-swatch-position ifelse-value (member? current-color swatch) [1 + position current-color swatch] [0]
report item next-swatch-position swatch
end

to recolor-hex-atMouse                                      ;; User method: set color of top moused hex to next color in swatch
ask selected-hex-reporter [set color (next-color-reporter color)]
end

to delete-hex-atMouse                                       ;; User method: delete the top moused hex
end

to add-walker-atMouse                                       ;; User method: add a walker on selected cell (no action if mouse outside world)
end

to add-walker                                               ;; turtle method: create a walker at this turtle
hatch-walkers 1 [
set size xDy * 2                                        ;; to extend head of walker to the centre of neighbor cell
set color pink
face one-of xNeighborsInGrid-reporter                   ;; face any xNeighbor in the grid (assumes 'no cell is an island')
]
set #walkers count walkers
end

to walk                                                     ;; walker method: step randomly, staying in-grid. Between steps the walker heads from where it came.
let xNeighbor xNeighbor-reporter ((round(heading / 60) + one-of [1 -1 0 0 0 0]) mod 6)  ;; mainly head straight, turning just +/-60 a third of the time
if xNeighbor = nobody [set xNeighbor one-of xNeighborsInGrid-reporter]  ;; if not in-grid, set xNeighbor to any in-grid
face xNeighbor
move-to xNeighbor
end

to-report xNeighborsInGrid-reporter                         ;; turtle reporter: all xNeighbor cells in the grid
report turtle-set map [ ?1 -> xNeighbor-reporter ?1 ] [0 1 2 3 4 5]
end

to test-xNeighbors                                          ;; User method: shows the xNeighbors of each individual cell
hatch-hexs 1[set color blue]
ask xNeighborsInGrid-reporter [hatch-hexs 1[set color gray]]
if user-yes-or-no? "Hit Enter to proceed to next cell" []
]
end

to-report xNeighbor-reporter [xHeadingArg]                  ;; turtle reporter: report xNeighbor cell in given direction, or "nobody" if it's off-grid
;; xHeading is the index (0,1,2,3,4 or 5 - clockwise, starting from North) of any xNeighbor of a cell
end
```

There are 19 versions of this model.

Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago playing with CC code at the end on Info Download this version
Ian Heath over 6 years ago trying to recover Info Download this version
Ian Heath over 6 years ago updated CC logo Download this version
Ian Heath over 6 years ago updated CC logo Download this version
Ian Heath over 6 years ago updated CC logo Download this version