classdef app1 < matlab.apps.AppBase

    % Properties that correspond to app components
    properties (Access = public)
        UIFigure                    matlab.ui.Figure
        OperatorEditField           matlab.ui.control.EditField
        OperatorEditFieldLabel      matlab.ui.control.Label
        LowerJawLabel               matlab.ui.control.Label
        UpperJawLabel               matlab.ui.control.Label
        PrecisionUndulatorLocationEvaluationSystemsPULSELabel  matlab.ui.control.Label
        STATUSEditField             matlab.ui.control.EditField
        STATUSEditFieldLabel        matlab.ui.control.Label
        CommentsTextArea            matlab.ui.control.TextArea
        CommentsTextAreaLabel       matlab.ui.control.Label
        NominalgapmmEditField       matlab.ui.control.NumericEditField
        NominalgapmmEditFieldLabel  matlab.ui.control.Label
        UndulatorEditField          matlab.ui.control.EditField
        UndulatorEditFieldLabel     matlab.ui.control.Label
        MeasurepolesButton          matlab.ui.control.Button
        UndulatortypeButtonGroup    matlab.ui.container.ButtonGroup
        SXUButton                   matlab.ui.control.RadioButton
        HESXUButton                 matlab.ui.control.RadioButton
        LocateundulatorButton       matlab.ui.control.Button
        UIAxes2                     matlab.ui.control.UIAxes
        UIAxes                      matlab.ui.control.UIAxes
    end

    % Callbacks that handle component events
    methods (Access = private)

        % Button pushed function: LocateundulatorButton
        function LocateundulatorButtonPushed(app, event)
            cd ('S:\magdata\LCLS-II-HE\Dover bench touch probe IO files')
            app.LocateundulatorButton.Enable = "off";
            app.MeasurepolesButton.Enable = "off";
            app.NominalgapmmEditField.Enable = "off";
            app.UndulatorEditField.Enable = "off";
            app.UndulatortypeButtonGroup.Enable = "off";
            app.CommentsTextArea.Enable = "off";
            app.OperatorEditField.Enable = "off";

            fid=fopen('GapChange.inp',"w");
            fprintf(fid,'%.4f %.4f', 10, 0);
            fclose(fid);

            fid=fopen('GapRequest.flg',"w");
            fclose(fid);

            pauseTime = 0.5;
            delete('Reply.txt');
            format long eng

            sel = app.UndulatortypeButtonGroup.SelectedObject;  % the selected radio button
    
            app.STATUSEditField.Value = 'Starting lateral pole face location...';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            outfilename='Dover.inp';
            usLateralPoleFace_x = -124758 * 0.5 / 1000;
            usLateralPoleFace_y = -51451 * 0.5 / 1000;

            %usLateralPoleFace_z = 379.013 + 2.5 - 0.5;
            usLateralPoleFace_z = importdata("usLateralPoleFace_z.txt");
            axis_y = -11.0370000000000e+000; % Fix

            fid=fopen(outfilename,"w");

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLateralPoleFace_x, axis_y,              usLateralPoleFace_z - 10);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLateralPoleFace_x, usLateralPoleFace_y, usLateralPoleFace_z - 10);
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   0   -1   0\n',usLateralPoleFace_x, usLateralPoleFace_y, usLateralPoleFace_z);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLateralPoleFace_x, usLateralPoleFace_y, usLateralPoleFace_z - 10);

            fclose(fid);
            

            fid=fopen('Request.flg',"w");
            fclose(fid);

            app.STATUSEditField.Value = 'Dover.inp input file and Request.flg created';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                app.STATUSEditField.Value = 'Locating the lateral pole face - measurement in progress...';
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again
                    end
                else
                    pause(1);
                end
            end
            delete('Reply.txt');
            pause(1);

            fid = fopen('Kugler.out', 'r');
            str = fgetl(fid);
            str = fgetl(fid);
            fclose(fid);

            usLateralPoleFaceCoord = sscanf(str, '%f');
            usLateralPoleFace_z = usLateralPoleFaceCoord(3) * 1e3;

            % fid = fopen('usLateralPoleFace_z.txt', 'w');
            % fprintf(fid, '%.4f', usLateralPoleFace_z);
            % fclose(fid);

            app.STATUSEditField.Value = sprintf('Lateral pole face z position: %.3f mm', usLateralPoleFace_z);
            pause(5);

            % Part 2: Locate the undulator

            app.STATUSEditField.Value = 'Beginning undulator location sequence...';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            if sel == app.SXUButton
                % SXU selected
                % SXU parameters (mm)
                Delta_lateralPoleFace_PoleFace = 1.197; % Note on pole face: The pole is more negative in z then the lateral pole face by about 1mm
                halfPeriod = 19.5;
                Delta_pole_jaw_y = 22; % This number was estimated by averaging the distance between the pole position and face position in y for upper and lower jaws
                Delta_poleFace_1stPole = 3.9; % Distance in z from the first pole face to the first pole center
                Delta_jawFace_poleCenter_x = 58;
                Delta_poleFace_LowerPole_y = 4.3185; % usLowerPole_y - (-40850 * 0.5 / 1000), Distance in y between the face pole measurement and the lower pole position. By eye, it looks about 5 mm
                margin = 3.608; % abs(usPoleFace_z - usPoleFaceEntrance_z) + 0.5, margin from pole face to move the probe rod to be capable of entering the tight space
                poleFace2poleFace = 3381.301;

                %3.38130000000000e+003

                usPoleFace_z = usLateralPoleFace_z-Delta_lateralPoleFace_PoleFace;
                dsPoleFace_z = usPoleFace_z + poleFace2poleFace;

                usLowerJawFace_x = -148082 * 0.5 / 1000 + 2.5;
                usLowerPole_y = -27213 * 0.5 / 1000 - 2.5;
                usUpperPole_y = -17131 * 0.5 / 1000 + 2.5;

                usPoleFaceEntrance_z = 377.208;

                % Approx coordinates. They correspond to absolute position of the sphere center, in mm
                ap=[usLowerJawFace_x + Delta_jawFace_poleCenter_x    usLowerPole_y-Delta_poleFace_LowerPole_y    usPoleFace_z                                           %US Pole Face
                    usLowerJawFace_x                                 usLowerPole_y-Delta_pole_jaw_y              usPoleFace_z + Delta_poleFace_1stPole + 3*halfPeriod   %US Lower Jaw Face
                    usLowerJawFace_x                                 usUpperPole_y+Delta_pole_jaw_y              usPoleFace_z + Delta_poleFace_1stPole + 3*halfPeriod   %US Upper Jaw Face
                    usLowerJawFace_x + Delta_jawFace_poleCenter_x    usLowerPole_y                               usPoleFace_z + Delta_poleFace_1stPole + 3*halfPeriod   %US Lower Pole
                    usLowerJawFace_x + Delta_jawFace_poleCenter_x    usUpperPole_y                               usPoleFace_z + Delta_poleFace_1stPole + 3*halfPeriod   %US Upper Pole
                    usLowerJawFace_x + Delta_jawFace_poleCenter_x    usLowerPole_y                               usPoleFace_z + Delta_poleFace_1stPole + 170*halfPeriod %DS Lower Pole
                    usLowerJawFace_x + Delta_jawFace_poleCenter_x    usUpperPole_y                               usPoleFace_z + Delta_poleFace_1stPole + 170*halfPeriod %DS Upper Pole
                    usLowerJawFace_x                                 usLowerPole_y-Delta_pole_jaw_y              usPoleFace_z + Delta_poleFace_1stPole + 170*halfPeriod %DS Lower Jaw Face
                    usLowerJawFace_x                                 usUpperPole_y+Delta_pole_jaw_y              usPoleFace_z + Delta_poleFace_1stPole + 170*halfPeriod %DS Lower Jaw Face
                    usLowerJawFace_x + Delta_jawFace_poleCenter_x    usLowerPole_y-Delta_poleFace_LowerPole_y    dsPoleFace_z];                                         %DS Pole Face

            else % sel == app.HESXUButton
                % HESXU selected
                gap   = 12;     % example
                taper = 0.2;
            end

            apOriginal = ap;

            clpclear_x=usLowerJawFace_x - 5; % Used the jaw face minus 5mm

            outfilename='Dover.inp';

            fid=fopen(outfilename,"w");

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(1,1),(ap(4,2)+ap(5,2))/2,ap(1,3) - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(1,1),ap(1,2),ap(1,3) - margin);

            % US Pole Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   0   -1   0\n',ap(1,1),ap(1,2),ap(1,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(1,1),ap(1,2),ap(1,3) - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(1,1),(ap(4,2)+ap(5,2))/2,ap(1,3) - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,(ap(4,2)+ap(5,2))/2,ap(1,3) - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(2,2),ap(2,3));

            % US Lower Jaw Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n',ap(2,1),ap(2,2),ap(2,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(2,2),ap(2,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(3,2),ap(3,3));

            % US Upper Jaw Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n',ap(3,1),ap(3,2),ap(3,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(3,2),ap(3,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(4,1),(ap(4,2)+ap(5,2))/2,ap(4,3));

            %U S Lower Pole
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  +1   0   0\n',ap(4,1),ap(4,2),ap(4,3));

            % US Upper Pole
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   -1   0   0\n',ap(4,1),ap(5,2),ap(4,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(6,1),(ap(6,2)+ap(7,2))/2,ap(6,3));

            % DS Lower Pole
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  +1   0   0\n',ap(6,1),ap(6,2),ap(6,3));

            % DS Upper Pole
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   -1   0   0\n',ap(6,1),ap(7,2),ap(6,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,(ap(6,2)+ap(7,2))/2,ap(6,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(8,2),ap(8,3));

            % DS Lower Jaw Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n',ap(8,1),ap(8,2),ap(8,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(8,2),ap(8,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(9,2),ap(9,3));

            % DS Upper Jaw Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n',ap(9,1),ap(9,2),ap(9,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(9,2),ap(9,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(10,1),(ap(6,2)+ap(7,2))/2,ap(10,3) + margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(10,1),ap(10,2),ap(10,3) + margin);

            % DS Pole Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   0  +1   0\n',ap(10,1),ap(10,2),ap(10,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(10,1),ap(10,2), ap(10,3) + margin);

            % Bring the carriage back to the US side
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,(ap(6,2)+ap(7,2))/2,100);

            fclose(fid);

            fid=fopen('Request.flg',"w");
            fclose(fid);

            app.STATUSEditField.Value = 'Dover.inp input file and Request.flg created';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again

                    end
                else
                    if isfile("Kugler.out")
                        fid = fopen('Kugler.out', 'r');
                        D = textscan(fid, '%f %f %f', 'HeaderLines', 1, 'CommentStyle', '$');
                        fclose(fid);

                        clear locateUndData;
                        locateUndData = cell2mat(D) * 1e3;
                        pointsMeas = size(locateUndData);
                        pointsMeas = pointsMeas(1);
                        pause(1);

                    end
                    if pointsMeas>0
                        app.STATUSEditField.Value = sprintf('Locating the undulator: Point #%d/10 measured', pointsMeas);
                    end
                    pause(1);
                end
            end
            delete('Reply.txt');

            if isfile("Kugler.out")
                fid = fopen('Kugler.out', 'r');
                C = textscan(fid, '%f %f %f', 'HeaderLines', 1, 'CommentStyle', '$');
                fclose(fid);

                clear ap;
                ap = cell2mat(C) * 1e3;
            end

             save measurementMatrix.mat ap apOriginal;

            if pointsMeas~=10
                app.STATUSEditField.Value = 'ERROR! Output data file has points missing!';
                error('Output data file has points missing');
            end

            app.STATUSEditField.Value = 'Pole faces, poles, and jaws have been located!';

            app.LocateundulatorButton.Enable = "on";
            app.MeasurepolesButton.Enable = "on";
            app.NominalgapmmEditField.Enable = "on";
            app.UndulatorEditField.Enable = "on";
            app.UndulatortypeButtonGroup.Enable = "on";
            app.CommentsTextArea.Enable = "on";
            app.OperatorEditField.Enable = "on";

           





        end

        % Button pushed function: MeasurepolesButton
        function MeasurepolesButtonPushed(app, event)


            app.LocateundulatorButton.Enable = "off";
            app.MeasurepolesButton.Enable = "off";
            app.NominalgapmmEditField.Enable = "off";
            app.UndulatorEditField.Enable = "off";
            app.UndulatortypeButtonGroup.Enable = "off";
            app.CommentsTextArea.Enable = "off";
            app.OperatorEditField.Enable = "off";

            % Parameters
            sel = app.UndulatortypeButtonGroup.SelectedObject;  % the selected radio button
            delete('Reply.txt');
            load measurementMatrix.mat

            cla(app.UIAxes);
            cla(app.UIAxes2);

            app.STATUSEditField.Value = 'Beginning pole-location sequence...';
            pause(5);

            clpclear_x = ap(2,1) - 5;

            %HE_undulator=0; %if it is an HE undulator this value should be 1, if it is an SXU undulator it should be 0

            Gap = app.NominalgapmmEditField.Value;

            fid=fopen('GapChange.inp',"w");
            fprintf(fid,'%.4f %.4f', Gap, 0);
            fclose(fid);

            fid=fopen('GapRequest.flg',"w");
            fclose(fid);

            Probetip_diameter=5; % mm
            xProbeDistBtwMeas=20; % mm

            midp=[mean(ap([2 3 8 9],1)), mean(ap([4 5 6 7],2)), mean(ap([1 10],3))];
            % midp is an array of 3 elements: x, y, and z
            % x is the average of x position lower/upper jaw face on US and DS plus the sphere radius
            % (Q1) Why to add the sphere radius? Pressumably (or idealy), the points
            % should be with respect to the sphere center
            % y is the average between the vertical center of US and DS pole
            yaw_l=(ap(8,1)-ap(2,1))/(ap(8,3)-ap(2,3));
            yaw_u=(ap(9,1)-ap(3,1))/(ap(9,3)-ap(3,3));
            yaw=(yaw_l+yaw_u)/2;
            pitch_l=(ap(6,2)-ap(4,2))/(ap(6,3)-ap(4,3));
            pitch_u=(ap(7,2)-ap(5,2))/(ap(7,3)-ap(5,3));
            pitch=(pitch_l+pitch_u)/2;



            % poleloc seems to have a pole number, a z position, and a distance in x
            % from the jaw face.
            % Q2: if the midp is at the center of the undulator in z, why does it start
            % at 5.19 mm? I would expect a large negative number.
            % Answer: it is compensante later
            ynom=(Gap-Probetip_diameter)/2;
            if sel == app.HESXUButton
                poleloc=[1	5.19	66.75
                    2	30.69	66.75
                    3	57.44	66.75
                    4	85.44	66.75
                    5	113.44	66.75
                    6	141.44	66.75
                    7	169.44	66.75
                    8	197.44	66.75
                    9	225.44	66.75
                    10	253.44	66.75
                    11	281.44	66.75
                    12	309.44	66.75
                    13	337.44	66.75
                    14	365.44	66.75
                    15	393.44	66.75
                    16	421.44	66.75
                    17	449.44	66.75
                    18	477.44	66.75
                    19	505.44	66.75
                    20	533.44	66.75
                    21	561.44	66.75
                    22	589.44	66.75
                    23	617.44	66.75
                    24	645.44	66.75
                    25	673.44	66.75
                    26	701.44	66.75
                    27	729.44	66.75
                    28	757.44	66.75
                    29	785.44	66.75
                    30	813.44	66.75
                    31	841.44	66.75
                    32	869.44	66.75
                    33	897.44	66.75
                    34	925.44	66.75
                    35	953.44	66.75
                    36	981.44	66.75
                    37	1009.44	66.75
                    38	1037.44	66.75
                    39	1065.44	66.75
                    40	1093.44	66.75
                    41	1121.44	66.75
                    42	1149.44	66.75
                    43	1177.44	66.75
                    44	1205.44	66.75
                    45	1233.44	66.75
                    46	1261.44	66.75
                    47	1289.44	66.75
                    48	1317.44	66.75
                    49	1345.44	66.75
                    50	1373.44	66.75
                    51	1401.44	66.75
                    52	1429.44	66.75
                    53	1457.44	66.75
                    54	1485.44	66.75
                    55	1513.44	66.75
                    56	1541.44	66.75
                    57	1569.44	66.75
                    58	1597.44	66.75
                    59	1625.44	66.75
                    60	1653.44	66.75
                    61	1681.44	66.75
                    62	1709.44	66.75
                    63	1737.44	66.75
                    64	1765.44	66.75
                    65	1793.44	66.75
                    66	1821.44	66.75
                    67	1849.44	66.75
                    68	1877.44	66.75
                    69	1905.44	66.75
                    70	1933.44	66.75
                    71	1961.44	66.75
                    72	1989.44	66.75
                    73	2017.44	66.75
                    74	2045.44	66.75
                    75	2073.44	66.75
                    76	2101.44	66.75
                    77	2129.44	66.75
                    78	2157.44	66.75
                    79	2185.44	66.75
                    80	2213.44	66.75
                    81	2241.44	66.75
                    82	2269.44	66.75
                    83	2297.44	66.75
                    84	2325.44	66.75
                    85	2353.44	66.75
                    86	2381.44	66.75
                    87	2409.44	66.75
                    88	2437.44	66.75
                    89	2465.44	66.75
                    90	2493.44	66.75
                    91	2521.44	66.75
                    92	2549.44	66.75
                    93	2577.44	66.75
                    94	2605.44	66.75
                    95	2633.44	66.75
                    96	2661.44	66.75
                    97	2689.44	66.75
                    98	2717.44	66.75
                    99	2745.44	66.75
                    100	2773.44	66.75
                    101	2801.44	66.75
                    102	2829.44	66.75
                    103	2857.44	66.75
                    104	2885.44	66.75
                    105	2913.44	66.75
                    106	2941.44	66.75
                    107	2969.44	66.75
                    108	2997.44	66.75
                    109	3025.44	66.75
                    110	3053.44	66.75
                    111	3081.44	66.75
                    112	3109.44	66.75
                    113	3137.44	66.75
                    114	3165.44	66.75
                    115	3193.44	66.75
                    116	3221.44	66.75
                    117	3249.44	66.75
                    118	3277.44	66.75
                    119	3305.44	66.75
                    120	3333.44	66.75
                    121	3360.19	66.75
                    122	3385.69	66.75];
            else
                poleloc=[1	3.9	58
                    2	23.4	58
                    3	42.9	58
                    4	62.4	58
                    5	81.9	58
                    6	101.4	58
                    7	120.9	58
                    8	140.4	58
                    9	159.9	58
                    10	179.4	58
                    11	198.9	58
                    12	218.4	58
                    13	237.9	58
                    14	257.4	58
                    15	276.9	58
                    16	296.4	58
                    17	315.9	58
                    18	335.4	58
                    19	354.9	58
                    20	374.4	58
                    21	393.9	58
                    22	413.4	58
                    23	432.9	58
                    24	452.4	58
                    25	471.9	58
                    26	491.4	58
                    27	510.9	58
                    28	530.4	58
                    29	549.9	58
                    30	569.4	58
                    31	588.9	58
                    32	608.4	58
                    33	627.9	58
                    34	647.4	58
                    35	666.9	58
                    36	686.4	58
                    37	705.9	58
                    38	725.4	58
                    39	744.9	58
                    40	764.4	58
                    41	783.9	58
                    42	803.4	58
                    43	822.9	58
                    44	842.4	58
                    45	861.9	58
                    46	881.4	58
                    47	900.9	58
                    48	920.4	58
                    49	939.9	58
                    50	959.4	58
                    51	978.9	58
                    52	998.4	58
                    53	1017.9	58
                    54	1037.4	58
                    55	1056.9	58
                    56	1076.4	58
                    57	1095.9	58
                    58	1115.4	58
                    59	1134.9	58
                    60	1154.4	58
                    61	1173.9	58
                    62	1193.4	58
                    63	1212.9	58
                    64	1232.4	58
                    65	1251.9	58
                    66	1271.4	58
                    67	1290.9	58
                    68	1310.4	58
                    69	1329.9	58
                    70	1349.4	58
                    71	1368.9	58
                    72	1388.4	58
                    73	1407.9	58
                    74	1427.4	58
                    75	1446.9	58
                    76	1466.4	58
                    77	1485.9	58
                    78	1505.4	58
                    79	1524.9	58
                    80	1544.4	58
                    81	1563.9	58
                    82	1583.4	58
                    83	1602.9	58
                    84	1622.4	58
                    85	1641.9	58
                    86	1661.4	58
                    87	1680.9	58
                    88	1700.4	58
                    89	1719.9	58
                    90	1739.4	58
                    91	1758.9	58
                    92	1778.4	58
                    93	1797.9	58
                    94	1817.4	58
                    95	1836.9	58
                    96	1856.4	58
                    97	1875.9	58
                    98	1895.4	58
                    99	1914.9	58
                    100	1934.4	58
                    101	1953.9	58
                    102	1973.4	58
                    103	1992.9	58
                    104	2012.4	58
                    105	2031.9	58
                    106	2051.4	58
                    107	2070.9	58
                    108	2090.4	58
                    109	2109.9	58
                    110	2129.4	58
                    111	2148.9	58
                    112	2168.4	58
                    113	2187.9	58
                    114	2207.4	58
                    115	2226.9	58
                    116	2246.4	58
                    117	2265.9	58
                    118	2285.4	58
                    119	2304.9	58
                    120	2324.4	58
                    121	2343.9	58
                    122	2363.4	58
                    123	2382.9	58
                    124	2402.4	58
                    125	2421.9	58
                    126	2441.4	58
                    127	2460.9	58
                    128	2480.4	58
                    129	2499.9	58
                    130	2519.4	58
                    131	2538.9	58
                    132	2558.4	58
                    133	2577.9	58
                    134	2597.4	58
                    135	2616.9	58
                    136	2636.4	58
                    137	2655.9	58
                    138	2675.4	58
                    139	2694.9	58
                    140	2714.4	58
                    141	2733.9	58
                    142	2753.4	58
                    143	2772.9	58
                    144	2792.4	58
                    145	2811.9	58
                    146	2831.4	58
                    147	2850.9	58
                    148	2870.4	58
                    149	2889.9	58
                    150	2909.4	58
                    151	2928.9	58
                    152	2948.4	58
                    153	2967.9	58
                    154	2987.4	58
                    155	3006.9	58
                    156	3026.4	58
                    157	3045.9	58
                    158	3065.4	58
                    159	3084.9	58
                    160	3104.4	58
                    161	3123.9	58
                    162	3143.4	58
                    163	3162.9	58
                    164	3182.4	58
                    165	3201.9	58
                    166	3221.4	58
                    167	3240.9	58
                    168	3260.4	58
                    169	3279.9	58
                    170	3299.4	58
                    171	3318.9	58
                    172	3338.4	58
                    173	3357.9	58
                    174	3377.4	58];
            end

            poleloc_und(:,3)=poleloc(:,2)-(poleloc(end,2)+poleloc(1,2))/2;
            poleloc_und(:,1:2)=0;
            % poleloc_und creates a matrix with 3 columns. 1st and 2nd columns are
            % zerod. Third has z positions distributed symmetrically around 0 (center)

            Ru=[1 0 -yaw;
                0 1 -pitch_u;
                yaw pitch_u 1];
            Rl=[1 0 -yaw;
                0 1 -pitch_l;
                yaw pitch_l 1];

            R = [1 0 -yaw;
                0 1 -pitch;
                yaw pitch 1];

            probe_u=poleloc_und*Ru;
            probe_l=poleloc_und*Rl;

            % Matrices need to be reviews. probe_l will have the poleloc_und rotated
            % according to the undulator

            probepu=[poleloc(:,3)+probe_u(:,1)+midp(1) probe_u(:,2)+midp(2) probe_u(:,3)+midp(3)];
            probepl=[poleloc(:,3)+probe_l(:,1)+midp(1) probe_l(:,2)+midp(2) probe_l(:,3)+midp(3)];

            % probepu is the points where the probe should measure
            % For x: it takes the known distance from the jaw face to the center (66.75
            % mm for HE, 58 mm for SXU) + the rotated array probe_u + the mid point +
            % the sphere radius
            % For y: it is the rotated array probe_u + the mid point.
            % For z: as it is for y
            % probeu and probel are essentially points in the undulator axis

            clear index p
            firstPoleNum = 3;
            lastPoleNu = 171; %Max 174
            poleDistIndx = 21;
            index = [firstPoleNum : poleDistIndx : lastPoleNu];
            timePerPole = 150; % s

            for n=1:4*length(index)
                p(n) = index(floor((n - 1)/4) + 1);
            end

            fid=fopen('Dover.inp',"w");
            %first clearance point outside undulator at location of first pole
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,probepu(1,2),probepu(1,3));
            for i=[firstPoleNum : poleDistIndx : lastPoleNu]
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  -1   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2)+Gap/2, probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   0   1   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',probepu(i,1) + xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  -1   0   0\n',probepu(i,1) + xProbeDistBtwMeas/2, probepu(i,2)+Gap/2, probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   0   1   0   0\n',probepu(i,1) + xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  +1   0   0\n',probepl(i,1) + xProbeDistBtwMeas/2, probepl(i,2)-Gap/2,probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   0   1   0   0\n',probepu(i,1) + xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  +1   0   0\n',probepl(i,1) - xProbeDistBtwMeas/2, probepl(i,2)-Gap/2,probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   0   1   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
            end
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,probepu(i,2),100);
            fclose(fid);

            fid=fopen('Request.flg',"w");
            fclose(fid);

            app.STATUSEditField.Value = 'Dover.inp input file and Request.flg created';
            pause(5);


            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again

                    end
                else
                    if isfile("Kugler.out")
                        fid = fopen('Kugler.out', 'r');
                        D = textscan(fid, '%f %f %f', 'HeaderLines', 1, 'CommentStyle', '$');
                        fclose(fid);

                        clear UndPoles;
                        UndPoles = cell2mat(D) * 1e3;
                        pointsMeas = size(UndPoles);
                        pointsMeas = pointsMeas(1);
                        %pointsMeas = int32(pointsMeas);
                        if pointsMeas>0
                            y = UndPoles(:,2); % mm
                            z = UndPoles(:,3) * 1e-3; % m
                            %p(pointsMeas) = index(floor((pointsMeas - 1)/4) + 1);
                        end

                        pause(1);

                    end
                    if pointsMeas>0
                        app.STATUSEditField.Value = sprintf('%d out of %d measured poles. Measured points: %d (~ %d min. left)', floor(pointsMeas/4), length(index), pointsMeas, round(timePerPole*(length(index) - floor(pointsMeas/4))/60));
                        plot(app.UIAxes, p(y > midp(2)), y(y > midp(2)), 'kx', 'LineStyle', 'none');
                        plot(app.UIAxes2, p(y < midp(2)), y(y < midp(2)), 'kx', 'LineStyle', 'none');

                        % Add grid
                        grid(app.UIAxes, 'on');
                        grid(app.UIAxes2, 'on');

                        % --- Add margin automatically ---
                        % ======== FIRST AXIS ========
                        xData1 = p(y > midp(2));
                        yData1 = y(y > midp(2));

                        if ~isempty(xData1)
                            dx = range(xData1);
                            dy = range(yData1);

                            % Handle single-point or zero-range case
                            if dx == 0
                                dx = max(abs(xData1(1)), 1);
                            end
                            if dy == 0
                                dy = max(abs(yData1(1)), 1);
                            end

                            % Apply limits (using min/max for multi-point, same for single)
                            %xlim(app.UIAxes, [min(xData1) - dx, max(xData1) + dx]);
                            xlim(app.UIAxes, [firstPoleNum-1, lastPoleNu + 1]);
                            ylim(app.UIAxes, [min(yData1) - dy * 0.05, max(yData1) + dy * 0.05]);
                        end


                        % ======== SECOND AXIS ========
                        xData2 = p(y < midp(2));
                        yData2 = y(y < midp(2));

                        if ~isempty(xData2)
                            dx2 = range(xData2);
                            dy2 = range(yData2);

                            % Handle single-point or zero-range case
                            if dx2 == 0
                                dx2 = max(abs(xData2(1)), 1);
                            end
                            if dy2 == 0
                                dy2 = max(abs(yData2(1)), 1);
                            end

                            % Apply limits
                            %xlim(app.UIAxes2, [min(xData2) - dx2, max(xData2) + dx2]);
                            xlim(app.UIAxes2, [firstPoleNum-1, lastPoleNu + 1]);
                            ylim(app.UIAxes2, [min(yData2) - dy2 * 0.05, max(yData2) + dy2 * 0.05]);
                        end

                        % if ~isempty(xData1)
                        %     dx = range(xData1);
                        %     dy = range(yData1);
                        % 
                        %     % Handle single-point case (zero range)
                        %     if dx == 0
                        %         dx = abs(xData1(1)) * 0.05;  % 5% of value
                        %         if dx == 0, dx = 1; end      % fallback if x = 0
                        %     end
                        %     if dy == 0
                        %         dy = abs(yData1(1)) * 0.05;  % 5% of value
                        %         if dy == 0, dy = 1; end
                        %     end
                        % 
                        %     % Apply limits safely
                        %     xlim(app.UIAxes, [xData1(1) - dx, xData1(1) + dx]);
                        %     ylim(app.UIAxes, [yData1(1) - dy, yData1(1) + dy]);
                        % end
                    end
                    pause(1);
                end
            end
            delete('Reply.txt');
            app.STATUSEditField.Value = sprintf('Completed! %d out of %d measured poles. Measured points: %d', floor(pointsMeas/4), length(index), pointsMeas);

            app.LocateundulatorButton.Enable = "on";
            app.MeasurepolesButton.Enable = "on";
            app.NominalgapmmEditField.Enable = "on";
            app.UndulatorEditField.Enable = "on";
            app.UndulatortypeButtonGroup.Enable = "on";
            app.CommentsTextArea.Enable = "on";
            app.OperatorEditField.Enable = "on";


        end
    end

    % Component initialization
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)

            % Create UIFigure and hide until all components are created
            app.UIFigure = uifigure('Visible', 'off');
            app.UIFigure.Color = [0.549 0.0784 0.0784];
            app.UIFigure.Position = [100 40 640 805];
            app.UIFigure.Name = 'MATLAB App';

            % Create UIAxes
            app.UIAxes = uiaxes(app.UIFigure);
            xlabel(app.UIAxes, 'Pole #')
            ylabel(app.UIAxes, 'y (mm)')
            zlabel(app.UIAxes, 'Z')
            app.UIAxes.XColor = [1 1 1];
            app.UIAxes.YColor = [1 1 1];
            app.UIAxes.ZColor = [1 1 1];
            app.UIAxes.Position = [35 233 578 185];

            % Create UIAxes2
            app.UIAxes2 = uiaxes(app.UIFigure);
            xlabel(app.UIAxes2, 'Pole #')
            ylabel(app.UIAxes2, 'y (mm)')
            app.UIAxes2.XColor = [1 1 1];
            app.UIAxes2.YColor = [1 1 1];
            app.UIAxes2.Position = [35 11 578 185];

            % Create LocateundulatorButton
            app.LocateundulatorButton = uibutton(app.UIFigure, 'push');
            app.LocateundulatorButton.ButtonPushedFcn = createCallbackFcn(app, @LocateundulatorButtonPushed, true);
            app.LocateundulatorButton.FontSize = 24;
            app.LocateundulatorButton.Position = [320 640 286 69];
            app.LocateundulatorButton.Text = 'Locate undulator';

            % Create UndulatortypeButtonGroup
            app.UndulatortypeButtonGroup = uibuttongroup(app.UIFigure);
            app.UndulatortypeButtonGroup.Title = 'Undulator type';
            app.UndulatortypeButtonGroup.Position = [40 541 100 70];

            % Create HESXUButton
            app.HESXUButton = uiradiobutton(app.UndulatortypeButtonGroup);
            app.HESXUButton.Text = 'HE SXU';
            app.HESXUButton.Position = [11 24 66 22];
            app.HESXUButton.Value = true;

            % Create SXUButton
            app.SXUButton = uiradiobutton(app.UndulatortypeButtonGroup);
            app.SXUButton.Text = 'SXU';
            app.SXUButton.Position = [11 2 65 22];

            % Create MeasurepolesButton
            app.MeasurepolesButton = uibutton(app.UIFigure, 'push');
            app.MeasurepolesButton.ButtonPushedFcn = createCallbackFcn(app, @MeasurepolesButtonPushed, true);
            app.MeasurepolesButton.FontSize = 36;
            app.MeasurepolesButton.FontWeight = 'bold';
            app.MeasurepolesButton.Position = [320 541 286 84];
            app.MeasurepolesButton.Text = 'Measure poles';

            % Create UndulatorEditFieldLabel
            app.UndulatorEditFieldLabel = uilabel(app.UIFigure);
            app.UndulatorEditFieldLabel.HorizontalAlignment = 'right';
            app.UndulatorEditFieldLabel.FontColor = [1 1 1];
            app.UndulatorEditFieldLabel.Position = [63 624 57 22];
            app.UndulatorEditFieldLabel.Text = 'Undulator';

            % Create UndulatorEditField
            app.UndulatorEditField = uieditfield(app.UIFigure, 'text');
            app.UndulatorEditField.Position = [135 624 130 22];
            app.UndulatorEditField.Value = 'HE-SXU-000';

            % Create NominalgapmmEditFieldLabel
            app.NominalgapmmEditFieldLabel = uilabel(app.UIFigure);
            app.NominalgapmmEditFieldLabel.HorizontalAlignment = 'right';
            app.NominalgapmmEditFieldLabel.FontColor = [1 1 1];
            app.NominalgapmmEditFieldLabel.Position = [16 687 104 22];
            app.NominalgapmmEditFieldLabel.Text = 'Nominal gap (mm)';

            % Create NominalgapmmEditField
            app.NominalgapmmEditField = uieditfield(app.UIFigure, 'numeric');
            app.NominalgapmmEditField.ValueDisplayFormat = '%.4f';
            app.NominalgapmmEditField.FontColor = [0.149 0.149 0.149];
            app.NominalgapmmEditField.Placeholder = '10.0000';
            app.NominalgapmmEditField.Position = [135 687 130 22];
            app.NominalgapmmEditField.Value = 10;

            % Create CommentsTextAreaLabel
            app.CommentsTextAreaLabel = uilabel(app.UIFigure);
            app.CommentsTextAreaLabel.HorizontalAlignment = 'right';
            app.CommentsTextAreaLabel.FontColor = [1 1 1];
            app.CommentsTextAreaLabel.Position = [153 600 63 22];
            app.CommentsTextAreaLabel.Text = 'Comments';

            % Create CommentsTextArea
            app.CommentsTextArea = uitextarea(app.UIFigure);
            app.CommentsTextArea.Position = [153 541 112 60];

            % Create STATUSEditFieldLabel
            app.STATUSEditFieldLabel = uilabel(app.UIFigure);
            app.STATUSEditFieldLabel.HorizontalAlignment = 'center';
            app.STATUSEditFieldLabel.FontSize = 18;
            app.STATUSEditFieldLabel.FontWeight = 'bold';
            app.STATUSEditFieldLabel.FontColor = [0 1 0];
            app.STATUSEditFieldLabel.Position = [40 500 578 23];
            app.STATUSEditFieldLabel.Text = 'STATUS';

            % Create STATUSEditField
            app.STATUSEditField = uieditfield(app.UIFigure, 'text');
            app.STATUSEditField.Editable = 'off';
            app.STATUSEditField.FontSize = 18;
            app.STATUSEditField.FontColor = [0.149 0.149 0.149];
            app.STATUSEditField.Position = [40 469 578 27];

            % Create PrecisionUndulatorLocationEvaluationSystemsPULSELabel
            app.PrecisionUndulatorLocationEvaluationSystemsPULSELabel = uilabel(app.UIFigure);
            app.PrecisionUndulatorLocationEvaluationSystemsPULSELabel.HorizontalAlignment = 'center';
            app.PrecisionUndulatorLocationEvaluationSystemsPULSELabel.FontName = 'Copperplate Gothic Bold';
            app.PrecisionUndulatorLocationEvaluationSystemsPULSELabel.FontSize = 24;
            app.PrecisionUndulatorLocationEvaluationSystemsPULSELabel.FontWeight = 'bold';
            app.PrecisionUndulatorLocationEvaluationSystemsPULSELabel.FontColor = [1 1 1];
            app.PrecisionUndulatorLocationEvaluationSystemsPULSELabel.Position = [12 736 623 64];
            app.PrecisionUndulatorLocationEvaluationSystemsPULSELabel.Text = {'Precision Undulator Location & Evaluation Systems'; '- PULSE -'};

            % Create UpperJawLabel
            app.UpperJawLabel = uilabel(app.UIFigure);
            app.UpperJawLabel.HorizontalAlignment = 'center';
            app.UpperJawLabel.FontSize = 14;
            app.UpperJawLabel.FontWeight = 'bold';
            app.UpperJawLabel.FontColor = [1 1 1];
            app.UpperJawLabel.Position = [4 415 632 22];
            app.UpperJawLabel.Text = 'Upper Jaw';

            % Create LowerJawLabel
            app.LowerJawLabel = uilabel(app.UIFigure);
            app.LowerJawLabel.HorizontalAlignment = 'center';
            app.LowerJawLabel.FontSize = 14;
            app.LowerJawLabel.FontWeight = 'bold';
            app.LowerJawLabel.FontColor = [1 1 1];
            app.LowerJawLabel.Position = [4 190 632 22];
            app.LowerJawLabel.Text = 'Lower Jaw';

            % Create OperatorEditFieldLabel
            app.OperatorEditFieldLabel = uilabel(app.UIFigure);
            app.OperatorEditFieldLabel.HorizontalAlignment = 'right';
            app.OperatorEditFieldLabel.FontColor = [1 1 1];
            app.OperatorEditFieldLabel.Position = [66 655 52 22];
            app.OperatorEditFieldLabel.Text = 'Operator';

            % Create OperatorEditField
            app.OperatorEditField = uieditfield(app.UIFigure, 'text');
            app.OperatorEditField.FontColor = [0.149 0.149 0.149];
            app.OperatorEditField.Position = [135 655 130 22];
            app.OperatorEditField.Value = 'JB';

            % Show the figure after all components are created
            app.UIFigure.Visible = 'on';
        end
    end

    % App creation and deletion
    methods (Access = public)

        % Construct app
        function app = app1

            % Create UIFigure and components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.UIFigure)

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.UIFigure)
        end
    end
end