I'm working on a project using libavg and a series of RectNodes. What I'm trying to do is play an animation that makes each node light up white for 2,5 seconds, and then fades back. Every time you click one of the nodes, the same animation should happen for that specific node.
I'm using the AVGApp class, and a list with RectNode id and how many times they are supposed to light up, like (id1, 2)
def playAnim(self, animarr):
for i in range(0, len(animarr)):
i, count = animarr[i]
sid = "r" + str(i)
node = g_player.getElementByID(sid)
while count > 0:
self.blink(node)
count -= 1
return
and my code for blink:
def blink(self, node):
pos = node.pos
size = node.size
covernode = avg.RectNode(pos=pos, size=size, fillopacity=0,
parent = self._parentNode, fillcolor="ffffff",
color="000000", strokewidth=2)
self.animObj = LinearAnim(covernode, 'fillopacity', 1000, 0, 1)
self.animObj.start()
self.animObj = LinearAnim(covernode, 'fillopacity', 1000, 1, 0)
self.animObj.start()
covernode.unlink(True)
return
I'm calling it with:
def _enter(self):
(some other stuff here)
print "Let's get started!"
self.playAnim(self.animArr)
print "Your turn!"
Any help is greatly appreciated, the libavg Reference isn't helping me much.
The problem is that anim.start() is non-blocking.
Instead of only returning after the animation is finished, it will return immediately and the animation will be executed concurrently. This means at the same time your function starts two animations and unlinks the node that should be animated.
So instead you should use the end callbacks that can be given to the animations to trigger one step after another. The the blink function could then look like this:
def blink(self, node):
pos = node.pos
size = node.size
covernode = avg.RectNode(pos=pos, size=size, fillopacity=0,
parent = self._parentNode, fillcolor="ffffff",
color="000000", strokewidth=2)
fadeOutAnim = LinearAnim(covernode, 'fillopacity', 1000, 1, 0, False,
None, covernode.unlink)
fadInAnim= LinearAnim(covernode, 'fillopacity', 1000, 0, 1, False,
None, fadeOutAnim.start)
fadInAnim.start()
If you want the node to stay white for a certain amount of time you have to insert another step using either a WaitAnim or player.setTimeout().
(https://www.libavg.de/reference/current/player.html#libavg.avg.Player)
def blink(self, node):
pos = node.pos
size = node.size
covernode = avg.RectNode(pos=pos, size=size, fillopacity=0,
parent = self._parentNode, fillcolor="ffffff",
color="000000", strokewidth=2)
fadeOutAnim = LinearAnim(covernode, 'fillopacity', 1000, 1, 0, False,
None, covernode.unlink
)
fadInAnimObj = LinearAnim(covernode, 'fillopacity', 1000, 0, 1, False,
None, lambda:self.wait(500, fadeOutAnim.start)
)
fadInAnimObj.start()
def wait(self, time, end_cb):
avg.Player.get().setTimeout(time, end_cb)
Related
I have seen quite a few questions regarding this issue, and I have not been able to wrap my head around it.
So here is a concrete example.
I create a cube and in edit mode I add loopcuts. No sweat!
I copy the code from the info window and I try it out in a script and I get the ominous RuntimeError: Operator bpy.ops.mesh.loopcut_slide.poll() expected a view3d region & editmesh error message.
I understand now that it is about first giving python the right context by overriding. And alas, I do not know how to do it!
Here is the code:
import bpy
import os
os.system("cls")
# remove the default cube...
objs = bpy.data.objects
for obj in objs:
if obj.name.find("Cube") == 0:
bpy.data.objects.remove(obj, do_unlink=True)
# add a cube!
bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=True, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
# do something to it to be sure that we have it...
bpy.data.objects['Cube'].scale[0] = 10
# THE CODE BELOW GIVES THE RuntimeError: Operator bpy.ops.mesh.loopcut_slide.poll() expected a view3d region & editmesh error message.
# What is the override code I have to use to fix it????????
bpy.ops.mesh.loopcut_slide(MESH_OT_loopcut={"number_cuts":16, "smoothness":0, "falloff":'INVERSE_SQUARE', "object_index":0, "edge_index":4, "mesh_select_mode_init":(True, False, False)}, TRANSFORM_OT_edge_slide={"value":0, "single_side":False, "use_even":False, "flipped":False, "use_clamp":True, "mirror":True, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "correct_uv":True, "release_confirm":False, "use_accurate":False})
import bpy
import os
os.system("cls")
objs = bpy.data.objects
for obj in objs:
if obj.name.find("Cube") == 0:
bpy.data.objects.remove(obj, do_unlink=True)
# add a cube!
bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=True, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
# do something to it to be sure that we have it...
bpy.data.objects['Cube'].scale[0] = 10
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
for region in area.regions:
if region.type == 'WINDOW':
override = {'area': area, 'region': region, 'edit_object':bpy.context.edit_object}
bpy.ops.mesh.loopcut_slide(override,MESH_OT_loopcut={"number_cuts":16, "smoothness":0, "falloff":'INVERSE_SQUARE', "object_index":0, "edge_index":4, "mesh_select_mode_init":(True, False, False)}, TRANSFORM_OT_edge_slide={"value":0, "single_side":False, "use_even":False, "flipped":False, "use_clamp":True, "mirror":True, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "correct_uv":True, "release_confirm":False, "use_accurate":False})
Everyone.
I have some animation file that the start time is not zero. I am trying to create a script that will set the animation timecode to zero. For example, the picture shows the timecode is not from zero. Thank you very much for your help。
enter image description here
I'm a bit late but this is probably still interesting to share!
You can set your current take's timespan easily using an FBTimeSpan() instance like this, by specifying a start and end frame as FBTime() objects:
lStartFrame = 0
lEndFrame = 100
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))
But I guess that what you are looking for is a way to offset your animation and make it start at 0, isn't it?
Here are two functions from my own library, using the Story mode to offset your current animation at a given frame. The first one works on the current or all characters of your scene (character animation track). The second one on selected conponents (generic animation track). For each one you can pass as argument the frame it should start from and if you want to frame the new timespan at the end (replace your old first/last frames with the new ones).
from pyfbsdk import *
def offset_character_animation_at_frame(frame = 0, all_chars = True, frame_anim=True):
''' Offset current/all(default) characters animation to a given frame, 0 by default '''
# get list of current/all characters
if all_chars:
char_list = FBSystem().Scene.Characters
else:
char_list = [FBApplication().CurrentCharacter]
# get initial timespan
lStartFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
lEndFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
# turn on Story mode
FBStory().Mute = False
# process character list
for char in char_list:
# set timespan
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))
# set current character
FBApplication().CurrentCharacter = char
# insert character animation track
track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, FBStory().RootFolder)
track.Name = '{}_charAnimTrack'.format(FBApplication().CurrentCharacter.Name)
track.Details.append(FBApplication().CurrentCharacter)
# insert take in story mode
take = FBSystem().CurrentTake
inserted_clip = track.CopyTakeIntoTrack(take.LocalTimeSpan, take)
# move inserted clip to given frame
inserted_clip.Start = FBTime(0,0,0,frame)
# frame new timespan
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, inserted_clip.Start.GetFrame(), 0), FBTime(0, 0, 0, inserted_clip.Stop.GetFrame(), 0))
# defining plot options and plot to current take
PlotOptions = FBPlotOptions()
PlotOptions.ConstantKeyReducerKeepOneKey = True
PlotOptions.PlotAllTakes = False
PlotOptions.PlotOnFrame = True
PlotOptions.PlotPeriod = FBTime( 0, 0, 0, 1 )
PlotOptions.PlotTranslationOnRootOnly = True
PlotOptions.PreciseTimeDiscontinuities = True
PlotOptions.RotationFilterToApply = FBRotationFilter.kFBRotationFilterGimbleKiller
PlotOptions.UseConstantKeyReducer = True
char.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton, PlotOptions)
# empty Story mode
for track in FBStory().RootFolder.Tracks:
for clip in track.Clips:
clip.FBDelete()
track.FBDelete()
# set back original timespan if specified
if not frame_anim:
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))
# turn off Story mode
FBStory().Mute = True
def offset_generic_animation_at_frame(frame = 0, frame_anim = True):
''' Offset selected components animation to a given frame, 0 by default '''
# get selected components
lModelList = FBModelList()
FBGetSelectedModels(lModelList)
if not lModelList:
raise ValueError("Select at least one component")
# get initial timespan
lStartFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
lEndFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
# turn on Story mode
FBStory().Mute = False
# set timespan
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))
# insert generic animation track and add selected components to it
track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackAnimation, FBStory().RootFolder)
track.Name = 'genericAnimTrack'
for comp in lModelList:
track.Details.append(comp)
# insert take in story mode
take = FBSystem().CurrentTake
inserted_clip = track.CopyTakeIntoTrack(take.LocalTimeSpan, take)
# move inserted clip to given frame
inserted_clip.Start = FBTime(0,0,0,frame)
# frame new timespan
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, inserted_clip.Start.GetFrame(), 0), FBTime(0, 0, 0, inserted_clip.Stop.GetFrame(), 0))
# plot selected take
lOptions = FBPlotOptions()
lOptions.ConstantKeyReducerKeepOneKey = False
lOptions.PlotAllTakes = False
lOptions.PlotOnFrame = True
lOptions.PlotPeriod = FBTime( 0, 0, 0, 1 )
lOptions.PlotTranslationOnRootOnly = False
lOptions.PreciseTimeDiscontinuities = True
lOptions.RotationFilterToApply = FBRotationFilter.kFBRotationFilterGimbleKiller
lOptions.UseConstantKeyReducer = False
FBSystem().CurrentTake.PlotTakeOnSelected(lOptions)
# empty Story mode
for track in FBStory().RootFolder.Tracks:
for clip in track.Clips:
clip.FBDelete()
track.FBDelete()
# set back original timespan if specified
if not frame_anim:
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))
# turn off Story mode
FBStory().Mute = True
# MAIN
offset_generic_animation_at_frame(frame = 0, frame_anim = False)
offset_character_animation_at_frame(frame = 0, all_chars = True, frame_anim=True)
def columnandcellformate(sheet_name,bold = 0,font_color = '#000000',bg_color = '#ffffff',align = '' ,bottom = 0 ,top = 3,right = 0,left = 0,font_size = 10 ,starcolumn = 0, endrow = 0 ):
global sheet_format
sheet_format=sheet_name.add_format({
'bottom':bottom,
'top' : top,
'bg_color':bg_color,
'font_color' : font_color,
'align':align,
'font_size':font_size,
'bold': bold,
'font_name':'Batang'
})
What is default value of top,bottom,right,left, My function is making cell top,bottom,right and left blank
I think your default background color may have been causing some issues with the cell borders. I've added a few conditions based on whether you want these called by your function or not. These conditions make use of Format Methods such as format.set_bg_color(), format.set_bottom() (see docs for more information on these). They only provide a background color if you change it from the default.
import xlsxwriter
def columnandcellformate(bold = 0, font_color = '#000000', bg_color = 'none', align = '' , bottom = 999, top = 999, right = 999, left = 999, font_size = 10):
global sheet_format
sheet_format=workbook.add_format({
'font_color' : font_color,
'align': align,
'font_size': font_size,
'bold': bold,
'font_name': 'Batang'
})
if bg_color != 'none':
sheet_format.set_bg_color(bg_color)
if bottom != 999:
sheet_format.set_bottom(bottom)
if top != 999:
sheet_format.set_top(top)
if right != 999:
sheet_format.set_right(right)
if left != 999:
sheet_format.set_left(left)
workbook = xlsxwriter.Workbook('test.xlsx')
ws = workbook.add_worksheet('test_1')
columnandcellformate()
ws.write('B1', 'foo', sheet_format)
columnandcellformate(bold = 1, font_color = '#9C0006', bg_color = '#FFC7CE', align = '', bottom = 2, top = 1, right = 1, left = 1, font_size = 10)
ws.write('B3', 'bar', sheet_format)
workbook.close()
Expected Output:
The default values for format properties are almost all 0/False. See the initialization code for a format object.
In my project I have to print some data stored in a database on the console. I have two functions that return string. I should print those data in two columns.
I thought of using the module curses in python to create those two columns.
So far all is good.
Another thing, is that my two function use the threading.Timer. So the string generated changes every 10 seconds for example if I set my Timer on 10.
So when I put the result of my function on the addstr() of a column, it prints the first String correctly, but nothing changes even if my string change. Otherwise when I resize for example the console, I notice that the string changes.
Here is my code :
import sys,os
import curses , curses.panel
import datetime
import time
import threading
def time_func():
printStr = threading.Timer(10,time_func)
printStr.start()
s = "Simple example that display datetime \n" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return s
def draw_menu():
k = 0
cursor_x = 0
cursor_y = 0
# Clear and refresh the screen
stdscr = curses.initscr()
stdscr.clear()
stdscr.refresh()
# Initialize colors in curses
curses.start_color()
curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE)
curses.curs_set(0)
# Loop where k is the last character pressed
while (k != ord('q')):
# Declaration of strings
statusbarstr = "Press 'q' to exit | STATUS BAR "
'''Draw borders of the different columns'''
height, width = stdscr.getmaxyx()
stdscr.border()
stdscr.vline(1, 3 * height // 4, '|', width - 2)
stdscr.vline(1, height // 4, '|', width - 2)
stdscr.refresh()
'''Initialize the Statistics column'''
column_one = curses.newwin(height - 2, 3 * width // 4, 1,
1)
_, a_x = column_one.getmaxyx()
column_one.attron(curses.color_pair(1))
column_one.attron(curses.A_BOLD)
column_one.addstr(0, a_x // 2 - 2, "column one")
column_one.hline(1, 0, '-', a_x)
column_one.attroff(curses.color_pair(1))
column_one.attroff(curses.A_BOLD)
# I want to add my string here for example :
line = time_func()
column_one.addstr(3,1, line)
column_one.noutrefresh()
'''Initialize the Alerts column'''
column_two = curses.newwin(height - 2, width // 4, 1,
3 * width // 4 )
_, s_x = column_two.getmaxyx()
column_two.attron(curses.color_pair(1))
column_two.attron(curses.A_BOLD)
column_two.addstr(0, s_x // 2 - 5, "column two")
column_two.hline(1, 0, '-', s_x)
column_two.attroff(curses.color_pair(1))
column_two.attroff(curses.A_BOLD)
column_two.addstr(3, s_x // 2 - 5,"test")
column_two.noutrefresh()
# Render status bar
stdscr.attron(curses.color_pair(3))
stdscr.addstr(height-1, 0, statusbarstr)
stdscr.addstr(height-1, len(statusbarstr), " " * (width - len(statusbarstr) - 1))
stdscr.attroff(curses.color_pair(3))
# Turning on attributes for title
stdscr.attron(curses.color_pair(2))
stdscr.attron(curses.A_BOLD)
# Rendering title
# Turning off attributes for title
stdscr.attroff(curses.color_pair(2))
stdscr.attroff(curses.A_BOLD)
# Print rest of text
stdscr.move(height - 2, width - 2)
# Refresh the screen
stdscr.refresh()
# Wait for next input
k = stdscr.getch()
def main():
curses.wrapper(draw_menu())
if __name__ == "__main__":
main()
The curses function draw_menu is waiting for input at the end of the loop. If you resize the terminal, that
k = stdscr.getch()
returns a KEY_RESIZE, and runs through the loop again.
You could change that to wait a short time before giving up on the getch. That would return a -1.
Usually that's done using timeout (in curses), e.g., 50 milliseconds. There's a wrapper for that in Python (and by the way its description is incorrect). You should read the ncurses manual page for timeout.
Sometimes people say to use nodelay, which is usually poor advice since it would make the draw_menu thread use most of the CPU time.
I need to write a xml vtk file in python with solids tetrahedrons. Specifically in a Polydata. I have a collection of tetrahedrons with x,y,z coordinates of each edge. I try to use vtk.vtkXMLPolyDataWriter() but I get this (only 2D triangles):
enter image description here
My code :
#!/usr/bin/env python
import vtk
points = vtk.vtkPoints()
points.InsertNextPoint(0, 0, 0)
points.InsertNextPoint(1, 0, 0)
points.InsertNextPoint(1, 1, 0)
points.InsertNextPoint(0, 1, 1)
tetra = vtk.vtkTetra()
tetra.GetPointIds().SetId(0, 0)
tetra.GetPointIds().SetId(1, 1)
tetra.GetPointIds().SetId(2, 2)
tetra.GetPointIds().SetId(3, 3)
cellArray = vtk.vtkCellArray()
cellArray.InsertNextCell(tetra)
polydata = vtk.vtkPolyData()
polydata.SetPoints(points)
polydata.SetPolys(cellArray)
polydata.Modified()
if vtk.VTK_MAJOR_VERSION <= 5:
polydata.Update()
writer = vtk.vtkXMLPolyDataWriter()
writer.SetFileName("Primal_geo.vtp");
if vtk.VTK_MAJOR_VERSION <= 5:
writer.SetInput(polydata)
else:
writer.SetInputData(polydata)
writer.Write()
So, how can i write this file?
Thanks!
XML is information in tags. It is kind of a free hand json.
So here we go.
Now let me start by saying that I am not familiar with vtk or it's features, so while I hope the code I provide here serves your purposes I am not sure that a more satisfactory (preexisting piece of vtk) doesn't exist.
That said I wrote this little something up.
#!/usr/bin/env python
import vtk
class vtkXMLparser:
points = None
scellArray = None
def tagSplit(self,line):
for n,k in enumerate(line):
go = none
fin = none
if(k == ">"):
if(go == none):
if(n>0):
if(line[n-1]!="\\"):
go = n+1
if(go != none):
if(k == "<"):
if(n>0):
if(line[n-1]!="\\"):
if(n<len(line)-1):
if(line[n+1]=="/"):
fin = n+1
tag = line[fin+2:len(line)-1]
content = line[go:fin]
return([tag,content])
def addNice(self,di,key,cont):
try:
di[key].append(cont)
except(KeyError):
di[key]=[]
di[key].append(cont)
def parse(self,f):
input = open(f,"r")
xml = input.read()
xml = xml.split("\n")
data = {}
for lineNumber,line in enumerate(xml):
parsedXmlLine = self.tagSplit(line)
self.addNice(data,parsedXmlLine[0],parsedXmlLine[1])
self.self.points(data)
self.tetra(data)
self.write()
def self.points(self,di):
self.points = vtk.vtkself.points()
for point in di["point"]:
self.points.InsertNextPoint(eval(point))
def tetra(self,di):
tetra = vtk.vtkTetra()
for id in di["tetra"]:
tetra.GetPointIds().SetId(eval(id))
self.cellArray = vtk.vtkself.cellArray()
self.cellArray.InsertNextCell(tetra)
def write(self):
polydata = vtk.vtkPolyData()
polydata.Setself.points(self.points)
polydata.SetPolys(self.cellArray)
polydata.Modified()
if vtk.VTK_MAJOR_VERSION <= 5:
polydata.Update()
writer = vtk.vtkXMLPolyDataWriter()
writer.SetFileName("Primal_geo.vtp");
if vtk.VTK_MAJOR_VERSION <= 5:
writer.SetInput(polydata)
else:
writer.SetInputData(polydata)
writer.Write()
i = vtkXMLparser()
i.parse("input.xml")
I would write an input file that looks something like this for your example.
<point>0, 0, 0</point>
<point>1, 0, 0</point>
<point>1, 1, 0</point>
<point>0, 1, 1</point>
<tetra>0, 0</tetra>
<tetra>1, 1</tetra>
<tetra>2, 2</tetra>
<tetra>3, 3</tetra>
I hope this helps!