I have found out for this use case that is more efficient to edit the header of the .laz file using binary file I/O to modify the offset values.
Here is my code:
def read_las_header(file):
file.seek(0)
header = file.read(227) # LAS 1.2 header
point_data_offset = struct.unpack('<I', header[96:100])[0]
point_record_length = struct.unpack('<H', header[105:107])[0]
num_point_records = struct.unpack('<I', header[107:111])[0]
x_scale = struct.unpack('<d', header[131:139])[0]
y_scale = struct.unpack('<d', header[139:147])[0]
z_scale = struct.unpack('<d', header[147:155])[0]
x_offset = struct.unpack('<d', header[155:163])[0]
y_offset = struct.unpack('<d', header[163:171])[0]
z_offset = struct.unpack('<d', header[171:179])[0]
return (header, point_data_offset, point_record_length, num_point_records, x_scale, y_scale, z_scale, x_offset, y_offset, z_offset)
def shift_laz_header(input_file_path, output_file_path, tx=0, ty=0, tz=0):
with open(input_file_path, 'rb') as infile:
header_data = read_las_header(infile)
header, point_data_offset, point_record_length, num_point_records, x_scale, y_scale, z_scale, x_offset, y_offset, z_offset = header_data
new_x_offset = x_offset + tx
new_y_offset = y_offset + ty
new_z_offset = z_offset + tz
print(f"Original X Offset: {x_offset}, New X Offset: {new_x_offset}")
print(f"Original Y Offset: {y_offset}, New Y Offset: {new_y_offset}")
print(f"Original Z Offset: {z_offset}, New Z Offset: {new_z_offset}")
updated_header = update_offsets_in_header(header, new_x_offset, new_y_offset, new_z_offset)
with open(output_file_path, 'wb') as outfile:
outfile.write(updated_header)
# Copy the rest of the file
infile.seek(227)
shutil.copyfileobj(infile, outfile)
print(f"Updated offsets in header: X={new_x_offset}, Y={new_y_offset}, Z={new_z_offset}")