my_functions.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. '''
  2. file that contains some functions that I don't
  3. want to re-write on each individual .py file
  4. '''
  5. import bpy, math, re
  6. from mathutils import Matrix
  7. ################################################
  8. # show message on screen for errors or warnnings
  9. # copied this code from a page I saw it in :)
  10. ################################################
  11. def show_message(message = "", title = "Message Box", icon = 'INFO'):
  12. #
  13. def draw(self, context):
  14. self.layout.label(text=message)
  15. bpy.context.window_manager.popup_menu(draw, title = title, icon = icon)
  16. #
  17. #######################################
  18. # calc_scale_matrix function
  19. # function to build the scale matrix
  20. #
  21. # x_scale (float) --> scaling in X axis
  22. # y_scale (float) --> scaling in Y axis
  23. # z_scale (float) --> scaling in Z axis
  24. #######################################
  25. def calc_scale_matrix(x_scale, y_scale, z_scale):
  26. #
  27. scale_matrix = Matrix(( [x_scale, 0, 0, 0],
  28. [0, y_scale, 0, 0],
  29. [0, 0, z_scale, 0],
  30. [0, 0, 0, 1]
  31. ))
  32. return scale_matrix
  33. #
  34. ###################################################
  35. # calc_rotation_matrix function
  36. # function to calculate the rotation matrix
  37. # for a Extrinsic Euler XYZ system
  38. #
  39. # x_angle (float) --> rot angle in X axis (radians)
  40. # y_angle (float) --> rot angle in Y axis (radians)
  41. # z_angle (float) --> rot angle in > axis (radians)
  42. ###################################################
  43. def calc_rotation_matrix(x_angle, y_angle, z_angle):
  44. #
  45. x_rot_mat = Matrix(([1, 0, 0, 0],
  46. [0, math.cos(x_angle), -math.sin(x_angle), 0],
  47. [0, math.sin(x_angle), math.cos(x_angle), 0],
  48. [0, 0, 0, 1]))
  49. y_rot_mat = Matrix(([math.cos(y_angle), 0, math.sin(y_angle), 0],
  50. [0, 1, 0, 0],
  51. [-math.sin(y_angle), 0, math.cos(y_angle), 0],
  52. [0, 0, 0, 1]))
  53. z_rot_mat = Matrix(([math.cos(z_angle), -math.sin(z_angle), 0, 0],
  54. [math.sin(z_angle), math.cos(z_angle), 0, 0],
  55. [0, 0, 1, 0],
  56. [0, 0, 0, 1]))
  57. return z_rot_mat * y_rot_mat * x_rot_mat
  58. #
  59. #################################################
  60. # calc_translation_matrix function
  61. # function to build the translation matrix
  62. #
  63. # x_translation (float) --> translation in X axis
  64. # y_translation (float) --> translation in Y axis
  65. # z_translation (float) --> translation in Z axis
  66. #################################################
  67. def calc_translation_matrix(x_translation, y_translation, z_translation):
  68. #
  69. translation_matrix = Matrix(( [1, 0, 0, x_translation],
  70. [0, 1, 0, y_translation],
  71. [0, 0, 1, z_translation],
  72. [0, 0, 0, 1]
  73. ))
  74. return translation_matrix
  75. #
  76. ##############################################################
  77. # interpolate function
  78. # used to find a value in an interval with the specified mode.
  79. # So that it is clear that the values are points that have 2
  80. # coordinates I will treat the input as they are (x,y) points
  81. # the function will either return m_x or m_y depending on
  82. # which of the middle point values is provided to the function
  83. # (set None to the variable going to be returned by the
  84. # function). Only linear interpolation is supported for now.
  85. #
  86. # l_x (float) --> left point X axis component
  87. # l_y (float) --> left point Y axis component
  88. # r_x (float) --> right point X axis component
  89. # r_y (float) --> right point Y axis component
  90. # m_x (float) --> middle point X axis component
  91. # m_y (float) --> middle point Y axis component
  92. # interp_type (string) --> "linear" for linear interpolation
  93. ##############################################################
  94. def interpolate(l_x, l_y, r_x, r_y, m_x, m_y, interp_type):
  95. #
  96. # variable to be returned
  97. result = 0
  98. ##############################################
  99. # if right point does not exist (special case)
  100. # return l_y as the interpolation result
  101. if (r_x == None or r_y == None):
  102. result = l_y
  103. return result
  104. ###############################
  105. # m_x is the one to be returned
  106. if (m_x == None):
  107. # linear interpolation
  108. if (interp_type == "linear"):
  109. m_x = (((r_x - l_x) / (r_y - l_y)) * (m_y - r_y)) + r_x
  110. result = m_x
  111. ###############################
  112. # m_y is the one to be returned
  113. if (m_y == None):
  114. # linear interpolation
  115. if (interp_type == "linear"):
  116. m_y = (((r_y - l_y) / (r_x - l_x)) * (m_x - r_x)) + r_y
  117. result = m_y
  118. return result
  119. #
  120. ####################################################################
  121. # find_left_right function
  122. # find the values and positions of the elements at the left and the
  123. # right of the element in position pos on the anim_array
  124. # elements will be used in the interpolate() function later
  125. #
  126. # anim_array (array of floats) --> anim property frame array its
  127. # length must the animation length
  128. # pos (int) --> position of the animation property value to be
  129. # later interpolated in the anim_array array
  130. ####################################################################
  131. def find_left_right(anim_array, pos):
  132. #
  133. #############################
  134. # create left/right variables
  135. l_val = 0
  136. l_val_pos = 0
  137. r_val = 0
  138. r_val_pos = 0
  139. #####################################
  140. # find near left value (has to exist)
  141. # read array from right to left
  142. for i in range(len(anim_array), -1, -1):
  143. #
  144. # skip elements at the right of
  145. # pos in anim_array
  146. if (i >= pos):
  147. continue
  148. # left value is found
  149. if (anim_array[i] != None):
  150. l_val = anim_array[i]
  151. l_val_pos = i
  152. break
  153. #
  154. ##############
  155. # special case
  156. ##############
  157. # if pos is the last element position on
  158. # the array r_val and r_val_pos do not exist
  159. if (pos == (len(anim_array) - 1)):
  160. return [l_val_pos, l_val, None, None]
  161. #########################################
  162. # find near right value (might not exist)
  163. # read array from left to right
  164. for i in range(len(anim_array)):
  165. #
  166. # skip elements at the left of
  167. # pos in anim_array
  168. if (i <= pos):
  169. continue
  170. # right value is found
  171. if (anim_array[i] != None):
  172. r_val = anim_array[i]
  173. r_val_pos = i
  174. break
  175. # if no value is found at the end of
  176. # the anim_array r_val and r_val_pos do not exist
  177. # (value does not change between the left value
  178. # found and the end of the animation)
  179. if (i == (len(anim_array) - 1)):
  180. return [l_val_pos, l_val, None, None]
  181. #
  182. # if all values are found, return them
  183. return [l_val_pos, l_val, r_val_pos, r_val]
  184. #
  185. #######################################################
  186. # convert_angle_to_180 function
  187. # function used by the convert_anim_rot_to_180 function
  188. # to convert a single angle in its representation on
  189. # the -180/+180 degree range (angles passed to the
  190. # function that are already in this range will be
  191. # returned without conversion)
  192. #
  193. # angle (float) --> angle to convert to the -180/+180
  194. # degree range (angle is expected to
  195. # be in degrees)
  196. #######################################################
  197. def convert_angle_to_180(angle):
  198. #
  199. # check if the angle really needs to be processed
  200. # i.e. is already inside the -180/+180 degree range
  201. if (angle >= -180 and angle <= 180):
  202. return angle
  203. # convert it otherwise
  204. # check if it is positive or negative
  205. # and set the opposite direction of the angle
  206. # if the angle is > 0 then its mesurement is clockwise (opposite is counter-clockwise)
  207. # if the angle is < 0 then its mesurement is counter-clockwise (opposite is clockwise)
  208. if (angle > 0):
  209. opposite_spin_dir = -1
  210. else: # it is negative
  211. opposite_spin_dir = 1
  212. # decrease the angle by 360 degrees until it
  213. # is in the -180/+180 degree interval
  214. while (abs(angle) > 180):
  215. angle = angle + (opposite_spin_dir * 360)
  216. return angle
  217. #
  218. ###############################################################
  219. # convert_anim_rot_to_180 function
  220. # used to re-calculate a rotation animation on an axis
  221. # so that angles used lay in between -180/180 degrees
  222. # done to avoid rotation animation data loss when extracting
  223. # said angles from a transformation matrix
  224. # this function calls the convert_angle_to_180() function
  225. # at the end of the function csv_keyframe_numbers is updated
  226. # with the new frames to be injected into the animation
  227. #
  228. # example:
  229. #
  230. # Original keyframes:
  231. # Frame 0 Frame 21 (2 keyframes)
  232. # 0º 360º
  233. #
  234. # Processed keyframes:
  235. # Frame 0 Frame 10 Frame 11 Frame 21 (4 keyframes)
  236. # 0º 171.4º -171.5º 0º
  237. #
  238. # rot_array (array of floats) --> bone rotation animation data
  239. # for a single axis
  240. # csv_keyframe_numbers (array of ints) --> original keyframes
  241. # of the animation
  242. #
  243. # Note: function will have problems interpreting keyframes with
  244. # high rotation diferences if the number of frames in
  245. # between said keyframes in lower than 2 times the spins
  246. # done in between those keyframe angles (thinking a fix)
  247. ###############################################################
  248. def convert_rot_anim_to_180(rot_array, csv_keyframe_numbers):
  249. #
  250. # temp rot array to store calculated values and keyframe position
  251. rot_array_cp = [[], []]
  252. # find the frames in which rot_array has values defined
  253. rot_array_kf = []
  254. for i in range(len(rot_array)):
  255. if (rot_array[i] != None):
  256. rot_array_kf.append(i)
  257. ###########################################################################
  258. # loop through each consecutive pair of keyframes of the rot_array_kf array
  259. for i in range(len(rot_array_kf) - 1):
  260. #
  261. # get left/right keyframe values and positions
  262. l_kf_pos = rot_array_kf[i]
  263. l_kf_val = rot_array[l_kf_pos]
  264. r_kf_pos = rot_array_kf[i + 1]
  265. r_kf_val = rot_array[r_kf_pos]
  266. # append l_kf_val to rot_array_cp (converted)
  267. rot_array_cp[0].append(l_kf_pos)
  268. rot_array_cp[1].append(convert_angle_to_180(l_kf_val))
  269. # get the rotation direction
  270. if (r_kf_val > l_kf_val): # clockwise
  271. rot_direction = 1
  272. else: # counter-clockwise
  273. rot_direction = -1
  274. ##############################################################
  275. # advance -180/+180 (depending on the rotation direction)
  276. # and generate the middle keyframe values
  277. # angle is fixed to the l_kf_val's closest 360 degree multiple
  278. angle_val = l_kf_val - convert_angle_to_180(l_kf_val)
  279. while (abs(r_kf_val - angle_val) > 180):
  280. #
  281. angle_val = angle_val + (rot_direction * 180)
  282. # find the frame (float) in which this value exists
  283. angle_pos = interpolate(l_kf_pos, l_kf_val, r_kf_pos, r_kf_val, None, angle_val, "linear")
  284. ############################################
  285. # find the 2 frames (integer) that are lower
  286. # and upper limits of this angle_pos
  287. lower_frame = int(angle_pos)
  288. upper_frame = int(angle_pos + 1)
  289. ###############################################################
  290. # interpolate to find the values on lower_frame and upper_frame
  291. lower_frame_value = convert_angle_to_180(interpolate(l_kf_pos, l_kf_val, r_kf_pos, r_kf_val, lower_frame, None, "linear"))
  292. upper_frame_value = convert_angle_to_180(interpolate(l_kf_pos, l_kf_val, r_kf_pos, r_kf_val, upper_frame, None, "linear"))
  293. ################################
  294. # append results to rot_array_cp
  295. # keyframes
  296. rot_array_cp[0].append(lower_frame)
  297. rot_array_cp[0].append(upper_frame)
  298. # values
  299. rot_array_cp[1].append(lower_frame_value)
  300. rot_array_cp[1].append(upper_frame_value)
  301. #
  302. #
  303. ##########################################
  304. # add the new keyframe values to rot_array
  305. # on their respective frame position
  306. for i in range(len(rot_array_cp[0])):
  307. rot_array[rot_array_cp[0][i]] = rot_array_cp[1][i]
  308. #######################################################
  309. # update the keyframes on csv_keyframe_numbers to store
  310. # the calculated keyframes numbers from rot_array_cp[0]
  311. # append those at the end of csv_keyframe_numbers
  312. for i in range(len(rot_array_cp[0])):
  313. value_found = False
  314. for j in range(len(csv_keyframe_numbers)):
  315. if (rot_array_cp[0][i] == csv_keyframe_numbers[j]):
  316. value_found = True
  317. break
  318. if (value_found == False):
  319. csv_keyframe_numbers.append(rot_array_cp[0][i])
  320. #