# -*- coding: utf-8 -*- #------------------------------------------------- #-- animation workbench trackreader #-- #-- microelly 2015 #-- #-- GNU Lesser General Public License (LGPL) #------------------------------------------------- import FreeCAD,PySide,os,FreeCADGui from PySide import QtCore, QtGui, QtSvg from PySide.QtGui import * import math import numpy as np App,Gui=FreeCAD,FreeCADGui import Draft,Part import Animation __vers__='0.1' import math,os import FreeCAD, Animation, PySide from Animation import say,sayErr,sayexc from EditWidget import EditWidget __vers__= '0.1' __dir__ = os.path.dirname(__file__) import FreeCAD,os,time,sys,traceback def sayexc(mess=''): exc_type, exc_value, exc_traceback = sys.exc_info() ttt=repr(traceback.format_exception(exc_type, exc_value,exc_traceback)) lls=eval(ttt) l=len(lls) l2=lls[(l-3):] FreeCAD.Console.PrintError(mess + "\n" +"--> ".join(l2)) def interpol2(filename,show=True): ''' interpolate data from filename_out.txt to filename_post.txt''' filename2=filename + "_out.txt" tv=[] xv=[] yv=[] zv=[] rx=[] ry=[] rz=[] ra=[] for line in open(filename + "_out.txt", "r"): line=line.rstrip('\r\n') ll= line.split(' ') if ll[0] == '#': continue llf=[] for z in ll: llf.append(float(z)) tv.append(llf[0]) xv.append(llf[1]) yv.append(llf[2]) zv.append(llf[3]) rx.append(llf[4]) ry.append(llf[5]) rz.append(llf[6]) ra.append(llf[7]) # interpolate import numpy as np import scipy from scipy.interpolate import interp1d #import matplotlib.pyplot as plt fx = interp1d(tv, xv, ) fy = interp1d(tv, yv, ) fz = interp1d(tv, zv, ) frx = interp1d(tv, rx,) fry = interp1d(tv, ry, ) frz = interp1d(tv, rz, ) fra = interp1d(tv, ra, ) xnew = np.linspace(0, 0.99, num=100, endpoint=True) #try: if show: plt.plot(tv, xv, 'o',tv,yv,'+',tv,zv,'*') plt.plot( xnew, fx(xnew), '-', xnew, fy(xnew), '--',xnew, fz(xnew), '.-', ) # plt.legend(['aaa','x','y','z'], loc='best') plt.title('Placement Interpolation Data') plt.xlabel('time relative') plt.ylabel('Placement Base') plt.savefig(filename +'.png') # plt.show() import ImageGui ImageGui.open(filename +'.png') #except: # pass # export data fout = open(filename + "_post.txt",'w') for t in xnew: try: l=' '.join(str(k) for k in [t,fx(t),fy(t),fz(t),frx(t),fry(t),frz(t),fra(t)]) fout.write(l+'\n') except: pass fout.close() #return [fx,fy,fz] def createTrackReader(name,target,filename): obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython",name) obj.addProperty("App::PropertyLink","target","Base","") obj.target=target obj.addProperty("App::PropertyString","filename","Base","") obj.filename=filename obj.addProperty("App::PropertyFloat","time","Base","") obj.time=0.0 obj.addProperty("App::PropertyPlacement","Placement","Results","") obj.Placement=FreeCAD.Placement() _TrackReader(obj) _ViewProviderTrackReader(obj.ViewObject) return obj class _TrackReader(Animation._Actor): def __init__(self,obj): obj.Proxy = self self.obj2 = obj self.Lock=False self.Changed=False self.path={} self.loadtrack() def loadtrack(self): interpol2(self.obj2.filename,False) for line in open(self.obj2.filename + "_post.txt", "r"): line=line.rstrip('\r\n') ll= line.split(' ') self.path[float(ll[0])]=FreeCAD.Placement( FreeCAD.Vector(float(ll[1]),float(ll[2]),float(ll[3])), FreeCAD.Vector(float(ll[4]),float(ll[5]),float(ll[6])), float(ll[7])*180/math.pi) print(self.path) def showtrack(self): interpol2(self.obj2.filename,True) for line in open(self.obj2.filename + "_post.txt", "r"): line=line.rstrip('\r\n') ll= line.split(' ') self.path[float(ll[0])]=FreeCAD.Placement( FreeCAD.Vector(float(ll[1]),float(ll[2]),float(ll[3])), FreeCAD.Vector(float(ll[4]),float(ll[5]),float(ll[6])), float(ll[7])*180/math.pi) print(self.path) def showtrack(self): interpol2(self.obj2.filename,True) for line in open(self.obj2.filename + "_post.txt", "r"): line=line.rstrip('\r\n') ll= line.split(' ') self.path[float(ll[0])]=FreeCAD.Placement( FreeCAD.Vector(float(ll[1]),float(ll[2]),float(ll[3])), FreeCAD.Vector(float(ll[4]),float(ll[5]),float(ll[6])), float(ll[7])*180/math.pi) print(self.path) def execute(self,obj): if self.Changed: say("self changed") self.Changed=False return if not self.Lock: self.obj2=obj self.Lock=True try: self.update() except: sayexc('update') self.Lock=False # # main execution detail # def update(self): say("update ") import math time=self.obj2.time say(str(time)) pl=self.path[time] self.obj2.target.Placement=pl self.obj2.Placement=pl def __getstate__(self): return None def __setstate__(self,state): return None def onChanged(self,obj,prop): pass def onBeforeChange(self,obj,prop): pass def initialize(self): pass def step(self,now): self.obj2.time=float(now)/100 class _ViewProviderTrackReader(Animation._ViewProviderActor): def getIcon(self): return __dir__ +'/icons/icon3.svg' def attach(self,vobj): say("attach " + str(vobj.Object.Label)) self.emenu=[["Reload Track",self.loadtrack],["Show Track",self.showtrack]] self.cmenu=[] self.Object = vobj.Object self.obj2=self.Object self.Object.Proxy.Lock=False self.Object.Proxy.Changed=False return def setupContextMenu(self, obj, menu): action = menu.addAction("About ") action.triggered.connect(self.showVersion) action = menu.addAction("Track Reader ...") action.triggered.connect(self.edit) def edit(self): self.dialog=EditWidget(self,self.emenu) self.dialog.show() def showVersion(self): QtGui.QMessageBox.information(None, "About ", "Animation Track Reader Node\n2015 microelly\nVersion " + __vers__ ) def loadtrack(self): self.obj2.Proxy.loadtrack() def showtrack(self): self.obj2.Proxy.showtrack() def dialer(self): ''' shows the position at the dialer time''' self.obj2.time=float(self.widget.dial.value())/100 say("dialer self time:" + str(self.obj2.time)) try: say(self.obj2.Proxy.path[round(self.obj2.time,2)]) self.obj2.target.Placement=self.obj2.Proxy.path[round(self.obj2.time,2)] except: pass FreeCAD.ActiveDocument.recompute() class _Function(Animation._Actor): def __init__(self,obj): obj.Proxy = self self.obj2 = obj self.Lock=False self.Changed=False self.path={} self.loadtrack() def loadtrack(self): # interpolate import numpy as np import scipy from scipy.interpolate import interp1d #import matplotlib.pyplot as plt wire=self.obj2.source.Shape if self.obj2.target==None: self.obj2.target=Draft.makeCircle(5) self.obj2.target.Label ="anim target for "+ self.obj2.source.Label # hier andere modi einbauen z. B. Endpunkte der edges #+# if self.obj2.usePoints: w=wire pts=[v.Point for v in w.Vertexes] else: pts=wire.discretize(self.obj2.count) tx=[p.x for p in pts] ty=[p.y for p in pts] tz=[p.z for p in pts] self.obj2.xlist=tx self.obj2.ylist=ty self.obj2.zlist=tz xmin=min(tx) tx=(np.array(tx)-xmin) xmax=max(tx) tx /= xmax # zmin=min(tz) # tz=(np.array(tz)-zmin) # zmax=max(tz) # tz /= zmax # siehe https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.interpolate.interp1d.html fx = interp1d(tx,ty,kind=self.obj2.kindInterpolation) fz = interp1d(tx,tz,kind=self.obj2.kindInterpolation) self.fx=fx self.xmin=xmin self.xmax=xmax ptsa=[FreeCAD.Vector((0.01*i*(xmax))+xmin,self.obj2.a*fx(0.01*i)+self.obj2.b, self.obj2.a*fz(0.01*i)+self.obj2.b,) for i in range(101)] #Draft.makeWire(ptsa) pol=Part.makePolygon(ptsa) try: self.k1.Shape=pol except: Part.show(pol) self.k1=App.ActiveDocument.ActiveObject self.k1.Label="cartesian Map for "+ self.obj2.source.Label # polare Darstellung ptsa=[FreeCAD.Vector(np.cos(np.pi*i/180),np.sin(np.pi*i/180),0)*(self.obj2.a*fx(1.0/360*i)+self.obj2.b) for i in range(361)] #Draft.makeWire(ptsa) pol=Part.makePolygon(ptsa) try: self.k2.Shape=pol except: Part.show(pol) self.k2=App.ActiveDocument.ActiveObject self.k2.Label="polar Map for "+ self.obj2.source.Label def execute(self,obj): if self.Changed: say("self changed") self.Changed=False return if not self.Lock: self.obj2=obj self.Lock=True try: self.update() except: sayexc('update') self.Lock=False def onChanged(self,obj,prop): if prop in ['source','count','a','b']: self.loadtrack() if prop in ['time','count']: self.update() # # main execution detail # def update(self): say("update ") import math time=self.obj2.time/100 say(str(time)) if self.obj2.mode=='cartesian': pl=FreeCAD.Vector((time*self.xmax)+self.xmin,self.obj2.a*self.fx(time)+self.obj2.b) if self.obj2.mode=='polar': # pl=FreeCAD.Vector((time*self.xmax)+self.xmin,self.fx(time)) pl=FreeCAD.Vector(np.cos(np.pi*time*2),np.sin(np.pi*time*2),0)*(self.obj2.a*self.fx(time)+self.obj2.b) if self.obj2.target != None: self.obj2.target.Placement.Base=pl self.obj2.target.purgeTouched() #self.obj2.Placement=pl def __getstate__(self): return None def __setstate__(self,state): return None def onBeforeChange(self,obj,prop): pass def initialize(self): pass def step(self,now): self.obj2.time=float(now) class _ViewProviderFunction(Animation._ViewProviderActor): def getIcon(self): return __dir__ +'/icons/icon3.svg' def attach(self,vobj): say("attach " + str(vobj.Object.Label)) self.emenu=[["Reload Track",self.loadtrack],["Show Track",self.showtrack]] self.cmenu=[] self.Object = vobj.Object self.obj2=self.Object self.Object.Proxy.Lock=False self.Object.Proxy.Changed=False return def setupContextMenu(self, obj, menu): action = menu.addAction("About ") action.triggered.connect(self.showVersion) action = menu.addAction("Update Graph ...") action.triggered.connect(self.Object.Proxy.loadtrack) def edit(self): self.dialog=EditWidget(self,self.emenu) self.dialog.show() def showVersion(self): QtGui.QMessageBox.information(None, "About ", "Animation Track Reader Node\n2015 microelly\nVersion " + __vers__ ) def loadtrack(self): self.obj2.Proxy.loadtrack() def showtrack(self): self.obj2.Proxy.showtrack() def dialer(self): ''' shows the position at the dialer time''' self.obj2.time=float(self.widget.dial.value())/100 say("dialer self time:" + str(self.obj2.time)) try: say(self.obj2.Proxy.path[round(self.obj2.time,2)]) self.obj2.target.Placement=self.obj2.Proxy.path[round(self.obj2.time,2)] except: pass FreeCAD.ActiveDocument.recompute() def runTA(): print("I'm TA") name="MyFunction" #def createTrackReader(name,target,filename): obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython",name) target=None obj.addProperty("App::PropertyLink","target","Base","") obj.addProperty("App::PropertyLink","source","Base","") #obj.source=App.ActiveDocument.Sketch obj.source=Gui.Selection.getSelection()[0] # obj.addProperty("App::PropertyLink","circle","Base","") obj.target=target # obj.addProperty("App::PropertyString","filename","Base","") #obj.filename=filename obj.addProperty("App::PropertyFloat","time","Base","") obj.time=0.0 obj.addProperty("App::PropertyFloat","a","F=a*f+b","").a=1 obj.addProperty("App::PropertyFloat","b","F=a*f+b","").b=0 obj.addProperty("App::PropertyInteger","count","","").count=40 obj.addProperty("App::PropertyPlacement","Placement","_comp","") obj.Placement=FreeCAD.Placement() obj.addProperty("App::PropertyEnumeration","mode","Base").mode=["cartesian","polar"] obj.addProperty("App::PropertyFloatList", "xlist", "_comp", "end") obj.addProperty("App::PropertyFloatList", "ylist", "_comp", "end") obj.addProperty("App::PropertyFloatList", "zlist", "_comp", "end") obj.addProperty("App::PropertyBool", "usePoints", "", "interpolate points").usePoints=True obj.addProperty("App::PropertyEnumeration","kindInterpolation","Base").kindInterpolation=['cubic','linear', 'nearest', 'zero', 'slinear', 'quadratic', ] _Function(obj) _ViewProviderFunction(obj.ViewObject) obj.Label="Interpolator for "+ obj.source.Label return obj