docs: def add_atoms_linearly(self, start_atom, end_atom, new_atoms, jitterbug = 0.2):
          '''A low-level function which adds new_atoms between start_atom and end_atom. This function does not validate the
             input i.e. the calling functions are responsible for ensuring that the insertion makes sense.
  
             Returns the PDB file content with the new atoms added. These atoms are given fresh serial numbers, starting
             from the first serial number larger than the current serial numbers i.e. the ATOM serial numbers do not now
             necessarily increase in document order.
  
             The jitter adds some X, Y, Z variability to the new atoms. This is important in the Rosetta software suite when
             placing backbone atoms as colinearly placed atoms will break the dihedral angle calculations (the dihedral angle
             over 4 colinear atoms is undefined).
             '''
  
          atom_name_map = {
              'CA' : ' CA ',
              'C' :  ' C  ',
              'N' :  ' N  ',
              'O' :  ' O  ',
          }
  
          assert(start_atom.residue.chain == end_atom.residue.chain)
          chain_id = start_atom.residue.chain
  
          # Initialize steps
          num_new_atoms = float(len(new_atoms))
          X, Y, Z = start_atom.x, start_atom.y, start_atom.z
          x_step = (end_atom.x - X) / (num_new_atoms + 1.0)
          y_step = (end_atom.y - Y) / (num_new_atoms + 1.0)
          z_step = (end_atom.z - Z) / (num_new_atoms + 1.0)
          D = math.sqrt(x_step * x_step + y_step * y_step + z_step * z_step)
          jitter = 0
          if jitterbug:
              jitter = (((x_step + y_step + z_step) / 3.0) * jitterbug) / D
  
          new_lines = []
          next_serial_number = max(sorted(self.atoms.keys())) + 1
          round = 0
          for new_atom in new_atoms:
              X, Y, Z = X + x_step, Y + y_step, Z + z_step
              if jitter:
                  if round % 3 == 0:
                      X, Y = X + jitter, Y - jitter
                  elif round % 3 == 1:
                      Y, Z = Y + jitter, Z - jitter
                  elif round % 3 == 2:
                      Z, X = Z + jitter, X - jitter
                  round += 1
              residue_id, residue_type, atom_name = new_atom
              assert(len(residue_type) == 3)
              assert(len(residue_id) == 6)
              new_lines.append('ATOM  {0} {1} {2} {3}   {4:>8.3f}{5:>8.3f}{6:>8.3f}  1.00  0.00              '.format(str(next_serial_number).rjust(5), atom_name_map[atom_name], residue_type, residue_id, X, Y, Z))
              next_serial_number += 1
  
          new_pdb = []
          in_start_residue = False
          for l in self.indexed_lines:
              if l[0] and l[3].serial_number == start_atom.serial_number:
                  in_start_residue = True
              if in_start_residue and l[3].serial_number != start_atom.serial_number:
                  new_pdb.extend(new_lines)
                  #colortext.warning('\n'.join(new_lines))
                  in_start_residue = False
              if l[0]:
                  #print(l[2])
                  new_pdb.append(l[2])
              else:
                  #print(l[1])
                  new_pdb.append(l[1])
  
          return '\n'.join(new_pdb)