private static float MeasureClearance(out bool skip, Ray2 sideLine, Vector2 point, LineSegment2 edgeSeg, Vector2 edgeDir)
        {
            var startSegPoint = edgeSeg.ClosestPoint(point);
            var sidePoint     = new Ray2(startSegPoint, edgeDir.Perpendicular()).Intersects(sideLine);

            if (!sidePoint.HasValue)
            {
                skip = true;
                return(0);
            }

            skip = false;
            return(sidePoint.Value.DistanceAlongA);
        }
        public static IEnumerable <Section> Sections(this IReadOnlyList <Vector2> outer, float width, out Vector2[] innerArr, out IReadOnlyList <IReadOnlyList <Vector2> > corners)
        {
            Contract.Requires(outer != null);
            Contract.Requires(width > 0);
            Contract.Ensures(Contract.Result <IEnumerable <Section> >() != null);

            innerArr = outer.Shrink(width, 1).ToArray();

            //Sanity check if shrinking has deleted the room!
            if (innerArr.Length == 0)
            {
                corners = new IReadOnlyList <Vector2> [0];
                return(Array.Empty <Section>());
            }

            //Create a place to put the results
            var results = new List <Section>(innerArr.Length * 2);

            //loop over segments of inner array
            //inner array length is always <= outer array length
            for (var i = 0; i < innerArr.Length; i++)
            {
                var a            = innerArr[i];
                var b            = innerArr[(i + 1) % innerArr.Length];
                var innerSegment = new LineSegment2(a, b);

                //find a parallel segment which we can project the inner segment onto completely
                float aT;
                float bT;
                var   outerSegmentIndex = FindOuterSegment(innerSegment, width, outer, out aT, out bT);

                if (outerSegmentIndex == -1)
                {
                    continue;
                }

                var outerSegment = new LineSegment2(outer[outerSegmentIndex], outer[(outerSegmentIndex + 1) % outer.Count]);

                //Clamp into the valid range
                var adjustedAT = aT.Clamp(0, 1);
                var adjustedBT = bT.Clamp(0, 1);

                //Calculate the locations of the adjusted points
                var aP = outerSegment.LongLine.PointAlongLine(adjustedAT);
                var bP = outerSegment.LongLine.PointAlongLine(adjustedBT);

                //Now adjust the inner points to match the adjusted outer points
                var innerStart = innerSegment.Start;
                if (Math.Abs(adjustedAT - aT) > float.Epsilon)
                {
                    innerStart = innerSegment.ClosestPoint(aP);
                }

                var innerEnd = innerSegment.End;
                if (Math.Abs(adjustedBT - bT) > float.Epsilon)
                {
                    innerEnd = innerSegment.ClosestPoint(bP);
                }

                results.Add(new Section(innerEnd, innerStart, aP, bP));
            }

            //Calculate corner sections
            corners = CalculateCorners(outer, width, results);

            return(results);
        }