<reponame>jt667/Hydralab-Pallet-Comparison
import os
import subprocess
from date_checker import date_boundary
from tempfile import mkstemp
from shutil import move
from os import fdopen, remove
from section_week import *

def z_shift(current_file,section,first_day,registration_folder):
    #Find the date of the current file
    date_index = current_file.find("201808")  + 6
    date =  current_file[date_index:date_index + 2]
    
    #Path to the median error of the M3C2 comparison of the wooden pallets of the current date compared to the first day
    median_error = registration_folder + "\\" + first_day + date + section + ".txt"
    
    #Returns the median error given by the median_error file 
    with open(median_error) as median_error_file:
        median_z_shift = median_error_file.readlines()[0]
    return median_z_shift


def replace(file_path, pattern, subst):
    #Create temp file
    fh, abs_path = mkstemp()
    with fdopen(fh,'w') as new_file:
        with open(file_path) as old_file:
            for line in old_file:
                new_file.write(line.replace(pattern, subst))
    #Remove original file
    remove(file_path)
    #Move new file
    move(abs_path, file_path)

def shifted_cloud(current_file,current_file_path,registration_folder,section,first_day,cc_path):
    #Generates a file containg in a 4 x 4 affine transformation matrix, translation is given by the first three rows in the last column
    #Translation vertically given by the median M3C2 value of the wooden pallet comparision of the date of the current file compared to the file on the first day of the week
    transformation_matrix_path = registration_folder + r"\translation.txt"
    transformation_matrix_file = open(transformation_matrix_path,'w')
    transformation_matrix_file.write("1 0 0 0\n")
    transformation_matrix_file.write("0 1 0 0\n")
    transformation_matrix_file.write("0 0 1 " + str(-float(z_shift(current_file,section,first_day,registration_folder))) + "\n")
    transformation_matrix_file.write("0 0 0 1\n")
    transformation_matrix_file.close()
    
    #List of all the file in the src folder before the file is translated
    all_files = os.listdir(current_file_path.replace("\\" + current_file,""))
    
    #Translates cloud vertically
    # -SILENT stops a cloud compare console popping up (useful for debug as it will stop the program after completing its task)
    # -O current_file_path opens the file with path given by current_file_path
    # -APPLY_TRANS applies the transformation given by the file with path given by transformation_matrix_path
    subprocess.run([cc_path,"-SILENT","-O", current_file_path, "-APPLY_TRANS", transformation_matrix_path], shell=True)
    
    #Returns the filename of the shifted cloud
    return diff(all_files,os.listdir(current_file_path.replace("\\" + current_file,"")))[0]
                        

def diff(li1, li2): 
    #Returns the files that are not contained in both lists (the symmetric difference of the lists)
    li_dif = [i for i in li1 + li2 if i not in li1 or i not in li2] 
    return li_dif

def z_shift_bin(overwrite,src,registration_folder,section,week,cc_path):
    
    print("Shifting clouds towards the first day of the week")
    print("")
    
    #Folder containing median values for the z shifts
    registration_errors = registration_folder + "\\Median"
    
    #First day of the week
    first_day = str(13 + (int(week)-1)*7)
    
    #List of files to be shifted, only files of the current section and week, that have not already been shifted and are not the first day of the week
    shift_files = [x for x in os.listdir(src) if "_Z_Shifted" not in x and "201808" + first_day not in x and "Zone" + section in x and date_boundary(x,week)]

    
    
    
    for filename in shift_files:
        #File path to the current file being shifted
        shift_path = src + "\\" + filename
        
        #Check if the shifted file already exists
        path_exists = os.path.exists(shift_path.replace(".bin","_Z_Shifted.bin"))
        
        if not path_exists or overwrite:
            
            #Generates the shifted cloud file and stores the output name given
            time_stamped_name = shifted_cloud(filename,shift_path,registration_errors,section,first_day,cc_path)
            
            #Deletes file if it already exists and the overwrite option is on
            if path_exists and overwrite:
                os.remove(shift_path.replace(".bin","_Z_Shifted.bin"))
            
            #Removes the time stamp from the shifted file name and adds "_Z_Shifted" to the filename
            os.rename(shift_path.replace(filename,time_stamped_name),shift_path.replace(".bin","_Z_Shifted.bin"))

def get_pallet_numbers(section,week):
    #Gets the pallet numbers from their filenames
    return [x[-5] for x in os.listdir(os.getcwd() + "\\parameter_files\\cropping_dimensions") if section + "_" +  week in x ]

