Truly Hexagonal Cells Example

Truly Hexagonal Cells Example preview image

1 collaborator

Me Ian Heath (Author)

Tags

geometry 

Tagged by Ian Heath over 10 years ago

grid 

Tagged by Ian Heath over 10 years ago

hexagon 

Tagged by Ian Heath over 10 years ago

Visible to everyone | Changeable by the author
Model was written in NetLogo 6.0.2 • Viewed 1209 times • Downloaded 173 times • Run 0 times
Download the 'Truly Hexagonal Cells Example' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


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.

COPYRIGHT AND LICENSE

Creative Commons Licence
by Ian J Heath is licensed under a Creative Commons Attribution 4.0 International License http://creativecommons.org/licenses/by/4.0/

Comments and Questions

Excellent

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

Posted about 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
;; selected-cell-reporter    <<< selected-hex-reporter, add-hex-atMouse, add-walker-atMouse
;; add-hex-atMouse           <<< User
;; add-hex                   <<< add-hex-atMouse
;; top-hex-reporter          <<< selected-hex-reporter, add-hex
;; next-color-reporter       <<< recolor-hex-atMouse, add-hex
;; recolor-hex-atMouse       <<< User
;; delete-hex-atMouse        <<< User
;; add-walker-atMouse        <<< User
;; add-walker                <<< add-walker-atMouse, setup            (sets             heading of walker)
;; xNeighborsInGrid-reporter <<< add-walker, walk, test-xNeighbors
;; walk                      <<< User                                 (uses and updates heading of walker)
;; 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"
  repeat #walkers [ask one-of cells [add-walker] ]          ;; add #walkers walkers

  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)
  ask selected-cell-reporter [add-hex]
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
  ask selected-hex-reporter [die]
end 

to add-walker-atMouse                                       ;; User method: add a walker on selected cell (no action if mouse outside world)
  ask selected-cell-reporter [add-walker]
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
  ask cells [
    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" []
    ask hexs [die]
  ]
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
  report one-of cells-at (item xHeadingArg xNeighbors-xDx) (item xHeadingArg xNeighbors-xDy)
end 

There are 19 versions of this model.

Uploaded by When Description Download
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
Ian Heath over 6 years ago Updated CC license Download this version
Ian Heath over 6 years ago Update to 6.0.2 Download this version
Ian Heath over 10 years ago Slight cosmetic tidy-up only Download this version
Ian Heath over 10 years ago Initial upload Download this version

Attached files

File Type Description Last updated
Truly Hexagonal Cells Example.png preview Preview for 'Truly Hexagonal Cells Example' over 10 years ago, by Ian Heath Download
Truly Hexagonal Cells Example.png preview Changed grid to white in order to show up better. over 10 years ago, by Ian Heath Download

This model does not have any ancestors.

This model does not have any descendants.