/// <summary>
        /// Generates a profile based in the input person data.
        /// An  Liegesimulator_2._0 profile consists of 4 letters. 3 of these letters are the same, the other one is individual. The individual one can have 1 out of 3 available firmnesses.
        /// The position of the individual profile role is based on the position of the person's lordosis area.
        /// This algorithm attempts to find the position and hardness of the individual role and returns a support profile.
        /// Currently, the lordosis is considered to be between then 6th and the 9th role and thus one of these roles has to be the individual one. All other roles are set to the neutral letter 'N'.
        /// </summary>
        /// <param name="gender"></param>
        /// <param name="height">Height in cm.</param>
        /// <param name="weight">Weight in kg.</param>
        /// <param name="pressureMeasurementValues">4 measurement values from the simulator's pressure measurement.</param>
        /// <returns></returns>
        public static Exception GetProfileForPerson(MeasurementPositions position, Genders gender, int height, int weight, int[] pressureMeasurementSupine, int[] pressureMeasurementLateral, out SfContactProfile result)
        {
            result = default(SfContactProfile);

            if (pressureMeasurementSupine == null || pressureMeasurementSupine.Length != 12)
            {
                return(new ArgumentException("Measurement values invalid!", "pressureMeasurementSupine"));
            }

            if (pressureMeasurementLateral == null || pressureMeasurementLateral.Length != 12)
            {
                return(new ArgumentException("Measurement values invalid!", "pressureMeasurementLateral"));
            }

            if (height < 1 || weight < 1)
            {
                return(new ArgumentException("Body data invalid!", "height/weight"));
            }

            result = new  SfContactProfile()
            {
                Gender = gender, Height = height, Weight = weight
            };
            result.SupportProfile = "NNNN".ToStringArray();

            /*Pelvis area is always the peak value from right to left. */
            int[] measurementArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral;
            int   pelvisIndex      = measurementArray.Length - 1;

            //get the pelvis index (peak value from bottom to top, taking 6 values into account)
            for (int i = measurementArray.Length - 1; i >= 6; i--)
            {
                if (measurementArray[i] >= measurementArray[pelvisIndex])
                {
                    pelvisIndex = i;
                }
                else if (measurementArray[i] < measurementArray[pelvisIndex])
                {
                    break;
                }
            }

            if (pelvisIndex == 11 && height < 190) //pelvis area cannot be at the last stamp for person smaller than 190cm
            {
                pelvisIndex = 10;
            }

            if (measurementArray[pelvisIndex] == measurementArray[pelvisIndex - 1])
            {
                pelvisIndex--;
            }

            /* now try to find the position of the lordosis role in order to be able to modify the hardness of the role in that position */
            int lordosisIndex = GenerationUtils.GetIndexOfMinimum(measurementArray, 5, pelvisIndex - 1);

            /*special rules to make sure the profile makes sense */
            if (lordosisIndex + 1 == pelvisIndex) //lordosis and pelvis index must not be after one another
            {
                lordosisIndex--;
            }

            if (lordosisIndex < 5)
            {
                lordosisIndex = 5; //lordosis must always be between role 6 and role 9
            }
            else if (lordosisIndex > 8)
            {
                lordosisIndex = 8; //lordosis must always be between role 6 and role 9
            }
            //calculate BMI
            double bmi = weight / (Math.Pow((double)height / 100d, 2));

            //determine the position and hardness of the individual lordosis role
            string replacementLetter = bmi < 20 ? "G" : bmi < 27 ? "R" : "B";                                     //< 20 means underweight person --> soft role. 20-27 = normal. >27 = overweight person --> firm role.
            int    replacementIndex  = lordosisIndex - 5;                                                         //-5 because the 4 roles used in  Liegesimulator_2._0 are roles 6 through 9 (and the indices represent roles 1 through 12)

            result.SupportProfile = result.SupportProfile.ReplaceAtIndex(replacementIndex, replacementLetter[0]); //replace the normal role in the standard profile with the individual role that was generated by the algorithm
            result.FirmRoleIndex  = lordosisIndex;
            return(null);
        }
        /// <summary>
        /// Generates a support profile using an intelligent algorithm for the specified customer.
        /// </summary>
        /// <param name="position"></param>
        /// <param name="pressureMeasurementSupine">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the back.</param>
        /// <param name="pressureMeasurementLateral">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the side.</param>
        /// <param name="gender"></param>
        /// <param name="personHeightCm">The height of the test person in centimeters.</param>
        /// <param name="personWeightKg">The weight of the test person in kilogram.</param>
        /// <param name="neutralProfileLetter">The letter representing the neutral (middle) stamp firmness on which the profile is based. For example, Vitario uses 'S' and Ergomometer NL uses 'D' as neutral stamp.</param>
        /// <param name="result">Holds the resulting profile that was generated through this algorithm. NULL if something went wrong.</param>
        /// <returns>Null if everything went fine or an exception.</returns>
        public static Exception GenerateProfileBasedOnPressureMapping(MeasurementPositions position, int[] pressureMeasurementSupine, int[] pressureMeasurementLateral, Genders gender, int personHeightCm, int personWeightKg, char neutralProfileLetter, out StampProfileGenerationResult result)
        {
            try
            {
                result = default(StampProfileGenerationResult);

                if (position == MeasurementPositions.Lateral)
                {
                    int shoulderIndex, lordosisIndex, pelvisIndex = pressureMeasurementSupine.Length - 1;

                    //generate the standard profile
                    string profile = string.Join("", Enumerable.Repeat(neutralProfileLetter, 12));
                    bool   personLyingPositionWrong = false;

                    #region Shoulder

                    /*Shoulder area is always stamps 1-4. If the measurement in supine position is bad (equal values), the measurement in lateral position is used. */
                    int[] shoulderAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral;
                    shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3);

                    if (GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) || shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if one of the values around the shoulder index is the same
                    {
                        shoulderAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementLateral : pressureMeasurementSupine;
                        shoulderIndex     = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3);
                    }

                    if (!GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) && shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if the value to the right is the same, move the shoulder index one to the right (e.g. 17 19 19 15)
                    {
                        shoulderIndex++;
                    }
                    else if (shoulderIndex == 0 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray) && shoulderAreaArray[2] == shoulderAreaArray[0]) //e.g. 17 17 17 19
                    {
                        shoulderIndex = 1;
                    }

                    //now generate the profile for this area
                    if (shoulderIndex == 0)
                    {
                        profile = profile.ReplaceAtIndex(0, 'T');
                        profile = profile.ReplaceAtIndex(1, 'K');
                        profile = profile.ReplaceAtIndex(2, 'K');

                        if (GenerationUtils.IsInRange(shoulderAreaArray[0], shoulderAreaArray[1], 2)) //if the first 2 values are similar, the profile changes a bit
                        {
                            profile = profile.ReplaceAtIndex(1, 'T');
                            profile = profile.ReplaceAtIndex(3, 'K');
                        }
                    }
                    else if (shoulderIndex == 1)
                    {
                        profile = profile.ReplaceAtIndex(0, 'K');
                        profile = profile.ReplaceAtIndex(1, 'T');
                        profile = profile.ReplaceAtIndex(2, 'K');

                        //if the values around the shoulder index are similar, the profile changes a bit
                        if (GenerationUtils.IsInRange(shoulderAreaArray[0], shoulderAreaArray[1], 2))
                        {
                            profile = profile.ReplaceAtIndex(0, 'T');
                            profile = profile.ReplaceAtIndex(3, 'K');
                        }

                        if (GenerationUtils.IsInRange(shoulderAreaArray[1], shoulderAreaArray[2], 2))
                        {
                            profile = profile.ReplaceAtIndex(2, 'T');
                            profile = profile.ReplaceAtIndex(3, 'K');
                        }
                    }
                    else if (shoulderIndex == 2 || shoulderIndex == 3) //indices at position 2 and 3 are treated the same, but an index at 3 hints that the person is not properly positioned on the mattress
                    {
                        profile = profile.ReplaceAtIndex(0, 'K');
                        profile = profile.ReplaceAtIndex(1, 'K');
                        profile = profile.ReplaceAtIndex(2, 'T');
                        profile = profile.ReplaceAtIndex(3, 'K');

                        if (shoulderAreaArray[1] + 2 >= shoulderAreaArray[2]) //if the value before the shoulder index is no more less than 2, the profile changes
                        {
                            if (gender == Genders.Female)
                            {
                                profile = profile.ReplaceAtIndex(0, 'T');
                                profile = profile.ReplaceAtIndex(1, 'T');
                            }
                            else
                            {
                                profile = profile.ReplaceAtIndex(0, 'W');
                                profile = profile.ReplaceAtIndex(1, 'T');
                            }
                        }

                        if (shoulderIndex == 3)
                        {
                            personLyingPositionWrong = true;
                        }
                    }

                    #endregion

                    #region Pelvis area
                    /*Pelvis area is always the peak value from right to left in a specific area. */
                    int[] pelvisAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral;

                    if (personHeightCm >= 170)
                    {
                        //get the pelvis index (peak value from bottom to top, taking 6 values into account)
                        for (int i = pelvisAreaArray.Length - 1; i >= 6; i--)
                        {
                            if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                            {
                                pelvisIndex = i;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    if (personHeightCm >= 160)
                    {
                        //get the pelvis index (peak value from bottom to top, taking 4 values into account)
                        for (int i = pelvisAreaArray.Length - 3; i >= 6; i--)
                        {
                            if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                            {
                                pelvisIndex = i;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else if (personHeightCm >= 150)
                    {
                        //get the pelvis index (peak value from bottom-3 to top, taking 3 values into account)
                        for (int i = pelvisAreaArray.Length - 4; i >= 6; i--)
                        {
                            if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                            {
                                pelvisIndex = i;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else //small persons < 150cm
                    {
                        //get the pelvis index (peak value from bottom-3 to top, taking 4 values into account)
                        for (int i = pelvisAreaArray.Length - 4; i >= 5; i--)
                        {
                            if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                            {
                                pelvisIndex = i;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    if (pelvisIndex == 11 && personHeightCm < 190) //pelvis area cannot be at the last stamp for person smaller than 190cm
                    {
                        pelvisIndex = 10;
                    }

                    //modify profile
                    profile = profile.ReplaceAtIndex(pelvisIndex, 'K');

                    if (gender == Genders.Male)                                                                           //males have a smaller pelvis area --> smaller range of values (+/- 3) and allow only 2 "K"-stamps
                    {
                        if (GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex - 1], 3)) //if the value before the pelvis index is within 3mB, change its corresponding profile stamp
                        {
                            profile = profile.ReplaceAtIndex(pelvisIndex - 1, 'K');
                        }
                    }
                    else //females have a bigger pelvis area --> higher range of values (+/- 5)
                    {
                        if (pelvisIndex < 11 && GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex + 1], 5)) //if the value after the pelvis index is within 4mB, change its corresponding profile stamp
                        {
                            profile = profile.ReplaceAtIndex(pelvisIndex + 1, 'K');
                        }

                        if (GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex - 1], 5)) //if the value before the pelvis index is within 5mB, change its corresponding profile stamp
                        {
                            profile = profile.ReplaceAtIndex(pelvisIndex - 1, 'K');
                        }
                    }
                    #endregion

                    #region Lordosis area
                    /* Lordosis area is between shoulder and pelvis area and can never be before stamp 5. The lordosis index is always the index of the lowest value between shoulder and pelvis. */

                    //calculate the BMI of the test person (determines which stamp is used in the lordosis area)
                    double heightM = personHeightCm / 100d;
                    double bmi     = personWeightKg / (heightM * heightM); //body mass index

                    int[] lordosisAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral;

                    lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1);

                    if (bmi > 30) //special rule: if the person is overweight, the lordosis index should be calculated based on the supine measurement
                    {
                        int lordosisIdxSupine  = GenerationUtils.GetIndexOfMinimum(pressureMeasurementSupine, 4, pelvisIndex - 1);
                        int lordosisIdxLateral = GenerationUtils.GetIndexOfMinimum(pressureMeasurementLateral, 4, pelvisIndex - 1);

                        if (lordosisIdxSupine > lordosisIdxLateral)
                        {
                            lordosisIndex = lordosisIdxSupine;
                        }
                    }

                    //this step is useless because we always use the lateral values here
                    if (lordosisAreaArray[lordosisIndex - 1] == lordosisAreaArray[lordosisIndex] && lordosisAreaArray[lordosisIndex + 1] == lordosisAreaArray[lordosisIndex]) //if the values around the lordosis index are equal, try to get a better result by using the lateral measurement
                    {
                        lordosisAreaArray = pressureMeasurementLateral;
                        lordosisIndex     = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1);
                    }

                    if (personHeightCm > 155 && lordosisIndex <= 4 && gender == Genders.Male) //special rule: lordosis area cannot be at stamp 5 or below for small persons
                    {
                        lordosisIndex = 5;
                    }
                    else if (personHeightCm > 160 && lordosisIndex <= 4 && gender == Genders.Female) //special rule: lordosis area cannot be at stamp 5 or below for small persons
                    {
                        lordosisIndex = 5;
                    }

                    if (pelvisIndex - lordosisIndex > 3) //special rule: if the distance between pelvis and lordosis is more than 2 stamps, something is wrong --> "move" the lordosis index closer to the pelvis index
                    {
                        lordosisIndex = pelvisIndex - 3;
                    }

                    if (pelvisIndex - lordosisIndex == 1) //special rule: if lordosis and pelvis indices were determined to be next to each other, they have to be separated by 1 stamp
                    {
                        lordosisIndex = lordosisIndex - 1;
                    }

                    //modify the profile
                    if ((gender == Genders.Male && bmi < 20) || (gender == Genders.Female && bmi < 19)) //person appears to be underweight --> neutral ("D" or "S") stamp (so the same stamp as in surrounding area)
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, neutralProfileLetter);
                    }
                    else if (bmi > 30) //person appears to be clearly overweight --> "B" stamp
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, 'B');
                    }
                    else
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, 'L');              //normal weight --> "L" stamp
                    }
                    if (lordosisIndex == pelvisIndex - 1 && profile[lordosisIndex] == 'K') //if the lordosis index is directly before the pelvis index, no 'K'-stamp is allowed in the lordosis area (which can't happen with the current algorithm anyways)
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, 'L');
                    }

                    //special rule: "K" must not come directly after "L"
                    if (profile.Contains("LK")) //"L" must not immediately followed by "K" (distance between lordosis and pelvis area is at least 1 neutral stamp)
                    {
                        profile = profile.Replace("LK", "L" + neutralProfileLetter.ToString());

                        if (profile.Contains("L" + neutralProfileLetter + neutralProfileLetter))                                            //e.g. "LDD"
                        {
                            profile = profile.Replace("L" + neutralProfileLetter + neutralProfileLetter, "L" + neutralProfileLetter + "K"); //add the replaced "K" at the end of the pelvis area
                        }
                    }

                    //special rule: if the lordosis index is on stamp 5, stamp 4 must be neutral and stamp 3 must not be "T"
                    if (lordosisIndex == 4)
                    {
                        profile = profile.ReplaceAtIndex(3, neutralProfileLetter);

                        if (profile[2] == 'T')
                        {
                            profile = profile.ReplaceAtIndex(2, 'K');
                        }
                    }
                    #endregion

                    result = new StampProfileGenerationResult()
                    {
                        SupportProfile = profile.Select(s => s.ToString()).ToArray(), IsPersonLyingPositionWrong = personLyingPositionWrong
                    };
                    return(null);
                }
                else if (position == MeasurementPositions.Supine)
                {
                    int shoulderIndex, lordosisIndex, pelvisIndex = pressureMeasurementSupine.Length - 1;

                    //generate the standard profile
                    string profile = string.Join("", Enumerable.Repeat(neutralProfileLetter, 12));
                    bool   personLyingPositionWrong = false;

                    #region Shoulder

                    /*Shoulder area is always stamps 1-3.  */
                    int[] shoulderAreaArray = pressureMeasurementSupine;
                    shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 2);

                    //now generate the profile for this area
                    if (shoulderIndex == 0)
                    {
                        profile = profile.ReplaceAtIndex(0, 'T');
                        profile = profile.ReplaceAtIndex(1, 'K');
                        profile = profile.ReplaceAtIndex(2, 'K');
                    }
                    else if (shoulderIndex == 1 || shoulderIndex == 2)
                    {
                        profile = profile.ReplaceAtIndex(0, 'K');
                        profile = profile.ReplaceAtIndex(1, 'T');
                        profile = profile.ReplaceAtIndex(2, 'K');
                    }

                    #endregion

                    #region Pelvis area
                    /*Pelvis area is always the peak value from right to left in a specific area. */
                    int[] pelvisAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral;

                    if (personHeightCm >= 170)
                    {
                        //get the pelvis index (peak value from bottom to top, taking 6 values into account)
                        for (int i = pelvisAreaArray.Length - 1; i >= 6; i--)
                        {
                            if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                            {
                                pelvisIndex = i;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    if (personHeightCm >= 160)
                    {
                        //get the pelvis index (peak value from bottom to top, taking 4 values into account)
                        for (int i = pelvisAreaArray.Length - 3; i >= 6; i--)
                        {
                            if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                            {
                                pelvisIndex = i;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else if (personHeightCm >= 150)
                    {
                        //get the pelvis index (peak value from bottom-3 to top, taking 3 values into account)
                        for (int i = pelvisAreaArray.Length - 4; i >= 6; i--)
                        {
                            if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                            {
                                pelvisIndex = i;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else //small persons < 150cm
                    {
                        //get the pelvis index (peak value from bottom-3 to top, taking 4 values into account)
                        for (int i = pelvisAreaArray.Length - 4; i >= 5; i--)
                        {
                            if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                            {
                                pelvisIndex = i;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    if (pelvisIndex == 11 && personHeightCm < 190) //pelvis area cannot be at the last stamp for person smaller than 190cm
                    {
                        pelvisIndex = 10;
                    }

                    //modify profile
                    profile = profile.ReplaceAtIndex(pelvisIndex, 'K');

                    #endregion

                    #region Lordosis area
                    /* Lordosis area is between shoulder and pelvis area and can never be before stamp 5. The lordosis index is always the index of the lowest value between shoulder and pelvis. */

                    //calculate the BMI of the test person (determines which stamp is used in the lordosis area)
                    double heightM = personHeightCm / 100d;
                    double bmi     = personWeightKg / (heightM * heightM); //body mass index

                    int[] lordosisAreaArray = pressureMeasurementSupine;

                    lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1);

                    if (personHeightCm > 155 && lordosisIndex <= 4 && gender == Genders.Male) //special rule: lordosis area cannot be at stamp 5 or below for small persons
                    {
                        lordosisIndex = 5;
                    }
                    else if (personHeightCm > 160 && lordosisIndex <= 4 && gender == Genders.Female) //special rule: lordosis area cannot be at stamp 5 or below for small persons
                    {
                        lordosisIndex = 5;
                    }

                    if (pelvisIndex - lordosisIndex == 1) //special rule: if lordosis and pelvis indices were determined to be next to each other, they have to be separated by 1 stamp
                    {
                        lordosisIndex = lordosisIndex - 1;
                    }

                    //modify the profile
                    if ((gender == Genders.Male && bmi < 20) || (gender == Genders.Female && bmi < 19)) //person appears to be underweight --> neutral ("D" or "S") stamp (so the same stamp as in surrounding area)
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, neutralProfileLetter);
                    }
                    else if (bmi > 30) //person appears to be clearly overweight --> "B" stamp
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, 'B');
                    }
                    else
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, 'L'); //normal weight --> "L" stamp
                    }
                    #endregion

                    result = new StampProfileGenerationResult()
                    {
                        SupportProfile = profile.Select(s => s.ToString()).ToArray(), IsPersonLyingPositionWrong = personLyingPositionWrong
                    };
                    return(null);
                }
                else
                {
                    return(null);
                }
            }
            catch (Exception ex)
            {
                result = default(StampProfileGenerationResult);
                return(ex);
            }
        }
Пример #3
0
        /// <summary>
        /// Generates a support profile using an intelligent algorithm for the specified customer.
        /// </summary>
        /// <param name="position"></param>
        /// <param name="pressureMeasurementSupine">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the back.</param>
        /// <param name="pressureMeasurementLateral">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the side.</param>
        /// <param name="gender"></param>
        /// <param name="personHeightCm">The height of the test person in centimeters.</param>
        /// <param name="personWeightKg">The weight of the test person in kilogram.</param>
        /// <param name="neutralProfileLetter">The letter representing the neutral (middle) role firmness on which the profile is based. For example, Vitario uses 'S' and Ergomometer NL uses 'D' as neutral element.</param>
        /// <param name="result">Holds the resulting profile that was generated through this algorithm. NULL if something went wrong.</param>
        /// <returns>Null if everything went fine or an exception.</returns>
        public static Exception GenerateProfileBasedOnPressureMapping(MeasurementPositions position, int[] pressureMeasurementSupine, int[] pressureMeasurementLateral, Genders gender, int personHeightCm, int personWeightKg, char neutralProfileLetter, out RoleProfileGenerationResult result)
        {
            try
            {
                result = default(RoleProfileGenerationResult);

                if (position == MeasurementPositions.Lateral)
                {
                    int shoulderIndex, lordosisIndex, pelvisIndex = pressureMeasurementSupine.Length - 1;

                    //generate the standard profile
                    string profile = string.Join("", Enumerable.Repeat(neutralProfileLetter, 12));
                    bool   personLyingPositionWrong = false;

                    #region Shoulder

                    /*Shoulder area is always roles 1-4. If the measurement in supine position is bad (equal values), the measurement in lateral position is used. */
                    int[] shoulderAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral;
                    shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3);

                    if (GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) || shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if one of the values around the shoulder index is the same
                    {
                        shoulderAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementLateral : pressureMeasurementSupine;
                        shoulderIndex     = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3);
                    }

                    if (!GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) && shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if the value to the right is the same, move the shoulder index one to the right (e.g. 17 19 19 15)
                    {
                        shoulderIndex++;
                    }
                    else if (shoulderIndex == 0 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray) && shoulderAreaArray[2] == shoulderAreaArray[0]) //e.g. 17 17 17 19
                    {
                        shoulderIndex = 1;
                    }

                    //now generate the profile for this area
                    if (shoulderIndex == 0)
                    {
                        profile = profile.ReplaceAtIndex(0, 'T');
                        profile = profile.ReplaceAtIndex(1, 'K');
                        profile = profile.ReplaceAtIndex(2, 'K');

                        if (GenerationUtils.IsInRange(shoulderAreaArray[0], shoulderAreaArray[1], 2)) //if the first 2 values are similar, the profile changes a bit
                        {
                            profile = profile.ReplaceAtIndex(1, 'T');
                            profile = profile.ReplaceAtIndex(3, 'K');
                        }
                    }
                    else if (shoulderIndex == 1)
                    {
                        profile = profile.ReplaceAtIndex(0, 'K');
                        profile = profile.ReplaceAtIndex(1, 'T');
                        profile = profile.ReplaceAtIndex(2, 'K');

                        //if the values around the shoulder index are similar, the profile changes a bit
                        if (GenerationUtils.IsInRange(shoulderAreaArray[0], shoulderAreaArray[1], 2))
                        {
                            profile = profile.ReplaceAtIndex(0, 'T');
                            profile = profile.ReplaceAtIndex(3, 'K');
                        }

                        if (GenerationUtils.IsInRange(shoulderAreaArray[1], shoulderAreaArray[2], 2))
                        {
                            profile = profile.ReplaceAtIndex(2, 'T');
                            profile = profile.ReplaceAtIndex(3, 'K');
                        }
                    }
                    else if (shoulderIndex == 2 || shoulderIndex == 3) //indices at position 2 and 3 are treated the same, but an index at 3 hints that the person is not properly positioned on the mattress
                    {
                        profile = profile.ReplaceAtIndex(0, 'K');
                        profile = profile.ReplaceAtIndex(1, 'K');
                        profile = profile.ReplaceAtIndex(2, 'T');
                        profile = profile.ReplaceAtIndex(3, 'K');

                        if (shoulderAreaArray[1] + 2 >= shoulderAreaArray[2]) //if the value before the shoulder index is no more less than 2, the profile changes
                        {
                            if (gender == Genders.Female)
                            {
                                profile = profile.ReplaceAtIndex(0, 'T');
                                profile = profile.ReplaceAtIndex(1, 'T');
                            }
                            else
                            {
                                profile = profile.ReplaceAtIndex(0, 'W');
                                profile = profile.ReplaceAtIndex(1, 'T');
                            }
                        }

                        if (shoulderIndex == 3)
                        {
                            personLyingPositionWrong = true;
                        }
                    }

                    #endregion

                    #region Pelvis area
                    /*Pelvis area is always the peak value from right to left. */
                    int[] pelvisAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral;

                    //get the pelvis index (peak value from bottom to top, taking 6 values into account)
                    for (int i = pelvisAreaArray.Length - 1; i >= 6; i--)
                    {
                        if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                        {
                            pelvisIndex = i;
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (pelvisIndex == 11 && personHeightCm < 190) //pelvis area cannot be at the last role for person smaller than 190cm
                    {
                        pelvisIndex = 10;
                    }

                    //modify profile
                    profile = profile.ReplaceAtIndex(pelvisIndex, 'K');

                    if (gender == Genders.Male)                                                                           //males have a smaller pelvis area --> smaller range of values (+/- 3) and allow only 2 "K"-roles
                    {
                        if (GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex - 1], 3)) //if the value before the pelvis index is within 4mB, change its corresponding profile role
                        {
                            profile = profile.ReplaceAtIndex(pelvisIndex - 1, 'K');
                        }
                    }
                    else //females have a bigger pelvis area --> higher range of values (+/- 5)
                    {
                        if (pelvisIndex < 11 && GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex + 1], 5)) //if the value after the pelvis index is within 4mB, change its corresponding profile role
                        {
                            profile = profile.ReplaceAtIndex(pelvisIndex + 1, 'K');
                        }

                        if (GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex - 1], 5)) //if the value before the pelvis index is within 4mB, change its corresponding profile role
                        {
                            profile = profile.ReplaceAtIndex(pelvisIndex - 1, 'K');
                        }
                    }
                    #endregion

                    #region Lordosis area
                    /* Lordosis area is between shoulder and pelvis area and can never be before role 5. The lordosis index is always the index of the lowest value between shoulder and pelvis. */

                    //calculate the BMI of the test person (determines which role is used in the lordosis area)
                    double heightM = personHeightCm / 100d;
                    double bmi     = personWeightKg / (heightM * heightM); //body mass index

                    int[] lordosisAreaArray = pressureMeasurementSupine;

                    lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1);

                    if (personHeightCm > 155 && lordosisIndex <= 4 && gender == Genders.Male) //special rule: lordosis area cannot be at role 5 or below for small persons
                    {
                        lordosisIndex = 5;
                    }
                    else if (personHeightCm > 160 && lordosisIndex <= 4 && gender == Genders.Female) //special rule: lordosis area cannot be at role 5 or below for small persons
                    {
                        lordosisIndex = 5;
                    }

                    if (pelvisIndex - lordosisIndex == 1) //special rule: if lordosis and pelvis indices were determined to be next to each other, they have to be separated by 1 role
                    {
                        lordosisIndex = lordosisIndex - 1;
                    }

                    //modify the profile
                    if (bmi > 30) //person appears to be clearly overweight --> "B" element
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, 'B');
                    }
                    else
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, neutralProfileLetter); //normal weight --> neutral element
                    }
                    //special rule: "K" must not come directly after "B"
                    if (profile.Contains("BK"))                                                                                                                                   //"B" must not be immediately followed by "K" (distance between lordosis and pelvis area is at least 1 neutral role)
                    {
                        profile = profile.Replace("BK", "B" + neutralProfileLetter).Replace("B" + neutralProfileLetter + neutralProfileLetter, "B" + neutralProfileLetter + "K"); //also add the replaced "K" at the end of the pelvis area
                    }
                    #endregion

                    result = new RoleProfileGenerationResult()
                    {
                        SupportProfile = profile.Select(s => s.ToString()).ToArray(), IsPersonLyingPositionWrong = personLyingPositionWrong
                    };
                    return(null);
                }
                else if (position == MeasurementPositions.Supine)
                {
                    int shoulderIndex, lordosisIndex, pelvisIndex = pressureMeasurementSupine.Length - 1;

                    //generate the standard profile
                    string profile = string.Join("", Enumerable.Repeat(neutralProfileLetter, 12));
                    bool   personLyingPositionWrong = false;

                    #region Shoulder
                    /*Shoulder area is always roles 1-3. Ony stam 1 and 2 can be changed to 'T'. */
                    int[] shoulderAreaArray = pressureMeasurementSupine;
                    shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 2);

                    //now generate the profile for this area
                    if (shoulderIndex == 0)
                    {
                        profile = profile.ReplaceAtIndex(0, 'T');
                        profile = profile.ReplaceAtIndex(1, 'K');
                        profile = profile.ReplaceAtIndex(2, 'K');
                    }
                    else if (shoulderIndex == 1 || shoulderIndex == 2)
                    {
                        profile = profile.ReplaceAtIndex(0, 'K');
                        profile = profile.ReplaceAtIndex(1, 'T');
                        profile = profile.ReplaceAtIndex(2, 'K');
                    }

                    #endregion

                    #region Pelvis area
                    /*Pelvis area is always the peak value from right to left. */
                    int[] pelvisAreaArray = pressureMeasurementSupine;

                    //get the pelvis index (peak value from bottom to top, taking 6 values into account)
                    for (int i = pelvisAreaArray.Length - 1; i >= 6; i--)
                    {
                        if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex])
                        {
                            pelvisIndex = i;
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (pelvisIndex == 11 && personHeightCm < 190) //pelvis area cannot be at the last role for person smaller than 190cm
                    {
                        pelvisIndex = 10;
                    }

                    //modify profile
                    profile = profile.ReplaceAtIndex(pelvisIndex, 'K');
                    #endregion

                    #region Lordosis area
                    /* Lordosis area is between shoulder and pelvis area and can never be before role 5. The lordosis index is always the index of the lowest value between shoulder and pelvis. */

                    //calculate the BMI of the test person (determines which role is used in the lordosis area)
                    double heightM = personHeightCm / 100d;
                    double bmi     = personWeightKg / (heightM * heightM); //body mass index

                    int[] lordosisAreaArray = pressureMeasurementSupine;

                    lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1);

                    if (personHeightCm > 155 && lordosisIndex <= 4 && gender == Genders.Male) //special rule: lordosis area cannot be at role 5 or below for small persons
                    {
                        lordosisIndex = 5;
                    }
                    else if (personHeightCm > 160 && lordosisIndex <= 4 && gender == Genders.Female) //special rule: lordosis area cannot be at role 5 or below for small persons
                    {
                        lordosisIndex = 5;
                    }

                    if (pelvisIndex - lordosisIndex == 1) //special rule: if lordosis and pelvis indices were determined to be next to each other, they have to be separated by 1 role
                    {
                        lordosisIndex = lordosisIndex - 1;
                    }

                    //modify the profile
                    if (bmi > 30) //person appears to be clearly overweight --> "B" role
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, 'B');
                    }
                    else
                    {
                        profile = profile.ReplaceAtIndex(lordosisIndex, neutralProfileLetter); //normal weight --> neutral role
                    }
                    //special rule: "K" must not come directly after "B"
                    if (profile.Contains("BK"))                                                                                                                                   //"B" must not immediately followed by "K" (distance between lordosis and pelvis area is at least 1 neutral role)
                    {
                        profile = profile.Replace("BK", "B" + neutralProfileLetter).Replace("B" + neutralProfileLetter + neutralProfileLetter, "B" + neutralProfileLetter + "K"); //also add the replaced "K" at the end of the pelvis area
                    }
                    #endregion

                    result = new RoleProfileGenerationResult()
                    {
                        SupportProfile = profile.Select(s => s.ToString()).ToArray(), IsPersonLyingPositionWrong = personLyingPositionWrong
                    };
                    return(null);
                }
                else
                {
                    return(null);
                }
            }
            catch (Exception ex)
            {
                result = default(RoleProfileGenerationResult);
                return(ex);
            }
        }