| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import FreeCAD, Part, os, FreeCADGui |
| | from FreeCAD import Base |
| | from math import * |
| | import ImportGui |
| | from builtins import open as pyopen |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| |
|
| | model_tab_filename = FreeCAD.getHomePath()+ "Mod/Idf/Idflibs/footprints_models.csv" |
| |
|
| | |
| |
|
| | step_path=FreeCAD.getHomePath()+ "Mod/Idf/Idflibs/" |
| |
|
| | ignore_hole_size=0.5 |
| | EmpDisplayMode=2 |
| |
|
| | IDF_sort=0 |
| |
|
| | IDF_diag=0 |
| | IDF_diag_path="/tmp" |
| |
|
| |
|
| | |
| | |
| | |
| |
|
| | def open(filename): |
| | """called when freecad opens an Emn file""" |
| | docname = os.path.splitext(os.path.basename(filename))[0] |
| | doc = FreeCAD.newDocument(docname) |
| | message='Started with opening of "'+filename+'" file\n' |
| | FreeCAD.Console.PrintMessage(message) |
| | process_emn(doc,filename) |
| |
|
| | def insert(filename,docname): |
| | """called when freecad imports an Emn file""" |
| | FreeCAD.setActiveDocument(docname) |
| | doc=FreeCAD.getDocument(docname) |
| | FreeCAD.Console.PrintMessage('Started import of "'+filename+'" file') |
| | process_emn(doc,filename) |
| |
|
| | def process_emn(doc,filename): |
| | """process_emn(document, filename)-> adds emn geometry from emn file""" |
| | emnfile=pyopen(filename, "r") |
| | emn_unit=1.0 |
| | emn_version=2 |
| | board_thickness=0 |
| | board_outline=[] |
| | drills=[] |
| | placement=[] |
| | place_item=[] |
| | emnlines=emnfile.readlines() |
| | emnfile.close() |
| | passed_sections=[] |
| | current_section="" |
| | section_counter=0 |
| | for emnline in emnlines: |
| | emnrecords=split_records(emnline) |
| | if len( emnrecords )==0 : continue |
| | if len( emnrecords[0] )>4 and emnrecords[0][0:4]==".END": |
| | passed_sections.append(current_section) |
| | current_section="" |
| | elif emnrecords[0][0]==".": |
| | current_section=emnrecords[0] |
| | section_counter=0 |
| | section_counter+=1 |
| | if current_section==".HEADER" and section_counter==2: |
| | emn_version=int(float(emnrecords[1])) |
| | FreeCAD.Console.PrintMessage("Emn version: "+emnrecords[1]+"\n") |
| | if current_section==".HEADER" and section_counter==3 and emnrecords[1]=="THOU": |
| | emn_unit=0.0254 |
| | FreeCAD.Console.PrintMessage("UNIT THOU\n" ) |
| | if current_section==".HEADER" and section_counter==3 and emnrecords[1]=="TNM": |
| | emn_unit=0.000010 |
| | FreeCAD.Console.PrintMessage("TNM\n" ) |
| | if current_section==".BOARD_OUTLINE" and section_counter==2: |
| | board_thickness=emn_unit*float(emnrecords[0]) |
| | FreeCAD.Console.PrintMessage("Found board thickness "+emnrecords[0]+"\n") |
| | if current_section==".BOARD_OUTLINE" and section_counter>2: |
| | board_outline.append([int(emnrecords[0]),float(emnrecords[1])*emn_unit,float(emnrecords[2])*emn_unit,float(emnrecords[3])]) |
| | if current_section==".DRILLED_HOLES" and section_counter>1 and float(emnrecords[0])*emn_unit>ignore_hole_size: |
| | drills.append([float(emnrecords[0])*emn_unit,float(emnrecords[1])*emn_unit,float(emnrecords[2])*emn_unit]) |
| | if current_section==".PLACEMENT" and section_counter>1 and fmod(section_counter,2)==0: |
| | place_item=[] |
| | place_item.append(emnrecords[2]) |
| | place_item.append(emnrecords[1]) |
| | place_item.append(emnrecords[0]) |
| | if current_section==".PLACEMENT" and section_counter>1 and fmod(section_counter,2)==1: |
| | place_item.append(float(emnrecords[0])*emn_unit) |
| | place_item.append(float(emnrecords[1])*emn_unit) |
| | place_item.append(float(emnrecords[emn_version])) |
| | place_item.append(emnrecords[emn_version+1]) |
| | place_item.append(emnrecords[emn_version+2]) |
| | FreeCAD.Console.PrintMessage(str(place_item)+"\n") |
| | placement.append(place_item) |
| | FreeCAD.Console.PrintMessage("\n".join(passed_sections)+"\n") |
| | FreeCAD.Console.PrintMessage("Proceed "+str(Process_board_outline(doc,board_outline,drills,board_thickness))+" outlines\n") |
| | placement.sort(key=lambda param: (param[IDF_sort],param[0])) |
| | process_emp(doc,filename,placement,board_thickness) |
| | place_steps(doc,placement,board_thickness) |
| |
|
| | def Process_board_outline(doc,board_outline,drills,board_thickness): |
| | """Process_board_outline(doc,board_outline,drills,board_thickness)-> number processed loops |
| | |
| | adds emn geometry from emn file""" |
| | vertex_index=-1; |
| | lines=-1 |
| | out_shape=[] |
| | out_face=[] |
| | for point in board_outline: |
| | vertex=Base.Vector(point[1],point[2],0) |
| | vertex_index+=1 |
| | if vertex_index==0: |
| | lines=point[0] |
| | elif lines==point[0]: |
| | if point[3]!=0 and point[3]!=360: |
| | out_shape.append(Part.Arc(prev_vertex,mid_point(prev_vertex,vertex,point[3]),vertex)) |
| | FreeCAD.Console.PrintMessage("mid point "+str(mid_point)+"\n") |
| | elif point[3]==360: |
| | per_point=Per_point(prev_vertex,vertex) |
| | out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,point[3]/2),vertex)) |
| | out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,-point[3]/2),vertex)) |
| | else: |
| | out_shape.append(Part.LineSegment(prev_vertex,vertex)) |
| | else: |
| | out_shape=Part.Shape(out_shape) |
| | out_shape=Part.Wire(out_shape.Edges) |
| | out_face.append(Part.Face(out_shape)) |
| | out_shape=[] |
| | vertex_index=0 |
| | lines=point[0] |
| | prev_vertex=vertex |
| | if lines!=-1: |
| | out_shape=Part.Shape(out_shape) |
| | out_shape=Part.Wire(out_shape.Edges) |
| | out_face.append(Part.Face(out_shape)) |
| | outline=out_face[0] |
| | FreeCAD.Console.PrintMessage("Added outline\n") |
| | if len(out_face)>1: |
| | for otl_cut in out_face[1: ]: |
| | outline=outline.cut(otl_cut) |
| | FreeCAD.Console.PrintMessage("Cutting shape inside outline\n") |
| | for drill in drills: |
| | FreeCAD.Console.PrintMessage("Cutting hole inside outline\n") |
| | out_shape=Part.makeCircle(drill[0]/2, Base.Vector(drill[1],drill[2],0)) |
| | out_shape=Part.Wire(out_shape.Edges) |
| | outline=outline.cut(Part.Face(out_shape)) |
| | doc_outline=doc.addObject("Part::Feature","Board_outline") |
| | doc_outline.Shape=outline.extrude(Base.Vector(0,0,-board_thickness)) |
| | grp=doc.addObject("App::DocumentObjectGroup", "Board_Geoms") |
| | grp.addObject(doc_outline) |
| | doc.Board_outline.ViewObject.ShapeColor=(0.0, 0.5, 0.0, 0.0) |
| | return lines+1 |
| |
|
| | def mid_point(prev_vertex,vertex,angle): |
| | """mid_point(prev_vertex,vertex,angle)-> mid_vertex |
| | |
| | returns mid point on arc of angle between prev_vertex and vertex""" |
| | angle=radians(angle/2) |
| | basic_angle=atan2(vertex.y-prev_vertex.y,vertex.x-prev_vertex.x)-pi/2 |
| | shift=(1-cos(angle))*hypot(vertex.y-prev_vertex.y,vertex.x-prev_vertex.x)/2/sin(angle) |
| | midpoint=Base.Vector((vertex.x+prev_vertex.x)/2+shift*cos(basic_angle),(vertex.y+prev_vertex.y)/2+shift*sin(basic_angle),0) |
| | return midpoint |
| |
|
| | def split_records(line_record): |
| | """split_records(line_record)-> list of strings(records) |
| | |
| | standard separator list separator is space, records containing encapsulated by " """ |
| | split_result=[] |
| | quote_pos=line_record.find('"') |
| | while quote_pos!=-1: |
| | if quote_pos>0: |
| | split_result.extend(line_record[ :quote_pos].split()) |
| | line_record=line_record[quote_pos: ] |
| | quote_pos=line_record.find('"',1) |
| | else: |
| | quote_pos=line_record.find('"',1) |
| | if quote_pos!=-1: |
| | split_result.append(line_record[ :quote_pos+1]) |
| | line_record=line_record[quote_pos+1: ] |
| | else: |
| | split_result.append(line_record) |
| | line_record="" |
| | quote_pos=line_record.find('"') |
| | split_result.extend(line_record.split()) |
| | return split_result |
| |
|
| | def process_emp(doc,filename,placement,board_thickness): |
| | """process_emp(doc,filename,placement,board_thickness) -> place components from emn file to board""" |
| | filename=filename.partition(".emn")[0]+".emp" |
| | empfile=pyopen(filename, "r") |
| | emp_unit=1.0 |
| | emp_version=2 |
| | comp_height=0 |
| | comp_outline=[] |
| | comp_GeometryName="" |
| | comp_PartNumber="" |
| | comp_height=0 |
| | emplines=empfile.readlines() |
| | empfile.close() |
| | passed_sections=[] |
| | current_section="" |
| | section_counter=0 |
| | comps=[] |
| | for empline in emplines: |
| | emprecords=split_records(empline) |
| | if len( emprecords )==0 : continue |
| | if len( emprecords[0] )>4 and emprecords[0][0:4]==".END": |
| | passed_sections.append(current_section) |
| | current_section="" |
| | if comp_PartNumber!="": |
| | if comp_height==0: |
| | comp_height=0.1 |
| | comps.append((comp_PartNumber,[Process_comp_outline(doc,comp_outline,comp_height),comp_GeometryName])) |
| | comp_PartNumber="" |
| | comp_outline=[] |
| | elif emprecords[0][0]==".": |
| | current_section=emprecords[0] |
| | section_counter=0 |
| | section_counter+=1 |
| | if current_section==".HEADER" and section_counter==2: |
| | emp_version=int(float(emprecords[1])) |
| | FreeCAD.Console.PrintMessage("Emp version: "+emprecords[1]+"\n") |
| | if (current_section==".ELECTRICAL" or current_section==".MECHANICAL") and section_counter==2 and emprecords[2]=="THOU": |
| | emp_unit=0.0254 |
| | if (current_section==".ELECTRICAL" or current_section==".MECHANICAL") and section_counter==2 and emprecords[2]=="MM": |
| | emp_unit=1 |
| | if (current_section==".ELECTRICAL" or current_section==".MECHANICAL") and section_counter==2: |
| | comp_outline=[] |
| | comp_GeometryName=emprecords[0] |
| | comp_PartNumber=emprecords[1] |
| | comp_height=emp_unit*float(emprecords[3]) |
| | if (current_section==".ELECTRICAL" or current_section==".MECHANICAL") and section_counter>2: |
| | comp_outline.append([float(emprecords[1])*emp_unit,float(emprecords[2])*emp_unit,float(emprecords[3])]) |
| | FreeCAD.Console.PrintMessage("\n".join(passed_sections)+"\n") |
| | |
| | if IDF_diag==1: |
| | empfile=pyopen(IDF_diag_path+"/footprint.lst", "w") |
| | for compx in comps: |
| | empfile.writelines(str(compx[1][1])+"\n") |
| | empfile.close() |
| | |
| | comps=dict(comps) |
| | grp=doc.addObject("App::DocumentObjectGroup", "EMP Models") |
| | for place_item in placement: |
| | if place_item[1] in comps: |
| | doc_comp=doc.addObject("Part::Feature",place_item[0]) |
| | FreeCAD.Console.PrintMessage("Adding EMP model "+str(place_item[0])+"\n") |
| | doc_comp.Shape=comps[place_item[1]][0] |
| | doc_comp.ViewObject.DisplayMode=EmpDisplayMode |
| | z_pos=0 |
| | rotateY=0 |
| | if place_item[6]=='BOTTOM': |
| | rotateY=pi |
| | z_pos=-board_thickness |
| | placmnt=Base.Placement(Base.Vector(place_item[3],place_item[4],z_pos),toQuaternion(rotateY,place_item[5]*pi/180,0)) |
| | doc_comp.Placement=placmnt |
| | grp.addObject(doc_comp) |
| | return 1 |
| |
|
| | def Process_comp_outline(doc,comp_outline,comp_height): |
| | """Process_comp_outline(doc,comp_outline,comp_height)->part shape |
| | Create solid component shape base on its outline""" |
| | vertex_index=-1; |
| | out_shape=[] |
| | if comp_outline==[]: |
| | comp_outline.append([0.0,0.0,0.0]) |
| | comp_outline.append([0.1,0.0,360.0]) |
| | for point in comp_outline: |
| | vertex=Base.Vector(point[0],point[1],0) |
| | vertex_index+=1 |
| | if vertex_index>0: |
| | if point[2]!=0 and point[2]!=360: |
| | out_shape.append(Part.Arc(prev_vertex,mid_point(prev_vertex,vertex,point[2]),vertex)) |
| | FreeCAD.Console.PrintMessage("mid point "+str(mid_point)+"\n") |
| | elif point[2]==360: |
| | per_point=Per_point(prev_vertex,vertex) |
| | out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,point[2]/2),vertex)) |
| | out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,-point[2]/2),vertex)) |
| | else: |
| | out_shape.append(Part.LineSegment(prev_vertex,vertex)) |
| | prev_vertex=vertex |
| | out_shape=Part.Shape(out_shape) |
| | out_shape=Part.Wire(out_shape.Edges) |
| | out_shape=Part.Face(out_shape) |
| | out_shape=out_shape.extrude(Base.Vector(0,0,comp_height)) |
| | return out_shape |
| |
|
| | def place_steps(doc,placement,board_thickness): |
| | """ place_steps(doc,placement,board_thickness)->place step models on board |
| | |
| | list of models and path to step files is set at start of this script |
| | model_tab_filename= "" & step_path="" """ |
| | model_file=pyopen(model_tab_filename, "r") |
| | model_lines=model_file.readlines() |
| | model_file.close() |
| | model_dict=[] |
| | if IDF_diag==1: |
| | model_file=pyopen(IDF_diag_path+"/missing_models.lst", "w") |
| | keys=[] |
| | step_dict=[] |
| | for model_line in model_lines: |
| | model_records=split_records(model_line) |
| | if len(model_records)>1 and model_records[0] and not model_records[0] in keys: |
| | keys.append(model_records[0]) |
| | model_dict.append((str(model_records[0]).replace('"',''),str(model_records[1]).replace('"',''))) |
| | model_dict=dict(model_dict) |
| | validkeys=filter(lambda x:x in [place_item[2] for place_item in placement], model_dict.keys()) |
| | FreeCAD.Console.PrintMessage("Step models to be loaded for footprints: "+str(validkeys)+"\n") |
| | grp=doc.addObject("App::DocumentObjectGroup", "Step Lib") |
| | for validkey in validkeys: |
| | ImportGui.insert(step_path+model_dict[validkey],FreeCAD.ActiveDocument.Name) |
| | impPart=FreeCAD.ActiveDocument.ActiveObject |
| | impPart.ViewObject.Visibility=0 |
| | impPart.Label=validkey |
| | grp.addObject(impPart) |
| | step_dict.append((validkey,impPart)) |
| | FreeCAD.Console.PrintMessage("Reading step file "+str(model_dict[validkey])+" for footprint "+str(validkey)+"\n") |
| | step_dict=dict(step_dict) |
| | grp=doc.addObject("App::DocumentObjectGroup", "Step Models") |
| | for place_item in placement: |
| | if place_item[2] in step_dict: |
| | step_model=doc.addObject("Part::Feature",place_item[0]+"_s") |
| | FreeCAD.Console.PrintMessage("Adding STEP model "+str(place_item[0])+"\n") |
| | step_model.Shape=step_dict[place_item[2]].Shape |
| | step_model.ViewObject.DiffuseColor=step_dict[place_item[2]].ViewObject.DiffuseColor |
| | z_pos=0 |
| | rotateY=0 |
| | if place_item[6]=='BOTTOM': |
| | rotateY=pi |
| | z_pos=-board_thickness |
| | placmnt=Base.Placement(Base.Vector(place_item[3],place_item[4],z_pos),toQuaternion(rotateY,place_item[5]*pi/180,0)) |
| | step_model.Placement=placmnt |
| | grp.addObject(step_model) |
| | else: |
| | if IDF_diag==1: |
| | model_file.writelines(str(place_item[0])+" "+str(place_item[2])+"\n") |
| | model_file.close() |
| |
|
| | def toQuaternion(heading, attitude,bank): |
| | """toQuaternion(heading, attitude,bank)->FreeCAD.Base.Rotation(Quternion)""" |
| | c1 = cos(heading/2) |
| | s1 = sin(heading/2) |
| | c2 = cos(attitude/2) |
| | s2 = sin(attitude/2) |
| | c3 = cos(bank/2) |
| | s3 = sin(bank/2) |
| | c1c2 = c1*c2 |
| | s1s2 = s1*s2 |
| | w = c1c2*c3 - s1s2*s3 |
| | x = c1c2*s3 + s1s2*c3 |
| | y = s1*c2*c3 + c1*s2*s3 |
| | z = c1*s2*c3 - s1*c2*s3 |
| | return FreeCAD.Base.Rotation(x,y,z,w) |
| |
|
| | def Per_point(prev_vertex,vertex): |
| | """Per_point(center,vertex)->per point |
| | |
| | returns opposite perimeter point of circle""" |
| | perpoint=Base.Vector(2*prev_vertex.x-vertex.x,2*prev_vertex.y-vertex.y,0) |
| | return perpoint |
| |
|
| |
|
| |
|