def cropping_pallets(bin_path,cropping_dimensions):
    #Returns a list of commands for subprocess 
    #e.g ["-O",bin_path,"-CROP",crop_dims[0],"-CLEAR","-O",bin_path,"-CROP",crop_dims[1],"-CLEAR"]
    
    open_list = ["-O" for x in range(len(cropping_dimensions))]
    bin_list = [bin_path for x in range(len(cropping_dimensions))]
    crop_list = ["-CROP" for x in range(len(cropping_dimensions))]
    clear_list = ["-CLEAR" for x in range(len(cropping_dimensions))]
    command_list = []
    for x in zip(open_list,bin_list,crop_list,cropping_dimensions,clear_list):
        command_list += list(x)
    return command_list
    
def pallet_list(pallet_files):
    open_list = ["-O" for x in range(len(pallet_files))]
    merge_list = []
    for x in zip(open_list,pallet_files):
        merge_list += list(x)
    return merge_list

def crop(overwrite,registration_folder,src,dest):
    #Path to the CloudCompare exe file
    cc_path = r"C:\Program Files\CloudCompare\CloudCompare.exe"
    
    #Creates the destination folder if it does not already exist
    os.makedirs(dest,exist_ok=True)
    dated_sections = determine_section_week(src)
    for pairs in dated_sections:
        section = pairs[0]
        week = pairs[1]
        
        #Translate the bin file using the median given from the M3C2 calculation on the wooden edges of the pallet
        z_shift_bin(overwrite,src,registration_folder,section,week,cc_path)
        
        print("Cropping the clouds")
        print("")
        
        pallet_dimensions = []
        
        #Read the cropping dimensions for each of the pallets
        for number in get_pallet_numbers(section,week):
            with open(os.getcwd() + "\\parameter_files\\cropping_dimensions\\" + section + "_" + week + "_pallet_" +  number + ".txt") as pallet_dims:
                pallet_dimensions += [pallet_dims.readline().replace("\n","")]
        
        
        #List the bin files in src for this section and week that have either been shifted using the median or are the first day of the week
        bin_files = [x for x in os.listdir(src) if "Zone" + section in x and date_boundary(x,week) and ("Z_Shifted" in x or "201808" + str(13 + (int(week)-1)*7) in x )]
        #List all the files in the src directory
        all_files = os.listdir(src)
        
        for filename in bin_files:
            #Path to the current bin file
            bin_path = src + "\\" + filename
            #Checks if the cropped bin file exists
            path_exists = os.path.exists(dest + "\\" +  filename.replace(".bin","_Cropped.bin") )
            
            if not path_exists or overwrite:
                
                #Crops the four pallets out of the cloud and saves then in individual files
                # -SILENT stops a cloud compare console popping up (useful for debug as it will stop the program after completing its task)
                # -O opens the file listed directly after
                # -CROP crops all loaded clouds with parameters {Xmin:Ymin:Zmin:Xmax:Ymax:Zmax}
                # -CLEAR clears all the loaded clouds
                #Cropping pallets produces the list containg command line code for any number of pallets
                subprocess.run([cc_path,"-SILENT"] + cropping_pallets(bin_path,pallet_dimensions) ,shell = True)
        
        
                bin_path = bin_path.replace(".bin","")
                print("Cropped the clouds for:")
                print(bin_path)
                print("")
                
                #Lists the cropped pallet files and assigns their file path
                pallet_files = [src + "\\" + x for x in diff(os.listdir(src),all_files)]
               
                #Merges the four pallets into one cloud
                # -SILENT stops a cloud compare console popping up (useful for debug as it will stop the program after completing its task)
                # -O opens the file listed directly after
                # -MERGE_CLOUDS merges all the loaded clouds
                subprocess.run([cc_path,"-SILENT"] + pallet_list(pallet_files) +["-MERGE_CLOUDS"],shell = True)
                
                print("Merged cropped clouds for:")
                print(bin_path)
                print("")
                
                #Deletes the individually cropped pallet files
                for pallet in pallet_files:
                    os.remove(pallet)
                
                #Finds the name of the merged file by comparing the list of files from before the cropping with the current list of files in the src directory
                merge_file = diff(os.listdir(src),all_files)[0] 
                
                #Deletes the old merged file if it already exists and the overwrite option was on
                if path_exists and overwrite:
                    os.remove(dest + "\\" + filename.replace(".bin","_Cropped.bin"))
                #Moves the merged file to the dest folder and adds "_Cropped" to the original filename
                os.rename(src + "\\" + merge_file,dest + "\\" + filename.replace(".bin","_Cropped.bin"))
                
        print("Section " + section + " week " + week + " completed.")
        print("")
