00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 import FreeCAD, Part, os, FreeCADGui, draftGui
00026 from FreeCAD import Base
00027 from math import *
00028
00029
00030
00031
00032
00033
00034
00035
00036 model_tab_filename = FreeCAD.getResourceDir()+ "Mod/Idf/lib/footprints_models.csv"
00037
00038 step_path=FreeCAD.getResourceDir()+ "Mod/Idf/lib/"
00039
00040
00041 ignore_hole_size=1
00042 EmpDisplayMode=2
00043
00044 IDF_sort=0
00045
00046 IDF_diag=1
00047 IDF_diag_path="C:/temp"
00048
00049
00050
00051
00052
00053
00054 pythonopen = open
00055
00056 def open(filename):
00057 """called when freecad opens an Emn file"""
00058 docname = os.path.splitext(os.path.basename(filename))[0]
00059 doc = FreeCAD.newDocument(docname)
00060 FreeCAD.setActiveDocument(docname)
00061 message='Started with opening of "'+filename+'" file\n'
00062 FreeCAD.Console.PrintMessage(message)
00063 process_emn(doc,filename)
00064
00065 def insert(filename,docname):
00066 """called when freecad imports an Emn file"""
00067 FreeCAD.setActiveDocument(docname)
00068 doc=FreeCAD.getDocument(docname)
00069 FreeCAD.Console.PrintMessage('Started import of "'+filename+'" file')
00070 process_emn(doc,filename)
00071
00072 def process_emn(doc,filename):
00073 """process_emn(document, filename)-> adds emn geometry from emn file"""
00074 emnfile=pythonopen(filename, "r")
00075 emn_unit=1.0
00076 emn_version=2
00077 board_thickness=0
00078 board_outline=[]
00079 drills=[]
00080 placement=[]
00081 place_item=[]
00082 emnlines=emnfile.readlines()
00083 emnfile.close()
00084 passed_sections=[]
00085 current_section=""
00086 section_counter=0
00087 for emnline in emnlines:
00088 emnrecords=split_records(emnline)
00089 if emnrecords[0][0:4]==".END":
00090 passed_sections.append(current_section)
00091 current_section=""
00092 elif emnrecords[0][0]==".":
00093 current_section=emnrecords[0]
00094 section_counter=0
00095 section_counter+=1
00096 if current_section==".HEADER" and section_counter==2:
00097 emn_version=int(float(emnrecords[1]))
00098 FreeCAD.Console.PrintMessage("Emn version: "+emnrecords[1]+"\n")
00099 if current_section==".HEADER" and section_counter==3 and emnrecords[1]=="THOU":
00100 emn_unit=0.0254
00101 FreeCAD.Console.PrintMessage("UNIT THOU\n" )
00102 if current_section==".HEADER" and section_counter==3 and emnrecords[1]=="TNM":
00103 emn_unit=0.000010
00104 FreeCAD.Console.PrintMessage("TNM\n" )
00105 if current_section==".BOARD_OUTLINE" and section_counter==2:
00106 board_thickness=emn_unit*float(emnrecords[0])
00107 FreeCAD.Console.PrintMessage("Found board thickness "+emnrecords[0]+"\n")
00108 if current_section==".BOARD_OUTLINE" and section_counter>2:
00109 board_outline.append([int(emnrecords[0]),float(emnrecords[1])*emn_unit,float(emnrecords[2])*emn_unit,float(emnrecords[3])])
00110 if current_section==".DRILLED_HOLES" and section_counter>2 and float(emnrecords[0])*emn_unit>ignore_hole_size:
00111 drills.append([float(emnrecords[0])*emn_unit,float(emnrecords[1])*emn_unit,float(emnrecords[2])*emn_unit])
00112 if current_section==".PLACEMENT" and section_counter>1 and fmod(section_counter,2)==0:
00113 place_item=[]
00114 place_item.append(emnrecords[2])
00115 place_item.append(emnrecords[1])
00116 place_item.append(emnrecords[0])
00117 if current_section==".PLACEMENT" and section_counter>1 and fmod(section_counter,2)==1:
00118 place_item.append(float(emnrecords[0])*emn_unit)
00119 place_item.append(float(emnrecords[1])*emn_unit)
00120 place_item.append(float(emnrecords[emn_version]))
00121 place_item.append(emnrecords[emn_version+1])
00122 place_item.append(emnrecords[emn_version+2])
00123 FreeCAD.Console.PrintMessage(str(place_item)+"\n")
00124 placement.append(place_item)
00125 FreeCAD.Console.PrintMessage("\n".join(passed_sections))
00126 FreeCAD.Console.PrintMessage("Proceed "+str(Process_board_outline(doc,board_outline,drills,board_thickness))+" outlines\n")
00127 placement.sort(key=lambda param: (param[IDF_sort],param[0]))
00128 process_emp(doc,filename,placement,board_thickness)
00129 place_steps(doc,placement,board_thickness)
00130
00131 def Process_board_outline(doc,board_outline,drills,board_thickness):
00132 """Process_board_outline(doc,board_outline,drills,board_thickness)-> number proccesed loops
00133
00134 adds emn geometry from emn file"""
00135 vertex_index=-1;
00136 lines=-1
00137 out_shape=[]
00138 out_face=[]
00139 for point in board_outline:
00140 vertex=Base.Vector(point[1],point[2],0)
00141 vertex_index+=1
00142 if vertex_index==0:
00143 lines=point[0]
00144 elif lines==point[0]:
00145 if point[3]!=0 and point[3]!=360:
00146 out_shape.append(Part.Arc(prev_vertex,mid_point(prev_vertex,vertex,point[3]),vertex))
00147 FreeCAD.Console.PrintMessage("mid point "+str(mid_point)+"\n")
00148 elif point[3]==360:
00149 per_point=Per_point(prev_vertex,vertex)
00150 out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,point[3]/2),vertex))
00151 out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,-point[3]/2),vertex))
00152 else:
00153 out_shape.append(Part.Line(prev_vertex,vertex))
00154 else:
00155 out_shape=Part.Shape(out_shape)
00156 out_shape=Part.Wire(out_shape.Edges)
00157 out_face.append(Part.Face(out_shape))
00158 out_shape=[]
00159 vertex_index=0
00160 lines=point[0]
00161 prev_vertex=vertex
00162 if lines!=-1:
00163 out_shape=Part.Shape(out_shape)
00164 out_shape=Part.Wire(out_shape.Edges)
00165 out_face.append(Part.Face(out_shape))
00166 outline=out_face[0]
00167 FreeCAD.Console.PrintMessage("Added outline\n")
00168 if len(out_face)>1:
00169 for otl_cut in out_face[1: ]:
00170 outline=outline.cut(otl_cut)
00171 FreeCAD.Console.PrintMessage("Cutting shape inside outline\n")
00172 for drill in drills:
00173 FreeCAD.Console.PrintMessage("Cutting hole inside outline\n")
00174 out_shape=Part.makeCircle(drill[0]/2, Base.Vector(drill[1],drill[2],0))
00175 out_shape=Part.Wire(out_shape.Edges)
00176 outline=outline.cut(Part.Face(out_shape))
00177 doc_outline=doc.addObject("Part::Feature","Board_outline")
00178 doc_outline.Shape=outline
00179 FreeCADGui.Selection.addSelection(doc_outline)
00180 FreeCADGui.runCommand("Draft_Upgrade")
00181 outline=FreeCAD.ActiveDocument.getObject("Union").Shape
00182 FreeCAD.ActiveDocument.removeObject("Union")
00183 doc_outline=doc.addObject("Part::Feature","Board_outline")
00184 doc_outline.Shape=outline.extrude(Base.Vector(0,0,-board_thickness))
00185 grp=doc.addObject("App::DocumentObjectGroup", "Board_Geoms")
00186 grp.addObject(doc_outline)
00187 doc.Board_outline.ViewObject.ShapeColor=(0.0, 0.5, 0.0, 0.0)
00188 return lines+1
00189
00190 def mid_point(prev_vertex,vertex,angle):
00191 """mid_point(prev_vertex,vertex,angle)-> mid_vertex
00192
00193 returns mid point on arc of angle between prev_vertex and vertex"""
00194 angle=radians(angle/2)
00195 basic_angle=atan2(vertex.y-prev_vertex.y,vertex.x-prev_vertex.x)-pi/2
00196 shift=(1-cos(angle))*hypot(vertex.y-prev_vertex.y,vertex.x-prev_vertex.x)/2/sin(angle)
00197 midpoint=Base.Vector((vertex.x+prev_vertex.x)/2+shift*cos(basic_angle),(vertex.y+prev_vertex.y)/2+shift*sin(basic_angle),0)
00198 return midpoint
00199
00200 def split_records(line_record):
00201 """split_records(line_record)-> list of strings(records)
00202
00203 standard separator list separator is space, records containting encapsulated by " """
00204 split_result=[]
00205 quote_pos=line_record.find('"')
00206 while quote_pos!=-1:
00207 if quote_pos>0:
00208 split_result.extend(line_record[ :quote_pos].split())
00209 line_record=line_record[quote_pos: ]
00210 quote_pos=line_record.find('"',1)
00211 else:
00212 quote_pos=line_record.find('"',1)
00213 if quote_pos!=-1:
00214 split_result.append(line_record[ :quote_pos+1])
00215 line_record=line_record[quote_pos+1: ]
00216 else:
00217 split_result.append(line_record)
00218 line_record=""
00219 quote_pos=line_record.find('"')
00220 split_result.extend(line_record.split())
00221 return split_result
00222
00223 def process_emp(doc,filename,placement,board_thickness):
00224 """process_emp(doc,filename,placement,board_thickness) -> place components from emn file to board"""
00225 filename=filename.partition(".emn")[0]+".emp"
00226 empfile=pythonopen(filename, "r")
00227 emp_unit=1.0
00228 emp_version=2
00229 comp_height=0
00230 comp_outline=[]
00231 comp_GeometryName=""
00232 comp_PartNumber=""
00233 comp_height=0
00234 emplines=empfile.readlines()
00235 empfile.close()
00236 passed_sections=[]
00237 current_section=""
00238 section_counter=0
00239 comps=[]
00240 for empline in emplines:
00241 emprecords=split_records(empline)
00242 if emprecords[0][0:4]==".END":
00243 current_section=""
00244 passed_sections.append(current_section)
00245 if comp_PartNumber!="":
00246 comps.append((comp_PartNumber,[Process_comp_outline(doc,comp_outline,comp_height),comp_GeometryName]))
00247 comp_PartNumber=""
00248 comp_outline=[]
00249 elif emprecords[0][0]==".":
00250 current_section=emprecords[0]
00251 section_counter=0
00252 section_counter+=1
00253 if current_section==".HEADER" and section_counter==2:
00254 emp_version=int(float(emprecords[1]))
00255 FreeCAD.Console.PrintMessage("Emp version: "+emprecords[1]+"\n")
00256 if (current_section==".ELECTRICAL" or current_section==".MECHANICAL") and section_counter==2 and emprecords[2]=="THOU":
00257 emp_unit=0.0254
00258 if (current_section==".ELECTRICAL" or current_section==".MECHANICAL") and section_counter==2 and emprecords[2]=="MM":
00259 emp_unit=1
00260 if (current_section==".ELECTRICAL" or current_section==".MECHANICAL") and section_counter==2:
00261 comp_outline=[]
00262 comp_GeometryName=emprecords[0]
00263 comp_PartNumber=emprecords[1]
00264 comp_height=emp_unit*float(emprecords[3])
00265 if (current_section==".ELECTRICAL" or current_section==".MECHANICAL") and section_counter>2:
00266 comp_outline.append([float(emprecords[1])*emp_unit,float(emprecords[2])*emp_unit,float(emprecords[3])])
00267 FreeCAD.Console.PrintMessage("\n".join(passed_sections))
00268
00269 if IDF_diag==1:
00270 empfile=pythonopen(IDF_diag_path+"/footprint.lst", "w")
00271 for compx in comps:
00272 empfile.writelines(str(compx[1][1])+"\n")
00273 empfile.close()
00274
00275 comps=dict(comps)
00276 grp=doc.addObject("App::DocumentObjectGroup", "EMP Models")
00277 for place_item in placement:
00278 if comps.has_key(place_item[1]):
00279 doc_comp=doc.addObject("Part::Feature",place_item[0])
00280 FreeCAD.Console.PrintMessage("Adding EMP model "+str(place_item[0])+"\n")
00281 doc_comp.Shape=comps[place_item[1]][0]
00282 doc_comp.ViewObject.DisplayMode=EmpDisplayMode
00283 z_pos=0
00284 rotateY=0
00285 if place_item[6]=='BOTTOM':
00286 rotateY=pi
00287 z_pos=-board_thickness
00288 placmnt=Base.Placement(Base.Vector(place_item[3],place_item[4],z_pos),toQuaternion(rotateY,place_item[5]*pi/180,0))
00289 doc_comp.Placement=placmnt
00290 grp.addObject(doc_comp)
00291 return 1
00292
00293 def Process_comp_outline(doc,comp_outline,comp_height):
00294 """Process_comp_outline(doc,comp_outline,comp_height)->part shape
00295 Create solid component shape base on its outline"""
00296 vertex_index=-1;
00297 out_shape=[]
00298 if comp_outline==[]:
00299 comp_outline.append([0.0,0.0,0.0])
00300 comp_outline.append([0.1,0.0,360.0])
00301 for point in comp_outline:
00302 vertex=Base.Vector(point[0],point[1],0)
00303 vertex_index+=1
00304 if vertex_index>0:
00305 if point[2]!=0 and point[2]!=360:
00306 out_shape.append(Part.Arc(prev_vertex,mid_point(prev_vertex,vertex,point[2]),vertex))
00307 FreeCAD.Console.PrintMessage("mid point "+str(mid_point)+"\n")
00308 elif point[2]==360:
00309 per_point=Per_point(prev_vertex,vertex)
00310 out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,point[2]/2),vertex))
00311 out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,-point[2]/2),vertex))
00312 else:
00313 out_shape.append(Part.Line(prev_vertex,vertex))
00314 prev_vertex=vertex
00315 out_shape=Part.Shape(out_shape)
00316 out_shape=Part.Wire(out_shape.Edges)
00317 out_shape=Part.Face(out_shape)
00318 out_shape=out_shape.extrude(Base.Vector(0,0,comp_height))
00319
00320 return out_shape
00321
00322 def place_steps(doc,placement,board_thickness):
00323 """ place_steps(doc,placement,board_thickness)->place step models on board
00324
00325 list of models and path to step files is set at start of this script
00326 model_tab_filename= "" & step_path="" """
00327 model_file=pythonopen(model_tab_filename, "r")
00328 model_lines=model_file.readlines()
00329 model_file.close()
00330 model_dict=[]
00331 model_file=pythonopen(IDF_diag_path+"/missing_models.lst", "w")
00332 keys=[]
00333
00334 step_dict=[]
00335 for model_line in model_lines:
00336 model_records=split_records(model_line)
00337 if len(model_records)>1 and model_records[0] and not model_records[0] in keys:
00338 keys.append(model_records[0])
00339 model_dict.append((str(model_records[0]).replace('"',''),str(model_records[1]).replace('"','')))
00340 model_dict=dict(model_dict)
00341 validkeys=filter(lambda x:x in [place_item[2] for place_item in placement], model_dict.keys())
00342 FreeCAD.Console.PrintMessage("Step models to be loaded for footprints: "+str(validkeys)+"\n")
00343 grp=doc.addObject("App::DocumentObjectGroup", "Step Models")
00344 for validkey in validkeys:
00345 step_dict.append((validkey,Part.read(step_path+"/"+model_dict[validkey])))
00346 FreeCAD.Console.PrintMessage("Reading step file "+str(model_dict[validkey])+" for footprint "+str(validkey)+"\n")
00347 step_dict=dict(step_dict)
00348 for place_item in placement:
00349 if step_dict.has_key(place_item[2]):
00350 step_model=doc.addObject("Part::Feature",place_item[0]+"_s")
00351 FreeCAD.Console.PrintMessage("Adding STEP model "+str(place_item[0])+"\n")
00352
00353
00354
00355 step_model.Shape=step_dict[place_item[2]]
00356 z_pos=0
00357 rotateY=0
00358 if place_item[6]=='BOTTOM':
00359 rotateY=pi
00360 z_pos=-board_thickness
00361 placmnt=Base.Placement(Base.Vector(place_item[3],place_item[4],z_pos),toQuaternion(rotateY,place_item[5]*pi/180,0))
00362 step_model.Placement=placmnt
00363 grp.addObject(step_model)
00364 else:
00365 if IDF_diag==1:
00366 model_file.writelines(str(place_item[0])+" "+str(place_item[2])+"\n")
00367 model_file.close()
00368
00369 def toQuaternion(heading, attitude,bank):
00370 """toQuaternion(heading, attitude,bank)->FreeCAD.Base.Rotation(Quternion)"""
00371 c1 = cos(heading/2)
00372 s1 = sin(heading/2)
00373 c2 = cos(attitude/2)
00374 s2 = sin(attitude/2)
00375 c3 = cos(bank/2)
00376 s3 = sin(bank/2)
00377 c1c2 = c1*c2
00378 s1s2 = s1*s2
00379 w = c1c2*c3 - s1s2*s3
00380 x = c1c2*s3 + s1s2*c3
00381 y = s1*c2*c3 + c1*s2*s3
00382 z = c1*s2*c3 - s1*c2*s3
00383 return FreeCAD.Base.Rotation(x,y,z,w)
00384
00385 def Per_point(prev_vertex,vertex):
00386 """Per_point(center,vertex)->per point
00387
00388 returns opposite perimeter point of circle"""
00389
00390
00391
00392 perpoint=Base.Vector(2*prev_vertex.x-vertex.x,2*prev_vertex.y-vertex.y,0)
00393 return perpoint
00394
00395