Commit e48ef0c6f4ac799071121415883b3eb24cafdcb9

Authored by André Araújo
1 parent f89e6e67
Exists in master

Adiciona movimento circular otimizado e remove o antigo, adiciona argumento '--'…

… a linha de comando do controller para evitar que o blender interprete o argumento JSON como path para um arquivo
.fuse_hidden000003cf00000002 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +[2015-07-28 22:23:30.895] ERROR:
  2 + File name: libras.py
  3 + Function name: <module>
  4 + Line code: 23
  5 + Type exception: ValueError
  6 + Message: Expecting value: line 1 column 1 (char 0)
  7 +[2015-07-28 22:25:38.946] INFO: All frames: 163
  8 +[2015-07-28 22:28:30.474] INFO: Rename: '/media/truecrypt1/Lavid/wikilibras/tmp/wikilibras-core/users/4/teste circular_0001-0163.mp4' to: '/media/truecrypt1/Lavid/wikilibras/tmp/wikilibras-core/users/4/teste circular.mp4'
  9 +[2015-07-28 23:17:31.963] INFO: All frames: 163
  10 +[2015-07-28 23:18:15.833] INFO: Rename: '/media/truecrypt1/Lavid/wikilibras/tmp/wikilibras-core/users/4/teste circular_0001-0163.mp4' to: '/media/truecrypt1/Lavid/wikilibras/tmp/wikilibras-core/users/4/teste circular.mp4'
  11 +[2015-07-28 23:35:35.942] INFO: All frames: 163
  12 +[2015-07-28 23:35:38.782] ERROR:
  13 + File name: controller.py
  14 + Function name: <module>
  15 + Line code: 18
  16 + Type exception: KeyboardInterrupt
  17 + Message:
... ...
Makefile
1   -BLEND = avatar_cartoon_v2.70.blend
  1 +BLEND = avatar_cartoon_v2.74.blend
2 2 CONTROLLER = controller.py
3 3 MAIN = libras.py
4 4 # Circular: ['circular', x, x, Raio=1, Voltas=3 CfM=0, PAr=80, Ori=0]
... ... @@ -20,7 +20,7 @@ py:
20 20 @echo "[\33[32;5mExecutando\33[m]\33[34;5m $(PYTHON) "$(CONTROLLER)" {JSON} ...\33[m"; $(PYTHON) "$(CONTROLLER)" $(JSON) && echo "$(DONE)" || echo "$(FAIL)"
21 21  
22 22 bpy:
23   - @echo "[\33[32;5mExecutando\33[m]\33[34;5m $(BLENDER) -b "$(BLEND)" -P "$(MAIN)" {JSON} ...\33[m"; $(BLENDER) -b "$(BLEND)" -P "$(MAIN)" $(JSON) && echo "$(DONE)" || echo "$(FAIL)"
  23 + @echo "[\33[32;5mExecutando\33[m]\33[34;5m $(BLENDER) -b "$(BLEND)" -P "$(MAIN)" -- {JSON} ...\33[m"; $(BLENDER) -b "$(BLEND)" -P "$(MAIN)" -- $(JSON) && echo "$(DONE)" || echo "$(FAIL)"
24 24  
25 25 help:
26 26 @echo ""
... ...
__init__.py
... ... @@ -0,0 +1,8 @@
  1 +
  2 +__all__ = (
  3 + "bmesh_collision"
  4 + "controller",
  5 + "libras",
  6 + "moves",
  7 + "pyutil",
  8 + "util")
... ...
avatar_cartoon_v2.74.blend
No preview for this file type
controller.py
... ... @@ -8,14 +8,14 @@ getcwd = dirname(abspath(__file__))
8 8  
9 9 from pyutil import printStackTrace
10 10  
11   -blend_path = join(getcwd, "avatar_cartoon_v2.70.blend")
  11 +blend_path = join(getcwd, "avatar_cartoon_v2.74.blend")
12 12 main_path = join(getcwd, "libras.py")
13 13 result = 0
14 14  
15 15 try:
16 16 # Caso seja necessário gravar logs do blender utilizar a linha de código abaixo
17   - # result = call(['blender', '-b', blend_path, '-P', main_path, argv[1]], stdout = open('bpy.log', 'w'))
18   - result = call(['blender', '-b', blend_path, '-P', main_path, argv[1]])
  17 + # result = call(['blender', '-b', blend_path, '-P', main_path, '--', argv[1]], stdout = open('bpy.log', 'w'))
  18 + result = call(['blender', '-b', blend_path, '-P', main_path, '--', argv[1]])
19 19 except:
20 20 result = printStackTrace(__file__)
21 21  
... ...
libras.py
... ... @@ -20,7 +20,7 @@ from pyutil import printStackTrace
20 20  
21 21 # tenta decodificar o argumento JSON recebido
22 22 try:
23   - json_input = json.loads(argv[5])
  23 + json_input = json.loads(argv[6])
24 24 except Exception:
25 25 printStackTrace(__file__)
26 26 exit(1)
... ... @@ -71,14 +71,14 @@ def configureHands():
71 71  
72 72 if(move in ["circular", "semicircular"]):
73 73 orientation, direction, radius, laps = json_input[hands[i]][1:5]
74   - endFrame = moves.circular_or_semiCircular(pose, orientation, direction, radius, laps, 5)
  74 + #endFrame = moves.circular_or_semiCircular(pose, orientation, direction, radius, laps, 5)
75 75 setHandConfiguration(actions[i], handParam, [endFrame], bones_[i])
76 76 elif(move == "retilineo"):
77 77 setHandConfiguration(actions[i], json_input[hands[i]][-6:-3], util.hands_default_frames, bones_[i])
78 78 setHandConfiguration(actions[i], handParam, util.hands_frames_retilineo, bones_[i])
79 79 elif(move == "senoidal"):
80 80 orientation, direction, radius, laps = json_input[hands[i]][1:5]
81   - endFrame = circular_or_semiCircular(pose, orientation, direction, radius, laps, 5)
  81 + #endFrame = circular_or_semiCircular(pose, orientation, direction, radius, laps, 5)
82 82 setHandConfiguration(actions[i], handParam, [endFrame], bones_[i])
83 83 elif(move == "contato"):
84 84 endFrame = moves.contato(actions[i], json_input[hands[i]], bones_[i], pose)
... ... @@ -89,12 +89,14 @@ def configureFace():
89 89 if(json_input["facialExp"] != []):
90 90 setFaceConfiguration(json_input["facialExp"], [endFrame/4], util.faceBonesConf)
91 91  
92   -poseDefault([1])
93   -configureHands()
94   -configureFace()
95   -poseDefault([endFrame + 15])
96   -
97   -# Default Pose
98   -print("Total frames: %.3i" % (endFrame))
99   -
100   -util.render_sign(json_input["userId"], json_input["signName"], 1, endFrame + 25)
101 92 \ No newline at end of file
  93 +def main():
  94 + poseDefault([1])
  95 + configureHands()
  96 + configureFace()
  97 + poseDefault([endFrame + 15])
  98 + # Default Pose
  99 + print("Total frames: %.3i" % (endFrame))
  100 + util.render_sign(json_input["userId"], json_input["signName"], 1, endFrame + 25)
  101 +
  102 +if __name__ == "__main__":
  103 + main()
... ...
moves.py
... ... @@ -7,7 +7,7 @@ import util
7 7 def contato(action, input_hand, bones, pose, initialFrame = 18):
8 8 currentFrame = initialFrame
9 9 contact_type = input_hand[1]
10   -
  10 +
