# NodeBox

Create visual output with Python programming code
Home Download Reference Tutorial Library Gallery About

# Glacier

Glacier draws a grid of interconnecting hexagonal elements with a recursive algorithm. The grid fades out after a certain amount of tiles. The algorithm contains a bug in the way hexes are spaced, but this actually creates a nice visual effect: the glaciers start drifting apart the further they are from the core. A global warming bug!

Script

    size(600, 600)

    hexwork = {}

    class Hex:

      def __init__(self, x, y, w, spacing=0):

        #Creates a new hexagonal at position x, y
        #with the given width w, and optional spacing.
        #Adds itself to the hexwork list.

        self.x = x
        self.y = y
        self.w = w
        self.spacing = spacing

        self.sides = []
        for i in range(6):
          self.sides.append(None)
        global hexwork
        hexwork[(self.x,self.y)] = self
        self.index = len(hexwork)

      def draw(self, tag=False, visit=None):

        #Draws this hexagonal on screen.
        #Optionally, tags the hexagonal with its index
        #in the hexwork list.

        #Additionally, you can supply a visit function
        #that accepts this self as a parameter.

        if visit != None: visit(self)

        w = self.w * 0.5
        star(self.x, self.y, 6, w, w*1.155)

        if tag:
          fontsize(w*0.25)
          f = fill()
          fill(f.r, f.g, f.b, 1)
          align(CENTER)
          text(str(self.index), self.x-self.w*0.5, self.y, self.w)
          fill(f)

      def rdraw(self, tag=False, visit=None, degrade=True, root=None):

        #Recursive draw:
        #draw all neighbours as well,
        #and their neighbours, and so on.

        if degrade == True:
          f = fill()
          fill(f.r, f.g, f.b, f.a * 0.98)

        self.draw(tag, visit)
        if root != None: line(self.x,self.y,root.x,root.y)
        for side in self.sides:
          if side != None and side != root:
            side.rdraw(tag, visit, degrade, root=self)

      def grow(self, max=6):

        #Creates neighbouring hexes for this hexagonal.
        #Creates all neighbours by default, or a given max
        #of random neighbours.

        if max < 1 or max > 6: return

        #The centerpoint offsets for neighbouring hexes.

        from random import shuffle
        center = [(0,-1),
                  (-0.865,-0.5),
                  (-0.865,0.5),
                  (0,1),
                  (0.865,0.5),
                  (0.865,-0.5)]

        shuffle(center)
        center = center[:max]
        #center.sort() #doesn't do what supposed to do

        #Create neighbours only if the neighbour does
        #not exist yet: if it is not defined by this
        #hex as a neighbour already, or its position
        #occurs in the hexwork list (and thus it is
        #already defined as someone else's neighbour).

        for i in range(max):
          dx, dy = center[i]
          dx = dx * (self.w+self.spacing) + self.x
          dy = dy * (self.w+self.spacing) + self.y
          global hexwork
          if self.sides[i] == None and not hexwork.has_key((dx,dy)):
            self.sides[i] = Hex(dx, dy, self.w)
            self.sides[i].sides[(i+3)%6] = self

      def rgrow(self, max=6):

        #Recursive growth:
        #grow neighbours for this hex,
        #grow neighbours for each neighbour, and so on.

        if max > 0:
          self.grow(max)
          for side in self.sides:
            if side != None:
              side.rgrow(max-1)

    def visit(hex):
      scale(random(0.98,1.01))
      rotate(0.1)

    root = Hex(400,400,70, spacing=100)
    root.rgrow()

    nofill()
    stroke(0.2,0.2,0.2)
    strokewidth(0.5)
    rect(0,0,WIDTH,HEIGHT)

    font("Arial")
    r = random(0.5,1)
    fill(0,0.5,r,0.75)
    stroke(0,0.5,r,0.75)
    strokewidth(0.25)
    root.rdraw(tag=True, visit=visit)