Advertisement
365tuwe

stpWriter.py

Apr 3rd, 2013
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.47 KB | None | 0 0
  1. '''
  2. stpWriter
  3. '''
  4.  
  5. import sys, os
  6. import argparse
  7.  
  8. from OCC.gp import gp_Pnt, gp_Dir, gp_Vec, gp_Pln, gp_Ax3
  9. from OCC.Utils.DataExchange.STEP import STEPExporter
  10. from OCC.TopoDS import TopoDS_Builder
  11. from OCC.TopoDS import TopoDS_Compound
  12. from OCC.TNaming import TNaming_Builder
  13. from OCC.TDF import TDF_Label
  14. import OCC.TDocStd as TDocStd
  15. import OCC.TCollection as TCollection
  16. import OCC.AppStd as AppStd
  17. from OCC.BRepBuilderAPI import BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeEdge
  18. from OCC.TopoDS import TopoDS_edge, TopoDS_vertex, TopoDS_wire
  19.  
  20. title = 'stpWriter'
  21.  
  22. def read_keyword_def(lines, dico_output):
  23.  
  24.     '''
  25.        Read the parameters corresponding to a keyword defined in a BDF file
  26.        (possibly on several lines).
  27.    '''
  28.    
  29.     linesToMod = lines[:]
  30.     drapAng    = None
  31.     try:
  32.         # Combine lines with *
  33.         star_lines = []
  34.         for k in range(len(linesToMod)):
  35.             if '*' in linesToMod[k][1:]:
  36.                 star_lines.append(k)
  37.         star_lines.sort()
  38.         star_lines.reverse()
  39.         for Lind in star_lines:
  40.             temp_line = linesToMod[Lind].strip().ljust(72)[:72]
  41.             # should the ending be used?
  42.             ending = linesToMod[Lind].strip().ljust(72)[72:]
  43.             try:
  44.                 if linesToMod[Lind+1][0] == '*':
  45.                     temp_line += linesToMod[Lind+1][8:].rstrip().ljust(64)
  46.                     linesToMod[Lind] = temp_line
  47.                     del linesToMod[Lind+1]
  48.                 else:
  49.                     continue
  50.             except IndexError:
  51.                 pass
  52.        
  53.         # Read the first line
  54.         line = linesToMod[0].strip()
  55.         if '*' in line: lcd = 16
  56.         else:           lcd = 8
  57.         typ  = line[:8].replace('*','').strip().upper()
  58.         name = line[8:8+lcd].strip().upper()
  59.         data = []
  60.         parameters = []
  61.  
  62.         for k in range(8+lcd,8+lcd*9,lcd):
  63.             if k >= len(line): parameters.append('')
  64.             else:              parameters.append(line[k:k+lcd].strip())
  65.         data.append(parameters)
  66.        
  67.         # Read the following lines for the same keyword
  68.         for line in linesToMod[1:]:
  69.             parameters = []
  70.             line       = line.replace('\n','').replace('\r','')
  71.            
  72.             # For a PCOMP, record in a list the first line and
  73.             # then each line corresponding to a ply definition
  74.             if typ == 'PCOMP':
  75.                 if 'draping angle' in line.lower():
  76.                     line.replace(':', '=')
  77.                     drapAng = str(line.split('=')[-1].replace('deg', '').strip())
  78.                     continue
  79.                
  80.                 for k in range(0,4*lcd,lcd):
  81.                     if k+8 >= len(line)*lcd/8:
  82.                         parameters.append('')
  83.                     else:
  84.                         parameters.append(line[k+8:k+8+lcd].strip())
  85.                 data.append(parameters)
  86.                 #explain why use just one field in the middle
  87.                 if line[5*lcd:5*lcd+lcd].strip():
  88.                     parameters = []
  89.                     for k in range(5*lcd,9*lcd,lcd):
  90.                         if k >= len(line)*lcd/8:
  91.                             parameters.append('')
  92.                         else:
  93.                             parameters.append(line[k:k+lcd].strip())
  94.                     data.append(parameters)
  95.            
  96.             elif typ == 'CORD2R':
  97.                 for k in range(8,len(line),lcd):
  98.                     parameters.append(line[k:k+lcd].strip())
  99.                 data.append(parameters)
  100.                
  101.             # For a PSHELL or MATi, record in a list each line
  102.             # corresponding to its definition
  103.             else:
  104.                 for k in range(8,9*lcd,lcd):
  105.                     if k >= len(line)*lcd/8:
  106.                         parameters.append('')
  107.                     else:
  108.                         parameters.append(line[k:k+lcd].strip())
  109.                 data.append(parameters)
  110.                
  111.         # Add inputs to dictionary and return
  112.         if typ not in ['FORCE','MOMENT']:
  113.             dico_output.setdefault(typ, {})[name] = data
  114.         else:
  115.         # for FORCE and MOMENT another hierarchy-level is needed
  116.             gridID = data[0][0]
  117.             if gridID in dico_output.get(typ, {}).get(name,{}):
  118.                 olddata = dico_output[typ][name].pop(gridID)
  119.                 for i in range(3,6):
  120.                     oldValue = conv2float(olddata[0][i])
  121.                     toAdd = conv2float(data[0][i])
  122.                     merged = oldValue + toAdd
  123.                     data[0][i] = normalize_Float(merged, 15).replace(' ','')
  124.             dico_output.setdefault(typ, {}).setdefault(name,{})[gridID] = data
  125.            
  126.         if drapAng: dico_output.setdefault('DRAPING ANGLE', {})[name] = drapAng
  127.     except Exception as currentEx:
  128.         print('An exception happened during reading a set of lines: ' + str(lines))
  129.  
  130.     return dico_output
  131.  
  132.  
  133. def read_bdf(bdf_path=None, default_path='*.bdf', keywords = [],
  134.              assume_bulk = 0, skip = 0, flagREST = 0):
  135.  
  136.     '''
  137.         Reads the BDF input file given in parameter (pops up a window to select a
  138.         file when "None" is used) and returns a dictionary containing the following
  139.         objects encountered:
  140.        
  141.             MAT1, MAT8, PCOMP, PSHELL, GRID, CTRIA3, CQUAD4, CBUSH, SUBCASE
  142.            
  143.         dico_FE_matprop[object_type][object_ID] = [[ Line1_parameters ],
  144.                                                    [ Line2_parameters ] ...]
  145.  
  146.         dico_FE_matprop['SUBCASE'][subcase_ID] = [subtitle, temperature_value]
  147.        
  148.         assume_bulk: Set to 1 if you want to read in an INCLUDE file without BEGIN BULK
  149.         skip       : Set to 1 if you want to skip all INCLUDEs in bdf/dat file
  150.         flagREST   : Set to 1 if you want to put all lines which are not recognized
  151.                         or not covered by keyword under the keyword 'REST'
  152.        
  153.     '''
  154.  
  155.     if not keywords:
  156.         keywords = ['MAT1'  , 'MAT8'  , 'PCOMP', 'PSHELL', 'GRID'   ,
  157.                     'CTRIA3', 'CQUAD4', 'CBUSH', 'CORD2R' ]
  158.  
  159.     # Target the BDF file to be read and read lines
  160.     bdf_path   =  bdf_path.replace('\\','/')
  161.     bdf_paths  = [bdf_path]  
  162.     Bulk_Flags = [assume_bulk]              # This flag indicates that the keyword "BEGIN BULK"
  163.                                               # has not yet been read for the BDF file in "bdf_paths"
  164.    
  165.     # Read shell and materials definition
  166.     dico_FE_matprop = {}
  167.     subtitle    = 'NC'
  168.     temp_id     = 'NC'
  169.     temp_id_flag    = 0
  170.  
  171.     temp_def    = {'NC': 'NC'}
  172.    
  173.     for bdp in bdf_paths:
  174.        
  175.         flag_Bulk = Bulk_Flags[bdf_paths.index(bdp)]
  176.        
  177.         try: bdfi = open(bdp)
  178.         except:
  179.             incl_name = bdp.split('/')[-1]
  180.             incl_path = eg.fileopenbox('Pick up the BDF include file: "'+
  181.                                        incl_name+'"', '', default_path)
  182.             if incl_path == None:
  183.                 bdfi = ''
  184.             else:
  185.                 bdfi = open(incl_path,'rb')
  186.  
  187.         if bdfi != '':
  188.  
  189.             data_lines = []
  190.             subcase_id = ''
  191.            
  192.             i = 0
  193.             for line in bdfi:
  194.                
  195.                 i += 1
  196.  
  197.                 if not flag_Bulk:
  198.                    
  199.                     typ = line.strip().upper()
  200.                    
  201.                     if typ[:7] == 'SUBCASE':
  202.                        
  203.                         if subcase_id != '':
  204.                             dico_FE_matprop.setdefault('SUBCASE',{}).setdefault(subcase_id,[subtitle, temp_id])
  205.                            
  206.                         subcase_id   = reanyinteger.findall(line)[0]
  207.                         subtitle     = 'NC'
  208.                         temp_id   = 'NC'
  209.                         temp_id_flag = 0
  210.                        
  211.                     elif typ[:8] == 'SUBTITLE':
  212.                         subtitle = line.replace('SUBTITLE','').replace('=','',1).strip()
  213.                        
  214.                     elif typ[:10] == 'TEMP(LOAD)' or typ[:17] == 'TEMPERATURE(LOAD)':
  215.                         temp_id = reanyinteger.findall(line)[0]
  216.                         temp_id_flag += 1
  217.                        
  218.                     elif typ[:13] == 'TEMP(INITIAL)' or typ[:20] == 'TEMPERATURE(INITIAL)':
  219.                         dico_FE_matprop.setdefault('SUBCASE',{})['INITIAL'] = ['INITIAL', reanyinteger.findall(line)[0]]
  220.                        
  221.                     elif typ[:10] == 'BEGIN BULK':
  222.                        
  223.                         if subcase_id != '':
  224.                             dico_FE_matprop.setdefault('SUBCASE',{}).setdefault(subcase_id,[subtitle, temp_id])
  225.                            
  226.                         flag_Bulk = 1
  227.                    
  228.                     elif typ[:7] == 'INCLUDE' and not skip:
  229.                         incl_name = line.split("'")[-2]
  230.                         incl_path = '/'.join(bdf_path.split('/')[:-1]) + '/' + incl_name
  231.                         bdf_paths.append(incl_path)
  232.                         Bulk_Flags.append(flag_Bulk)
  233.  
  234.                 else:
  235.                    
  236.                     typ = line[:8].replace('*',' ').strip().upper()
  237.                        
  238.                     if data_lines:
  239.                         if line[:8].replace('*',' ') == ' '*8:
  240.                             data_lines.append(line)
  241.                             continue
  242.                         elif line[0] == '$':
  243.                             if 'draping angle' in line.lower():
  244.                                 data_lines.append(line)
  245.                                 continue
  246.                             else:
  247.                                 continue
  248.                         elif '*' in line and len(line) < 8:
  249.                             data_lines.append(line)
  250.                             continue
  251.                         else:
  252.                             dico_FE_matprop = read_keyword_def(data_lines, dico_FE_matprop)
  253.                             data_lines    = []
  254.                            
  255.                     if typ in keywords:
  256.                         data_lines.append(line)
  257.                        
  258.                     elif typ == 'TEMPD':
  259.                         temp_def[reanyinteger.findall(line)[0]] = reanynumber2.findall(line)[-1]
  260.                    
  261.                     elif typ == 'INCLUDE' and not skip:
  262.                         incl_name = line.split("'")[-2]
  263.                         incl_path = '/'.join(bdf_path.split('/')[:-1]) + '/' + incl_name
  264.                         bdf_paths.append(incl_path)
  265.                         Bulk_Flags.append(flag_Bulk)
  266.                     #useful if bdf file should be read in and written out in a similar way
  267.                     elif flagREST:
  268.                         dico_FE_matprop.setdefault('REST', []).append((i,line))
  269.  
  270.  
  271.             if data_lines:
  272.                 dico_FE_matprop = read_keyword_def(data_lines, dico_FE_matprop)
  273.                 data_lines    = []
  274.  
  275.             if subcase_id != '':
  276.                 dico_FE_matprop['SUBCASE'][subcase_id] = [subtitle, temp_id]
  277.  
  278.             bdfi.close()
  279.  
  280.     # Check if the temperatures are defined in C or K
  281.     temp_li = []
  282.     for i in temp_def:
  283.         try: temp_li.append(float(temp_def[i]))
  284.         except: None
  285.     if temp_li != [] and max(temp_li) > 200: # It is assumed that temperatures are defined in K in the model
  286.         for i in temp_def:
  287.             try: temp_def[i] = str(float(temp_def[i]) - 273.15)
  288.             except: None
  289.     nonValids = set()
  290.     # Check that material definitions #MAT1 are correct
  291.     if 'MAT1' in dico_FE_matprop:
  292.         for mid in dico_FE_matprop['MAT1']:
  293.            
  294.             missing = []
  295.             try: E = float(dico_FE_matprop['MAT1'][mid][0][0])
  296.             except: missing.append('E')
  297.             try: G = float(dico_FE_matprop['MAT1'][mid][0][1])
  298.             except: missing.append('G')
  299.             try: v = float(dico_FE_matprop['MAT1'][mid][0][2])
  300.             except: missing.append('v')
  301.            
  302.             if len(missing) == 1:
  303.                 if missing[0] == 'E':
  304.                     E = 2*G*(1+v)
  305.                     dico_FE_matprop['MAT1'][mid][0][0] = str(E)
  306.                 elif missing[0] == 'G':
  307.                     G = E/(2*(1+v))
  308.                     dico_FE_matprop['MAT1'][mid][0][1] = str(G)
  309.                 elif missing[0] == 'v':
  310.                     v = E/(2*G) - 1
  311.                     dico_FE_matprop['MAT1'][mid][0][2] = str(v)
  312.  
  313.             elif len(missing) > 1:
  314.                 nonValids.add(mid)
  315.         while nonValids:
  316.             nonValids.pop()
  317.             del dico_FE_matprop['MAT1'][mid]
  318.  
  319.     # Check that material definitions #MAT8 are correct
  320.    
  321.     if 'MAT8' in dico_FE_matprop:
  322.         for mid in dico_FE_matprop['MAT8']:
  323.            
  324.             missing = []
  325.             try:    float(dico_FE_matprop['MAT8'][mid][0][0])
  326.             except: missing.append('El')
  327.             try:    float(dico_FE_matprop['MAT8'][mid][0][1])
  328.             except: missing.append('Et')
  329.             try:    float(dico_FE_matprop['MAT8'][mid][0][3])
  330.             except: missing.append('Glt')
  331.             try:    float(dico_FE_matprop['MAT8'][mid][0][2])
  332.             except: missing.append('vlt')
  333.  
  334.             if len(missing) != 0:
  335.                 nonValids.add(mid)
  336.         while nonValids:
  337.             nonValids.pop()
  338.             del dico_FE_matprop['MAT8'][mid]
  339.  
  340.     # Complete the subcases temperatures definition
  341.        
  342.     if dico_FE_matprop.get('SUBCASE',{}).get('INITIAL',['NC','NC'])[1] == 'NC':
  343.         temp_def['DEFAULT_INIT_20'] = '20.'
  344.  
  345.     LC_without_T = []
  346.     for subcase_id in dico_FE_matprop.get('SUBCASE',{}):
  347.         if dico_FE_matprop['SUBCASE'][subcase_id][1] == 'NC':
  348.             LC_without_T.append(subcase_id)
  349.             init_id = dico_FE_matprop['SUBCASE']['INITIAL'][1]
  350.             dico_FE_matprop['SUBCASE'][subcase_id][1] = init_id
  351.     LC_without_T.sort()
  352.        
  353.     for subcase_id in dico_FE_matprop.get('SUBCASE',{}):
  354.         temp_id = dico_FE_matprop['SUBCASE'][subcase_id][1]
  355.         if temp_id in temp_def:
  356.             temp_val = temp_def[temp_id]
  357.             dico_FE_matprop['SUBCASE'][subcase_id].append(temp_val)
  358.  
  359.     return dico_FE_matprop, bdf_paths
  360.  
  361.  
  362. def write_step(dicBdf, scale=1, title='Title', fileName=None, setElems=set()):
  363.    
  364.     '''
  365.         write_step: write a step file which contains faces build from the elements from the dicBdf
  366.        
  367.     '''
  368.    
  369.     allTria = set(dicBdf.get('CTRIA3',{}).keys())
  370.     allQuad = set(dicBdf.get('CQUAD4',{}).keys())
  371.     allElems = allTria | allQuad
  372.     if not setElems:
  373.         validElems = allElems
  374.     else:
  375.         validElems = setElems & allElems
  376.        
  377.     validQuads = validElems & allQuad
  378.     faceset_quad=WiresFromElements(dicBdf,validQuads,1)
  379.    
  380.     validTrias = validElems & allTria
  381.     faceset_tria=WiresFromElements(dicBdf,validTrias,0)
  382.    
  383.     allFaces=faceset_quad | faceset_tria
  384.    
  385.     stepWriter=STEPExporter(fileName)
  386.    
  387.     label = TDF_Label()
  388.    
  389.     comp = TopoDS_Compound()
  390.     compBuilder = TopoDS_Builder()
  391.     compBuilder.MakeCompound(comp)
  392.     for shape in allFaces:
  393.         compBuilder.Add(comp, shape)
  394.     stepWriter.add_shape(comp)
  395.     stepWriter.write_file()
  396.    
  397.     return fileName
  398.  
  399. def WiresFromElements(bdf,elements,quad):
  400.    
  401.     wire_set=set([])
  402.     for elem in elements:
  403.         if quad:
  404.             nodes=bdf['CQUAD4'][elem][0][1:5]
  405.         elif not quad:
  406.             nodes=bdf['CTRIA3'][elem][0][1:4]
  407.         pnt_list=[]
  408.         edge_list=[]
  409.         for node in nodes:
  410.             x=conv2float(bdf['GRID'][node][0][1])
  411.             y=conv2float(bdf['GRID'][node][0][2])
  412.             z=conv2float(bdf['GRID'][node][0][3])
  413.             pnt_list.append(gp_Pnt(x,y,z))
  414.         for i,point in enumerate(pnt_list):
  415.             edge=BRepBuilderAPI_MakeEdge(pnt_list[i-1],pnt_list[i]).Edge()
  416.             edge_list.append(edge)
  417.         buildWire=makeWirefromWires()
  418.         buildWire.Add(edge_list,1)
  419.         wire=buildWire.Build()
  420.         wire_set.add(wire)
  421.        
  422.     return wire_set
  423.  
  424. def conv2float(val):
  425.  
  426.     try:
  427.         return float(val)
  428.     except:
  429.         val = val[0] + val[1:].replace('-','E-').replace('+','E+')
  430.         return float(val)
  431.  
  432. class makeWirefromWires(object):
  433.    
  434.     def __init__(self):
  435.         self.buildWire=BRepBuilderAPI_MakeWire()
  436.            
  437.     def Add(self,wire,flagEdgeList=0):
  438.        
  439.         edgelist=[]
  440.         if not flagEdgeList:
  441.             exp=TopExp_Explorer(wire,TopAbs_EDGE)
  442.             while exp.More():
  443.                 edgelist.append(exp.Current())
  444.                 exp.Next()
  445.         else:
  446.             edgelist=wire
  447.        
  448.         count=0
  449.         while edgelist:
  450.             count+=1
  451.             if count==1000:
  452.                 print 'CAUTION:'
  453.                 print 'When your wire consists of more than 1000 edges... Sorry!:'
  454.                 print ' -> Please change the number of counts in  class makeWirefromWires in occ_module.py'
  455.                 print 'Otherwise the function Add in class BRepBuilderAPI_MakeWire failed:'
  456.                 print ' -> please check the order of your added wires or set down the step tolerance'
  457.                 exit()
  458.                
  459.             for edge in edgelist:
  460.                 self.buildWire.Add(TopoDS_edge(edge))
  461.                 if self.buildWire.IsDone():
  462.                     edgelist.remove(edge)
  463.  
  464.     def Build(self):
  465.         topoWire = self.buildWire.Wire()
  466.         return topoWire
  467.        
  468. if __name__ == '__main__':
  469.  
  470.     # command line arguments parser
  471.     p = argparse.ArgumentParser(description='Read bdf and save as step.', epilog='Example:\n./stpWriter.py input.bdf output.step [options]')
  472.  
  473.     # postitional arguments
  474.     p.add_argument("infile", help="Input file")
  475.     p.add_argument("outfile", help="Output file")
  476.  
  477.     # parse everything
  478.     args = p.parse_args()
  479.  
  480.     bdfFile = args.infile
  481.     stepFile = args.outfile
  482.  
  483.     dicBdf, paths = read_bdf(bdf_path=bdfFile, assume_bulk=1)
  484.     write_step(dicBdf,
  485.               fileName = stepFile,
  486.               setElems = set([]))
  487.  
  488. ## END OF stpWriter.py
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement