示例#1
0
        public void KeyValueSort(float[] keys)
        {
            int[] values = keys.Select(k => (int)(k * 1000)).ToArray();

            SortUtility.Sort(keys, values.AsSpan());
            VerifySorted(keys, values);
        }
示例#2
0
        public void Sort(float[] data)
        {
            float[] expected = data.ToArray();

            Array.Sort(expected);

            SortUtility.Sort(data);

            Assert.Equal(expected, data);
        }
示例#3
0
        public void SortSlice()
        {
            float[] data = { 3, 2, 1, 0, -1 };

            Span <float> slice = data.AsSpan(1, 3);

            SortUtility.Sort(slice);
            float[] actual   = slice.ToArray();
            float[] expected = { 0, 1, 2 };

            Assert.Equal(actual, expected);
        }
        private static IEnumerable Sort(IEnumerable collection, string sortExpression)
        {
            string propertyName = sortExpression;
            bool   reverse      = false;

            if (propertyName.EndsWith("DESC"))
            {
                reverse      = true;
                propertyName = propertyName.Substring(0, propertyName.Length - 5);
            }
            return(SortUtility.Sort(collection, propertyName, reverse));
        }
示例#5
0
        /// <inheritdoc />
        public int FindIntersections(PointF start, PointF end, Span <PointF> buffer, IntersectionRule intersectionRule)
        {
            this.EnsureInternalPathsInitalized();

            int totalAdded = 0;

            InternalPath.PointOrientation[] orientations = ArrayPool <InternalPath.PointOrientation> .Shared.Rent(buffer.Length); // the largest number of intersections of any sub path of the set is the max size with need for this buffer.

            Span <InternalPath.PointOrientation> orientationsSpan = orientations;

            try
            {
                foreach (var ip in this.internalPaths)
                {
                    Span <PointF> subBuffer = buffer.Slice(totalAdded);
                    Span <InternalPath.PointOrientation> subOrientationsSpan = orientationsSpan.Slice(totalAdded);

                    var position = ip.FindIntersectionsWithOrientation(start, end, subBuffer, subOrientationsSpan);
                    totalAdded += position;
                }

                Span <float> distances = stackalloc float[totalAdded];
                for (int i = 0; i < totalAdded; i++)
                {
                    distances[i] = Vector2.DistanceSquared(start, buffer[i]);
                }

                var activeBuffer           = buffer.Slice(0, totalAdded);
                var activeOrientationsSpan = orientationsSpan.Slice(0, totalAdded);
                SortUtility.Sort(distances, activeBuffer, activeOrientationsSpan);

                if (intersectionRule == IntersectionRule.Nonzero)
                {
                    totalAdded = InternalPath.ApplyNonZeroIntersectionRules(activeBuffer, activeOrientationsSpan);
                }
            }
            finally
            {
                ArrayPool <InternalPath.PointOrientation> .Shared.Return(orientations);
            }

            return(totalAdded);
        }
        /// <summary>
        /// Based on a line described by <paramref name="start" /> and <paramref name="end" />
        /// populates a buffer for all points on the path that the line intersects.
        /// </summary>
        /// <param name="start">The start.</param>
        /// <param name="end">The end.</param>
        /// <param name="buffer">The buffer.</param>
        /// <param name="orientationsSpan">The buffer for storeing the orientation of each intersection.</param>
        /// <returns>number of intersections hit</returns>
        public int FindIntersectionsWithOrientation(PointF start, PointF end, Span <PointF> buffer, Span <PointOrientation> orientationsSpan)
        {
            if (this.points.Length < 2)
            {
                return(0);
            }

            int count = buffer.Length;

            this.ClampPoints(ref start, ref end);

            var target = new Segment(start, end);

            int polyCorners = this.points.Length;

            if (!this.closedPath)
            {
                polyCorners -= 1;
            }

            int     position  = 0;
            Vector2 lastPoint = MaxVector;

            PassPointData[] precaclulate = ArrayPool <PassPointData> .Shared.Rent(this.points.Length);

            Span <PassPointData> precaclulateSpan = precaclulate.AsSpan(0, this.points.Length);

            try
            {
                // pre calculate relative orientations X places ahead and behind
                Vector2          startToEnd           = end - start;
                PointOrientation prevOrientation      = CalulateOrientation(startToEnd, this.points[polyCorners - 1].Point - end);
                PointOrientation nextOrientation      = CalulateOrientation(startToEnd, this.points[0].Point - end);
                PointOrientation nextPlus1Orientation = CalulateOrientation(startToEnd, this.points[1].Point - end);

                // iterate over all points and precalculate data about each, pre cacluating it relative orientation
                for (int i = 0; i < polyCorners && count > 0; i++)
                {
                    ref Segment edge = ref this.points[i].Segment;

                    // shift all orientations along but one place and fill in the last one
                    PointOrientation pointOrientation = nextOrientation;
                    nextOrientation      = nextPlus1Orientation;
                    nextPlus1Orientation = CalulateOrientation(startToEnd, this.points[WrapArrayIndex(i + 2, this.points.Length)].Point - end);

                    // should this point cause the last matched point to be excluded
                    bool removeLastIntersection = nextOrientation == PointOrientation.Colinear &&
                                                  pointOrientation == PointOrientation.Colinear &&
                                                  nextPlus1Orientation != prevOrientation &&
                                                  (this.closedPath || i > 0) &&
                                                  (IsOnSegment(target, edge.Start) || IsOnSegment(target, edge.End));

                    // is there any chance the segments will intersection (do their bounding boxes touch)
                    bool doIntersect = false;
                    if (pointOrientation == PointOrientation.Colinear || pointOrientation != nextOrientation)
                    {
                        doIntersect = (edge.Min.X - Epsilon) <= target.Max.X &&
                                      (edge.Max.X + Epsilon) >= target.Min.X &&
                                      (edge.Min.Y - Epsilon) <= target.Max.Y &&
                                      (edge.Max.Y + Epsilon) >= target.Min.Y;
                    }

                    precaclulateSpan[i] = new PassPointData
                    {
                        RemoveLastIntersectionAndSkip = removeLastIntersection,
                        RelativeOrientation           = pointOrientation,
                        DoIntersect = doIntersect
                    };

                    prevOrientation = pointOrientation;
                }

                // seed the last point for deduping at begining of closed line
                if (this.closedPath)
                {
                    int prev = polyCorners - 1;

                    if (precaclulateSpan[prev].DoIntersect)
                    {
                        lastPoint = FindIntersection(this.points[prev].Segment, target);
                    }
                }

                for (int i = 0; i < polyCorners && count > 0; i++)
                {
                    int next = WrapArrayIndex(i + 1, this.points.Length);

                    if (precaclulateSpan[i].RemoveLastIntersectionAndSkip)
                    {
                        if (position > 0)
                        {
                            position--;
                            count++;
                        }

                        continue;
                    }

                    if (precaclulateSpan[i].DoIntersect)
                    {
                        Vector2 point = FindIntersection(this.points[i].Segment, target);
                        if (point != MaxVector)
                        {
                            if (lastPoint.Equivalent(point, Epsilon2))
                            {
                                lastPoint = MaxVector;

                                int last = WrapArrayIndex(i - 1 + polyCorners, polyCorners);

                                // hit the same point a second time do we need to remove the old one if just clipping
                                if (this.points[next].Point.Equivalent(point, Epsilon))
                                {
                                    next = i;
                                }

                                if (this.points[last].Point.Equivalent(point, Epsilon))
                                {
                                    last = i;
                                }

                                PointOrientation side  = precaclulateSpan[next].RelativeOrientation;
                                PointOrientation side2 = precaclulateSpan[last].RelativeOrientation;

                                if (side != side2)
                                {
                                    // differnet side we skip adding as we are passing through it
                                    continue;
                                }
                            }

                            // only need to track this during odd non zero rulings
                            orientationsSpan[position] = precaclulateSpan[i].RelativeOrientation;
                            buffer[position]           = point;
                            position++;
                            count--;
                        }

                        lastPoint = point;
                    }
                    else
                    {
                        lastPoint = MaxVector;
                    }
                }

                Vector2      startVector = start;
                Span <float> distances   = stackalloc float[position];
                for (int i = 0; i < position; i++)
                {
                    distances[i] = Vector2.DistanceSquared(startVector, buffer[i]);
                }

                var activeBuffer           = buffer.Slice(0, position);
                var activeOrientationsSpan = orientationsSpan.Slice(0, position);
                SortUtility.Sort(distances, activeBuffer, activeOrientationsSpan);

                return(position);
            }