/// <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);
            }
        }
예제 #2
0
        /// <summary>
        /// Generates a 3-letter pillow 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="result">Holds the resulting pillow setup that was generated through this algorithm.</param>
        /// <returns>NULL if everything went fine or an exception.</returns>
        public static Exception GenerateProfileBasedOnPressureMapping(TestpersonSleepPositions sleepPosition, int[] pressureMeasurementSupine, int[] pressureMeasurementLateral, Genders gender, out PillowProfileGenerationResult result)
        {
            try
            {
                PillowBaseModuleVariants baseModule = PillowBaseModuleVariants.NoRole;
                PillowInsertVariants     inserts    = PillowInsertVariants.None;
                PillowWedgeVariants      wedge      = PillowWedgeVariants.None;

                if (sleepPosition == TestpersonSleepPositions.Lateral) //calculation for lateral position is more complex than the other 2
                {
                    #region Lateral sleeping position
                    int shoulderIndex;

                    /* Determine shoudler index (highest pressure from roles 1-4) */
                    int[] shoulderAreaArray = pressureMeasurementLateral;
                    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;
                    }

                    int shoulderIndexPressureValue = pressureMeasurementLateral[shoulderIndex]; //the absolute pressure value in millibar
                    baseModule = PillowBaseModuleVariants.WithRole;                             //we always have the base module

                    if (gender == Genders.Female)
                    {
                        if (shoulderIndexPressureValue < 8)
                        {
                            inserts = PillowInsertVariants.Thin;
                            wedge   = PillowWedgeVariants.ThickTowardsHeadEnd;
                        }
                        else if (shoulderIndexPressureValue < 14)
                        {
                            inserts = PillowInsertVariants.Thick;
                            wedge   = PillowWedgeVariants.ThickTowardsHeadEnd;
                        }
                        else
                        {
                            inserts = PillowInsertVariants.Both;
                            wedge   = PillowWedgeVariants.ThickTowardsHeadEnd;
                        }
                    }
                    else
                    {
                        if (shoulderIndexPressureValue < 7)
                        {
                            inserts = PillowInsertVariants.Thin;
                            wedge   = PillowWedgeVariants.ThickTowardsHeadEnd;
                        }
                        else if (shoulderIndexPressureValue < 13)
                        {
                            inserts = PillowInsertVariants.Thick;
                            wedge   = PillowWedgeVariants.ThickTowardsHeadEnd;
                        }
                        else
                        {
                            inserts = PillowInsertVariants.Both;
                            wedge   = PillowWedgeVariants.ThickTowardsHeadEnd;
                        }
                    }
                    #endregion
                }
                else if (sleepPosition == TestpersonSleepPositions.Supine)
                {
                    //supine position only adds a wedge for males
                    if (gender == Genders.Male)
                    {
                        baseModule = PillowBaseModuleVariants.WithRole;
                        wedge      = PillowWedgeVariants.ThickTowardsHeadEnd;
                    }
                    else
                    {
                        baseModule = PillowBaseModuleVariants.WithRole;
                    }
                }
                else if (sleepPosition == TestpersonSleepPositions.Prone)
                {
                    //prone position is always only with the base module; nothing else
                    baseModule = PillowBaseModuleVariants.WithRole;
                }

                //concat the resulting pillow code
                string code = ((int)baseModule).ToString() + ((int)inserts).ToString() + ((int)wedge).ToString();
                result = new PillowProfileGenerationResult()
                {
                    PillowCode = code, BaseModule = baseModule, Inserts = inserts, Wedge = wedge
                };

                return(null);
            }
            catch (Exception ex)
            {
                result = default(PillowProfileGenerationResult);
                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);
            }
        }