src.acoustools.Fabrication.Optimise

  1from torch import Tensor
  2from acoustools.Utilities import create_points
  3
  4def interweave_points(lcode:str, num_points:int=2, min_offset_lines:int=100, extruder:Tensor|None=None, codes_to_combine:list[str]= ['L0','L1','L2','L3']):
  5    '''
  6    Will optimise a lcode file by making single point lcode use multiple points at once \n
  7    Currently seems to perform slightly weirdly sometimes adding a rogue line between configurations commands - should work though
  8    :param lcode: filename of lcode file
  9    :param num_points: Maximum number of points allowed
 10    :param min_offset_lines: minimum number of linesafter starting one point before starting a new point 
 11    :param extruder: extruder position:
 12    :param codes_to_combine: The codes that can be combined in one line - note that if different codes are present it may break
 13    '''
 14
 15    #The rogue single lines after a C0 i think come from the fact that the interweaved line becomes L1...; C0; which is then split so the C0 is placed first
 16    #This means the L command is left alone on a line and the C0 comes after -> this seems like its ok? There isnt two drops to levitate 
 17    #It is slightly less efficient -> You could move the C0 above the rogue line and then have two on the next but on thw whole isnt too bad
 18    blocks = []
 19    c_blocks = []
 20    pre_c_blocks = []
 21    start_c_block = ''
 22    
 23    if extruder is None:
 24        extruder = create_points(1,1,0,-0.04, 0.04)
 25    extruder_x = extruder[:,0].item()
 26    extruder_y = extruder[:,1].item()
 27    extruder_z = extruder[:,2].item()
 28    
 29
 30    block = ''
 31    c_block = ''
 32    pre_c_block = ''
 33
 34    add_to_start = False
 35
 36    with open(lcode, 'r') as f:
 37        lines = f.readlines()
 38        found_L = False
 39        for line in lines:
 40            
 41            if line.startswith('L') and not found_L:
 42                found_L = True
 43                start_c_block = c_block
 44                c_block = ''
 45            
 46            if found_L:
 47                parts = line.replace(';','').rstrip().split(':')
 48                command = parts[0]
 49                args = parts[1:]
 50                
 51                if command in codes_to_combine:
 52                    x,y,z = lcode_coordinates_to_xyz(args[0]) #This assumes only one point per line
 53                    if x == extruder_x and y == extruder_y and z == extruder_z and block != '':
 54                        blocks.append(block)
 55                        c_blocks.append(c_block)
 56                        
 57                        block = line
 58                        c_block = ''
 59
 60                        pre_c_blocks.append(pre_c_block)
 61                        pre_c_block = ''
 62
 63                    else:
 64                        block += line
 65                else: #C commands mostly
 66                    if line.startswith('O0'): #End the block!
 67                        add_to_start = True
 68                        continue
 69
 70                    if not add_to_start:
 71                        c_block += line
 72                    else:
 73                        pre_c_block += line
 74                        add_to_start = False
 75
 76            else:
 77                c_block += line
 78    
 79
 80    current_blocks = []
 81    current_blocks.append(blocks[0])
 82    gap = 0
 83    i = 0
 84    N_blocks = len(blocks)
 85    interweaved = []
 86    blocks_done = 0
 87    while len(current_blocks) > 0:
 88        gap += 1
 89        if gap > min_offset_lines and len(current_blocks) < num_points and i+1 < N_blocks: #We can add a new block
 90            interweaved.append(pre_c_blocks[i])
 91            i += 1
 92            current_blocks.append(blocks[i])
 93            gap = 0
 94            
 95        line, current_blocks = combine_lines_from_blocks(current_blocks)
 96        interweaved.append(line)
 97        
 98            
 99        if '' in current_blocks: #If the block is empty ...
