%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PREEMIE SCALING SCRIPT
%
% ABOUT:
% This code takes a set of measurements performed on an infant, and a reference
% model, and performs the necessary preprocessing steps to enable the PIPER
% software to scale the reference model.
%
% The reference model used in the development of this work consisted of a surface
% mesh of an infant created in LS-DYNA.
%
%
%
%
%
% Created by : ABR august@lightness.eu
% Date : 2024-06-11


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% INITIALIZATION
%
clear all; close all; clc
format compact


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% REFERENCE MEASUREMENTS
%
% The matrix preemie_babies should be a n x 5 matrix. Each row represents a
% baby measurement to achieve using PIPER scaling.
%
% The columns represent:
%   1 : L_tot   = Total length of the body (mm)
%   2 : L_S_gr  = Length from the shoulders to the groin (torso length) (mm)
%   3 : W       = Shoulder width (mm)
%   4 : HC      = Head circumference (mm)
%   5 : MASS    = Mass (g)
%
% A n x 1 structure preemie_baby_name contains the identifying name of each
% baby measurement.
preemie_babies = [380.00	150.00	110.00	300.00  1775.0
                  450.00	190.00	130.00	320.00  2185.0
                  510.00	240.00	170.00	360.00  3282.0];
preemie_baby_name = { '38cm_5th\'
                      '45cm_50th\'
                      '51cm_95th\'};


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% SETTINGS
%
% A number of settings are possible to control the scaling behavior. These settings
% are set here.
%
% The settings are collected in the structure scaling_options.
%
% A second structure, format_options, contains formatting rules.
%
scaling_options.isotropic_match_length = true;             % Try to get a good fit by isotropically scaling the reference body to match total length.
                                                           % Script will not work if this option is not set to TRUE.
scaling_options.center_and_align_body = true;              % If true, center and align prior to other operations
                                                           % Script will not work if this option is not set to TRUE.
scaling_options.scale_torso_in_plane_method = 2;           % 1 : Isotropic in-plane scaling with shoulder width.
                                                           % 2 : Only y-coordinates are scaled, not the x-coordinates. (preferred)
                                                           % 3 : Torso scaled to try to match mass.
scaling_options.scale_head_method = 3;                     % 1 : Scaling against total length
                                                           % 2 : Scaling proportional to head circumference scaling
                                                           % 3 : No scaling (preferred)
scaling_options.scale_arms_method = 2;                     % 1 : Arms are scaled as if part of the torso
                                                           % 2 : Arms are not scaled, only translated to match shoulder position (preferred)
scaling_options.legs_y = 1;                                % 1 : Rigid translation of legs in y direction

format_options.plot_flag = false;                          % True : Many diagnostic plots are generated and saved to file
format_options.dlmwrite_options = {'delimiter',' ', 'precision','%4.6f'};
                                                           % Settings when writing to file using the dlmwrite function
format_options.pngprintOptions   = {'-dpng','-r600'};      % Export settings for any figures generated
format_options.cfile_translate_X = [-300 0 300];           % Distances to move each new model along X
format_options.cfile_translate_Z = [0    0   0];           % Distances to move each new model along Z
format_options.align_bodies      = false;                   % If true, align groins to [0, 0, 0].
                                                           % Otherwise isotropic scaling will likely shift the groin position
format_options.step_by_step_reporting = false;              % If true, reports the key measurements calculated on the tcp
                                                           % after each transformation. This is quite verbose but very good for debugging.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FILE POINTERS
%
% The script uses prepared files and programs. The paths to these files and
% programs are set here. In general, they are machine dependent.
%
% All the file pointers are collected in the file_pointers structure which is then
% passed as necessary.
%
% In general, the inputs have input in the name while the outputs have output
% in their name.
%
% In general, a field with
%     "dir" in the name is a directory.
%     "path" is the full search path to the file
%     "name" is the file name, without the absolute path

% Running directory
file_pointers.top_dir             = [cd filesep];
file_pointers.plot_dir            = [file_pointers.top_dir '98_Plots' filesep];
file_pointers.input_dir           = [file_pointers.top_dir '01_Input_files' filesep];
file_pointers.output_dir          = [file_pointers.top_dir '0A_Output_files' filesep];
file_pointers.compare_output_dir  = [file_pointers.top_dir '99A_Comparison' filesep];
file_pointers.morphed_dir_name    = 'morphed_outputs';

% PIPER INSTALLATION
% PIPER top directory
file_pointers.piper_dir           = 'Piper_1.1.0';
% File name for the PIPER Python script file to be generated for each baby
file_pointers.piper_script_name   = 'piper_ctrl.py';
% File name for the PIPER batch script file to be generated for each baby
file_pointers.piper_bat_name      = 'piper_exe.bat';


% REFERENCE FILES TO READ
% PIPER PMR file.
file_pointers.pmr_file_input      = [file_pointers.input_dir 'Surface_Model_w_Joints_v0_0_1.pmr'];
file_pointers.pmr_file_name       = 'Surface_Model_w_Joints_v0_0_1.pmr';

% Reference model. This file is read and the contents are editted, before the file
% is saved in the appropriate place.
file_pointers.k_file_to_mod       = [file_pointers.input_dir 'Surface_Model_w_Joints_v0_0_1.k'];
file_pointers.k_file_out_name     = 'Surface_Model_w_Joints_v0_0_1.k';

% Source Control Points (SCP) to read. These are prepared in a separate file,
% imported, and the updated data is written to the appropriate place.
file_pointers.scp_file_to_read    = [file_pointers.input_dir 'SCP_Surface_Model_w_Joints_v0_0_2'];
file_pointers.scp_out_name        = 'scp';
file_pointers.tcp_out_name        = 'tcp';

file_pointers.cfile_out_name      = 'read_all_front_view.cfile';

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% SELECTION INDICES
%
% The kriging is performed by moving a set of control points. Source control
% points (scp) are positioned on the reference mesh. The scripts move the Target
% control points (tcp). The scp and tcp are then passed to PIPER along with the
% reference surface mesh.
%
% As different parts of the model are scaled differently, it is conventient to
% split the cps into groups by where on the surface mesh they are located.
%
% The best way of organising this information is with a csv file containing the
% following information:
%
% 1. Source point index
% 2. Corresponding node number at the same position
% 3. Associated body part
% 4. Key point, if applicable
% 5. Comments, if applicable

selIdx.head         = [1:13 22 34 71:74 95];
selIdx.torso        = [32:33 42 56:60 62:70 84 93:94 103 117:121];
selIdx.arms_yneg    = [83 87:90 99:102 104:112 122];
selIdx.arms_ypos    = [23 26:29 38:41 43:51 61];
selIdx.arms         = sort([selIdx.arms_yneg selIdx.arms_ypos]);
selIdx.foot_to_knee = [14:21 35:36 52:55 75:82 96:97 113:116];
selIdx.knee_to_hip  = [24:25 30:31 37 85:86 91:92 98];
selIdx.legs         = sort([selIdx.knee_to_hip selIdx.foot_to_knee]);


% Column 1: control point index
% Column 2: Node number
key_points.C1  = [  6	 1703196];    % Top of head
key_points.C3  = [ 66	35006303];    % Groin
key_points.C4  = [ 14	 7009325];    % Left heel
key_points.C5  = [117	35010323];    % RHS shoulder
key_points.C6  = [ 56	20003333];    % LHS shoulder
key_points.C7  = [  2	 1703104];    % Part of head circumference
key_points.C11 = [ 10	 1703717];    % Part of head circumference
key_points.C12 = [  9	 1703465];    % Part of head circumference
key_points.C13 = [  7	 1703211];    % Part of head circumference
key_points.C14 = [  8	 1703583];    % Part of head circumference
key_points.C15 = [ 37	20001177];    % Knee joint centre
key_points.C16 = [ 60	30006179];    % Hip joint centre



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FOLDER GENERATION
%
%
if not(exist(file_pointers.plot_dir , 'dir') == 7)
    mkdir(file_pointers.plot_dir)
end
if not(exist(file_pointers.compare_output_dir , 'dir') == 7)
    mkdir(file_pointers.compare_output_dir)
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% INITIALIZE STRUCTURES TO HOLD RESULTS
%
%
% Mass of each baby after morphing
baby_mass_output = [];
% Total length of each baby after morphing
baby_Ltot_output = [];
% File name of morphed model
baby_k_file_output = {};
% Collect all export folders
export_folders_output = {};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% MAIN LOOP
%

for fLoop = 1:length(preemie_baby_name)
  disp('****************************************************************')
  disp(['STARTING GENERATION OF ' preemie_baby_name{fLoop}(1:end-1)])

  % Create folders
  export_folder = [file_pointers.output_dir preemie_baby_name{fLoop}];
  if not(exist(export_folder, 'dir') == 7)
    mkdir(export_folder)
  end

  copyfile(file_pointers.pmr_file_input , [export_folder flip(strtok(flip(file_pointers.pmr_file_input),'\'))])
  if not(exist([export_folder file_pointers.morphed_dir_name] , 'dir') == 7)
    mkdir([export_folder file_pointers.morphed_dir_name])
  end

  % Select the key measurements to be used
  baby_measurements = preemie_babies(fLoop, :);

  % Update target points
  scale_cad_by_scp(baby_measurements, scaling_options, export_folder, file_pointers, format_options, selIdx, key_points)

  % Build a PIPER script
  build_piper_batch_script(export_folder, file_pointers);

  % Build a PIPER batch call file
  build_piper_bat_file(export_folder, file_pointers);

  % Call bat file and generated kriged representation
  if format_options.step_by_step_reporting
    system([export_folder file_pointers.piper_bat_name]);
  else
    system([export_folder file_pointers.piper_bat_name  ' > NUL']);
  end


  % Calculated actual key measurements on the morphed mesh
  [baby_mass_output(fLoop), baby_Ltot_output(fLoop)] = calculate_key_outputs_from_morphed_model( export_folder, file_pointers, baby_measurements, key_points);

  % Collect the output file path
  baby_k_file_output{fLoop} = [export_folder file_pointers.morphed_dir_name filesep file_pointers.k_file_out_name];

  % Collect the export folder
  export_folders_output{fLoop} = export_folder;
end

% Build a CFILE for comparison of the generated models
build_comparison_cfile(export_folders_output, file_pointers, format_options);



