Example #1
0
        /// <summary>
        /// http://alienryderflex.com/polygon_fill/
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="polygon"></param>
        /// <param name="fillVolume"></param>
        /// <param name="dimX"></param>
        /// <param name="dimY"></param>
        /// <param name="dimZ"></param>
        /// <param name="sliceZ"></param>
        /// <param name="fillValue"></param>
        /// <returns></returns>
        private static VoxelCounts FillPolygonAndCount(
            PointF[] polygon,
            ushort[] fillVolume,
            ushort fillValue,
            Volume2D <byte> countVolume,
            byte foregroundId)
        {
            var         bounds            = GetBoundingBox(polygon);
            const float epsilon           = 0.01f;
            var         length            = polygon.Length;
            var         nodeIntersections = new IntersectionXPoint[length * 2];
            var         nodeX             = new float[length];
            var         polygonX          = new float[length];
            var         polygonY          = new float[length];

            for (var index = 0; index < length; index++)
            {
                var point = polygon[index];
                polygonX[index] = point.X;
                polygonY[index] = point.Y;
            }

            var voxelCounts = new VoxelCounts();

            // Loop through the rows of the image.
            for (int y = 0; y < countVolume.DimY; y++)
            {
                float yPlusEpsilon  = y + epsilon;
                float yMinusEpsilon = y - epsilon;

                if ((yPlusEpsilon < bounds.Top && yMinusEpsilon < bounds.Top) ||
                    (yPlusEpsilon > bounds.Bottom && yMinusEpsilon > bounds.Bottom))
                {
                    continue;
                }

                // Build a list of nodes, sorted
                int nodesBoth = FindIntersections(polygonX, polygonY, nodeIntersections, y, yPlusEpsilon, yMinusEpsilon);

                // Merge
                int nodes = MergeIntersections(nodeIntersections, nodeX, nodesBoth);

                // Fill the pixels between node pairs.
                voxelCounts += FillNodePairsAndCount(
                    fillVolume,
                    fillValue,
                    epsilon,
                    nodeX,
                    y,
                    nodes,
                    countVolume,
                    foregroundId);
            }

            return(voxelCounts);
        }
Example #2
0
        /// <summary>
        /// Fills all points that fall inside of a given polygon, and at the same time,
        /// aggregate statistics on what values are present at the filled pixel
        /// positions in a "count volume" that has the same size as the fill volume.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="U"></typeparam>
        /// <param name="polygon"></param>
        /// <param name="fillVolume"></param>
        /// <param name="dimX"></param>
        /// <param name="dimY"></param>
        /// <param name="dimZ"></param>
        /// <param name="sliceZ"></param>
        /// <param name="fillValue"></param>
        /// <param name="countVolume"></param>
        /// <param name="foregroundId"></param>
        /// <returns></returns>
        public static VoxelCounts FillPolygonAndCount(
            PointInt[] polygon,
            ushort[] fillVolume,
            ushort fillValue,
            Volume2D <byte> countVolume,
            byte foregroundId)
        {
            polygon     = polygon ?? throw new ArgumentNullException(nameof(polygon));
            fillVolume  = fillVolume ?? throw new ArgumentNullException(nameof(fillVolume));
            countVolume = countVolume ?? throw new ArgumentNullException(nameof(countVolume));

            if (polygon.Length == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(polygon), "The polygon does not contain any points.");
            }

            if (fillVolume.Length != countVolume.Length)
            {
                throw new ArgumentException("The fill and the count volume must have the same size.", nameof(fillVolume));
            }

            var  pointsAsFloat   = polygon.Select(point => new PointF(point.X, point.Y)).ToArray();
            uint foregroundCount = 0;
            uint otherCount      = 0;
            var  countArray      = countVolume.Array;
            var  dimX            = countVolume.DimX;

            foreach (var point in polygon)
            {
                // Manually computing index, rather than relying on GetIndex, brings substantial speedup.
                var index = point.X + dimX * point.Y;
                if (fillVolume[index] != fillValue)
                {
                    fillVolume[index] = fillValue;
                    if (countArray[index] == foregroundId)
                    {
                        foregroundCount++;
                    }
                    else
                    {
                        otherCount++;
                    }
                }
            }

            var voxelCountsAtPoints = new VoxelCounts(foregroundCount, otherCount);
            var voxelCountsInside   = FillPolygonAndCount(
                pointsAsFloat,
                fillVolume,
                fillValue,
                countVolume,
                foregroundId);

            return(voxelCountsAtPoints + voxelCountsInside);
        }
Example #3
0
 /// <summary>
 /// Creates a new instance of the class.
 /// </summary>
 /// <param name="points"></param>
 /// <param name="voxelCounts"></param>
 /// <param name="insideOfPolygon"></param>
 /// <param name="isBackground"></param>
 /// <param name="startPointMinimumY"></param>
 public PolygonPoints(
     PointInt[] points,
     VoxelCounts voxelCounts,
     ushort insideOfPolygon,
     bool isInside,
     PointInt startPointMinimumY)
 {
     Points             = points ?? throw new ArgumentNullException(nameof(points));
     VoxelCounts        = voxelCounts ?? throw new ArgumentNullException(nameof(voxelCounts));
     InsideOfPolygon    = insideOfPolygon;
     IsInnerContour     = isInside;
     StartPointMinimumY = startPointMinimumY;
 }