100            current_blocks.remove('') #Then remove it ...
101            interweaved.append([c_blocks[blocks_done],]) #Add the post commands ...
102            blocks_done += 1 # And remember we have completed a block
103
104        if len(current_blocks) == 0 and blocks_done < N_blocks: #Check we dont run out of blocks before starting the next one
105            current_blocks.append(blocks[blocks_done])
106
107    i = 0
108    with open(lcode, 'w') as f:
109        f.write(start_c_block)
110
111        for lines in interweaved:
112            c_commands = ''
113            command = ''
114            arguments = []
115            for line in lines:
116                if line.startswith('L'):
117                    line=line.replace(';','').rstrip()
118                    spt = line.split(':')
119                    command = spt[0]
120                    if command in codes_to_combine:
121                        coords = spt[1]
122                        xyz = lcode_coordinates_to_xyz(coords)
123                        xyz = [str(a) for a in xyz]
124                        coords_str = ','.join(xyz)
125                        arguments.append(coords_str)
126                        
127                
128                else:
129                    c_commands += line
130            # print(arguments)   
131            # if len(arguments) == 0:
132            #         print(command)
133            if command != '':
134                arguments_string = ':'.join(arguments)
135                f.write(command + ":" + arguments_string + ';\n')
136            if c_commands != '':
137                f.write(c_commands)
138
139    
140def lcode_coordinates_to_xyz(coordinates:str) -> tuple[float]:
141    '''
142    @private
143    '''
144    coordinates = coordinates.split(',')
145    x = float(coordinates[0])
146    y = float(coordinates[1])
147    z = float(coordinates[2])
148
149    return x,y,z
150
151
152def combine_lines_from_blocks(blocks) -> tuple[list[str],list[str]]:
153    '''
154    @private
155    '''
156    top_lines = []
157    new_blocks = []
158    for block in blocks:
159        ls = block.split('\n')
160        top_lines.append(ls[0])
161        new_blocks.append('\n'.join(ls[1:]))
162    
163    
164    return top_lines, new_blocks
def interweave_points( lcode: str, num_points: int = 2, min_offset_lines: int = 100, extruder: torch.Tensor | None = None, codes_to_combine: list[str] = ['L0', 'L1', 'L2', 'L3']):
  5def interweave_points(lcode:str, num_points:int=2, min_offset_lines:int=100, extruder:Tensor|None=None, codes_to_combine:list[str]= ['L0','L1','L2','L3']):
  6    '''
  7    Will optimise a lcode file by making single point lcode use multiple points at once \n
  8    Currently seems to perform slightly weirdly sometimes adding a rogue line between configurations commands - should work though
  9    :param lcode: filename of lcode file
 10    :param num_points: Maximum number of points allowed
 11    :param min_offset_lines: minimum number of linesafter starting one point before starting a new point 
 12    :param extruder: extruder position:
 13    :param codes_to_combine: The codes that can be combined in one line - note that if different codes are present it may break
 14    '''
 15
 16    #The rogue single lines after a C0 i think come from the fact that the interweaved line becomes L1...; C0; which is then split so the C0 is placed first
 17    #This means the L command is left alone on a line and the C0 comes after -> this seems like its ok? There isnt two drops to levitate 
 18    #It is slightly less efficient -> You could move the C0 above the rogue line and then have two on the next but on thw whole isnt too bad
 19    blocks = []
 20    c_blocks = []
 21    pre_c_blocks = []
 22    start_c_block = ''
 23    
 24    if extruder is None:
 25        extruder = create_points(1,1,0,-0.04, 0.04)
 26    extruder_x = extruder[:,0].item()
 27    extruder_y = extruder[:,1].item()
 28    extruder_z = extruder[:,2].item()
 29    
 30
 31    block = ''
 32    c_block = ''
 33    pre_c_block = ''
 34
 35    add_to_start = False
 36
 37    with open(lcode, 'r') as f:
 38        lines = f.readlines()
 39        found_L = False
 40        for line in lines:
 41            
 42            if line.startswith('L') and not found_L:
 43                found_L = True
 44                start_c_block = c_block
 45                c_block = ''
 46            
 47            if found_L:
 48                parts = line.replace(';','').rstrip().split(':')
 49                command = parts[0]
 50                args = parts[1:]
 51                
 52                if command in codes_to_combine:
 53                    x,y,z = lcode_coordinates_to_xyz(args[0]) #This assumes only one point per line
 54                    if x == extruder_x and y == extruder_y and z == extruder_z and block != '':
 55                        blocks.append(block)
 56                        c_blocks.append(c_block)
 57                        
 58                        block = line
 59                        c_block = ''
 60
 61                        pre_c_blocks.append(pre_c_block)
 62                        pre_c_block = ''
 63
 64                    else:
 65                        block += line
 66                else: #C commands mostly
 67                    if line.startswith('O0'): #End the block!
 68                        add_to_start = True
 69                        continue
 70
 71                    if not add_to_start:
 72                        c_block += line
 73                    else:
 74                        pre_c_block += line
 75                        add_to_start = False
 76
 77            else:
 78                c_block += line
 79    
 80
 81    current_blocks = []
 82    current_blocks.append(blocks[0])
 83    gap = 0
 84    i = 0
 85    N_blocks = len(blocks)
 86    interweaved = []
 87    blocks_done = 0
 88    while len(current_blocks) > 0:
 89        gap += 1
 90        if gap > min_offset_lines and len(current_blocks) < num_points and i+1 < N_blocks: #We can add a new block
 91            interweaved.append(pre_c_blocks[i])
 92            i += 1
 93            current_blocks.append(blocks[i])
 94            gap = 0
 95            
 96        line, current_blocks = combine_lines_from_blocks(current_blocks)
 97        interweaved.append(line)
 98        
 99            
100        if '' in current_blocks: #If the block is empty ...
101            current_blocks.remove('') #Then remove it ...
102            interweaved.append([c_blocks[blocks_done],]) #Add the post commands ...
103            blocks_done += 1 # And remember we have completed a block
104
105        if len(current_blocks) == 0 and blocks_done < N_blocks: #Check we dont run out of blocks before starting the next one
106            current_blocks.append(blocks[blocks_done])
107
108    i = 0
109    with open(lcode, 'w') as f:
110        f.write(start_c_block)
111
112        for lines in interweaved:
113            c_commands = ''
114            command = ''
115            arguments = []
116            for line in lines:
117                if line.startswith('L'):
118                    line=line.replace(';','').rstrip()
119                    spt = line.split(':')
120                    command = spt[0]
121                    if command in codes_to_combine:
122                        coords = spt[1]
123                        xyz = lcode_coordinates_to_xyz(coords)
124                        xyz = [str(a) for a in xyz]
125                        coords_str = ','.join(xyz)
126                        arguments.append(coords_str)
127                        
128                
129                else:
130                    c_commands += line
131            # print(arguments)   
132            # if len(arguments) == 0:
133            #         print(command)
134            if command != '':
135                arguments_string = ':'.join(arguments)
136                f.write(command + ":" + arguments_string + ';\n')
137            if c_commands != '':
138                f.write(c_commands)

Will optimise a lcode file by making single point lcode use multiple points at once

Currently seems to perform slightly weirdly sometimes adding a rogue line between configurations commands - should work though

Parameters
  • lcode: filename of lcode file
  • num_points: Maximum number of points allowed
  • min_offset_lines: minimum number of linesafter starting one point before starting a new point
  • extruder: extruder position:
  • codes_to_combine: The codes that can be combined in one line - note that if different codes are present it may break