text: # ================
  # SOFTWARE LICENSE
  # ================
  
  # The MIT License (MIT)
  
  # Copyright (c) 2020 Yutaka Sawai (Varipon)
  
  # Permission is hereby granted, free of charge, to any person obtaining a copy
  # of this software and associated documentation files (the "Software"), to deal
  # in the Software without restriction, including without limitation the rights
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  # copies of the Software, and to permit persons to whom the Software is
  # furnished to do so, subject to the following conditions:
  
  # The above copyright notice and this permission notice shall be included in all
  # copies or substantial portions of the Software.
  
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  # SOFTWARE.
  
  # ==============================================================
  # LICENSE FOR CONTENT PROCEDURALLY GENERATED USING THIS SOFTWARE
  # ==============================================================
  
  # All content procedurally generated by this software and its permutations
  # are licensed under Creative Commons Attribution By 3.0:
  
  # https://creativecommons.org/licenses/by/3.0/
  
  
  #!/usr/bin/python
  
  import bpy
  from bpy import *
  
  import mathutils
  import math
  from mathutils import *
  from math import *
  
  
  class Formula:
  
      def __init__(self, P, A, J, move, part, helicity, start, end):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
          
          # joint number
          self.J = J
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints α(n) -> a[n], β(n) -> b[n], γ(n) -> y[n], δ(n) -> o[n]
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A, self.J, self.helicity, self.rig, self.move, self.part)
  
  
      def configMovement(self, P, A, J, a, b, y, o):
  
          mat_a = [0 for i in range(4)] # Joint α matrix
          mat_b = [0 for i in range(self.J)] # Joint β matrix
          mat_y = [0 for i in range(self.J)] # Joint γ matrix
          mat_o = [0 for i in range(self.J)] # Joint δ matrix
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
  
          a[0] = mathutils.Euler((-A - E + (D * 0.5), -A - (D * 0.5), 0.0), 'XYZ')
          print ("a0 =", a[0])
          mat_a[0] = Matrix.Translation(a[0])
  
          a[3] = mathutils.Euler((0-a[0].x, 0-a[0].y, 0-a[0].z), 'XYZ')
          print ("a3 =", a[3])
          mat_a[3] = Matrix.Translation(a[3]) 
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
          mat_y[1] = Matrix.Translation(y[1])
  
  ### pattern A
  
          b[2] = mathutils.Euler((a[0].x + E + (A * 2), a[0].y + (A * 2), 0.0), 'XYZ')
          print ("b2 =", b[2])
          mat_b[2] = Matrix.Translation(b[2])
  
          b[3] = mathutils.Euler((a[0].x + E - (D * 0.5), a[0].y - (A * 2), 0.0), 'XYZ')
          print ("b3 =", b[3])
          mat_b[3] = Matrix.Translation(b[3])
          
          y[2] = mathutils.Euler((a[0].x + E, a[0].y, 0.0), 'XYZ')
          print ("y2 =", y[2])
          mat_y[2] = Matrix.Translation(y[2])
  
          y[3] = mathutils.Euler((a[0].x + E - (D * 0.5), a[0].y - (D * 0.5), 0.0), 'XYZ')
          print ("y3 =", y[3])
          mat_y[3] = Matrix.Translation(y[3])
  
          o[2] = mathutils.Euler((a[0].x + E + (A * 2), a[0].y - (A * 2), 0.0), 'XYZ')
          print ("o2 =", o[2])
          mat_o[2] = Matrix.Translation(o[2])
          
          o[3] = mathutils.Euler((a[0].x + E - (D * 0.5) - (A * 2), a[0].y - (D * 0.5) - (A * 2), 0.0), 'XYZ')
          print ("o3 =", o[3])
          mat_o[3] = Matrix.Translation(o[3])
  
  ### pattern A end
  
          org_rot_mat = Matrix.Rotation(math.radians(0), 4, 'Z')
  
          # define the rotation
          rot_mat = Matrix.Rotation(math.radians(-45), 4, 'Z')   
  
          for j in range(2, J - 2):
  
              mat_y[j + 2] = mat_a[0] @ org_rot_mat @ rot_mat @ mat_a[3] @ mat_y[j]
  
  #            obj.matrix_world = mat_y[j + 2]
              # extract components back out of the matrix
              loc, rot, sca = mat_y[j + 2].decompose()
              y[j + 2] = mathutils.Euler(loc, 'XYZ')
              print("y"+str(j + 2)+" = ", y[j + 2], rot, sca)
  
              mat_b[j + 2] = mat_a[0] @ org_rot_mat @ rot_mat @ mat_a[3] @ mat_b[j]
              
  #            obj.matrix_world = mat_b[j + 2]
              # extract components back out of the matrix
              loc, rot, sca = mat_b[j + 2].decompose()
              b[j + 2] = mathutils.Euler(loc, 'XYZ')
              print("b"+str(j + 2)+" = ", b[j + 2], rot, sca)
  
              mat_o[j + 2] = mat_a[0] @ org_rot_mat @ rot_mat @ mat_a[3] @ mat_o[j]
              
  #            obj.matrix_world = mat_o[j + 2]
              # extract components back out of the matrix
              loc, rot, sca = mat_o[j + 2].decompose()
              o[j + 2] = mathutils.Euler(loc, 'XYZ')
              print("o"+str(j + 2)+" = ", o[j + 2], rot, sca)
  
  
      def constructMovement(self, J, helicity, amt, rig, a, b, y, o):
  
          # Linkages
          aa = [[0 for i in range(4)] for j in range(4)] # Link α(i) - α(j)
          ab = [[0 for i in range(4)] for j in range(4)] # Link α(i) - β(j)
          ya = [[0 for i in range(4)] for j in range(4)] # Link γ(i) - α(j)
          ao = [[0 for i in range(4)] for j in range(4)] # Link α(i) - δ(j)
          ob = [[0 for i in range(self.J)] for j in range(self.J)] # Link δ(i) - β(j)
          yy = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - γ(j)
          by = [[0 for i in range(self.J)] for j in range(self.J)] # Link β(i) - γ(j)
          yo = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - δ(j)
  
          rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
          rig.show_in_front = True
          amt.show_names = True
          amt.display_type = 'STICK'
  #        amt.display_type = 'BBONE'
  
          # Link object to scene
  
          bpy.data.collections['movement'].objects.link(rig)
          bpy.context.view_layer.objects.active = rig
          bpy.context.view_layer.update()
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          # Construction Linkage
          aa[2][1] = amt.edit_bones.new('a2a1')
          aa[2][1].head = a[2]
          aa[2][1].tail = a[1]
          
          ab[1][1] = amt.edit_bones.new('a1b1')
          ab[1][1].head = a[1]
          ab[1][1].tail = b[1]
          ab[1][1].parent = aa[2][1]
   
          by[1][1] = amt.edit_bones.new('b1y1')
          by[1][1].head = b[1]
          by[1][1].tail = y[1]
          by[1][1].parent = ab[1][1]
          by[1][1].use_inherit_rotation = False
  
          ya[1][2] = amt.edit_bones.new('y1a2')
          ya[1][2].head = y[1]
          ya[1][2].tail = a[2]
          ya[1][2].parent = by[1][1]
  
          ao[2][1] = amt.edit_bones.new('a2o1')
          ao[2][1].head = a[2]
          ao[2][1].tail = o[1]
          ao[2][1].parent = ya[1][2]
  
          ob[1][2] = amt.edit_bones.new('o1b2')
          ob[1][2].head = o[1]
          ob[1][2].tail = b[2]
          ob[1][2].parent = ao[2][1]
          
          yy[1][2] = amt.edit_bones.new('y1y2')
          yy[1][2].head = y[1]
          yy[1][2].tail = y[2]
          yy[1][2].parent = by[1][1]
  
          for j in range(2, J - 1):
  
              by[j][j] = amt.edit_bones.new('b'+ str(j) + 'y'+ str(j))
              by[j][j].head = b[j]
              by[j][j].tail = y[j]
              by[j][j].parent = ob[j-1][j]
  
              yo[j][j] = amt.edit_bones.new('y'+ str(j) + 'o'+ str(j))
              yo[j][j].head = y[j]
              yo[j][j].tail = o[j]
              yo[j][j].parent = yy[j-1][j]
  
              yy[j][j+1] = amt.edit_bones.new('y'+ str(j) + 'y'+ str(j+1))
              yy[j][j+1].head = y[j]
              yy[j][j+1].tail = y[j+1]
              yy[j][j+1].parent = by[j][j]
  
              if j < (J-2):
                  ob[j][j+1] = amt.edit_bones.new('o'+ str(j) + 'b'+ str(j+1))
                  ob[j][j+1].head = o[j]
                  ob[j][j+1].tail = b[j+1]
                  ob[j][j+1].parent = yo[j][j]
  
          # all bones select
  
          # Bone constraints. Armature must be in pose mode.
          bpy.ops.object.mode_set(mode='POSE')
  
          bpy.ops.pose.select_all(action="SELECT")
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          if helicity == 'right':
              bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Z')
          else:
              bpy.ops.armature.calculate_roll(type='GLOBAL_NEG_Z')
   
          # IK constraint
          cns = rig.pose.bones['y1a2'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'a2a1'
          cns.chain_count = 2
          cns.use_stretch = False
  
          for j in range(2, J - 1):
              cns = rig.pose.bones['b'+str(j) +'y'+str(j)].constraints.new('IK')
              cns.name = 'Ik'
              cns.target = rig
              cns.subtarget = 'y'+str(j)+'o'+str(j)
              cns.iterations = 500
              cns.chain_count = 2
              cns.use_stretch = False
  
          bpy.ops.object.mode_set(mode='OBJECT')
          
  
      def configRotation(self, rig, interval, frame_start, frame_end, start, end):
  
          # Bone constraints. Armature must be in pose mode.
          bpy.ops.object.mode_set(mode='POSE')
  
          # key insert 
          keyframe_insert_interval = interval
  
          rig.pose.bones["a1b1"].rotation_mode = 'XYZ'
          rig.pose.bones["a1b1"].rotation_euler.z = math.radians(start) 
          rig.pose.bones["a1b1"].keyframe_insert(data_path="rotation_euler",frame=frame_start)
  
          rig.pose.bones["a1b1"].rotation_mode = 'XYZ'
          rig.pose.bones["a1b1"].rotation_euler.z = math.radians(end)
          rig.pose.bones["a1b1"].keyframe_insert(data_path="rotation_euler",frame=frame_end)
  
          for curve in bpy.context.active_object.animation_data.action.fcurves:
              cycles = curve.modifiers.new(type='CYCLES')
              cycles.mode_before = 'REPEAT_OFFSET'
              cycles.mode_after = 'REPEAT_OFFSET'
  
              for keyframe in curve.keyframe_points:
                  keyframe.interpolation = 'LINEAR'
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.000"].copy()
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for n in range(1, J - 1):
  
              if n <= (J-2):
  
                  # Pattern 2 of by
                  obj_joint = bpy.data.objects["joint.green.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yy
                  obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
                  obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
  
              if n <= (J-3):
  
                  # Pattern 1 of ob
                  obj_joint = bpy.data.objects["joint.blue.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q*2 + Q*(n % 2)*6 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yo
                  obj_joint = bpy.data.objects["joint.copper.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n+1)+"o"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  
  
      def constructLink(self, A, J, helicity, rig, move, part):
  
          # Move and rotate the tip bone in pose mode
          bpy.context.view_layer.objects.active = rig 
  
          Y = 1.1838*A
  
          for n in rig.pose.bones:
              if n.name != "o" + str(J-2) + "b" + str(J-1):
                  # we can get the object from the pose bone
                  obj = n.id_data
                  matrix_final = obj.matrix_world @ n.matrix
  
                  # Create armature and object
                  lnk = bpy.data.armatures.new(n.name[:len(n.name)]+'.data.' + helicity)
                  lnk_rig = bpy.data.objects.new(n.name[:len(n.name)]+'.link.' + helicity, lnk)
                  lnk_rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
  
                  # rig.show_in_front = True
                  lnk.show_names = True
                  lnk.display_type = 'STICK'
  
                  bpy.data.collections['link'].objects.link(lnk_rig)
                  bpy.context.view_layer.objects.active = lnk_rig
                  bpy.context.view_layer.update()
  
                  # Create bones
  
                  # mode='EDIT'
                  bpy.ops.object.editmode_toggle()
      
                  link = lnk.edit_bones.new(n.name[:len(n.name)])
                  link.head = (0.0, 0.0, 0.0)
                  link.tail = (0.0, Y, 0.0)
  
                  link_head = lnk.edit_bones.new('head')
                  link_head.head = (0.0, 0.0, 0.1)
                  link_head.tail = (0.0, 0.0, 0.0)
                  link_head.parent = link
                  link_head.use_inherit_scale = False
  
                  link_tail = lnk.edit_bones.new('tail')
                  link_tail.head = (0.0, Y, 0.0)
                  link_tail.tail = (0.0, Y, -0.1)
                  link_tail.parent = link
                  link_tail.use_inherit_scale = False
  
                  bpy.ops.object.mode_set(mode='OBJECT')
  
                  ob = bpy.data.objects[n.name[:len(n.name)]+'.mesh.' + move + '.' + part +'.' + helicity]
                  ob.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
      
                  # Give mesh object an armature modifier, using vertex groups but
                  # not envelopes
                  mod = ob.modifiers.new('MyRigModif', 'ARMATURE')
                  mod.object = lnk_rig
                  mod.use_bone_envelopes = False
                  mod.use_vertex_groups = True
  
                  # Bone constraints. Armature must be in pose mode.
                  bpy.ops.object.mode_set(mode='POSE')
   
                  # Copy rotation constraints Base -> Tip
                  pBase = lnk_rig.pose.bones[n.name[:len(n.name)]]
                  cns = pBase.constraints.new('COPY_LOCATION')
                  cns.name = 'Copy_Location'
                  cns.target = rig
                  cns.subtarget = n.name[:len(n.name)]
                  cns.owner_space = 'WORLD'
                  cns.target_space = 'WORLD'
  
                  # Copy rotation constraints Base -> Tip
                  pBase = lnk_rig.pose.bones[n.name[:len(n.name)]]
                  cns = pBase.constraints.new('COPY_ROTATION')
                  cns.name = 'Copy_Rotation'
                  cns.target = rig
                  cns.subtarget = n.name[:len(n.name)]
                  cns.owner_space = 'WORLD'
                  cns.target_space = 'WORLD'
  
                  # StretchTo constraint Mid -> Tip with influence 0.5
                  cns1 = pBase.constraints.new('STRETCH_TO')
                  cns1.name = 'Stretch'
                  cns1.target = rig
                  cns1.subtarget = n.name[:len(n.name)]
                  cns1.head_tail = 1
                  cns1.rest_length = Y
                  cns1.influence = 1
                  cns1.keep_axis = 'PLANE_Z'
                  cns1.volume = 'NO_VOLUME'
  
                  bpy.ops.object.mode_set(mode='OBJECT')
  
  
  class Finger(Formula):
      
      J = 6 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end, y2, y3, y4, y5):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
   
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
          
          # phalanx length
          self.y2 = y2
          self.y3 = y3
          self.y4 = y4
          self.y5 = y5
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o,
              self.y2, self.y3, self.y4, self.y5)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A, self.J, self.helicity, self.rig, self.move, self.part)
  
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o, y2, y3, y4, y5):
          
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          y[2] = y2
          print ("y2 =", y[2])
  
          y[3] = y3
          print ("y3 =", y[3])
  
          y[4] = y4
          print ("y4 =", y[4])
  
          y[5] = y5
          print ("y5 =", y[5])
  
  
          b[2] = mathutils.Euler((y[2].x+0.10012, y[2].y+0.170067, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler((y[3].x-0.12471, y[3].y-0.03395, 0.0), 'XYZ')
          print ("b3 =", b[3])
          
          b[4] = mathutils.Euler((y[4].x-0.11426, y[4].y-0.03342, 0.0), 'XYZ')
          print ("b4 =", b[4])
  
  
          o[2] = mathutils.Euler((y[2].x+0.09016, y[2].y+0.142795, 0.0), 'XYZ')
          print ("o2 =", o[2])
          
          o[3] = mathutils.Euler((y[3].x+0.07367, y[3].y+0.09711, 0.0), 'XYZ')
          print ("o3 =", o[3])
  
          o[4] = mathutils.Euler((y[4].x+0.00899, y[4].y+0.03297, 0.0), 'XYZ')
          print ("o4 =", o[4])
          
          
  class Wrist(Formula):
  
      J = 3 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end, 
          disciple_loc, disciple_rot, disciple):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple
          self.disciple = disciple
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(self.J)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master        
          self.setParent(self.helicity, self.move, self.rig, 
              self.disciple_loc, self.disciple_rot, self.disciple)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(1.25*self.A*0.8, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(1.25*self.A*0.8, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
          
          y[2] = mathutils.Euler((-A, -(0.173028/0.351)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          o[1] = mathutils.Euler(((-0.77453/0.351)*A, -A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
      def constructMovement(self, J, helicity, amt, rig, a, b, y, o):
  
          # Linkages
          aa = [[0 for i in range(4)] for j in range(4)] # Link α(i) - α(j)
          ab = [[0 for i in range(4)] for j in range(4)] # Link α(i) - β(j)
          ya = [[0 for i in range(4)] for j in range(4)] # Link γ(i) - α(j)
          yy = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - γ(j)
          by = [[0 for i in range(self.J)] for j in range(self.J)] # Link β(i) - γ(j)
          yo = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - δ(j)
  
          rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
          rig.show_in_front = True
          amt.show_names = True
          amt.display_type = 'STICK'
  #        amt.display_type = 'BBONE'
  
          # Link object to scene
  
          bpy.data.collections['movement'].objects.link(rig)
          bpy.context.view_layer.objects.active = rig
          bpy.context.view_layer.update()
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          # Construction Linkage
          aa[2][1] = amt.edit_bones.new('a2a1')
          aa[2][1].head = a[2]
          aa[2][1].tail = a[1]
          
          ab[1][1] = amt.edit_bones.new('a1b1')
          ab[1][1].head = a[1]
          ab[1][1].tail = b[1]
          ab[1][1].parent = aa[2][1]
   
          by[1][1] = amt.edit_bones.new('b1y1')
          by[1][1].head = b[1]
          by[1][1].tail = y[1]
          by[1][1].parent = ab[1][1]
          by[1][1].use_inherit_rotation = False
  
          ya[1][2] = amt.edit_bones.new('y1a2')
          ya[1][2].head = y[1]
          ya[1][2].tail = a[2]
          ya[1][2].parent = by[1][1]
  
          yo[1][1] = amt.edit_bones.new('y1o1')
          yo[1][1].head = y[1]
          yo[1][1].tail = o[1]
          yo[1][1].parent = ya[1][2]
     
          yy[1][2] = amt.edit_bones.new('y1y2')
          yy[1][2].head = y[1]
          yy[1][2].tail = y[2]
          yy[1][2].parent = by[1][1]
  
          # all bones select
  
          # Bone constraints. Armature must be in pose mode.
          bpy.ops.object.mode_set(mode='POSE')
  
          bpy.ops.pose.select_all(action="SELECT")
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          if helicity == 'right':
              bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Z')
          else:
              bpy.ops.armature.calculate_roll(type='GLOBAL_NEG_Z')
   
          # IK constraint
          cns = rig.pose.bones['y1a2'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'a2a1'
          cns.chain_count = 2
          cns.use_stretch = False
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
      # Parent set disciple to master        
      def setParent(self, helicity, move, rig, disciple_loc, disciple_rot, disciple):
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.context.scene.frame_current = 0
  
          bpy.ops.object.select_all(action='DESELECT')
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'y1o1' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          # disciple position
          disciple.rig.location.x += disciple_loc[0]
          disciple.rig.location.y += disciple_loc[1]
          disciple.rig.location.z += disciple_loc[2]
  
          disciple.rig.rotation_euler = disciple_rot
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.000"].copy()
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.y1o1"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          n = 1
  
          # Pattern 2 of by
          obj_joint = bpy.data.objects["joint.green.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          # Pattern 2 of yy
          obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
          obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
          
  
  class Arm(Formula):
  
      J = 6 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end, disciple_loc, disciple_rot, disciple):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple
          self.disciple = disciple
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master        
          self.setParent(self.helicity, self.move, self.rig, self.disciple_loc, self.disciple_rot, self.disciple)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(1.25*self.A*0.8, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(1.25*self.A*0.8, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          b[2] = mathutils.Euler(((5.09706/0.421838)*A, (-4.40177/0.421838)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler(((4.42782/0.421838)*A, (-5.57913/0.421838)*A, 0.0), 'XYZ')
          print ("b3 =", b[3])
          
          b[4] = mathutils.Euler(((8.9072/0.421838)*A, (-8.64497/0.421838)*A, 0.0), 'XYZ')
          print ("b4 =", b[4])
          
          y[2] = mathutils.Euler(((4.25396/0.421838)*A, (-5.24574/0.421838)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          y[3] = mathutils.Euler(((4.65994/0.421838)*A, (-5.5441/0.421838)*A, 0.0), 'XYZ')
          print ("y3 =", y[3])
  
          o[2] = mathutils.Euler(((4.35098/0.421838)*A, (-5.11169/0.421838)*A, 0.0), 'XYZ')
          print ("o2 =", o[2])
          
          o[3] = mathutils.Euler(((4.43448/0.421838)*A, (-5.1725/0.421838)*A, 0.0), 'XYZ')
          print ("o3 =", o[3])
         
          o[4] = mathutils.Euler(((9.03584/0.421838)*A, (-7.93583/0.421838)*A, 0.0), 'XYZ')
          print ("o4 =", o[4])
          
          y[4] = mathutils.Euler(((8.96184/0.421838)*A, (-8.0663/0.421838)*A, 0.0), 'XYZ')
          print ("y4 =", y[4])
          
          y[5] = mathutils.Euler(((9.21442/0.421838)*A, (-8.20853/0.421838)*A, 0.0), 'XYZ')
          print ("y5 =", y[5])
  
      # Parent set disciple to master
      def setParent(self, helicity, move, rig, disciple_loc, disciple_rot, disciple):
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.context.scene.frame_current = 0
  
          bpy.ops.object.select_all(action='DESELECT')
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'b4y4' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          # disciple position
          disciple.rig.location.x += disciple_loc[0]
          disciple.rig.location.y += disciple_loc[1]
          disciple.rig.location.z += disciple_loc[2]
  
          disciple.rig.rotation_euler = disciple_rot
          
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.000"].copy()
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for n in range(1, J - 1):
  
              if n <= (J-2):
  
                  # Pattern 2 of by
                  obj_joint = bpy.data.objects["joint.green.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yy
                  obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
                  obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
  
              if n <= (J-3):
  
                  # Pattern 1 of ob
                  if n == 3:
                      obj_joint = bpy.data.objects["joint.blue.o3b4.arm"].copy()
                  else:
                      obj_joint = bpy.data.objects["joint.blue.001"].copy()
                  
                  obj_joint.location = (0.0, 0.0, -Q*2 + Q*(n % 2)*6 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yo
                  obj_joint = bpy.data.objects["joint.copper.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n+1)+"o"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
          
  
  class Wing(Formula):
      
      J = 6 #joint number
      
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end,
          disciple_loc, disciple_rot, disciple):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
          
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
          self.disciple = disciple
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
          self.w = [0 for i in range(self.J+1)] # Joint ω
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.helicity, self.a, self.b, self.y, self.o, self.w)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o, self.w)
   
          # Parent set disciple to master      
          self.setParent(self.helicity, self.move, self.rig,
                  self.disciple_loc, self.disciple_rot, self.disciple)
   
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A * 1, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A * 1, self.J, self.helicity, self.rig, self.move, self.part)
  
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, helicity, a, b, y, o, w):
          
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          y[2] = mathutils.Euler((1.404781*A, -3.404781*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          y[3] = mathutils.Euler((-1*A, -5.809552*A, 0.0), 'XYZ')
          print ("y3 =", y[3])
  
          y[4] = mathutils.Euler((-1*A, -9.273811*A, 0.0), 'XYZ')
          print ("y4 =", y[4])
  
          b[2] = mathutils.Euler((3.404781*A, -1.404781*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler((-1*A, -4.400871*A, 0.0), 'XYZ')
          print ("b3 =", b[3])
  
          o[2] = mathutils.Euler((2.400871*A, -4.400871*A, 0.0), 'XYZ')
          print ("o2 =", o[2])
          
          o[3] = mathutils.Euler((-1.191309*A, -6.000875*A, 0.0), 'XYZ')
          print ("o3 =", o[3])
  
          if helicity == 'right':
              H = 1
          else:
              H = -1
              
          w[0] = mathutils.Euler((-A , y[4].y, -B * H), 'XYZ')
          print ("w0 =", w[0])
        
          w[1] = mathutils.Euler((-A , y[4].y, -B*2 * H), 'XYZ')
          print ("w1 =", w[1])
  
          w[2] = mathutils.Euler((-0.933934/0.276443*A, -2.41649/0.276443*A, 0.469071/0.276443*A * H), 'XYZ')
          w[3] = mathutils.Euler((-0.933934/0.276443*A, -2.41649/0.276443*A, -0.181153/0.276443*A * H), 'XYZ')
          print ("w2 =", w[2])
          print ("w3 =", w[3])
      
          w[4] = mathutils.Euler((-0.933934/0.276443*A, -2.41649/0.276443*A, -0.758736/0.276443* A * H), 'XYZ')
          print ("w4 =", w[4])
          w[5] = mathutils.Euler((-0.933934/0.276443*A, -2.41649/0.276443*A, -3.05221/0.276443* A * H), 'XYZ')
          print ("w5 =", w[5])
          
  
      def constructMovement(self, J, helicity, amt, rig, a, b, y, o, w):
  
          # Linkages
          aa = [[0 for i in range(4)] for j in range(4)] # Link α(i) - α(j)
          ab = [[0 for i in range(4)] for j in range(4)] # Link α(i) - β(j)
          ya = [[0 for i in range(4)] for j in range(4)] # Link γ(i) - α(j)
          ao = [[0 for i in range(4)] for j in range(4)] # Link α(i) - δ(j)
          ob = [[0 for i in range(self.J)] for j in range(self.J)] # Link δ(i) - β(j)
          yy = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - γ(j)
          by = [[0 for i in range(self.J)] for j in range(self.J)] # Link β(i) - γ(j)
          yo = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - δ(j)
  
          rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
          rig.show_in_front = True
          amt.show_names = True
          amt.display_type = 'STICK'
  #        amt.display_type = 'BBONE'
  
          # Link object to scene
  
          bpy.data.collections['movement'].objects.link(rig)
          bpy.context.view_layer.objects.active = rig
          bpy.context.view_layer.update()
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          # Construction Linkage
          aa[2][1] = amt.edit_bones.new('a2a1')
          aa[2][1].head = a[2]
          aa[2][1].tail = a[1]
          
          ab[1][1] = amt.edit_bones.new('a1b1')
          ab[1][1].head = a[1]
          ab[1][1].tail = b[1]
          ab[1][1].parent = aa[2][1]
   
          by[1][1] = amt.edit_bones.new('b1y1')
          by[1][1].head = b[1]
          by[1][1].tail = y[1]
          by[1][1].parent = ab[1][1]
          by[1][1].use_inherit_rotation = False
  
          ya[1][2] = amt.edit_bones.new('y1a2')
          ya[1][2].head = y[1]
          ya[1][2].tail = a[2]
          ya[1][2].parent = by[1][1]
  
          ao[2][1] = amt.edit_bones.new('a2o1')
          ao[2][1].head = a[2]
          ao[2][1].tail = o[1]
          ao[2][1].parent = ya[1][2]
  
          ob[1][2] = amt.edit_bones.new('o1b2')
          ob[1][2].head = o[1]
          ob[1][2].tail = b[2]
          ob[1][2].parent = ao[2][1]
          
          yy[1][2] = amt.edit_bones.new('y1y2')
          yy[1][2].head = y[1]
          yy[1][2].tail = y[2]
          yy[1][2].parent = by[1][1]
  
          for j in range(2, J - 2):
  
              by[j][j] = amt.edit_bones.new('b'+ str(j) + 'y'+ str(j))
              by[j][j].head = b[j]
              by[j][j].tail = y[j]
              by[j][j].parent = ob[j-1][j]
  
              yo[j][j] = amt.edit_bones.new('y'+ str(j) + 'o'+ str(j))
              yo[j][j].head = y[j]
              yo[j][j].tail = o[j]
              yo[j][j].parent = yy[j-1][j]
  
              yy[j][j+1] = amt.edit_bones.new('y'+ str(j) + 'y'+ str(j+1))
              yy[j][j+1].head = y[j]
              yy[j][j+1].tail = y[j+1]
              yy[j][j+1].parent = by[j][j]
  
              if j < (J-3):
  
                  ob[j][j+1] = amt.edit_bones.new('o'+ str(j) + 'b'+ str(j+1))
                  ob[j][j+1].head = o[j]
                  ob[j][j+1].tail = b[j+1]
                  ob[j][j+1].parent = yo[j][j]
  
  
          # y4 2 fulcrum vector
          y4_fulcrum = amt.edit_bones.new('y4_fulcrum')
          y4_fulcrum.head = y[4]
          y4_fulcrum.tail = w[0]
          y4_fulcrum.parent = yy[3][4]
  
          y4_fulcrum_tail = amt.edit_bones.new('y4_fulcrum.tail')
          y4_fulcrum_tail.head = w[0]
          y4_fulcrum_tail.tail = w[1]
          y4_fulcrum_tail.parent = y4_fulcrum
  
  
          # formula y3y4 ginbal_ring x-axis
          g_y3y4_x = amt.edit_bones.new('g_y3y4.x')
          g_y3y4_x.head = y[3]
          g_y3y4_x.tail = y[4]
          g_y3y4_x.parent = by[3][3]
  
          # formula y3y4 ginbal_ring z-axis
          g_y3y4_z = amt.edit_bones.new('g_y3y4.z')
          g_y3y4_z.head = y[4]
          g_y3y4_z.tail = w[0]
          g_y3y4_z.parent = g_y3y4_x
  
          # formula b4y4 ginbal_ring x-axis
  #        g_b4y4_x = amt.edit_bones.new('g_b4y4.x')
  #        g_b4y4_x.head = b[4]
  #        g_b4y4_x.tail = y[4]
  #        g_b4y4_x.parent = ob[3][4]
  
          # formula b4y4 ginbal_ring z-axis
  #        g_b4y4_z = amt.edit_bones.new('g_b4y4.z')
  #        g_b4y4_z.head = y[4]
  #        g_b4y4_z.tail = w[0]
  #        g_b4y4_z.parent = g_b4y4_x
  
  
          # fulcrum 2 y4
          fulcrum_y4 = amt.edit_bones.new('fulcrum_y4')
          fulcrum_y4.head = w[4]
          fulcrum_y4.tail = w[3]
          fulcrum_y4.parent = aa[2][1]
  
          # fulcrum y4 tail
          fulcrum_y4_tail = amt.edit_bones.new('fulcrum_y4.tail')
          fulcrum_y4_tail.head = w[3]
          fulcrum_y4_tail.tail = w[2]
          fulcrum_y4_tail.parent = fulcrum_y4
      
  
          # fulcrum gimbal 1 y-axis
          g_1_y = amt.edit_bones.new('g_1.y')
          g_1_y.head = mathutils.Euler((w[4].x, y[4].y + 0.7504, w[4].z), 'XYZ')
          g_1_y.tail = w[4]
          g_1_y.parent = aa[2][1]
  
          # fulcrum gimbal 2 x-axis
          g_2_x = amt.edit_bones.new('g_2.x')
          g_2_x.head = w[4]
          g_2_x.tail = w[3]
          g_2_x.parent = g_1_y
      
      
          # wings gimbal 3 z-axis
          g_3_z = amt.edit_bones.new('g_3.z')
          g_3_z.head = w[4]
          g_3_z.tail = w[5]
          g_3_z.parent = g_2_x
  
  #        # wings gimbal 4 z-axis
  #        g_4_z = amt.edit_bones.new('g_4.z')
  #        g_4_z.head = w[5]
  #        g_4_z.tail = w[6]
  #        g_4_z.parent = g_2_x
  
          # all bones select
  
          # Bone constraints. Armature must be in pose mode.
          bpy.ops.object.mode_set(mode='POSE')
  
          bpy.ops.pose.select_all(action="SELECT")
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          if helicity == 'right':
              bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Z')
          else:
              bpy.ops.armature.calculate_roll(type='GLOBAL_NEG_Z')
   
          # IK constraint
          cns = rig.pose.bones['y1a2'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'a2a1'
          cns.chain_count = 2
          cns.use_stretch = False
  
          for j in range(2, J - 2):
              cns = rig.pose.bones['b'+str(j) +'y'+str(j)].constraints.new('IK')
              cns.name = 'Ik'
              cns.target = rig
              cns.subtarget = 'y'+str(j)+'o'+str(j)
              cns.iterations = 500
              cns.chain_count = 2
              cns.use_stretch = False
  
          # IK constraint y4 -> fulcrum
          cns = rig.pose.bones['y4_fulcrum'].constraints.new('DAMPED_TRACK')
          cns.name = 'Damped Track'
          cns.target = rig
          cns.subtarget = 'fulcrum_y4'
          cns.head_tail = 0
  
          # IK constraint fulcrum -> y4
          cns = rig.pose.bones['fulcrum_y4'].constraints.new('DAMPED_TRACK')
          cns.name = 'Damped Track'
          cns.target = rig
          cns.subtarget = 'y3y4'
          cns.head_tail = 1
  
          # IK constraint g_1.z - g_2.x - y4
          cns = rig.pose.bones['g_2.x'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'fulcrum_y4.tail'
          cns.pole_target = rig
          cns.pole_subtarget = 'fulcrum_y4'
          cns.chain_count = 2
          cns.use_stretch = False
          cns.pole_angle = math.radians(-90)
  
          # Copy rotation constraints
          cns = rig.pose.bones['g_3.z'].constraints.new('COPY_ROTATION')
          cns.name = 'Copy_Rotation'
          cns.target = rig
          cns.subtarget = 'g_y3y4.z'
          cns.owner_space = 'WORLD'
          cns.target_space = 'WORLD'
  
          # Copy rotation constraints
  #        cns = rig.pose.bones['g_4.z'].constraints.new('COPY_ROTATION')
  #        cns.name = 'Copy_Rotation'
  #        cns.target = rig
  #        cns.subtarget = 'g_b4y4.z'
  #        cns.owner_space = 'WORLD'
  #        cns.target_space = 'WORLD'
  
          # IK constraint
          cns = rig.pose.bones['g_y3y4.z'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'y4_fulcrum.tail'
          cns.pole_target = rig
          cns.pole_subtarget = 'y4_fulcrum'
          cns.chain_count = 2
          cns.use_stretch = False
          cns.pole_angle = math.radians(90)
  
          # IK constraint
  #        cns = rig.pose.bones['g_b4y4.z'].constraints.new('IK')
  #        cns.name = 'Ik'
  #        cns.target = rig
  #        cns.subtarget = 'y4_fulcrum.tail'
  #        cns.pole_target = rig
  #        cns.pole_subtarget = 'y4_fulcrum'
  #        cns.chain_count = 2
  #        cns.use_stretch = False
  #        if helicity == 'right':
  #            cns.pole_angle = math.radians(90)
  #        else:
  #            cns.pole_angle = math.radians(-90)
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
  
      # Parent set disciple to master      
      def setParent(self, helicity, move, rig, 
              disciple_loc, disciple_rot, disciple ):
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.context.scene.frame_current = 0
  
          bpy.ops.object.select_all(action='DESELECT')
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'g_3.z' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          # disciple position
          disciple.rig.location.x += disciple_loc[0]
          disciple.rig.location.y += disciple_loc[1]
          disciple.rig.location.z += disciple_loc[2]
  
          disciple.rig.rotation_euler = disciple_rot
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
          
          obj_joint = bpy.data.objects["joint.cursor"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y4_fulcrum.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.cursor"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y4_fulcrum.tail.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.cursor"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "fulcrum_y4.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.cursor"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "fulcrum_y4.tail.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  #        Z = Q*17
  
  #        obj_joint = bpy.data.objects["joint.gold.000"].copy()
  
          if helicity == 'right':
              obj_joint = bpy.data.objects["joint.gold.wing.a2a1.L"].copy()
          else:
              obj_joint = bpy.data.objects["joint.gold.wing.a2a1.R"].copy()
  
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for n in range(1, J - 2):
  
              # Pattern 2 of by
              obj_joint = bpy.data.objects["joint.green.001"].copy()
              obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
              obj_joint.scale = (A, A, A)
              obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
              bpy.data.collections['link'].objects.link(obj_joint)
  
              if n <= (J-4):
  
                  # Pattern 1 of ob
                  obj_joint = bpy.data.objects["joint.blue.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q*2 + Q*(n % 2)*6 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yy
                  obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
                  obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
              if n <= (J-5):
  
                  # Pattern 2 of yo
                  obj_joint = bpy.data.objects["joint.copper.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n+1)+"o"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
                  
  
          obj_joint = bpy.data.objects["joint.gold.y3y4.001"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y3y4.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.gold.g_y3y4.x.001"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "g_y3y4.x.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.gold.g_y3y4.z.wing"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "g_y3y4.z.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
          
          obj_joint = bpy.data.objects["joint.green.g_1.y.001"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "g_1.y.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
          
          obj_joint = bpy.data.objects["joint.blue.g_2.x.wing"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "g_2.x.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
          
          obj_joint = bpy.data.objects["joint.silver.g_3.z.wing"].copy()
          obj_joint.location = (0.0, 0.0, 0.0)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "g_3.z.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  
      def constructLink(self, A, J, helicity, rig, move, part):
  
          # Move and rotate the tip bone in pose mode
          bpy.context.view_layer.objects.active = rig 
  
          Y = 1.1838*A
  
          for n in rig.pose.bones:
  
              if n.name != "y3o3":
  #            if n.name != "o" + str(J-2) + "b" + str(J-1):
                  # we can get the object from the pose bone
                  obj = n.id_data
                  matrix_final = obj.matrix_world @ n.matrix
  
                  # Create armature and object
                  lnk = bpy.data.armatures.new(n.name[:len(n.name)]+'.data.' + helicity)
                  lnk_rig = bpy.data.objects.new(n.name[:len(n.name)]+'.link.' + helicity, lnk)
                  lnk_rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
  
                  # rig.show_in_front = True
                  lnk.show_names = True
                  lnk.display_type = 'STICK'
  
                  bpy.data.collections['link'].objects.link(lnk_rig)
                  bpy.context.view_layer.objects.active = lnk_rig
                  bpy.context.view_layer.update()
  
                  # Create bones
  
                  # mode='EDIT'
                  bpy.ops.object.editmode_toggle()
      
                  link = lnk.edit_bones.new(n.name[:len(n.name)])
                  link.head = (0.0, 0.0, 0.0)
                  link.tail = (0.0, Y, 0.0)
  
                  link_head = lnk.edit_bones.new('head')
                  link_head.head = (0.0, 0.0, 0.1)
                  link_head.tail = (0.0, 0.0, 0.0)
                  link_head.parent = link
                  link_head.use_inherit_scale = False
  
                  link_tail = lnk.edit_bones.new('tail')
                  link_tail.head = (0.0, Y, 0.0)
                  link_tail.tail = (0.0, Y, -0.1)
                  link_tail.parent = link
                  link_tail.use_inherit_scale = False
  
                  bpy.ops.object.mode_set(mode='OBJECT')
  
                  ob = bpy.data.objects[n.name[:len(n.name)]+'.mesh.' + move + '.' + part +'.' + helicity]
                  ob.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
      
                  # Give mesh object an armature modifier, using vertex groups but
                  # not envelopes
                  mod = ob.modifiers.new('MyRigModif', 'ARMATURE')
                  mod.object = lnk_rig
                  mod.use_bone_envelopes = False
                  mod.use_vertex_groups = True
  
                  # Bone constraints. Armature must be in pose mode.
                  bpy.ops.object.mode_set(mode='POSE')
   
                  # Copy rotation constraints Base -> Tip
                  pBase = lnk_rig.pose.bones[n.name[:len(n.name)]]
                  cns = pBase.constraints.new('COPY_LOCATION')
                  cns.name = 'Copy_Location'
                  cns.target = rig
                  cns.subtarget = n.name[:len(n.name)]
                  cns.owner_space = 'WORLD'
                  cns.target_space = 'WORLD'
  
                  # Copy rotation constraints Base -> Tip
                  pBase = lnk_rig.pose.bones[n.name[:len(n.name)]]
                  cns = pBase.constraints.new('COPY_ROTATION')
                  cns.name = 'Copy_Rotation'
                  cns.target = rig
                  cns.subtarget = n.name[:len(n.name)]
                  cns.owner_space = 'WORLD'
                  cns.target_space = 'WORLD'
  
                  # StretchTo constraint Mid -> Tip with influence 0.5
                  cns1 = pBase.constraints.new('STRETCH_TO')
                  cns1.name = 'Stretch'
                  cns1.target = rig
                  cns1.subtarget = n.name[:len(n.name)]
                  cns1.head_tail = 1
                  cns1.rest_length = Y
                  cns1.influence = 1
                  cns1.keep_axis = 'PLANE_Z'
                  cns1.volume = 'NO_VOLUME'
  
                  bpy.ops.object.mode_set(mode='OBJECT')
  
  
  class Neck(Formula):
  
      J = 4 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(self.J)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A*0.4, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A*0.4, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          y[2] = mathutils.Euler((-A, (-1/0.747868)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          o[1] = mathutils.Euler(((-2.44947/0.747868)*A, -A, 0.0), 'XYZ')
          print ("o1 =", o[1])
          
          b[2] = mathutils.Euler(((-2.57187/0.747868)*A, (-1.44199/0.747868)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
      def constructMovement(self, J, helicity, amt, rig, a, b, y, o):
  
          # Linkages
          aa = [[0 for i in range(4)] for j in range(4)] # Link α(i) - α(j)
          ab = [[0 for i in range(4)] for j in range(4)] # Link α(i) - β(j)
          ya = [[0 for i in range(4)] for j in range(4)] # Link γ(i) - α(j)
  #        ao = [[0 for i in range(4)] for j in range(4)] # Link α(i) - δ(j)
          ob = [[0 for i in range(self.J)] for j in range(self.J)] # Link δ(i) - β(j)
          yy = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - γ(j)
          by = [[0 for i in range(self.J)] for j in range(self.J)] # Link β(i) - γ(j)
          yo = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - δ(j)
  
          rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
          rig.show_in_front = True
          amt.show_names = True
          amt.display_type = 'STICK'
  #        amt.display_type = 'BBONE'
  
          # Link object to scene
  
          bpy.data.collections['movement'].objects.link(rig)
          bpy.context.view_layer.objects.active = rig
          bpy.context.view_layer.update()
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          # Construction Linkage
          aa[2][1] = amt.edit_bones.new('a2a1')
          aa[2][1].head = a[2]
          aa[2][1].tail = a[1]
          
          ab[1][1] = amt.edit_bones.new('a1b1')
          ab[1][1].head = a[1]
          ab[1][1].tail = b[1]
          ab[1][1].parent = aa[2][1]
   
          by[1][1] = amt.edit_bones.new('b1y1')
          by[1][1].head = b[1]
          by[1][1].tail = y[1]
          by[1][1].parent = ab[1][1]
          by[1][1].use_inherit_rotation = False
  
          ya[1][2] = amt.edit_bones.new('y1a2')
          ya[1][2].head = y[1]
          ya[1][2].tail = a[2]
          ya[1][2].parent = by[1][1]
  
          yo[1][1] = amt.edit_bones.new('y1o1')
          yo[1][1].head = y[1]
          yo[1][1].tail = o[1]
          yo[1][1].parent = ya[1][2]
  
          ob[1][2] = amt.edit_bones.new('o1b2')
          ob[1][2].head = o[1]
          ob[1][2].tail = b[2]
          ob[1][2].parent = yo[1][1]
     
          yy[1][2] = amt.edit_bones.new('y1y2')
          yy[1][2].head = y[1]
          yy[1][2].tail = y[2]
          yy[1][2].parent = by[1][1]
  
          # all bones select
  
          # Bone constraints. Armature must be in pose mode.
          bpy.ops.object.mode_set(mode='POSE')
  
          bpy.ops.pose.select_all(action="SELECT")
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          if helicity == 'right':
              bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Z')
          else:
              bpy.ops.armature.calculate_roll(type='GLOBAL_NEG_Z')
   
          # IK constraint
          cns = rig.pose.bones['y1a2'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'a2a1'
          cns.chain_count = 2
          cns.use_stretch = False
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.000"].copy()
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.y1o1"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          n = 1
  
          # Pattern 2 of by
          obj_joint = bpy.data.objects["joint.green.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          # Pattern 2 of yy
          obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
          obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
          
          # Pattern 1 of ob
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2 + Q*(n % 2)*6 +Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  
  
  class RightShoulder(Formula):
  
      J = 5 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end,
              disciple_loc, disciple_rot, disciple):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple
          self.disciple = disciple
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master       
          self.setParent(self.helicity, self.move, self.rig, self.disciple_loc, self.disciple_rot, self.disciple)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
          
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          b[2] = mathutils.Euler(((A*3/0.431828)*A, (A/0.431828)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler(((-A/0.431828)*A, (-2.52868/0.431828)*A, 0.0), 'XYZ')
          print ("b3 =", b[3])
          
          y[2] = mathutils.Euler(((A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          y[3] = mathutils.Euler(((A/0.431828)*A, (-2.52868/0.431828)*A, 0.0), 'XYZ')
          print ("y3 =", y[3])
  
          o[2] = mathutils.Euler(((-A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
          print ("o2 =", o[2])
          
          o[3] = mathutils.Euler(((A/0.431828)*A, (-3.39723/0.431828)*A, 0.0), 'XYZ')
          print ("o3 =", o[3])
          
          y[4] = mathutils.Euler(((A*3/0.431828)*A, (-2.52868/0.431828)*A, 0.0), 'XYZ')
          print ("y4 =", y[4])
  
      # Parent set disciple to master        
      def setParent(self, helicity, move, rig, disciple_loc, disciple_rot, disciple):
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.context.scene.frame_current = 0
  
          bpy.ops.object.select_all(action='DESELECT')
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'b3y3' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          # disciple position
          disciple.rig.location.x += disciple_loc[0]
          disciple.rig.location.y += disciple_loc[1]
          disciple.rig.location.z += disciple_loc[2]
  
          disciple.rig.rotation_euler = disciple_rot
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.000"].copy()
          obj_joint.location = (0.0, 0.0, -Q*0+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.002"].copy()
          obj_joint.location = (0.0, 0.0, +Q*4+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*6+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*1+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for n in range(1, J - 1):
  
              if n <= (J-2):
  
                  if n == 1:
                      
                      obj_joint = bpy.data.objects["joint.green.002"].copy()
                      obj_joint.location = (0.0, 0.0, +Q*2 + Q*((n+1) % 2)*4 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)                    
  
                  else:
                      # Pattern 2 of by
                      obj_joint = bpy.data.objects["joint.green.001"].copy()
                      obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)
  
              if n <= (J-3):
  
                  # Pattern 2 of yy
                  obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
                  obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  if n == 1:
                      # Pattern 1 of ob
                      obj_joint = bpy.data.objects["joint.blue.002"].copy()
                      obj_joint.location = (0.0, 0.0, +Q*1 + Q*(n % 2)*6 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)
  
                  else:
                      # Pattern 1 of ob
                      obj_joint = bpy.data.objects["joint.blue.001"].copy()
                      obj_joint.location = (0.0, 0.0, -Q*2 + Q*(n % 2)*6 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yo
                  obj_joint = bpy.data.objects["joint.copper.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n+1)+"o"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.gold.spine.y3y4"].copy()
          obj_joint.location = (0.0, 0.0, +Q*(1 - (3 % 2))*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y3y4.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  
  
  class LeftShoulder(RightShoulder):
  
      J = 5 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end,
          disciple_loc, disciple_rot, disciple):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple
          self.disciple = disciple
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master       
          self.setParent(self.helicity, self.move, self.rig, self.disciple_loc, self.disciple_rot, self.disciple)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
          
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          b[2] = mathutils.Euler(((A*3/0.431828)*A, (A/0.431828)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler(((-A/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
          print ("b3 =", b[3])
          
          y[2] = mathutils.Euler(((A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          y[3] = mathutils.Euler(((A/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
          print ("y3 =", y[3])
  
          o[2] = mathutils.Euler(((-A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
          print ("o2 =", o[2])
          
          o[3] = mathutils.Euler(((A/0.431828)*A, (2.53357/0.431828)*A, 0.0), 'XYZ')
          print ("o3 =", o[3])
          
          y[4] = mathutils.Euler(((A*3/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
          print ("y4 =", y[4])
  
  
  class Costa(Formula):
  
      J = 4 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end, 
          disciple_loc, disciple_rot, disciple, disciple2,
          disciple3_loc, disciple3_rot, disciple3):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple
          self.disciple = disciple
          self.disciple2 = disciple2
  
          # disciple position
          self.disciple3_loc = disciple3_loc
          self.disciple3_rot = disciple3_rot
  
          # disciple
          self.disciple3 = disciple3
  
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(self.J)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master       
          self.setParent(self.helicity, self.move, self.rig, 
              self.disciple_loc, self.disciple_rot, self.disciple, self.disciple2,
              self.disciple3_loc, self.disciple3_rot, self.disciple3)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(1.25*self.A*0.4, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(1.25*self.A*0.4, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
          
          y[2] = mathutils.Euler((-A, (-1.21859/0.905211)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          o[1] = mathutils.Euler(((-3.03345/0.905211)*A, -A, 0.0), 'XYZ')
          print ("o1 =", o[1])
          
          b[2] = mathutils.Euler(((-3.03345/0.905211)*A, (-1.21859/0.905211)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          o[2] = mathutils.Euler((-A, (-1.39359/0.905211)*A, 0.0), 'XYZ')
          print ("o2 =", o[2])
  
      def constructMovement(self, J, helicity, amt, rig, a, b, y, o):
  
          # Linkages
          aa = [[0 for i in range(4)] for j in range(4)] # Link α(i) - α(j)
          ab = [[0 for i in range(4)] for j in range(4)] # Link α(i) - β(j)
          ya = [[0 for i in range(4)] for j in range(4)] # Link γ(i) - α(j)
  #        ao = [[0 for i in range(4)] for j in range(4)] # Link α(i) - δ(j)
          ob = [[0 for i in range(self.J)] for j in range(self.J)] # Link δ(i) - β(j)
          yy = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - γ(j)
          by = [[0 for i in range(self.J)] for j in range(self.J)] # Link β(i) - γ(j)
          yo = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - δ(j)
  
          rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
          rig.show_in_front = True
          amt.show_names = True
          amt.display_type = 'STICK'
  #        amt.display_type = 'BBONE'
  
          # Link object to scene
  
          bpy.data.collections['movement'].objects.link(rig)
          bpy.context.view_layer.objects.active = rig
          bpy.context.view_layer.update()
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          # Construction Linkage
          aa[2][1] = amt.edit_bones.new('a2a1')
          aa[2][1].head = a[2]
          aa[2][1].tail = a[1]
          
          ab[1][1] = amt.edit_bones.new('a1b1')
          ab[1][1].head = a[1]
          ab[1][1].tail = b[1]
          ab[1][1].parent = aa[2][1]
   
          by[1][1] = amt.edit_bones.new('b1y1')
          by[1][1].head = b[1]
          by[1][1].tail = y[1]
          by[1][1].parent = ab[1][1]
          by[1][1].use_inherit_rotation = False
  
          ya[1][2] = amt.edit_bones.new('y1a2')
          ya[1][2].head = y[1]
          ya[1][2].tail = a[2]
          ya[1][2].parent = by[1][1]
  
          yo[1][1] = amt.edit_bones.new('y1o1')
          yo[1][1].head = y[1]
          yo[1][1].tail = o[1]
          yo[1][1].parent = ya[1][2]
  
          ob[1][2] = amt.edit_bones.new('o1b2')
          ob[1][2].head = o[1]
          ob[1][2].tail = b[2]
          ob[1][2].parent = yo[1][1]
          
          yy[1][2] = amt.edit_bones.new('y1y2')
          yy[1][2].head = y[1]
          yy[1][2].tail = y[2]
          yy[1][2].parent = by[1][1]
  
          by[2][2] = amt.edit_bones.new('b'+ str(2) + 'y'+ str(2))
          by[2][2].head = b[2]
          by[2][2].tail = y[2]
          by[2][2].parent = ob[1][2]
  
          yo[2][2] = amt.edit_bones.new('y'+ str(2) + 'o'+ str(2))
          yo[2][2].head = y[2]
          yo[2][2].tail = o[2]
          yo[2][2].parent = yy[1][2]
  
          # all bones select
  
          # Bone constraints. Armature must be in pose mode.
          bpy.ops.object.mode_set(mode='POSE')
  
          bpy.ops.pose.select_all(action="SELECT")
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          if helicity == 'right':
              bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Z')
          else:
              bpy.ops.armature.calculate_roll(type='GLOBAL_NEG_Z')
   
          # IK constraint
          cns = rig.pose.bones['y1a2'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'a2a1'
          cns.chain_count = 2
          cns.use_stretch = False
  
          cns = rig.pose.bones['b2y2'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'y2o2'
          cns.iterations = 500
          cns.chain_count = 2
          cns.use_stretch = False
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
      # Parent set disciple to master        
      def setParent(self, helicity, move, rig, 
          disciple_loc, disciple_rot, disciple, disciple2,
          disciple3_loc, disciple3_rot, disciple3):
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.context.scene.frame_current = 0
  
          bpy.ops.object.select_all(action='DESELECT')
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'y1o1' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple.rig.select_set(state=True)
          disciple2.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
          
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'o1b2' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple3.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
          
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          # disciple position
          disciple.rig.location.x += disciple_loc[0]
          disciple.rig.location.y += disciple_loc[1]
          disciple.rig.location.z += disciple_loc[2]
  
          disciple.rig.rotation_euler = disciple_rot
  
          # disciple2 position
          disciple2.rig.location.x += disciple_loc[0]
          disciple2.rig.location.y += disciple_loc[1]
          disciple2.rig.location.z += disciple_loc[2]
  
          disciple2.rig.rotation_euler = disciple_rot
  
          # disciple3 position
          disciple3.rig.location.x += disciple3_loc[0]
          disciple3.rig.location.y += disciple3_loc[1]
          disciple3.rig.location.z += disciple3_loc[2]
  
          disciple3.rig.rotation_euler = disciple3_rot
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.000"].copy()
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.y1o1"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          n = 1
  
          # Pattern 2 of by
          obj_joint = bpy.data.objects["joint.green.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          # Pattern 2 of yy
          obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
          obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          # Pattern 1 of ob
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2 + Q*(n % 2)*6 +Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          # Pattern 2 of yo
          obj_joint = bpy.data.objects["joint.copper.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y"+str(n+1)+"o"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          n = 2
          
          # Pattern 2 of by
          obj_joint = bpy.data.objects["joint.green.b2y2"].copy()
          obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  
  
  class Spine(Formula):
  
      J = 7 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end,
              disciple_loc, disciple_rot, disciple,
              disciple2_loc, disciple2_rot, disciple2, disciple3):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple position
          self.disciple2_loc = disciple2_loc
          self.disciple2_rot = disciple2_rot
  
          # disciple
          self.disciple = disciple
          self.disciple2 = disciple2
          self.disciple3 = disciple3
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master       
          self.setParent(self.helicity, self.move, self.rig, 
              self.disciple_loc, self.disciple_rot, self.disciple, 
              self.disciple2_loc, self.disciple2_rot, self.disciple2, self.disciple3)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(1.25*self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(1.25*self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
          
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          b[2] = mathutils.Euler(((3.37305/0.578724)*A, (-2.2156/0.578724)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler(((3.37305/0.578724)*A, (-6.16738/0.578724)*A, 0.0), 'XYZ')
          print ("b3 =", b[3])
  
          b[4] = mathutils.Euler(((1.05816/0.578724)*A, (-4.5305/0.578724)*A, 0.0), 'XYZ')
          print ("b4 =", b[4])
  
          y[2] = mathutils.Euler(((2.2156/0.578724)*A, (-3.37305/0.578724)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          y[3] = mathutils.Euler(((5.00993/0.578724)*A, (-6.16738/0.578724)*A, 0.0), 'XYZ')
          print ("y3 =", y[3])
  
          o[2] = b[2]
          print ("o2 =", o[2])
          
          o[3] = mathutils.Euler(((5.00993/0.578724)*A, (-4.5305/0.578724)*A, 0.0), 'XYZ')
          print ("o3 =", o[3])
                  
          y[4] = y[2]
          print ("y4 =", y[4])
          
          o[4] = b[4]
          print ("o4 =", o[4])
  
          b[5] = mathutils.Euler(((-1.73617/0.578724)*A, (-1.73617/0.578724)*A, 0.0), 'XYZ')
          print ("b5 =", b[5])
  
          y[5] = y[1]
          print ("y5 =", y[5])
  
          o[5] = b[5]
          
          y[6] = mathutils.Euler(((-3.37305/0.578724)*A, (2.2156/0.578724)*A, 0.0), 'XYZ')
          print ("y6 =", y[6])
  
      # Parent set disciple to master        
      def setParent(self, helicity, move, rig, 
          disciple_loc, disciple_rot, disciple,
          disciple2_loc, disciple2_rot, disciple2, disciple3):
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.context.scene.frame_current = 0
  
          bpy.ops.object.select_all(action='DESELECT')
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'y5y6' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
          
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'y3y4' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple2.rig.select_set(state=True)
          disciple3.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
          
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          # disciple position
          disciple.rig.location.x += disciple_loc[0]
          disciple.rig.location.y += disciple_loc[1]
          disciple.rig.location.z += disciple_loc[2]
  
          disciple.rig.rotation_euler = disciple_rot
  
          # disciple2 position
          disciple2.rig.location.x += disciple2_loc[0]
          disciple2.rig.location.y += disciple2_loc[1]
          disciple2.rig.location.z += disciple2_loc[2]
  
          disciple2.rig.rotation_euler = disciple2_rot
  
          # disciple3 position
          disciple3.rig.location.x += disciple2_loc[0]
          disciple3.rig.location.y += disciple2_loc[1]
          disciple3.rig.location.z += disciple2_loc[2]
  
          disciple3.rig.rotation_euler = disciple2_rot
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.spine.a2a1"].copy()
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for n in range(1, J - 1):
              
              if n >= (3):
                  N=-Q*5
              else:
                  N=-Q*0
  
              if n <= (J-2):
  
                  # Pattern 2 of by
                  obj_joint = bpy.data.objects["joint.green.001"].copy()
                  obj_joint.location = (0.0, 0.0, N-Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
              if n <= (J-3):
  
                  # Pattern 2 of yy
                  if n == (2):
                      obj_joint = bpy.data.objects["joint.gold.spine.y2y3"].copy()
                  else:
                      obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
  
                  obj_joint.location = (0.0, 0.0, N+Q*(1 - (n % 2))*2+Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 1 of ob
                  if n == (2):
                      obj_joint = bpy.data.objects["joint.blue.spine.o2b3"].copy()
                  else:
                      obj_joint = bpy.data.objects["joint.blue.001"].copy()
                      
                  obj_joint.location = (0.0, 0.0, N-Q*2 + Q*(n % 2)*6 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yo
                  if n == (2):
                      obj_joint = bpy.data.objects["joint.copper.spine.y3o3"].copy()
                  else:
                      obj_joint = bpy.data.objects["joint.copper.001"].copy()
  
                  obj_joint.location = (0.0, 0.0, N-Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n+1)+"o"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
  
          obj_joint = bpy.data.objects["joint.gold.spine.y5y6"].copy()
          obj_joint.location = (0.0, 0.0, N+Q*(1 - (n % 2))*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y5y6.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  
  
  
  class LeftIlium(Formula):
  
      J = 5 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end, disciple_loc, disciple_rot, disciple):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple
          self.disciple = disciple
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master       
          self.setParent(self.helicity, self.move, self.rig, self.disciple_loc, self.disciple_rot, self.disciple)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
          
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          b[2] = mathutils.Euler(((A*3/0.431828)*A, (A/0.431828)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler(((-A/0.431828)*A, (-2.52868/0.431828)*A, 0.0), 'XYZ')
          print ("b3 =", b[3])
          
          y[2] = mathutils.Euler(((A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          y[3] = mathutils.Euler(((A/0.431828)*A, (-2.52868/0.431828)*A, 0.0), 'XYZ')
          print ("y3 =", y[3])
  
          o[2] = mathutils.Euler(((-A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
          print ("o2 =", o[2])
          
          o[3] = mathutils.Euler(((A/0.431828)*A, (-3.39723/0.431828)*A, 0.0), 'XYZ')
          print ("o3 =", o[3])
          
          y[4] = mathutils.Euler(((A*3/0.431828)*A, (-2.52868/0.431828)*A, 0.0), 'XYZ')
          print ("y4 =", y[4])
          
      # Parent set disciple to master        
      def setParent(self, helicity, move, rig, disciple_loc, disciple_rot, disciple):
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.context.scene.frame_current = 0
  
          bpy.ops.object.select_all(action='DESELECT')
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'b3y3' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          # disciple position
          disciple.rig.location.x += disciple_loc[0]
          disciple.rig.location.y += disciple_loc[1]
          disciple.rig.location.z += disciple_loc[2]
  
          disciple.rig.rotation_euler = disciple_rot
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.000"].copy()
          obj_joint.location = (0.0, 0.0, -Q*0+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.002"].copy()
          obj_joint.location = (0.0, 0.0, +Q*4+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*6+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*1+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for n in range(1, J - 1):
  
              if n <= (J-2):
  
                  if n == 1:
                      
                      obj_joint = bpy.data.objects["joint.green.002"].copy()
                      obj_joint.location = (0.0, 0.0, +Q*2 + Q*((n+1) % 2)*4 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)
  
                  elif n == 3:
  
                      obj_joint = bpy.data.objects["joint.green.003"].copy()
                      obj_joint.location = (0.0, 0.0, +Q*2 + Q*((n+1) % 2)*4 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)
  
                  else:
                      # Pattern 2 of by
                      obj_joint = bpy.data.objects["joint.green.001"].copy()
                      obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)
  
              if n <= (J-3):
  
                  # Pattern 2 of yy
                  obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
                  obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  if n == 1:
                      # Pattern 1 of ob
                      obj_joint = bpy.data.objects["joint.blue.002"].copy()
                      obj_joint.location = (0.0, 0.0, +Q*1 + Q*(n % 2)*6 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)
  
                  else:
                      # Pattern 1 of ob
                      obj_joint = bpy.data.objects["joint.blue.001"].copy()
                      obj_joint.location = (0.0, 0.0, -Q*2 + Q*(n % 2)*6 +Z)
                      obj_joint.scale = (A, A, A)
                      obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                      bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yo
                  obj_joint = bpy.data.objects["joint.copper.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n+1)+"o"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.gold.spine.y3y4"].copy()
          obj_joint.location = (0.0, 0.0, +Q*(1 - (3 % 2))*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y3y4.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  
  
  class RightIlium(LeftIlium):
  
      J = 5 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end, disciple_loc, disciple_rot, disciple):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple
          self.disciple = disciple
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master       
          self.setParent(self.helicity, self.move, self.rig, self.disciple_loc, self.disciple_rot, self.disciple)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A*0.6, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
          
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
  
          b[2] = mathutils.Euler(((A*3/0.431828)*A, (A/0.431828)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler(((-A/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
          print ("b3 =", b[3])
          
          y[2] = mathutils.Euler(((A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          y[3] = mathutils.Euler(((A/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
          print ("y3 =", y[3])
  
          o[2] = mathutils.Euler(((-A/0.431828)*A, (-A/0.431828)*A, 0.0), 'XYZ')
          print ("o2 =", o[2])
          
          o[3] = mathutils.Euler(((A/0.431828)*A, (2.53357/0.431828)*A, 0.0), 'XYZ')
          print ("o3 =", o[3])
          
          y[4] = mathutils.Euler(((A*3/0.431828)*A, (1.66503/0.431828)*A, 0.0), 'XYZ')
          print ("y4 =", y[4])
          
          
  class Leg(Formula):
  
      J = 7 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(4)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(1.25*self.A*0.8, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(1.25*self.A*0.8, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          o[1] = mathutils.Euler((A, A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
          
          b[2] = mathutils.Euler(((8.90101/0.45)*A, (-7.03036/0.45)*A, 0.0), 'XYZ')
          print ("b2 =", b[2])
  
          b[3] = mathutils.Euler(((7.90887/0.45)*A, (-8.44138/0.45)*A, 0.0), 'XYZ')
          print ("b3 =", b[3])
  
          b[4] = mathutils.Euler(((7.17232/0.45)*A, (-14.408/0.45)*A, 0.0), 'XYZ')
          print ("b4 =", b[4])
          
          b[5] = mathutils.Euler(((10.941/0.45)*A, (-18.1588/0.45)*A, 0.0), 'XYZ')
          print ("b5 =", b[5])
  
          y[2] = mathutils.Euler(((8.00326/0.45)*A, (-7.93191/0.45)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          y[3] = mathutils.Euler(((8.22152/0.45)*A, (-8.57337/0.45)*A, 0.0), 'XYZ')
          print ("y3 =", y[3])
  
          y[4] = mathutils.Euler(((8.9772/0.45)*A, (-17.0146/0.45)*A, 0.0), 'XYZ')
          print ("y4 =", y[4])
  
          y[5] = mathutils.Euler(((10.3029/0.45)*A, (-19.1128/0.45)*A, 0.0), 'XYZ')
          print ("y5 =", y[5])
  
          y[6] = mathutils.Euler(((11.0059/0.45)*A, (-20.2281/0.45)*A, 0.0), 'XYZ')
          print ("y6 =", y[6])
  
          o[2] = mathutils.Euler(((8.20021/0.45)*A, (-7.87145/0.45)*A, 0.0), 'XYZ')
          print ("o2 =", o[2])
  
          o[3] = mathutils.Euler(((9.42872/0.45)*A, (-8.42836/0.45)*A, 0.0), 'XYZ')
          print ("o3 =", o[3])
          
          o[4] = mathutils.Euler(((9.12426/0.45)*A, (-18.5453/0.45)*A, 0.0), 'XYZ')
          print ("o4 =", o[4])
          
          o[5] = mathutils.Euler(((10.6439/0.45)*A, (-19.2635/0.45)*A, 0.0), 'XYZ')
          print ("o5 =", o[5])
          
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          if part == 'leg-right':
              obj_joint = bpy.data.objects["joint.gold.a2a1.leg-right"].copy()
          else:
              obj_joint = bpy.data.objects["joint.gold.a2a1.leg-left"].copy()
          
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for n in range(1, J - 1):
  
              if n <= (J-2):
  
                  # Pattern 2 of by
                  obj_joint = bpy.data.objects["joint.green.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yy
                  obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
                  obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
  
              if n <= (J-3):
  
                  # Pattern 1 of ob
                  obj_joint = bpy.data.objects["joint.blue.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q*2 + Q*(n % 2)*6 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "o"+str(n)+"b"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
                  # Pattern 2 of yo
                  obj_joint = bpy.data.objects["joint.copper.001"].copy()
                  obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
                  obj_joint.scale = (A, A, A)
                  obj_joint.name = "y"+str(n+1)+"o"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
                  bpy.data.collections['link'].objects.link(obj_joint)
  
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
          
          
  class Sacrum(Formula):
  
      J = 3 #joint number
  
      # Overriding
      def __init__(self, P, A, move, part, helicity, start, end, 
          disciple_loc, disciple_rot, disciple):
  
          global interval
          global frame_start
          global frame_end
  
          self.interval = interval
          self.frame_start = frame_start
          self.frame_end = frame_end
  
          # pivot factor
          self.P = P
  
          # scale factor
          self.A = A 
  
          # name
          self.move = move
  
          # element
          self.part = part
  
          # element helicity
          self.helicity = helicity
  
          self.start = start
          self.end = end
  
          # disciple position
          self.disciple_loc = disciple_loc
          self.disciple_rot = disciple_rot
  
          # disciple
          self.disciple = disciple
  
          # Create armature and object
          self.amt = bpy.data.armatures.new(move + '.' + part + '.' + helicity + '.data')
          self.rig = bpy.data.objects.new(move + '.' + part + '.' + helicity, self.amt)
  
          # Joints
          self.a = [0 for i in range(self.J)] # Joint α
          self.b = [0 for i in range(self.J)] # Joint β
          self.y = [0 for i in range(self.J)] # Joint γ
          self.o = [0 for i in range(self.J)] # Joint δ
  
          # Configuration Movement
          self.configMovement(self.P, self.A, self.J, self.a, self.b, self.y, self.o)
  
          # Construction Movement
          self.constructMovement(self.J, self.helicity, self.amt, self.rig, self.a, self.b, self.y, self.o)
  
          # Parent set disciple to master
          self.setParent(self.helicity, self.move, self.rig,
              self.disciple_loc, self.disciple_rot, self.disciple)
  
          # Construction Rotation
          self.configRotation(self.rig, self.interval, self.frame_start, self.frame_end, self.start, self.end)
  
          # Configuration Linkage
          self.configLink(self.A, self.J, self.helicity, self.rig, self.move, self.part)
  
          # Construction Linkage
          self.constructLink(self.A, self.J, self.helicity, self.rig, self.move, self.part)
  
      # Overriding Configuration Movement
      def configMovement(self, P, A, J, a, b, y, o):
  
          a[1] = mathutils.Euler((P, A, 0.0), 'XYZ')
          print ("a1 =", a[1])
  
          a[2] = mathutils.Euler((A, -A, 0.0), 'XYZ')
          print ("a2 =", a[2])
  
          b[1] = mathutils.Euler((-A, A, 0.0), 'XYZ')
          print ("b1 =", b[1])
  
          B = A * 2 * sqrt (2)
          C = B + (B * sqrt (2))
          D = C * sqrt (2)
          E = C + D
  
          y[1] = mathutils.Euler((-A, -A, 0.0), 'XYZ')
          print ("y1 =", y[1])
          
          y[2] = mathutils.Euler((-A, -(0.173028/0.431828)*A, 0.0), 'XYZ')
          print ("y2 =", y[2])
  
          o[1] = mathutils.Euler(((-0.77453/0.431828)*A, -A, 0.0), 'XYZ')
          print ("o1 =", o[1])
  
      def constructMovement(self, J, helicity, amt, rig, a, b, y, o):
  
          # Linkages
          aa = [[0 for i in range(4)] for j in range(4)] # Link α(i) - α(j)
          ab = [[0 for i in range(4)] for j in range(4)] # Link α(i) - β(j)
          ya = [[0 for i in range(4)] for j in range(4)] # Link γ(i) - α(j)
          yy = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - γ(j)
          by = [[0 for i in range(self.J)] for j in range(self.J)] # Link β(i) - γ(j)
          yo = [[0 for i in range(self.J)] for j in range(self.J)] # Link γ(i) - δ(j)
  
          rig.location = mathutils.Euler((0.0, 0.0, 0.0), 'XYZ')
          rig.show_in_front = True
          amt.show_names = True
          amt.display_type = 'STICK'
  #        amt.display_type = 'BBONE'
  
          # Link object to scene
  
          bpy.data.collections['movement'].objects.link(rig)
          bpy.context.view_layer.objects.active = rig
          bpy.context.view_layer.update()
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          # Construction Linkage
          aa[2][1] = amt.edit_bones.new('a2a1')
          aa[2][1].head = a[2]
          aa[2][1].tail = a[1]
          
          ab[1][1] = amt.edit_bones.new('a1b1')
          ab[1][1].head = a[1]
          ab[1][1].tail = b[1]
          ab[1][1].parent = aa[2][1]
   
          by[1][1] = amt.edit_bones.new('b1y1')
          by[1][1].head = b[1]
          by[1][1].tail = y[1]
          by[1][1].parent = ab[1][1]
          by[1][1].use_inherit_rotation = False
  
          ya[1][2] = amt.edit_bones.new('y1a2')
          ya[1][2].head = y[1]
          ya[1][2].tail = a[2]
          ya[1][2].parent = by[1][1]
  
          yo[1][1] = amt.edit_bones.new('y1o1')
          yo[1][1].head = y[1]
          yo[1][1].tail = o[1]
          yo[1][1].parent = ya[1][2]
     
          yy[1][2] = amt.edit_bones.new('y1y2')
          yy[1][2].head = y[1]
          yy[1][2].tail = y[2]
          yy[1][2].parent = by[1][1]
  
          # all bones select
  
          # Bone constraints. Armature must be in pose mode.
          bpy.ops.object.mode_set(mode='POSE')
  
          bpy.ops.pose.select_all(action="SELECT")
  
          # Edit
          bpy.ops.object.editmode_toggle()
  
          if helicity == 'right':
              bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Z')
          else:
              bpy.ops.armature.calculate_roll(type='GLOBAL_NEG_Z')
   
          # IK constraint
          cns = rig.pose.bones['y1a2'].constraints.new('IK')
          cns.name = 'Ik'
          cns.target = rig
          cns.subtarget = 'a2a1'
          cns.chain_count = 2
          cns.use_stretch = False
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
      # Parent set disciple to master
      def setParent(self, helicity, move, rig, disciple_loc, disciple_rot, disciple):
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.context.scene.frame_current = 0
  
          bpy.ops.object.select_all(action='DESELECT')
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig
  
          bpy.ops.object.editmode_toggle()
  
          parent_bone = 'y1o1' # choose the bone name which you want to be the parent
  
          rig.data.edit_bones.active = rig.data.edit_bones[parent_bone]
  
          bpy.ops.object.mode_set(mode='OBJECT')
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          disciple.rig.select_set(state=True)
  
          rig.select_set(state=True)
          bpy.context.view_layer.objects.active = rig    #the active object will be the parent of all selected object
  
          bpy.ops.object.parent_set(type='BONE', keep_transform=True)
  
          bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
          # disciple position
          disciple.rig.location.x += disciple_loc[0]
          disciple.rig.location.y += disciple_loc[1]
          disciple.rig.location.z += disciple_loc[2]
  
          disciple.rig.rotation_euler = disciple_rot
  
      def configLink(self, A, J, helicity, rig, move, part):
  
          bpy.ops.object.mode_set(mode='OBJECT')
      
          Q = (0.18648+0.146446)*A
      #   Z = -Q*2
          Z = 0.0
  
          obj_joint = bpy.data.objects["joint.gold.000"].copy()
          obj_joint.location = (0.0, 0.0, -Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a2a1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.silver.001"].copy()
          obj_joint.location = (0.0, 0.0, +Q+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1a2.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.copper.y1o1.sacrum.B"].copy()
          obj_joint.location = (0.0, 0.0, +Q*3+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y1o1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          obj_joint = bpy.data.objects["joint.blue.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "a1b1.mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          n = 1
  
          # Pattern 2 of by
          obj_joint = bpy.data.objects["joint.green.001"].copy()
          obj_joint.location = (0.0, 0.0, -Q + Q*((n+1) % 2)*4 +Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "b"+str(n)+"y"+str(n)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          # Pattern 2 of yy
          obj_joint = bpy.data.objects["joint.gold.00"+str(1 + (n+1) % 2)].copy()
          obj_joint.location = (0.0, 0.0, +Q*(1 - (n % 2))*2+Z)
          obj_joint.scale = (A, A, A)
          obj_joint.name = "y"+str(n)+"y"+str(n+1)+".mesh." + move + '.' + part +'.' + helicity
          bpy.data.collections['link'].objects.link(obj_joint)
  
          for ob in data.collections['link'].objects:
              if "mesh" in ob.name:
                  ob.select_set(state = True, view_layer = None)
  
          bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', object=True, obdata=True, material=True, animation=True)
          bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
          bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  
  
  def formula():
  
  # pivot factor
      P = 0
  
  # scale factor
      A = 1
      
  # joint number
      J = 6
      
  # name
      move = 'formula'
  
  # element
      part = 'universe'
  
  # left or right
      helicity = 'left'
  
      start = 0
      end = start+360
  
      formula = Formula(P, A, J, move, part, helicity, start, end)
  
  
  def hands():
  
  # name
      move = 'butterfly-stroke'
  
      # scale factor
      A = 0.107
  
      # pivot factor
      P = -0.048266
  
  # config nonlocal
      global middle_left
      global middle_right
  
  # finger element
      part = 'middle-left'
  
  # phalanx length
      y2 = mathutils.Euler((1.427, -1.08668, 0.0), 'XYZ')
      y3 = mathutils.Euler((2.15534, -1.56395, 0.0), 'XYZ')
      y4 = mathutils.Euler((2.67012, -1.90121, 0.0), 'XYZ')
      y5 = mathutils.Euler((2.90459, -2.05473, 0.0), 'XYZ')
  
  # left finger element
      helicity = 'left'
  
      start = 0.0
      end = start+720
  
      middle_left = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)
      
      middle_left.rig.location = (0.0, 0.0, 0.0)
      middle_left.rig.rotation_euler = mathutils.Euler((math.radians(0), math.radians(0), math.radians(0)), 'XYZ')
  
  # finger element
      part = 'middle-right'
  
  # right finger element
      helicity = 'right'
  
      start = 0.0
      end = start-720
  
      middle_right = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)    
  
      middle_right.rig.location = (0.0, 0.0, 0.0)
      middle_right.rig.rotation_euler = mathutils.Euler((math.radians(180-0), math.radians(0), math.radians(0)), 'XYZ')
  
  
  # finger element
      part = 'ring-left'
  
      y2 = mathutils.Euler((1.36978, -1.04933, 0.0), 'XYZ')
      y3 = mathutils.Euler((2.16696, -1.57161, 0.0), 'XYZ')
      y4 = mathutils.Euler((2.63809, -1.8803, 0.0), 'XYZ')
      y5 = mathutils.Euler((2.87256, -2.03382, 0.0), 'XYZ')
  
  # left finger element
      helicity = 'left'
  
      start = 0.0
      end = start+720
  
      ring_left = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)
  
      ring_left.rig.location = (-0.010689, 0.001192, 0.241051)
      ring_left.rig.rotation_euler = mathutils.Euler((math.radians(-5.10153), math.radians(-1.70737), math.radians(0.02464)), 'XYZ')
  
  # finger element
      part = 'ring-right'
  
  # right finger element
      helicity = 'right'
  
      start = 0.0
      end = start-720
  
      ring_right = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)    
  
      ring_right.rig.location = (-0.010689, -0.001192, 0.241051)
      ring_right.rig.rotation_euler = mathutils.Euler((math.radians(180+5.10153), math.radians(-1.70737), math.radians(-0.02464)), 'XYZ')
  
  
  # finger element
      part = 'little-left'
      
      y2 = mathutils.Euler((1.45986, -1.08525, 0.0), 'XYZ')
      y3 = mathutils.Euler((2.10861, -1.50077, 0.0), 'XYZ')
      y4 = mathutils.Euler((2.5324, -1.77219, 0.0), 'XYZ')
      y5 = mathutils.Euler((2.72302, -1.89418, 0.0), 'XYZ')
  
  # left finger element
      helicity = 'left'
  
      start = 0.0
      end = start+720
  
      little_left = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)
  
      little_left.rig.location = (-0.020568, 0.002289, 0.463882)
      little_left.rig.rotation_euler = mathutils.Euler((math.radians(-10.1646), math.radians(-2.09755), math.radians(-0.518101)), 'XYZ')
  
  # finger element
      part = 'little-right'
  
  # right finger element
      helicity = 'right'
  
      start = 0.0
      end = start-720
  
      little_right = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)
  
      little_right.rig.location = (-0.020568, -0.002289, 0.463882)
      little_right.rig.rotation_euler = mathutils.Euler((math.radians(180+10.1646), math.radians(-2.09755), math.radians(0.518101)), 'XYZ')
  
  
  # finger element
      part = 'index-left'
  
      y2 = mathutils.Euler((1.36561, -1.0465, 0.0), 'XYZ')
      y3 = mathutils.Euler((2.0559, -1.49887, 0.0), 'XYZ')
      y4 = mathutils.Euler((2.52701, -1.80756, 0.0), 'XYZ')
      y5 = mathutils.Euler((2.76149, -1.96108, 0.0), 'XYZ')
  
  # left finger element
      helicity = 'left'
  
      start = 0.0
      end = start+720
  
      index_left = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)
  
      index_left.rig.location = (0.012703, -0.00141, -0.286505)
      index_left.rig.rotation_euler = mathutils.Euler((math.radians(2.53073), math.radians(2.85122), math.radians(0.320067)), 'XYZ')
  
  # finger element
      part = 'index-right'
  
  # right finger element
      helicity = 'right'
  
      start = 0.0
      end = start-720
  
      index_right = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)
  
      index_right.rig.location = (0.012703, 0.00141, -0.286505)
      index_right.rig.rotation_euler = mathutils.Euler((math.radians(180-2.53073), math.radians(2.85122), math.radians(-0.320067)), 'XYZ')
  
  
  # finger element
      part = 'thumb-left'
  
      P = -0.075869 #pivot factor
  
      y2 = mathutils.Euler((0.265988, -0.219792, 0.0), 'XYZ')
      y3 = mathutils.Euler((1.0999, -0.768173, 0.0), 'XYZ')
      y4 = mathutils.Euler((1.71494, -1.17263, 0.0), 'XYZ')
      y5 = mathutils.Euler((1.97601, -1.3443, 0.0), 'XYZ')
  
  # left finger element
      helicity = 'left'
  
      start = 0.0
      end = start+720
  
      thumb_left = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)
  
      thumb_left.rig.location = (0.009956, -0.090396, -0.3247)
      thumb_left.rig.rotation_euler = mathutils.Euler((math.radians(87.8968), math.radians(-3.16487), math.radians(-23.1096)), 'XYZ')
  
  # finger element
      part = 'thumb-right'
  
  # right finger element
      helicity = 'right'
  
      start = 0.0
      end = start-720
  
      thumb_right = Finger(P, A, move, part, helicity, start, end, y2, y3, y4, y5)
  
      thumb_right.rig.location = (0.009956, 0.090396, -0.3247)
      thumb_right.rig.rotation_euler = mathutils.Euler((math.radians(180-87.8968), math.radians(-3.16487), math.radians(23.1096)), 'XYZ')
  
  
  # Parent set four fingers to middle finger
      bpy.ops.object.mode_set(mode='OBJECT')
  
      bpy.context.scene.frame_current = 0
  
  # left hand
      bpy.ops.object.select_all(action='DESELECT')
      middle_left.rig.select_set(state=True)
      bpy.context.view_layer.objects.active = middle_left.rig
  
      bpy.ops.object.editmode_toggle()
  
      parent_bone = 'a2a1' # choose the bone name which you want to be the parent
  
      middle_left.rig.data.edit_bones.active = middle_left.rig.data.edit_bones[parent_bone]
  
      bpy.ops.object.mode_set(mode='OBJECT')
  
      bpy.ops.object.select_all(action='DESELECT') #deselect all objects
      ring_left.rig.select_set(state=True)
      little_left.rig.select_set(state=True)
      index_left.rig.select_set(state=True)
      thumb_left.rig.select_set(state=True)
      middle_left.rig.select_set(state=True)
      bpy.context.view_layer.objects.active = middle_left.rig    #the active object will be the parent of all selected object
  
      bpy.ops.object.parent_set(type='BONE', keep_transform=True)
  
  # right hand
      bpy.ops.object.select_all(action='DESELECT') #deselect all objects
      middle_right.rig.select_set(state=True)
      bpy.context.view_layer.objects.active = middle_right.rig
  
      bpy.ops.object.editmode_toggle()
  
      parent_bone = 'a2a1' # choose the bone name which you want to be the parent
  
      middle_right.rig.data.edit_bones.active = middle_right.rig.data.edit_bones[parent_bone]
  
      bpy.ops.object.mode_set(mode='OBJECT')
  
      bpy.ops.object.select_all(action='DESELECT') #deselect all objects
      ring_right.rig.select_set(state=True)
      little_right.rig.select_set(state=True)
      index_right.rig.select_set(state=True)
      thumb_right.rig.select_set(state=True)
      middle_right.rig.select_set(state=True)
      bpy.context.view_layer.objects.active = middle_right.rig    #the active object will be the parent of all selected object
  
      bpy.ops.object.parent_set(type='BONE', keep_transform=True)
  
      bpy.ops.object.select_all(action='DESELECT') #deselect all objects
  
  
  def wrists():
      
  # scale factor
      A = 0.351
      
  # pivot factor
      P = 0
  
  # name
      move = 'butterfly-stroke'
  
  
  # wrist element
      part = 'wrist-left'
  
  # helicity
      helicity = 'left'
  
      start = -180
      end = start+720
  
      fingers_loc = ((0.220934/0.351)*A, (-0.44811/0.351)*A, (0.0/0.351)*A)
      fingers_rot = mathutils.Euler((math.radians(183.232), math.radians(-1.67988), math.radians(218.587)), 'XYZ')
  
      global middle_left
      middle_finger = middle_left
      
      global wrist_left
      wrist_left = Wrist(P, A, move, part, helicity, start, end, fingers_loc, fingers_rot, middle_finger)
  
  
  # right wrist element
      part = 'wrist-right'
  
  # helicity
      helicity = 'left'
  
      start = -180
      end = start+720
      
      fingers_loc = ((0.221547/0.351)*A, (-0.44811/0.351)*A, (0.0/0.351)*A)
      fingers_rot = mathutils.Euler((math.radians(-4.00983), math.radians(-180.839), math.radians(38.4748)), 'XYZ')
  
      global middle_right
      middle_finger = middle_right
      
      global wrist_right
      wrist_right = Wrist(P, A, move, part, helicity, start, end, fingers_loc, fingers_rot, middle_finger)
  
  
  def arms():
  
  # scale factor
      A = 0.421838
  
  # pivot factor
      P = 0.0
  
  # name
      move = 'butterfly-stroke'
  
  # arm element
      part = 'arm-left'
  
  # left arm element
      helicity = 'left'
  
      start = 90
      end = start-720
  
      wrist_loc = ((8.47909/0.421838)*A, (-7.96666/0.421838)*A, (0.062914/0.421838)*A)
      wrist_rot = mathutils.Euler((math.radians(4.90343), math.radians(365.395), math.radians(-326.5)), 'XYZ')
  
      global wrist_left
      wrist = wrist_left
  
      global arm_left
      arm_left = Arm(P, A, move, part, helicity, start, end, wrist_loc, wrist_rot, wrist)
  
  # arm element
      part = 'arm-right'
  
  # right arm element
      helicity = 'right'
  
      start = -90
      end = start+720
  
      wrist_loc = ((8.47903/0.421838)*A, (-7.96571/0.421838)*A, (-0.062896/0.421838)*A)
      wrist_rot = mathutils.Euler((math.radians(-183.771), math.radians(185.66), math.radians(-146.521)), 'XYZ')
  
      global wrist_right
      wrist = wrist_right
  
      global arm_right
      arm_right = Arm(P, A, move, part, helicity, start, end, wrist_loc, wrist_rot, wrist)
  
  
  def wings():
  
  # scale factor
      A = 0.276443
  
  # pivot factor
      P = 0.0
      
  # name
      move = 'butterfly-stroke'
  
  # element
      part = 'wing-left'
  
  # left or right
      helicity = 'right'
  
      start = 0
      end = start+720
      
      global arm_left
  
      arm_loc = ((-0.954287/0.276443)*A, (-1.83997/0.276443)*A, (-0.930181/0.276443)*A)
      arm_rot = mathutils.Euler((math.radians(457.937), math.radians(12.8696), math.radians(-288.261)), 'XYZ')
  
      global wing_left
      wing_left = Wing(P, A, move, part, helicity, start, end,
              arm_loc, arm_rot, arm_left)
  
  # element
      part = 'wing-right'
  
  # left or right
      helicity = 'left'
  
      start = 0
      end = start-720
  
      global arm_right
  
      arm_loc = ((-0.955332/0.276443)*A, (-1.84346/0.276443)*A, (0.932282/0.276443)*A)
      arm_rot = mathutils.Euler((math.radians(-97.9361), math.radians(-12.8712), math.radians(71.7387)), 'XYZ')
  
      global wing_right
      wing_right = Wing(P, A, move, part, helicity, start, end,
              arm_loc, arm_rot, arm_right)
  
  
  def neck():
  
  # scale factor
      A = 0.747868
  
  # pivot factor
      P = 0
      
  # name
      move = 'butterfly-stroke'
  
  # element
      part = 'neck'
  
  # left or right
      helicity = 'left'
  
      start = -90
      end = start+720
  
      global neck
      neck = Neck(P, A, move, part, helicity, start, end)
  
  
  def shoulder():
  
      start = 0
      end = start
  
  # name
      move = 'butterfly-stroke'
      
  # scale factor
      A = 0.431828
  
  # pivot factor
      P = (-0.132154/0.431828)*A
  
  # element
      part = 'left-shoulder'
  
  # left or right
      helicity = 'left'
  
      global wing_left
      wing = wing_left
  
  #    wing_loc = ((3.02945/0.431828)*A, (2.19805/0.431828)*A, (1.18803/0.431828)*A)
      wing_loc = ((3.13634/0.431828)*A, (1.66209/0.431828)*A, (1.83474/0.431828)*A)
      wing_rot = mathutils.Euler((math.radians(90), math.radians(10.8), math.radians(0.0)), 'XYZ')
  
      global shoulder_left
      shoulder_left = LeftShoulder(P, A, move, part, helicity, start, end,
          wing_loc, wing_rot, wing)
  
  # element
      part = 'right-shoulder'
  
      global wing_right
      wing = wing_right
  
  #    wing_loc = ((2.8999/0.431828)*A, (-1.74019/0.431828)*A, (0.791003/0.431828)*A)
      wing_loc = ((3.13667/0.431828)*A, (-2.52172/0.431828)*A, (1.83588/0.431828)*A)
      wing_rot = mathutils.Euler((math.radians(90), math.radians(10.8), math.radians(-360)), 'XYZ')
  
      global shoulder_right
      shoulder_right = RightShoulder(P, A, move, part, helicity, start, end,
          wing_loc, wing_rot, wing)
  
  
  def costa():
  
  # scale factor
      A = 0.905211
  
  # pivot factor
      P = (-0.680016/0.905211)*A
      
  # name
      move = 'butterfly-stroke'
  
  # element
      part = 'costa'
  
  # left or right
      helicity = 'left'
  
      start = 0
      end = start
  
      global shoulder_left
      global shoulder_right
  
  #    shoulder_loc = ((-4.04079/0.905211)*A, (-0.437921/0.905211)*A, (-0.00634/0.905211)*A)
      shoulder_loc = ((-3.20023/0.905211)*A, (-0.470447/0.905211)*A, (-2.85518/0.905211)*A)
      shoulder_rot = mathutils.Euler((math.radians(180), math.radians(266.769), math.radians(-180)), 'XYZ')
  
      global neck
  
      neck_loc = ((-3.79402/0.905211)*A, (-0.912465/0.905211)*A, (-0.67128/0.905211)*A)
      neck_rot = mathutils.Euler((math.radians(270), math.radians(0.0), math.radians(0.0)), 'XYZ')
  
      global costa
      costa = Costa(P, A, move, part, helicity, start, end,
          shoulder_loc, shoulder_rot, shoulder_left, shoulder_right,
          neck_loc, neck_rot, neck)
  
  
  def legs():
  
  # scale factor
      A = 0.45
  
  # pivot factor
      P = (-0.15/0.45)*A
      
  # name
      move = 'butterfly-stroke'
  
  # element
      part = 'leg-left'
  
  # left or right
      helicity = 'left'
  
      start = 0
      end = start-360*4
  
      global leg_left
      leg_left = Leg(P, A, move, part, helicity, start, end)
  
  # element
      part = 'leg-right'
  
  # left or right
      helicity = 'left'
  
      global leg_right
      leg_right = Leg(P, A, move, part, helicity, start, end)
  
  
  def ilium():
  
  # scale factor
      A = 0.431828
  
  # pivot factor
      P = (-0.394368/0.431828)*A
      
  # name
      move = 'butterfly-stroke'
  
  # element
      part = 'ilium-left'
  
  # left or right
      helicity = 'left'
  
      start = 0
      end = start
  
      global leg_left
  
      leg = leg_left
  
      leg_loc = ((0.449371/0.431828)*A, (-2.72434/0.431828)*A, (-2.60798/0.431828)*A)
      leg_rot = mathutils.Euler((math.radians(-90), math.radians(81.2159), math.radians(360)), 'XYZ')
  
      global ilium_left
      ilium_left = LeftIlium(P, A, move, part, helicity, start, end, leg_loc, leg_rot, leg)
  
  # element
      part = 'ilium-right'
      
      global leg_right
      
      leg = leg_right
  
      leg_loc = ((0.456231/0.431828)*A, (1.878/0.431828)*A, (-2.5617/0.431828)*A)
      leg_rot = mathutils.Euler((math.radians(-270), math.radians(98.7841), math.radians(180)), 'XYZ')
  
      global ilium_right
      ilium_right = RightIlium(P, A, move, part, helicity, start, end, leg_loc, leg_rot, leg)
  
  
  def spine():
  
  # scale factor
      A = 0.578724
  
  # pivot factor
      P = (-0.434043/0.578724)*A
      
  # name
      move = 'butterfly-stroke'
  
  # element
      part = 'spine'
  
  # left or right
      helicity = 'left'
  
      start = 0
      end = start-720
  
      global costa
      global ilium_left
      global ilium_right
  
      costa_loc = ((-1.21214/0.578724)*A, (0.065733/0.578724)*A, (0.898559/0.578724)*A)
      costa_rot = mathutils.Euler((math.radians(-269.418), math.radians(0.102854), math.radians(-46.0784)), 'XYZ')
  
      ilium_loc = ((5.9265/0.578724)*A, (-3.83625/0.578724)*A, (-0.429515/0.578724)*A)
      ilium_rot = mathutils.Euler((math.radians(-90), math.radians(0), math.radians(330.958)), 'XYZ')
  
      global spine
      spine = Spine(P, A, move, part, helicity, start, end,
          costa_loc, costa_rot, costa, ilium_loc, ilium_rot, ilium_left, ilium_right)
  
  def sacrum():
  
  # scale factor
      A = 0.431828
  
  # pivot factor
      P = (-0.054239/0.431828)*A
      
  # name
      move = 'butterfly-stroke'
  
  # element
      part = 'sacrum'
  
  # left or right
      helicity = 'left'
  
      start = 222
      end = start
  
      global spine
  
      spine_loc = ((-2.13769/0.431828)*A, (-0.411599/0.431828)*A, (9.19501/0.431828)*A)
      spine_rot = mathutils.Euler((math.radians(-270), math.radians(60), math.radians(180)), 'XYZ')
  
      global sacrum
      sacrum = Sacrum(P, A, move, part, helicity, start, end,
          spine_loc, spine_rot, spine)
  
      sacrum_loc = ((0.407279/0.431828)*A, (10.8952/0.431828)*A, (13.6722/0.431828)*A)
      sacrum_rot = mathutils.Euler((math.radians(90.0), math.radians(86.0913), math.radians(0.0)), 'XYZ')
  
      # position
      sacrum.rig.location.x += sacrum_loc[0]
      sacrum.rig.location.y += sacrum_loc[1]
      sacrum.rig.location.z += sacrum_loc[2]
  
      sacrum.rig.rotation_euler = sacrum_rot
  
  
  def main(origin):
      
      # create new collection
      newCol = bpy.data.collections.new('movement')
      # link the newCol to the scene
      bpy.context.scene.collection.children.link(newCol)
  
      newCol = bpy.data.collections.new('link')
      bpy.context.scene.collection.children.link(newCol)
  
      global interval
      global frame_start
      global frame_end
  
      frame_start = 0
      frame_end = 240
  
      interval = frame_end - frame_start
  
  #    formula()
      hands()
      wrists()
      arms()
      wings()
      neck()
      shoulder()
      costa()
      legs()
      ilium()
      spine()
      sacrum()
  
  if __name__ == "__main__":
      # renaming of corrada objects
  #    for ob in context.collection.objects:
  #        if "joint_" in ob.name:
  #            ob.name = ob.name.replace("_", ".")
              
      main((0.0, 0.0, 0.0))
  