# Use noise to animate some objects in wave pattern import sys, code, random, os, math, bpy, canvas, colorsys from math import sqrt, pi, sin, ceil from random import TWOPI

sys.path.append(os.path.dirname(os.path.dirname(__file__))) import helpers

class Waves(canvas.Canvas):

COUNT=5

def render(self):
  count = self.COUNT
  # Size of grid.
  extents = 8.0
  # The height of each cube will be animated, so we'll specify the minimum and maximum scale.
  sz = (extents / count)
  base_object = helpers.infer_primitive(random.choice(self.PRIMITIVES), location = (100, 100, 100), radius=sz)
  helpers.assign_material(base_object, helpers.random_material(self.MATERIALS_NAMES))
  minsz = sz * 0.25
  maxsz = sz * extents
  # To convert abstract grid position within loop to real-world coordinate.
  jprc = 0.0
  kprc = 0.0
  countf = 1.0 / (count - 1)
  diffex = extents * 2
  y = 0.0
  x = 0.0
  centerz = 0.0
  centery = 0.0
  centerx = 0.0
  # The maximum possible distance is used to normalize the distance.
  rise = 0.0
  run = 0.0
  normdist = 0.0
  maxdist = sqrt(2 * extents * extents)
  # For generating the wave.
  offset = 0.0
  angle = 0.0
  # Loop through grid y axis.
  for j in range(0, count, 1):
    jprc = j * countf
    y = -extents + jprc * diffex
    # Calculate rise.
    rise = y - centery
    rise *= rise
    # Loop through grid x axis.
    for k in range(0, count, 1):
      kprc = k * countf
      x = -extents + kprc * diffex
      # Calculate run.
      run = x - centerx
      run *= run
      # Find normalized distance using Pythogorean theorem.
      # Remap the normalized distance to a range -PI .. PI
      normdist = sqrt(rise + run) / maxdist
      offset = -TWOPI * normdist + pi
      current = helpers.duplicate_object(base_object)
      current.location = (centerx + x, centery + y, centerz)
      current.name = 'Object ({0:0>2d}, {1:0>2d})'.format(k, j)
      current.data.name = 'Mesh ({0:0>2d}, {1:0>2d})'.format(k, j)
      for f in range(0, self.NUMBER_OF_FRAMES, 1):
        # Convert the keyframe into an angle.
        fprc = f * 1.0 / (self.NUMBER_OF_FRAMES - 1)
        angle = TWOPI * fprc
        # Set the scene to the current frame.
        bpy.context.scene.frame_set(f)
        # Change the scale.
        # sin returns a value in the range -1 .. 1. abs changes the range to 0 .. 1.
        # The values are remapped to the desired scale with min + percent * (max - min).
        current.scale.z = minsz + abs(sin(offset + angle)) * (maxsz - minsz)
        helpers.add_frame([current], ['scale'])