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