public void ClippedTriangleGapInIntersections()
        {
            Polygon simplePath = new Polygon(new LinearLineSegment(
                                                 new PointF(10, 10),
                                                 new PointF(200, 150),
                                                 new PointF(50, 300)));

            Polygon hole1 = new Polygon(new LinearLineSegment(
                                            new PointF(37, 85),
                                            new PointF(93, 85),
                                            new PointF(65, 137)));

            IPath clippedPath = simplePath.Clip(hole1);
            IPath outline     = clippedPath.GenerateOutline(5, new[] { 1f });

            PointF[] buffer = new PointF[20];

            PointF start = new PointF(outline.Bounds.Left - 1, 102);
            PointF end   = new PointF(outline.Bounds.Right + 1, 102);

            int matches  = outline.FindIntersections(start, end, buffer, 0);
            int maxIndex = buffer.Select((x, i) => new { x, i }).Where(x => x.x.X > 0).Select(x => x.i).Last();

            Assert.Equal(matches - 1, maxIndex);
        }
Beispiel #2
0
        public void SmallRingAtLargeCoords_HorizontalScansShouldFind4IntersectionPoints(int w, int h, int r, int thickness)
        {
            int cx = w - 2 * r;
            int cy = h - 2 * 3;

            EllipsePolygon ellipse = new EllipsePolygon(cx, cy, r);
            IPath          path    = ellipse.GenerateOutline(thickness);

            int yMin = cy - r + thickness + 1;
            int yMax = cy + r - thickness;

            PointF[] buffer = new PointF[16];

            List <int> badPositions = new List <int>();

            for (int y = yMin; y < yMax; y++)
            {
                PointF start = new PointF(-1, y);
                PointF end   = new PointF(w + 1, y);

                int intersectionCount = path.FindIntersections(start, end, buffer);
                if (intersectionCount != 4)
                {
                    badPositions.Add(y);
                }
            }

            if (badPositions.Any())
            {
                string badPoz = string.Join(',', badPositions);
                this.Output.WriteLine($"BAD: {badPositions.Count} of {yMax - yMin}: {badPoz}");

                Assert.True(false);
            }
        }
        public int ScanY(IPath shape, int y, float[] buffer, int length, int offset)
        {
            PointF start = new PointF(shape.Bounds.Left - 1, y);
            PointF end   = new PointF(shape.Bounds.Right + 1, y);

            PointF[] innerbuffer = ArrayPool <PointF> .Shared.Rent(length);

            Span <PointF> span = new Span <PointF>(innerbuffer);

            try
            {
                int count = shape.FindIntersections(start, end, span);

                for (int i = 0; i < count; i++)
                {
                    buffer[i + offset] = innerbuffer[i].X;
                }

                return(count);
            }
            finally
            {
                ArrayPool <PointF> .Shared.Return(innerbuffer);
            }
        }
        public void SpecificMisses(string name, int yScanLine)
        {
            IPath polygon = ShapesData[name];

            int intersections = polygon.FindIntersections(new Vector2(polygon.Bounds.Left - 1, yScanLine), new Vector2(polygon.Bounds.Right + 1, yScanLine)).Count();

            Assert.True(intersections % 2 == 0, $"crosssection of '{name}' at '{yScanLine}' produced {intersections} intersections");
        }
        public void ShapeMissingEdgeHits(string name)
        {
            IPath polygon = ShapesData[name];
            int   top     = (int)Math.Ceiling(polygon.Bounds.Top);
            int   bottom  = (int)Math.Floor(polygon.Bounds.Bottom);

            for (int y = top; y <= bottom; y++)
            {
                IEnumerable <PointF> intersections = polygon.FindIntersections(new Vector2(polygon.Bounds.Left - 1, y), new Vector2(polygon.Bounds.Right + 1, y));
                if (intersections.Count() % 2 != 0)
                {
                    Assert.True(false, $"crosssection of '{name}' at '{y}' produced {intersections.Count()} number of intersections");
                }
            }
        }