11 11 if (contact_type == "alisar"):
12 12 currentFrame = alisar(action, input_hand, pose, bones, initialFrame)
13 13 elif (contact_type == "cocar"):
... ... @@ -23,19 +23,19 @@ def riscar(action, input_hand, bones, pose, initialFrame = 18, bnAntBracoDegree
23 23 endFrame = initialFrame + 2 * frameJump
24 24 handParam = input_hand[-3:]
25 25 lado = "R" if util.rightBonesConf == bones else "L"
26   -
  26 +
27 27 bnAntBraco = bpy.context.object.pose.bones["BnAntBraco." + lado]
28 28 bnAntBraco.bone.select = True
29 29 util.apply_rotation(bnAntBraco, "Z", currentFrame, endFrame, bnAntBracoDegree)
30 30 currentFrame += frameJump
31 31 util.apply_rotation(bnAntBraco, "Z", currentFrame, endFrame, (-1)*(bnAntBracoDegree+1))
32 32 bnAntBraco.bone.select = False
33   -
  33 +
34 34 currentFrame = initialFrame
35 35 util.setPose(action, handParam, [currentFrame], bones)
36 36 bnMao = bpy.context.object.pose.bones["BnMao." + lado]
37 37 bnMao.bone.select = True
38   - util.apply_rotation(bnMao, "Y", currentFrame, endFrame, bnMaoDegree)
  38 + util.apply_rotation(bnMao, "Y", currentFrame, endFrame, bnMaoDegree)
39 39 currentFrame += frameJump
40 40 util.apply_rotation(bnMao, "Y", currentFrame, endFrame, (-2)*bnMaoDegree)
41 41 currentFrame += frameJump
... ... @@ -55,18 +55,18 @@ def tocar(action, input_hand, bones, pose, initialFrame = 18, degree = 30, frame
55 55 bnMao = bpy.context.object.pose.bones[lado]
56 56 bnMao.bone.select = True
57 57 currentFrame += frameJump
58   - util.apply_rotation(bnMao, "X", currentFrame, endFrame, -degree)
  58 + util.apply_rotation(bnMao, "X", currentFrame, endFrame, -degree)
59 59 currentFrame += frameJump
60 60 util.apply_rotation(bnMao, "X", currentFrame, endFrame, degree)
61 61 util.setPose([action[0]], [handParam[0]], [currentFrame], bones)
62 62 currentFrame += frameJump
63 63 bnMao.bone.select = False
64 64 return currentFrame
65   -
  65 +
66 66 def cocar(action, input_hand, bones, initialFrame = 18, repetition = 2, frameJump = 6):
67   - currentFrame = initialFrame
  67 + currentFrame = initialFrame
68 68 pa_index = input_hand[-1]
69   -
  69 +
70 70 for i in range(0, repetition):
71 71 util.setPose(action, [util.cocar_mao_aberta_index, pa_index, util.cocar_orientation_index], [currentFrame], bones)
72 72 currentFrame += frameJump
... ... @@ -80,7 +80,7 @@ def alisar(action, input_hand, pose, bones, initialFrame = 18, frameJump = 10, w
80 80 orientation, repetition = input_hand[2:4]
81 81 handParam = input_hand[-3:]
82 82 util.setPose(action, handParam, util.hands_default_frames, bones)
83   -
  83 +
84 84 if (orientation == "perpendicular"):
85 85 currentFrame = alisar_xy(pose, 1, repetition, initialFrame, frameJump, width)
86 86 elif (orientation == "paralelo"):
... ... @@ -89,16 +89,16 @@ def alisar(action, input_hand, pose, bones, initialFrame = 18, frameJump = 10, w
89 89 currentFrame = alisar_diagonal(pose, True, repetition, initialFrame, frameJump, width)
90 90 elif (orientation == "diagonal-esquerda"):
91 91 currentFrame = alisar_diagonal(pose, False, repetition, initialFrame, frameJump, width)
92   -
  92 +
93 93 util.setPose(action, handParam, [currentFrame], bones)
94 94 return currentFrame
95 95  
96 96 def alisar_xy(pose, orientation_index, repetition, initialFrame = 18, frameJump = 10, width = 0.25):
97 97 currentFrame = initialFrame
98 98 center = pose.location.x, pose.location.y, pose.location.z
99   -
  99 +
100 100 for i in range(0, repetition):
101   - pose.location[orientation_index] = center[orientation_index] - width
  101 + pose.location[orientation_index] = center[orientation_index] - width
102 102 util.keyframe_insert(pose, 'location', currentFrame)
103 103 currentFrame += frameJump
104 104 pose.location[orientation_index] = center[orientation_index] + width
... ... @@ -109,25 +109,27 @@ def alisar_xy(pose, orientation_index, repetition, initialFrame = 18, frameJump
109 109 def alisar_diagonal(pose, to_right, repetition, initialFrame = 18, frameJump = 10, width = 0.25):
110 110 currentFrame = initialFrame
111 111 center = pose.location.x, pose.location.y, pose.location.z
112   -
  112 +
113 113 for i in range(0, repetition):
114 114 pose.location[0] = center[0] - width if to_right else center[0] - width
115 115 pose.location[1] = center[1] - width if to_right else center[1] + width
116   -
  116 +
117 117 util.keyframe_insert(pose, 'location', currentFrame)
118 118 currentFrame += frameJump
119   -
  119 +
120 120 pose.location[0] = center[0] + width if to_right else center[0] + width
121 121 pose.location[1] = center[1] + width if to_right else center[1] - width
122 122 util.keyframe_insert(pose, 'location', currentFrame)
123 123 currentFrame += frameJump
124 124 return currentFrame
125 125  
  126 +"""
  127 +# descontinuada: circular_or_semiCircular
126 128 def circular_or_semiCircular(pose, orientation, direction, radius, laps, intensity = 5, initialFrame = 18, turn = None):
127 129 center = pose.location.x, pose.location.y, pose.location.z
128 130 if(orientation == 'perpendicular'):
129 131 if(direction == 'horario'):
130   - endFrame = locationCircular(center, radius, 1, 0, 2, pose, 0, laps, intensity, initialFrame, turn)
  132 + endFrame = circular(center, radius, 1, 0, 2, pose, 0, laps, intensity, initialFrame, turn)
131 133 else:
132 134 endFrame = locationCircular(center, radius, 0, 1, 2, pose, 0, laps, intensity, initialFrame, turn)
133 135 elif(orientation == 'paralelo'):
... ... @@ -141,177 +143,56 @@ def circular_or_semiCircular(pose, orientation, direction, radius, laps, intensi
141 143 else:
142 144 endFrame = locationCircular(center, radius, 0, 2, 1, pose, 0, laps, intensity, initialFrame, turn)
143 145 return endFrame
144   -
145   -# center[3]: float vector (posição xyz centro)
146   -# radius: float (distancia do centro)
147   -# i_axis: int (indice do eixo i [0 | 1 | 2])
148   -# j_axis: int (indice do eixo j [0 | 1 | 2])
149   -# k_axis: int (indice do eixo k [0 | 1 | 2])
150   -def locationCircular(center, radius, i_axis, j_axis, k_axis, pose, initialPosition, laps, frameJump = 5, initialFrame = 18, turn = None):
151   - sqrt22 = radius * (math.sqrt(2) / 2)
152   - rad2 = (radius/2)
153   - currentFrame = initialFrame
154   - for l in range(initialPosition, initialPosition + math.floor(8 * laps) + 1):
155   - if ((l % 8) == 0):
156   - pose.location[i_axis] = center[i_axis] + radius
157   - pose.location[j_axis] = center[j_axis]
158   - pose.location[k_axis] = center[k_axis]
159   - util.keyframe_insert(pose, 'location', currentFrame)
160   - currentFrame += frameJump
161   - if ((l % 8) == 1):
162   - pose.location[i_axis] = center[i_axis] + sqrt22
163   - pose.location[j_axis] = center[j_axis] + sqrt22
164   - pose.location[k_axis] = center[k_axis]
165   - if(turn == 1):
166   - pose.location[i_axis] = center[i_axis] + sqrt22
167   - pose.location[j_axis] = center[j_axis] + rad2
168   - pose.location[k_axis] = center[k_axis] - rad2
169   - elif(turn == -1):
170   - pose.location[i_axis] = center[i_axis] + sqrt22
171   - pose.location[j_axis] = center[j_axis] + rad2
172   - pose.location[k_axis] = center[k_axis] + rad2
173   - util.keyframe_insert(pose, 'location', currentFrame)
174   - currentFrame += frameJump
175   - if ((l % 8) == 2):
176   - pose.location[i_axis] = center[i_axis]
177   - pose.location[j_axis] = center[j_axis] + radius
178   - pose.location[k_axis] = center[k_axis]
179   - if(turn == 1):
180   - pose.location[j_axis] = center[j_axis] + sqrt22
181   - pose.location[k_axis] = center[k_axis] - sqrt22
182   - elif(turn == -1):
183   - pose.location[j_axis] = center[j_axis] + sqrt22
184   - pose.location[k_axis] = center[k_axis] + sqrt22
185   - util.keyframe_insert(pose, 'location', currentFrame)
186   - currentFrame += frameJump
187   - if ((l % 8) == 3):
188   - pose.location[i_axis] = center[i_axis] - sqrt22
189   - pose.location[j_axis] = center[j_axis] + sqrt22
190   - pose.location[k_axis] = center[k_axis]
191   - if(turn == 1):
192   - pose.location[i_axis] = center[i_axis] - sqrt22
193   - pose.location[j_axis] = center[j_axis] + rad2
194   - pose.location[k_axis] = center[k_axis] - rad2
195   - elif(turn == -1):
196   - pose.location[i_axis] = center[i_axis] - sqrt22
197   - pose.location[j_axis] = center[j_axis] + rad2
198   - pose.location[k_axis] = center[k_axis] + rad2
199   - util.keyframe_insert(pose, 'location', currentFrame)
200   - currentFrame += frameJump
201   -
202   - if ((l % 8) == 4):
203   - pose.location[i_axis] = center[i_axis] - radius
204   - pose.location[j_axis] = center[j_axis]
205   - pose.location[k_axis] = center[k_axis]
206   - util.keyframe_insert(pose, 'location', currentFrame)
207   - currentFrame += frameJump
208   -
209   - if ((l % 8) == 5):
210   - pose.location[i_axis] = center[i_axis] - sqrt22
211   - pose.location[j_axis] = center[j_axis] - sqrt22
212   - pose.location[k_axis] = center[k_axis]
213   - if(turn == 1):
214   - pose.location[i_axis] = center[i_axis] - sqrt22
215   - pose.location[j_axis] = center[j_axis] - rad2
216   - pose.location[k_axis] = center[k_axis] + rad2
217   - elif(turn == -1):
218   - pose.location[i_axis] = center[i_axis] - sqrt22
219   - pose.location[j_axis] = center[j_axis] - rad2
220   - pose.location[k_axis] = center[k_axis] - rad2
221   - util.keyframe_insert(pose, 'location', currentFrame)
222   - currentFrame += frameJump
223   -
224   - if ((l % 8) == 6):
225   - pose.location[i_axis] = center[i_axis]
226   - pose.location[j_axis] = center[j_axis] - radius
227   - pose.location[k_axis] = center[k_axis]
228   - if(turn == 1):
229   - pose.location[j_axis] = center[j_axis] - sqrt22
230   - pose.location[k_axis] = center[k_axis] + sqrt22
231   - elif(turn == -1):
232   - pose.location[j_axis] = center[j_axis] - sqrt22
233   - pose.location[k_axis] = center[k_axis] - sqrt22
234   - util.keyframe_insert(pose, 'location', currentFrame)
235   - currentFrame += frameJump
236   -
237   - if ((l % 8) == 7):
238   - pose.location[i_axis] = center[i_axis] + sqrt22
239   - pose.location[j_axis] = center[j_axis] - sqrt22
240   - pose.location[k_axis] = center[k_axis]
241   - if(turn == 1):
242   - pose.location[i_axis] = center[i_axis] + sqrt22
243   - pose.location[j_axis] = center[j_axis] - rad2
244   - pose.location[k_axis] = center[k_axis] + rad2
245   - elif(turn == -1):
246   - pose.location[i_axis] = center[i_axis] + sqrt22
247   - pose.location[j_axis] = center[j_axis] - rad2
248   - pose.location[k_axis] = center[k_axis] - rad2
249   - util.keyframe_insert(pose, 'location', currentFrame)
250   - currentFrame += frameJump
251   - currentFrame -= frameJump
252   - return currentFrame
253   -
254   -def locationHelicoidal(center, startRadius, incRadius, x, y, z,pose, currentLoc, laps, frameJump):
255   - sqrt22 = radius * math.sqrt(2) / 2
256   - allLaps = math.floor(8 * laps) + 1
257   -
258   - #for i in range(currentLoc, currentLoc + math.floor(8 * laps) + 1):
259   - for i in range(currentLoc, currentLoc + allLaps):
260   - print("All Laps:", allLaps)
261   - if ((i % 8) == 0 ):
262   - pose.location[x] = center[x] + radius
263   - pose.location[y] = center[y]
264   - pose.location[z] += incRadius /allLaps
265   - util.keyframe_insert(pose, 'location', bpy.context.scene.frame_end)
266   - bpy.context.scene.frame_end += frameJump
267   -
268   - if ((i % 8) == 1):
269   - pose.location[x] = center[x] + sqrt22
270   - pose.location[y] = center[y] + sqrt22
271   - pose.location[z] += incRadius /allLaps
272   - util.keyframe_insert(pose, 'location', bpy.context.scene.frame_end)
273   - bpy.context.scene.frame_end += frameJump
274   -
275   - if ((i % 8) == 2):
276   - pose.location[x] = center[x]
277   - pose.location[y] = center[y] + radius
278   - pose.location[z] += incRadius /allLaps
279   - util.keyframe_insert(pose, 'location', bpy.context.scene.frame_end)
280   - bpy.context.scene.frame_end += frameJump
281   -
282   - if ((i % 8) == 3):
283   - pose.location[x] = center[x] - sqrt22
284   - pose.location[y] = center[y] + sqrt22
285   - pose.location[z] += incRadius /allLaps
286   - util.keyframe_insert(pose, 'location', bpy.context.scene.frame_end)
287   - bpy.context.scene.frame_end += frameJump
288   -
289   - if ((i % 8) == 4):
290   - pose.location[x] = center[x] - radius
291   - pose.location[y] = center[y]
292   - pose.location[z] += incRadius /allLaps
293   - util.keyframe_insert(pose, 'location', bpy.context.scene.frame_end)
294   - bpy.context.scene.frame_end += frameJump
295   -
296   - if ((i % 8) == 5):
297   - pose.location[x] = center[x] - sqrt22
298   - pose.location[y] = center[y] - sqrt22
299   - pose.location[z] += incRadius /allLaps
300   - util.keyframe_insert(pose, 'location', bpy.context.scene.frame_end)
301   - bpy.context.scene.frame_end += frameJump
302   -
303   - if ((i % 8) == 6):
304   - pose.location[x] = center[x]
305   - pose.location[y] = center[y] - radius
306   - pose.location[z] += incRadius /allLaps
307   - util.keyframe_insert(pose, 'location', bpy.context.scene.frame_end)
308   - bpy.context.scene.frame_end += frameJump
309   -
310   - if ((i % 8) == 7):
311   - pose.location[x] = center[x] + sqrt22
312   - pose.location[y] = center[y] - sqrt22
313   - pose.location[z] += incRadius /allLaps
314   - util.keyframe_insert(pose, 'location', bpy.context.scene.frame_end)
315   - bpy.context.scene.frame_end += frameJump
316   -
317   - bpy.context.scene.frame_end -= frameJump
  146 +"""
  147 +
  148 +# Obs.: A velocidade do movimento vai ser a relacao entre tamanho do raio e o periodo
  149 +# quanto maior o periodo mais keyframes
  150 +# quanto menor o raio mais rapido
  151 +# exemplos:
  152 +# raio: "pequeno" raio = 0.5, velocidade: "rapido" periodo = 25
  153 +# raio: "pequeno" raio = 0.5, velocidade: "normal" periodo = 35
  154 +# raio: "pequeno" raio = 0.5, velocidade: "lento" periodo = 45
  155 +# raio: "normal" raio = 1.0, velocidade: "rapido" periodo = 35
  156 +# raio: "normal" raio = 1.0, velocidade: "normal" periodo = 45
  157 +# raio: "normal" raio = 1.0, velocidade: "lento" periodo = 55
  158 +# raio: "grande" raio = 1.5, velocidade: "rapido" periodo = 45
  159 +# raio: "grande" raio = 1.5, velocidade: "normal" periodo = 55
  160 +# raio: "grande" raio = 1.5, velocidade: "lento" periodo = 65
  161 +# @param obj: (objeto) bone, mesh, e.g.
  162 +# @param itFrame: (int) posicao onde o primeiro keyframe vai ser inserido
  163 +# @param raio: (int) raio da circunferencia
  164 +# @param periodo: (int) quantidade de keyframes necessarios para completar uma volta completa
  165 +# @param x: (int) in [0,1,2] define qual eixo vai variar no seno (0 = eixo X, 1 = eixo Y, 2 = eixo Z)
  166 +# @param y: (int) in [0,1,2] define qual eixo vai variar no cosseno (0 = eixo X, 1 = eixo Y, 2 = eixo Z)
  167 +# @param ladoOposto: (bool) inverte o lado da primeira posicao (pode ser util em alguns casos para espelhar)
  168 +# @param inverterDirecao (bool) inverte o sentido do movimento (horario para anti-horario)
  169 +def circular(obj, itFrame, raio, periodo, x = 0, y = 1, ladoOposto = False, inverterDirecao = False):
  170 + # limita inferiormente
  171 + if (periodo < 16):
  172 + periodo = 16
  173 + # limita superiormente
  174 + elif (periodo > 360):
  175 + periodo = 360
  176 + # muda lado inicial
  177 + if (ladoOposto):
  178 + k = round(periodo / 2)
  179 + else:
  180 + k = 0
  181 + # evita estouro dos indices
  182 + x %= 3
  183 + y %= 3
  184 + # inverte direcao do movimento
  185 + if (inverterDirecao):
  186 + tmp = x
  187 + x = y
  188 + y = tmp
  189 + # copia posicao inicial para transladar
  190 + loc = [obj.location[0], obj.location[1], obj.location[2]]
  191 + for i in range(k, periodo + k):
  192 + # pequena otimizacao para reduzir a quantidade de keyframes
  193 + if (itFrame % 2 == 0):
  194 + obj.location[x] = loc[x] + (raio * math.cos(i / periodo * (2 * math.pi)))
  195 + obj.location[y] = loc[y] + (raio * math.sin(i / periodo * (2 * math.pi)))
  196 + obj.keyframe_insert(data_path='location', frame=itFrame, index=-1)
  197 + itFrame += 1
  198 + return periodo - 1
... ...