/// <summary>
 /// Compares two <see cref="UParameterIndexAndMonotonicity"/> values by their u parameters.
 /// </summary>
 /// <param name="first">The first value</param>
 /// <param name="second">The second value</param>
 private static int CompareUParameterIndexAndMonotonicityByUParameter(UParameterIndexAndMonotonicity first, UParameterIndexAndMonotonicity second)
 {
     return(first.UParameter.CompareTo(second.UParameter));
 }
        /// <summary>
        /// For a contour consisting of one portion monotonically increasing in u-parameter and the other monotonically decreasing, return the <see cref="SingleContourSegmentwiseCoverage"/>
        /// where there are matching points (at the same u-parameter) on both the increasing and decreasing portions.
        /// </summary>
        /// <param name="monotonicIncreasingChunk">Portion of contour with monotonically increasing u-parameters</param>
        /// <param name="monotonicDecreasingChunk">Portion of contour with monotonically decreasing u-parameters</param>
        internal static SingleContourSegmentwiseCoverage GetSingleContourSegmentwiseCoverage(ExtrudedContourMonotonicChunk monotonicIncreasingChunk, ExtrudedContourMonotonicChunk monotonicDecreasingChunk)
        {
            List <UParameterIndexAndMonotonicity> allContourPointUParameters = new List <UParameterIndexAndMonotonicity>();
            List <Vector2WithUV> monotonicIncreasingPoints = monotonicIncreasingChunk.Points;
            List <Vector2WithUV> monotonicDecreasingPoints = monotonicDecreasingChunk.Points;

            //Skip the last point in each chunk so as to not double-count the 'endpoints' of min/max u-parameter
            for (int i = 0; i < monotonicIncreasingPoints.Count - 1; i++)
            {
                allContourPointUParameters.Add(new UParameterIndexAndMonotonicity(monotonicIncreasingPoints[i].UV.x, i, true));
            }
            for (int i = 1; i < monotonicDecreasingPoints.Count; i++)
            {
                allContourPointUParameters.Add(new UParameterIndexAndMonotonicity(monotonicDecreasingPoints[i].UV.x, i, false));
            }
            allContourPointUParameters.Sort(CompareUParameterIndexAndMonotonicityByUParameter);

            allContourPointUParameters.RemoveAt(allContourPointUParameters.Count - 1);
            allContourPointUParameters.RemoveAt(0);
            int numInBetweenUParameters = allContourPointUParameters.Count;

            var firstPoint = monotonicIncreasingPoints[0];
            var lastPoint  = monotonicDecreasingPoints[monotonicDecreasingPoints.Count - 1];
            List <Vector2WithUV> increasingChunkPoints = new List <Vector2WithUV>();
            List <Vector2WithUV> decreasingChunkPoints = new List <Vector2WithUV>();

            for (int i = 0; i < numInBetweenUParameters; i++)
            {
                UParameterIndexAndMonotonicity uParameterIndexAndMonotonicity = allContourPointUParameters[i];
                ExtrudedContourMonotonicChunk  givenMonotonicChunk            = uParameterIndexAndMonotonicity.IsMonotonicIncreasing ? monotonicIncreasingChunk : monotonicDecreasingChunk;
                ExtrudedContourMonotonicChunk  otherMonotonicChunk            = uParameterIndexAndMonotonicity.IsMonotonicIncreasing ? monotonicDecreasingChunk : monotonicIncreasingChunk;
                Vector2WithUV givenMonotonicChunkPoint = givenMonotonicChunk.Points[uParameterIndexAndMonotonicity.Index];
                Vector2WithUV matchingMonotonicChunkPoint;
                bool          gotMatchingPoint = otherMonotonicChunk.GetClosestPoint(uParameterIndexAndMonotonicity.UParameter, out matchingMonotonicChunkPoint);
                if (gotMatchingPoint)
                {
                    var increasingPoint = uParameterIndexAndMonotonicity.IsMonotonicIncreasing ? givenMonotonicChunkPoint : matchingMonotonicChunkPoint;
                    var decreasingPoint = uParameterIndexAndMonotonicity.IsMonotonicIncreasing ? matchingMonotonicChunkPoint : givenMonotonicChunkPoint;
                    increasingChunkPoints.Add(increasingPoint);
                    decreasingChunkPoints.Add(decreasingPoint);
                }
            }

            //Now remove connected segments pairs that are effectively duplicates of a neighbouring segment
            for (int i = increasingChunkPoints.Count - 1; i > 0; i--)
            {
                var increasingPoint     = increasingChunkPoints[i];
                var decreasingPoint     = increasingChunkPoints[i];
                var prevIncreasingPoint = increasingChunkPoints[i - 1];
                var prevDecreasingPoint = increasingChunkPoints[i - 1];

                bool increasingAreClose = ConnectedSegmentPointsAreClose(prevIncreasingPoint, increasingPoint);
                bool decreasingAreClose = ConnectedSegmentPointsAreClose(prevDecreasingPoint, decreasingPoint);
                if (increasingAreClose && decreasingAreClose)
                {
                    increasingChunkPoints.RemoveAt(i);
                    decreasingChunkPoints.RemoveAt(i);
                }
            }

            return(new SingleContourSegmentwiseCoverage(firstPoint, lastPoint, increasingChunkPoints, decreasingChunkPoints));
        }