Beispiel #6
0
        /// <summary>
        /// Finds the intersections.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="start">The start.</param>
        /// <param name="end">The end.</param>
        /// <returns>
        /// The points along the line the intersect with the boundaries of the polygon.
        /// </returns>
        public static IEnumerable <Vector2> FindIntersections(this IPath path, Vector2 start, Vector2 end)
        {
            var buffer = ArrayPool <Vector2> .Shared.Rent(path.MaxIntersections);

            try
            {
                var hits    = path.FindIntersections(start, end, buffer, path.MaxIntersections, 0);
                var results = new Vector2[hits];
                for (var i = 0; i < hits; i++)
                {
                    results[i] = buffer[i];
                }

                return(results);
            }
            finally
            {
                ArrayPool <Vector2> .Shared.Return(buffer);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Finds the intersections.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="start">The start.</param>
        /// <param name="end">The end.</param>
        /// <returns>
        /// The points along the line the intersect with the boundaries of the polygon.
        /// </returns>
        public static IEnumerable <PointF> FindIntersections(this IPath path, PointF start, PointF end)
        {
            PointF[] buffer = ArrayPool <PointF> .Shared.Rent(path.MaxIntersections);

            try
            {
                int      hits    = path.FindIntersections(start, end, buffer, 0);
                PointF[] results = new PointF[hits];
                for (int i = 0; i < hits; i++)
                {
                    results[i] = buffer[i];
                }

                return(results);
            }
            finally
            {
                ArrayPool <PointF> .Shared.Return(buffer);
            }
        }
Beispiel #8
0
        public void SmallRingAtLargeCoords_HorizontalScansShouldFind4IntersectionPoints(int w, int h, int r, int thickness)
        {
            int cx = w - (2 * r);
            int cy = h - (2 * 3);

            var   ellipse = new EllipsePolygon(cx, cy, r);
            IPath path    = ellipse.GenerateOutline(thickness);

            int yMin = cy - r + thickness + 1;
            int yMax = cy + r - thickness;

            var buffer = new PointF[16];

            var badPositions = new List <int>();

            for (int y = yMin; y < yMax; y++)
            {
                var start = new PointF(-1, y);
                var end   = new PointF(w + 1, y);

                int intersectionCount = path.FindIntersections(start, end, buffer);
                if (intersectionCount != 4)
                {
                    badPositions.Add(y);
                }
            }

            if (badPositions.Count > 0)
            {
                // The char overload is causing mysterious build failures in Visual Studio
                string badPoz = string.Join(",", badPositions);
                this.Output.WriteLine($"BAD: {badPositions.Count} of {yMax - yMin}: {badPoz}");

                Assert.True(false);
            }
        }
Beispiel #9
0
            private Buffer2D <float> Render(IPath path)
            {
                Size size = Rectangle.Ceiling(path.Bounds).Size;

                size = new Size(size.Width + (this.offset * 2), size.Height + (this.offset * 2));

                float subpixelCount = 4;
                float offset        = 0.5f;

                if (this.Options.Antialias)
                {
                    offset        = 0f; // we are antialising skip offsetting as real antalising should take care of offset.
                    subpixelCount = this.Options.AntialiasSubpixelDepth;
                    if (subpixelCount < 4)
                    {
                        subpixelCount = 4;
                    }
                }

                // take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it.
                Buffer2D <float> fullBuffer = this.MemoryAllocator.Allocate2D <float>(size.Width + 1, size.Height + 1, true);

                using (IBuffer <float> bufferBacking = this.MemoryAllocator.Allocate <float>(path.MaxIntersections))
                    using (IBuffer <PointF> rowIntersectionBuffer = this.MemoryAllocator.Allocate <PointF>(size.Width))
                    {
                        float subpixelFraction      = 1f / subpixelCount;
                        float subpixelFractionPoint = subpixelFraction / subpixelCount;

                        for (int y = 0; y <= size.Height; y++)
                        {
                            Span <float> scanline      = fullBuffer.GetRowSpan(y);
                            bool         scanlineDirty = false;
                            float        yPlusOne      = y + 1;

                            for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
                            {
                                var           start            = new PointF(path.Bounds.Left - 1, subPixel);
                                var           end              = new PointF(path.Bounds.Right + 1, subPixel);
                                Span <PointF> intersectionSpan = rowIntersectionBuffer.GetSpan();
                                Span <float>  buffer           = bufferBacking.GetSpan();
                                int           pointsFound      = path.FindIntersections(start, end, intersectionSpan);

                                if (pointsFound == 0)
                                {
                                    // nothing on this line skip
                                    continue;
                                }

                                for (int i = 0; i < pointsFound && i < intersectionSpan.Length; i++)
                                {
                                    buffer[i] = intersectionSpan[i].X;
                                }

                                QuickSort.Sort(buffer.Slice(0, pointsFound));

                                for (int point = 0; point < pointsFound; point += 2)
                                {
                                    // points will be paired up
                                    float scanStart = buffer[point];
                                    float scanEnd   = buffer[point + 1];
                                    int   startX    = (int)MathF.Floor(scanStart + offset);
                                    int   endX      = (int)MathF.Floor(scanEnd + offset);

                                    if (startX >= 0 && startX < scanline.Length)
                                    {
                                        for (float x = scanStart; x < startX + 1; x += subpixelFraction)
                                        {
                                            scanline[startX] += subpixelFractionPoint;
                                            scanlineDirty     = true;
                                        }
                                    }

                                    if (endX >= 0 && endX < scanline.Length)
                                    {
                                        for (float x = endX; x < scanEnd; x += subpixelFraction)
                                        {
                                            scanline[endX] += subpixelFractionPoint;
                                            scanlineDirty   = true;
                                        }
                                    }

                                    int nextX = startX + 1;
                                    endX  = Math.Min(endX, scanline.Length); // reduce to end to the right edge
                                    nextX = Math.Max(nextX, 0);
                                    for (int x = nextX; x < endX; x++)
                                    {
                                        scanline[x]  += subpixelFraction;
                                        scanlineDirty = true;
                                    }
                                }
                            }

                            if (scanlineDirty)
                            {
                                if (!this.Options.Antialias)
                                {
                                    for (int x = 0; x < size.Width; x++)
                                    {
                                        if (scanline[x] >= 0.5)
                                        {
                                            scanline[x] = 1;
                                        }
                                        else
                                        {
                                            scanline[x] = 0;
                                        }
                                    }
                                }
                            }
                        }
                    }

                return(fullBuffer);
            }