Skip to content

Instantly share code, notes, and snippets.

@5263
Last active December 17, 2015 17:49
Show Gist options
  • Save 5263/5649053 to your computer and use it in GitHub Desktop.
Save 5263/5649053 to your computer and use it in GitHub Desktop.
Import ft designer (*.ftm) files into FreeCAD
import os
if open.__module__ == '__builtin__':
pythonopen = open # to distinguish python built-in open function from the one declared here
ftdpath='C:/Program Files (x86)/fischertechnik designer'
partnamelang='NAME' #german
#partnamelang='ENG' #english
ftmmotorstr = "MotorSpeed%d=0\nMOTORROTATION%d=0\nMOTORSTATUS%d=0\nMotor%d=\nMOTORSOUND%d=0"
ftmfiletrailer="""[COMMON]
Version=1
Count=%(count)d
InfModell=
InfOriginal=
InfGebaut=
TubeCount=0
KinematikCount=0
CollisionCount=0
HalbzeugCount=0
%(motors)
KeyCount=0
AniLength=125
[CAMERA]
PositionX=0
PositionY=1
PositionZ=-10
DirectionX=0
DirectionY=0
DirectionZ=-1
UpX=0
UpY=1
UpZ=0
TargetX=0
TargetY=0
TargetZ=0
[LOGIKCOMMON]
BLOCKCOUNT=0
CONNCOUNT=0
"""
class connection():
def __init__(self,secdict):
import FreeCAD
self.name=secdict[partnamelang].decode('latin1') #german or english
pos=FreeCAD.Vector(floatg(secdict['X']),floatg(secdict['Y']),floatg(secdict['Z']))
frot=prttorot(floatg(secdict['PF']),floatg(secdict['RF']),floatg(secdict['TF']))
#if 'PN' in secdict and 'RN' in secdict and 'TN' in secdict:
nrot=prttorot(floatg(secdict.get('PN','0')),floatg(secdict.get('RN','0')),floatg(secdict.get('TN','0')))#purpose is unclear
self.Placement = FreeCAD.Placement(pos,frot)
self.num= secdict.get('id')
if self.num is not None:
self.num=int(self.num[4:])
def __repr__(self):
return "<%u-%s>"%(self.num,self.name)
def getdefdatabase():
dict1={}
import os
path=os.path.join(ftdpath,'def')
filenames=os.listdir(os.path.join(ftdpath,'def'))
for filename in filenames:
defpath=os.path.join(path,filename)
partdef= def2list(defpath)
partdefdict = ftlist2ftdict(partdef)
key=partdefdict['COMMON']['ORGNUMBER']
dict1[key]=partdefdict
#partname=os.path.splitext(os.path.basename(filename))[0]
#partfname=partdefdict['COMMON'][partnamelang].decode('latin1') #Part name
#partoffset=FreeCAD.Vector(floatg(partdefdict['OFFSET']['X']),floatg(partdefdict['OFFSET']['Y']),floatg(partdefdict['OFFSET']['Z']))
#shortname = partname
#longname ='%s_%s' %(shortname,partfname)
#partmeshfilename=ftdpath+'/%s/%s.stl'%(partlib,partname)
#print filename
def formatfloat(f1):
f2=float(f1)
if f2.is_integer():
return "%d"%f2
elif abs(f2)<10 and abs(f2)>0.09:
return ("%f"%f2).replace('.',',')
else:
return ("%0.14E"%f2).replace('.',',')
def formatvector(vec,postfix):
vecindex="XYZ"
return "\n".join(["%s%s=%s"%(vecindex[index],postfix,formatfloat(velm)) for index,velm in enumerate(vec)])
def formatpart(placement,color,Phase,Number,PartNum,RepCount):
formats="[%(id)s]\nNAME=%(NAME)s\n%(VECPOS)s\n%(VECUP)s\n%(VECDIR)s\nCOLOR=%(COLOR)s\nPHASE=%(PHASE)s\n"
partdict={}
matrixlst=placement.toMatrix().A
partdict['VECPOS']=formatvector(placement.Base.multiply(0.1),'POS')
partdict['VECUP']=formatvector(matrixlst[1:10:4],'UP')
partdict['VECDIR']=formatvector(matrixlst[2:11:4],'DIR')
partdict['COLOR']= formatfloat(round(color[0]*0xff+color[1]*0xff00+color[2]*0xff0000))
partdict['NAME']='F%s_%d' % (PartNum,RepCount or 1)
partdict['PHASE']=int(Phase or 1)
partdict['id']='PART%d' % int(Number)
return formats % partdict
def floatg(fstr):
return float(fstr.replace(',','.').lstrip('#'))
def prttorot(p,r,t):
import FreeCAD
#'xyz-prt'
pr=FreeCAD.Rotation(FreeCAD.Vector(-1,0,0),p)
rr=FreeCAD.Rotation(FreeCAD.Vector(0,0,1),r)
tr=FreeCAD.Rotation(FreeCAD.Vector(0,1,0),t)
return pr.multiply(rr).multiply(tr)
def def2list(filename):
fh=pythonopen(filename)
ftobjects=[]
for line in fh:
if line:
lines=line.strip()
if lines.startswith('[') and lines.endswith(']'):
newobj={'id':lines[1:-1].upper()}
ftobjects.append(newobj);
elif '=' in lines:
key, value = lines.split('=',1)
newobj[key.upper()]=value
return ftobjects
def ftlist2ftdict(ftlist):
retdict={}
for item in ftlist:
id = item['id']
retdict[id]=item.copy()
return retdict
def getoffset(partname):
import FreeCAD
#partname=ftpartobj['NAME'].split('_')[0][1:] #revove trailing F from Part Number
partpath=ftdpath+'/def/%s.def'%partname
partdef= def2list(partpath)
partdefdict = ftlist2ftdict(partdef)
#print partdefdict.keys()
#partfname=partdefdict['COMMON'][partnamelang].decode('latin1') #Part name
return FreeCAD.Vector(floatg(partdefdict['OFFSET']['X']),floatg(partdefdict['OFFSET']['Y']),floatg(partdefdict['OFFSET']['Z']))
def drawconnections(partdefdict,pos,rot,shortname): #doesn't work
def drawcoordinatesystem(shortname,partplacement,pos,rot,drawy=False,length=10):
import FreeCAD
import Draft
dwirex=Draft.makeWire([partplacement.multVec(pos),partplacement.multVec(rot.multVec(FreeCAD.Vector(length,0,0)).add(pos))])
dwirez=Draft.makeWire([partplacement.multVec(pos),partplacement.multVec(rot.multVec(FreeCAD.Vector(0,0,length)).add(pos))])
dwirex.Label='%s-X'%(shortname)
dwirez.Label='%s-Z'%(shortname)
dwirex.ViewObject.LineColor= (0.5,0.0,0.0)
dwirez.ViewObject.LineColor= (0.0,0.0,0.5)
if drawy:
dwirey=Draft.makeWire([partplacement.multVec(pos),partplacement.multVec(rot.multVec(FreeCAD.Vector(0,length,0)).add(pos))])
dwirey.Label='%s-Y'%(shortname)
dwirey.ViewObject.LineColor= (0.0,0.5,0.0)
import FreeCAD
for secname,secdict in partdefdict.iteritems():
if secname.startswith('CONN') and secname != 'CONNECTIONS':
connname=secdict['NAME'].decode('latin1')
partplacement=FreeCAD.Placement(pos,rot)
connpos=FreeCAD.Vector(floatg(secdict['X']),floatg(secdict['Y']),floatg(secdict['Z']))
pf,rf,tf=(floatg(secdict['PF']),floatg(secdict['RF']),floatg(secdict['TF']))
#pn,rn,tn=(floatg(secdict['PN']),floatg(secdict['RN']),floatg(secdict['TN']))
drawcoordinatesystem('%s-%s' % (shortname,connname),partplacement,connpos,prttorot(pf,rf,tf))
def open(filename):
"called when freecad opens a file."
import FreeCAD
docname = os.path.splitext(os.path.basename(filename))[0]
doc = FreeCAD.newDocument(docname)
loadfiletodoc(doc,filename)
def insert(filename,docname):
"called when freecad imports a file"
import FreeCAD
try:
doc=FreeCAD.getDocument(docname)
except:
doc=FreeCAD.newDocument(docname)
loadfiletodoc(doc,filename)
def fclabeltoftpart(label,name):
import re
moimp=re.match("P(\d+)_N(\d+)_([^_]+)_.*",label)
if moimp:
Phase,Number,PartNum = moimp.groups()
RepCount = None
print moimp.groups()
else:
sname=name.lstrip('_')
if len(sname)==4 or len(sname)==7:
sname='0'+sname
if len(sname)==8:
RepCount = int(sname[5:8])+1
else:
RepCount = 1
PartNum=sname[0:5]
Phase,Number = None,None
return (Phase,Number,PartNum,RepCount)
def export(exportList,filename):
"called when freecad exports a file"
import FreeCAD
efile = pythonopen(filename,'w')
meshlist=[obj for obj in exportList if obj.isDerivedFrom('Mesh::Feature')]
for objindex,obj in enumerate(meshlist):
pospar=fclabeltoftpart(obj.Label,obj.Name)
Phase,Number,PartNum,RepCount = pospar
#todo sort and regenerate Part Number and ids
correctedplacement=FreeCAD.Placement(obj.Placement.Base.sub(obj.Placement.Rotation.multVec(getoffset(PartNum))),obj.Placement.Rotation)
efile.write(formatpart(correctedplacement,obj.ViewObject.ShapeColor, Phase,objindex+1,PartNum,RepCount))
efile.write('\n')
efile.write(ftmfiletrailer%{'count':len(meshlist),'motors':"\n".join((ftmmotorstr % (5*(e,))) for e in range(1,9))})
efile.close()
def importrandompart(doc=None,drawconns=True,drawchildren=True):
import FreeCAD
import random
partfilename="%s/def/%s" % (ftdpath,random.choice( os.listdir(ftdpath+'/def')))
if doc is None:
doc=FreeCAD.newDocument()
print partfilename
ftpartformrepository(partfilename).addtofreecad(doc,drawconns,drawchildren)
def loadfiletodoc(doc,filename):
import FreeCAD
if filename.lower().endswith('.ftm'):
ftmodel(filename).addtofreecad(doc)
elif filename.lower().endswith('.part'):
ftpartfromfile(filename).addtofreecad(doc,drawconns=True,drawchildren=True)
elif filename.lower().endswith('.def'):
ftpartformrepository(filename).addtofreecad(doc,drawconns=True,drawchildren=True)
doc.recompute()
def shape_oese_negativ():
import FreeCAD
import Part
zylauss=Part.makeCylinder(3.2,20,FreeCAD.Vector(0,0,-10))
zylinn=Part.makeCylinder(2,2,FreeCAD.Vector(0,0,-1))
boxpl=Part.makeBox(2,6,1.2,FreeCAD.Vector(1.5,-3,-0.6))
boxmi=Part.makeBox(2,6,1.2,FreeCAD.Vector(-3.5,-3,-0.6))
boxes=boxpl.fuse(boxmi)
return zylauss.cut(boxes).fuse(zylinn)
def shape_oese_winkeltraeger(laengezmm=30):
import FreeCAD
import Part
zylinn=Part.makeCylinder(2,laengezmm,FreeCAD.Vector(0,0,-laengezmm/2.0))
box=Part.makeBox(3,7,laengezmm,FreeCAD.Vector(-1.5,-3.5,-laengezmm/2.0))
return zylinn.fuse(box).removeSplitter()
def shape_strebe(laengemm=30,b1=2.8,r1=3.975):
import FreeCAD
import Part
cyl1=Part.makeCylinder(r1,b1,FreeCAD.Vector(0,-0.5,-b1/2))
cyl2=Part.makeCylinder(r1,b1,FreeCAD.Vector(0,laengemm+0.5,-b1/2))
box=Part.makeBox(r1*2,laengemm+1,b1,FreeCAD.Vector(-r1,-0.5,-b1/2))
return box.fuse(cyl1).fuse(cyl2).removeSplitter()
def shape_i_strebe(laengemm=60,subtractbox=True):
import FreeCAD
import Part
posshape=shape_strebe(laengemm)
oen1=shape_oese_negativ()
oen2=oen1.copy()
oen2.Placement=FreeCAD.Placement(FreeCAD.Vector(0,laengemm,0),FreeCAD.Rotation())
beforebox = posshape.cut(oen1).cut(oen2)
if not subtractbox:
return beforebox
else:
boxshape1=Part.makeBox(4,laengemm-9,1,FreeCAD.Vector(-2,4.5,0.8))
boxshape2=Part.makeBox(4,laengemm-9,1,FreeCAD.Vector(-2,4.5,-1.8))
return beforebox.cut(boxshape1).cut(boxshape2)
def shape_zapfen(hoehe=2.6):
import FreeCAD
import Part
cyl1=Part.makeCylinder(2,8)
cyl1.Placement=FreeCAD.Placement(FreeCAD.Vector(0,-2.1,-4),FreeCAD.Rotation(-90,0.0,0.0))
nut1=cyl1.fuse(\
Part.makeBox(3,2,8,FreeCAD.Vector(-1.5,-2,-4))).common(\
Part.makeBox(8,2.8,8,FreeCAD.Vector(-4,- hoehe,-4))).removeSplitter()
nut2=nut1.copy()
nut2.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,90,0))
return nut1.common(nut2)
def shape_nut_flach(laengezmm=15,hoehe=2.8,breite=3.1):
import FreeCAD
import Part
cyl1=Part.makeCylinder(2,laengezmm)
cyl1.Placement=FreeCAD.Placement(FreeCAD.Vector(0,-2.1,0),FreeCAD.Rotation(90,0.0,0.0))
return cyl1.fuse(\
Part.makeBox(breite,2,laengezmm,FreeCAD.Vector(-breite/2.0,-2,0))).common(\
Part.makeBox(8,hoehe,laengezmm,FreeCAD.Vector(-4,-hoehe,0))).removeSplitter()
def shape_nut(laengezmm=15,breite=3.0):
import FreeCAD
import Part
cyl1=Part.makeCylinder(2,laengezmm)
cyl1.Placement=FreeCAD.Placement(FreeCAD.Vector(0,-2.1,0),FreeCAD.Rotation(90,0,0))
return cyl1.fuse( Part.makeBox(breite,2,laengezmm,FreeCAD.Vector(-breite/2.0,-2,0)))\
.removeSplitter()
def shape_zapfen_bs(hoehe=2.4,withstandoff=False):
import FreeCAD
import Part
zapfen=shape_zapfen(hoehe)
cyl1=Part.makeCylinder(0.4,8)
box=Part.makeBox(0.8,2,8,FreeCAD.Vector(-0.4,0,0))
slot=box.fuse(cyl1).removeSplitter()
slot.Placement=FreeCAD.Placement(FreeCAD.Vector(-2,-2.1,-2),\
FreeCAD.Rotation(180,-45,0))
cyl2=Part.makeCylinder(2.35,5)
cyl2.Placement=FreeCAD.Placement(FreeCAD.Vector(), FreeCAD.Rotation(0,0,90))
box1=Part.makeBox(9,1,1.2,FreeCAD.Vector(-4.5,-0.1,-0.6))
box2=box1.copy()
box2.Placement=FreeCAD.Placement(FreeCAD.Vector(), FreeCAD.Rotation(0,90,0))
withoutstandoff=zapfen.cut(slot).common(cyl2)
if not withstandoff:
return withoutstandoff
else:
standoff=box1.fuse(box2).removeSplitter()
standoff.Placement=FreeCAD.Placement(FreeCAD.Vector(), FreeCAD.Rotation(0,45,0))
return withoutstandoff.fuse(standoff)
def shape_baustein(laengemm=15,zapfenhinten=False,bohrungen=0):
import FreeCAD
import Part
box = Part.makeBox(15,laengemm,15,FreeCAD.Vector(-7.5,0,-7.5))
if bohrungen > 0:
bb1=Part.makeBox(20,4.15,4.15,FreeCAD.Vector(-10,-2.075,-2.075))
bb2=Part.makeBox(4.15,4.15,20,FreeCAD.Vector(-2.075,-2.075,-10))
bohrung=bb1.fuse(bb2).removeSplitter()
for bi in xrange(bohrungen):
bohrung.Placement=FreeCAD.Placement(\
FreeCAD.Vector(0,(bi+1)*(laengemm/(bohrungen+1.0)),0),\
FreeCAD.Rotation())
box=box.cut(bohrung)
# box.fuse(shape_zapfen(2.4))
nut0=shape_nut(laengemm)
nut1=nut0.copy()
nuty=nut0.copy()
nut1.Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,-7.5), FreeCAD.Rotation(0,0,-90))
#nut2=nut0.copy()
nut0.Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,7.5),FreeCAD.Rotation(180,0,90))
nutz=nut1.fuse(nut0)
nutx=nutz.copy()
nutx.Placement=FreeCAD.Placement(FreeCAD.Vector(),FreeCAD.Rotation(0,90,0))
nuty.Placement=FreeCAD.Placement(FreeCAD.Vector(-7.5,laengemm,0),\
FreeCAD.Rotation(0,90,0))
boxny0=Part.makeBox(4.4,4.4,4,FreeCAD.Vector(-7.5 ,laengemm-4.4,-2))
boxny1=Part.makeBox(4.4,4.4,4,FreeCAD.Vector(7.5-4.4,laengemm-4.4,-2))
zapfenv=shape_zapfen_bs(2.4)
nutxz=nutx.fuse(nutz)
if zapfenhinten:
zapfenh=zapfenv.copy()
zapfenh.Placement=FreeCAD.Placement(FreeCAD.Vector(0,laengemm,0),\
FreeCAD.Rotation(0,0,180))
return box.fuse(zapfenv).fuse(zapfenh).cut(nutxz)
else:
nut=nutxz.fuse(nuty.fuse(boxny0.fuse(boxny1)))
return box.cut(nut).removeSplitter().fuse(zapfenv)
def shape_winkeltraeger(laengemm=60):
import FreeCAD
import Part
boxo=Part.makeBox(15,laengemm,15,FreeCAD.Vector(-7.5,0,-7.5))
boxi=Part.makeBox(13,laengemm-5.5,13,FreeCAD.Vector(-5.5,2,-5.5))
traeger1=boxo.cut(boxi)
nut=shape_nut_flach()
nut.Placement=FreeCAD.Placement(FreeCAD.Vector(0,laengemm,-2.5),FreeCAD.Rotation())
traeger1=boxo.cut(boxi).cut(nut).fuse(shape_zapfen())
oese1=shape_oese_winkeltraeger()
oese2=oese1.copy()
oese1.Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,-7.5),FreeCAD.Rotation())
oese2.Placement=FreeCAD.Placement(FreeCAD.Vector(-7.5,0,0),FreeCAD.Rotation(0,90,0))
oesep=oese1.fuse(oese2)
len1=laengemm // 15
for i in range(len1):
oesep.Placement=FreeCAD.Placement(FreeCAD.Vector(0,7.5+i*15),FreeCAD.Rotation())
traeger1=traeger1.cut(oesep)
return traeger1
def shape_x_strebe(laengemm=60,subtractbox=True):
import FreeCAD
import Part
len1=laengemm // 15
tmpshape=shape_strebe(laengemm)
oesetemplate=shape_oese_negativ()
boxshape=Part.makeBox(4,7,1)
for i in range(len1+1):
oesetemplate.Placement=FreeCAD.Placement(FreeCAD.Vector(0,15.0*i,0),FreeCAD.Rotation())
tmpshape=tmpshape.cut(oesetemplate)
if subtractbox and i != len1:
boxshape.Placement=FreeCAD.Placement(FreeCAD.Vector(-2,4+15.0*i,0.8),FreeCAD.Rotation())
tmpshape=tmpshape.cut(boxshape)
boxshape.Placement=FreeCAD.Placement(FreeCAD.Vector(-2,4+15.0*i,-1.8),FreeCAD.Rotation())
tmpshape=tmpshape.cut(boxshape)
return tmpshape
def parsealldefs():
partsdict={}
for relfilename in os.listdir(ftdpath+'/def'):
if relfilename.endswith('.def'):
partpath="%s/def/%s" % (ftdpath,relfilename)
partdef= def2list(partpath)
partdefdict = ftlist2ftdict(partdef)
if 'COMMON' in partdefdict and 'ORGNUMBER' in partdefdict['COMMON']:
key=partdefdict['COMMON']['ORGNUMBER']
else:
key=relfilename.split('.',1)[0]
partsdict[key]=partdefdict
return partsdict
def connsforpartsdict():
return dict([(key,extractconnectionsfromdict(partdefdict)) for key,partdefdict in parsealldefs().iteritems()])
def partswithoffsetrot():
for key,value in parsealldefs().iteritems():
offset=value['OFFSET']
if 'RX' in offset and (floatg(offset['RX']) or floatg(offset['RY']) or floatg(offset['RZ'])):
yield (key,value)
def alignftparts(placementbasepart,placementconnbp,placementconnmp): #dysfunctional
return placementbasepart.multiply(placementconnbp).multiply(placementconnmp.inverse())
#return placementconnbp.multiply(placementconnmp.inverse())
#return placementbasepart.multiply(placementconnmp.inverse()).multiply(placementconnbp)
#return placementconnmp.inverse().multiply(placementconnbp).multiply(placementbasepart)
def alignftpobjs(baseobj,moveableobj,baseconn=0,moveableconn=0):
#allpartsconndict = allpartsconndict or connsforpartsdict()
basepartname=fclabeltoftpart(baseobj.Label,baseobj.Name)[2]
basepartconns=getpartconnectionsbypartname(basepartname) #allpartsconndict[basepartname]
moveablepartname=fclabeltoftpart(moveableobj.Label,moveableobj.Name)[2]
moveablepartconns=getpartconnectionsbypartname(moveablepartname) #allpartsconndict[moveablepartname]
if isinstance(baseconn, int):
baseconnobj=basepartconns[baseconn]
else:
pass
#TBD: String search for connection name
if isinstance(moveableconn, int):
moveableconnobj=moveablepartconns[moveableconn]
else:
pass
#TBD: String search for connection name
correctedplacement=FreeCAD.Placement(baseobj.Placement.Base.sub(baseobj.Placement.Rotation.multVec(getoffset(basepartname))),baseobj.Placement.Rotation)
newplacement=alignftparts(correctedplacement,baseconnobj.Placement,moveableconnobj.Placement)
moveableobj.Placement=FreeCAD.Placement(newplacement.Base.add(newplacement.Rotation.multVec(getoffset(moveablepartname))),newplacement.Rotation)
class ftpart():
def addtofreecad(self,doc=None,drawconns=True,drawchildren=True,placement=None,\
name=None,labelprefix='',color=None):
import FreeCAD
if placement is None:
placement = FreeCAD.Placement()
#Todo Support Child Objects
partfname= self.getfullname()
if not labelprefix:
longname = '%s_%s' % (self.shortpartnum,partfname)
else:
longname = '%s_%s' % (labelprefix,partfname)
import Mesh
obj=self.addtofreecadobj(doc,name or self.shortpartnum)
obj.Label=longname
obj.Placement=placement.multiply(self.homepos())
if FreeCAD.GuiUp:
obj.ViewObject.ShapeColor = color or self.getcolor()
obj.ViewObject.Transparency=self.gettransparancy()
if hasattr(obj.ViewObject,'CreaseAngle'):
obj.ViewObject.CreaseAngle = 12.00
if drawchildren:
for ChildPartNum in self.children:
findpart(ChildPartNum).addtofreecad(doc,drawconns=False,drawchildren=True)
if drawconns:
drawconnections(self.partdefdict,FreeCAD.Vector(),FreeCAD.Rotation(),self.shortpartnum)
return obj
class ftpartmesh(ftpart):
def _parsedef(self,str1):
ftobjects=[]
for line in str1.splitlines():
if line:
lines=line.strip()
if lines.startswith('[') and lines.endswith(']'):
newobj={'id':lines[1:-1].upper()}
ftobjects.append(newobj);
elif '=' in lines:
key, value = lines.split('=',1)
newobj[key.upper()]=value
retdict={}
for item in ftobjects:
id = item['id']
retdict[id]=item.copy()
self.partdefdict=retdict
#saveconnections
connlist=[]
for secname,secdict in self.partdefdict.iteritems():
if secname.startswith('CONN') and secname != 'CONNECTIONS':
try:
connlist.append(connection(secdict))
except Exception as e:
print str(secdict).encode('utf8'),e
raise
connlist.sort(key=lambda x :x.num)
self.connections=connlist
#safechildren
children=[]
for secname,secdict in self.partdefdict.iteritems():
if secname.startswith('CHILD') and secname != 'CHILDS':
children.append((int(secname[5:]),secdict['NUMBER']))
children.sort()#key=lambda x:x[0])
if len(children) > 0:
self.children=zip(*children)[1]
else:
self.children=()
#if 'COMMON' in partdefdict and 'ORGNUMBER' in partdefdict['COMMON']:
# key=partdefdict['COMMON']['ORGNUMBER']
#else:
# key=relfilename.split('.',1)[0]
#partsdict[key]=partdefdict
def addtofreecadobj(self,doc,name=None):
import Mesh
meshobj=doc.addObject('Mesh::Feature',name or self.shortpartnum)
meshobj.Mesh=self.addmeshtofreecad()
return meshobj
def getfullname(self):
return self.partdefdict['COMMON'][partnamelang].decode('latin1') #Part name
def getoffset(self):
import FreeCAD
return FreeCAD.Vector(floatg(self.partdefdict['OFFSET']['X']),\
floatg(self.partdefdict['OFFSET']['Y']),\
floatg(self.partdefdict['OFFSET']['Z']))
def homepos(self):
import FreeCAD
return FreeCAD.Placement(self.getoffset(),FreeCAD.Rotation())
#FreeCAD.Placement(pos.add(rot.multVec(partoffset)),rot)
def gettransparancy(self):
if 'ALPHA' in self.partdefdict['COLOR']:
return ((1-floatg(self.partdefdict['COLOR']['ALPHA']))*100)
else:
return 0
def getcolor(self):
partlibcolordict=self.partdefdict['COLOR']
return int(partlibcolordict['RED'])/255.0,\
int(partlibcolordict['GREEN'])/255.0, \
int(partlibcolordict['BLUE'])/255.0
class ftpartinternal(ftpart):
import FreeCAD
P=FreeCAD.Placement
V=FreeCAD.Vector
R=FreeCAD.Rotation
internalparts={\
# ( (func,args,kwargs), placement, color ... )
#Building blocks
'32879':((shape_baustein,(30,),{}),P(V(-30,0,7.5),R(-90,0,0)), ), #bs30sw
'16251':((shape_baustein,(30,),{}),P(V(-30,0,7.5),R(-90,0,0)), ), #bs30rt
'36528':((shape_baustein,(30,),{}),P(V(-30,0,7.5),R(-90,0,0)), ), #bs30ge
#'C0050':(), #standoff bs sw
'32880':((shape_baustein,(30,),{'bohrungen':1}),P(V(0,0,30),R(-90,0,-90)), ), #bs30sw hole
'32881':((shape_baustein,(15,),{}),P(), ), #bs15sw
'16252':((shape_baustein,(15,),{}),P(), ), #bs15rt
'36529':((shape_baustein,(15,),{}),P(), ), #bs15ge
#'C0051':(), #standoff bs sw
'32882':((shape_baustein,(15,True),{}),P(), ), #bs15dual
#31003-31005 #old building blocks
#struts
'38544':((shape_i_strebe,(15,),{}),P(V(0,-15,0),R()), ), #istrut15ge
'31764':((shape_i_strebe,(30,),{}),P(V(0,-15,0),R()), ), #istrut30ge
'36328':((shape_i_strebe,(45,),{}),P(V(0,-22.5,0),R()), ), #istrut45ge
'36322':((shape_i_strebe,(60,),{}),P(V(0,-30,0),R()), ), #istrut60ge
'32200':((shape_i_strebe,(75,),{}),P(V(0,-37.5,0),R()), ), #istrut75ge
'31765':((shape_i_strebe,(90,),{}),P(V(0,-45,0),R()), ), #istrut90ge
'36335':((shape_i_strebe,(120,),{}),P(V(0,-60,0),R()), ), #istrut120ge
'38542':((shape_i_strebe,(42.426,),{}),P(), ), #istrut42.4ge
'36326':((shape_i_strebe,(63.640,),{}),P(), ), #istrut63.6ge
'35058':((shape_i_strebe,(84.852,),{}),P(), ), #istrut84.8ge
'35059':((shape_i_strebe,(106.066,),{}),P(), ), #istrut106ge
'36336':((shape_i_strebe,(196.706,),{}),P(), ), #istrut196.6ge
'36914':((shape_i_strebe,(15,),{}),P(V(0,-15,0),R()), ), #istrut15gr
'36924':((shape_i_strebe,(120,),{}),P(V(0,-60,0),R()), ), #istrut120gr
'36370':((shape_i_strebe,(63.640,),{}),P(V(0,-31.8198,0),R()), ), #istrut63.6gr
'35057':((shape_i_strebe,(106.066,),{}),P(), ), #istrut106gr
'38538':((shape_x_strebe,(30,),{}),P(V(0,-15,0),R()), ), #xstrut30ge
'38541':((shape_x_strebe,(45,),{}),P(), ), #xstrut45ge
'38540':((shape_x_strebe,(60,),{}),P(), ), #xstrut60ge
'38545':((shape_x_strebe,(75,),{}),P(), ), #xstrut75ge
'38531':((shape_x_strebe,(90,),{}),P(), ), #xstrut90ge
'35060':((shape_x_strebe,(120,),{}),P(), ), #xstrut120ge
'36912':((shape_x_strebe,(30,),{}),P(), ), #xstrut30gr
'36913':((shape_x_strebe,(45,),{}),P(), ), #xstrut45gr
'36952':((shape_x_strebe,(60,),{}),P(), ), #xstrut60gr
'36923':((shape_x_strebe,(75,),{}),P(), ), #xstrut75gr
'38543':((shape_x_strebe,(90,),{}),P(), ), #xstrut90gr
'38546':((shape_x_strebe,(120,),{}),P(), ), #xstrut120gr
#angle gr
'35053':((shape_winkeltraeger,(15,),{}),P(), ), #angleg15ge
'36922':((shape_winkeltraeger,(15,),{}),P(), ), #angleg15sw
'27471':((shape_winkeltraeger,(15,),{}),P(), ), #angleg15rt
#zwei zapfen 36298,36950
'36299':((shape_winkeltraeger,(30,),{}),P(), ), #angleg30ge
'27472':((shape_winkeltraeger,(30,),{}),P(), ), #angleg30rt
'36920':((shape_winkeltraeger,(30,),{}),P(), ), #angleg30sw
'36297':((shape_winkeltraeger,(60,),{}),P(), ), #angleg60ge
'36921':((shape_winkeltraeger,(60,),{}),P(), ), #angleg60sw
'78728':((shape_winkeltraeger,(60,),{}),P(), ), #angleg60rt
'32223':((shape_winkeltraeger,(120,),{}),P(), ), #angleg120rt
'36294':((shape_winkeltraeger,(120,),{}),P(), ), #angleg120ge
'36293':((shape_winkeltraeger,(120,),{}),P(), ), #angleg120sw
#def shape_winkeltraeger(laengemm=60):
}
def __init__(self,fname):
if fname.upper() in self.internalparts:
self.shortpartnum=fname
else:
raise KeyError #no BREP available
def getfullname(self):
return self.shortpartnum #ToDo
def homepos(self):
return self.internalparts[self.shortpartnum][1]
def getcolor(self):
return 0.5,0.5,0.5
def gettransparancy(self):
return 0
#import FreeCAD
#return FreeCAD.Placement(partoffset,FreeCAD.Rotation())
# def getoffset(self):
# import FreeCAD
# return FreeCAD.Vector()
def addtofreecadobj(self,doc,name=None):
import Part
obj=doc.addObject('Part::Feature',name or self.shortpartnum)
func,args,kwargs=self.internalparts[self.shortpartnum][0]
obj.Shape=func(*args,**kwargs)
return obj
class ftpartfromfile(ftpartmesh):
def __init__(self,fname):
import struct
f1=pythonopen(fname)
partheader=f1.read(45)
self.shortpartnum=partheader[40:45]
filelengths=struct.unpack('IIIIII',partheader[16:40])
filesdict={'partnum':self.shortpartnum}
for key,length in zip(('stl','bmp','def','lowresstl','jpg','nrm'), filelengths):
filesdict[key]=f1.read(length)
self.filesdict=filesdict
self._parsedef(filesdict['def'])
def addmeshtofreecad(self,highres=True):
if highres:
stlstr=self.filesdict['stl']
else:
stlstr=self.filesdict['lowresstl']
import FreeCAD,Mesh
import os,tempfile,time
dir1=tempfile.gettempdir()
#inputfilename=os.path.join(dir1,'pisc-%s.stl' % self.shortname)
inputfilename=tempfile.mktemp('-%s.stl'%self.shortpartnum)
inputfile = pythonopen(inputfilename,'wb')
inputfile.write(stlstr)
inputfile.close()
partmesh = Mesh.read(inputfilename)
os.unlink(inputfilename)
return partmesh
class ftpartformrepository(ftpartmesh):
def __init__(self,shortnum):
import os
if os.path.isfile(shortnum): #full path of def
pdir,pname = os.path.split(shortnum)
self.shortpartnum=pname.rsplit('.',1)[0]
self.libpath=os.path.normpath('%s/..'%pdir)
deffilename=shortnum
else:
self.shortpartnum=shortnum
deffilename=ftdpath+'/def/%s.def'% shortnum
self.libpath=ftdpath
deffile=pythonopen(deffilename)
self._parsedef(deffile.read())
def addmeshtofreecad(self,highres=True):
import FreeCAD,Mesh
if highres:
stldir='hires'
else:
stldir='lores'
#partname=os.path.splitext(os.path.basename(filename))[0] #use self.shortname
partmeshfilename='%s/%s/%s.stl'%(self.libpath,stldir,self.shortpartnum)
partmesh = Mesh.read(partmeshfilename)
return partmesh
class ftmodel():
def __init__(self,filename):
self.modellist=def2list(filename)
def addtofreecad(self,doc=None,drawconns=True,drawchildren=True):
import FreeCAD
groups={}
for ftpartobj in self.modellist:
if ftpartobj['id'].startswith('PART'):
groupname='phase%02d' % int(ftpartobj['PHASE'])
if groupname not in groups:
groups[groupname] = doc.addObject("App::DocumentObjectGroup",groupname)
partname=ftpartobj['NAME'].split('_')[0][1:] #revove trailing F from Part Number
pos=FreeCAD.Vector(floatg(ftpartobj['XPOS'])*10,floatg(ftpartobj['YPOS'])*10,floatg(ftpartobj['ZPOS'])*10)
dirz=FreeCAD.Vector(floatg(ftpartobj['XDIR']),floatg(ftpartobj['YDIR']),floatg(ftpartobj['ZDIR']))
upy=FreeCAD.Vector(floatg(ftpartobj['XUP']),floatg(ftpartobj['YUP']),floatg(ftpartobj['ZUP']))
missingx=upy.cross(dirz) #first row of rotation matrix
rotmat=FreeCAD.Matrix(missingx[0],upy[0],dirz[0],0,missingx[1],upy[1],dirz[1],0,missingx[2],upy[2],dirz[2])
rot=FreeCAD.Placement(rotmat).Rotation
shortname ='N%04d_%s' %(int(ftpartobj['id'][4:]),ftpartobj['NAME'][1:])
longname ='P%02d_%s' %(int(ftpartobj['PHASE']),shortname)
bgr=int(ftpartobj['COLOR'])
partmodelcolor=(bgr & 0x0000ff ) /(0x0000ff*1.0),(bgr & 0x00ff00 ) /(0x00ff00*1.0),(bgr & 0xff0000 ) /(0xff0000*1.0)
obj=findpart(partname).addtofreecad(doc,drawconns=False,drawchildren=False,\
placement=FreeCAD.Placement(pos,rot),name=shortname,labelprefix=longname,color=partmodelcolor)
groups[groupname].addObject(obj)
def compareparts(partname):
import FreeCAD
doc=FreeCAD.ActiveDocument
rpart = ftpartformrepository(partname)
ipart = ftpartinternal(partname)
rpart.addtofreecad(doc,drawconns=False,drawchildren=False)
ipart.addtofreecad(doc,drawconns=False,drawchildren=False)
def findpart(partname):
part = None
try:
part = ftpartinternal(partname)
except KeyError:
part = ftpartformrepository(partname)
return part
def registerFCTypes():
import FreeCAD
FreeCAD.addExportType("fischertechnik designer Model (*.ftm)","piscator")
FreeCAD.addImportType("fischertechnik designer Model (*.ftm)","piscator")
FreeCAD.addImportType("fischertechnik designer Part (*.def)","piscator")
FreeCAD.addImportType("fischertechnik designer Part (*.part)","piscator")
if __name__ == '__main__':
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment