public void Crawl(Point startingPoint, Color targetColor, Color newColor)
        {
            if (ColorComparer.AreAlike(targetColor, newColor))
                throw new ArgumentException(nameof(targetColor) + " can't be alike " + nameof(newColor));

            Scanlines.Clear();

            // Initialize the starting point
            if (IsValid(startingPoint.X, startingPoint.Y, targetColor))
                MarkAsInvalid(startingPoint.X, startingPoint.Y, newColor);
            else
                return;

            // Adds the first scanlineData to the stack
            var firstLine = new ScanlineData(left: startingPoint.X,
                right: startingPoint.X,
                y: startingPoint.Y,
                directionTheCrawlerIsGoing: ScanlineData.Direction.None,
                shouldBeExtendedLeft: true,
                shouldBeExtendedRight: true);
            Scanlines.Push(firstLine);

            while (Scanlines.Count > 0)
            {
                var currentLine = Scanlines.Pop();

                if (currentLine.ShouldBeExtendedLeft)
                    currentLine = CrawLeft(currentLine, targetColor, newColor);
                if (currentLine.ShouldBeExtendedRight)
                    currentLine = CrawRight(currentLine, targetColor, newColor);

                // Bitmap's minimum y value is known to be 0
                if (currentLine.Y >= 0)
                    CheckAbove(currentLine, targetColor, newColor);

                //if (CurrentY < MaximumY - 1)
                //    CheckBelow();
            }
        }
        private void CheckAbove(ScanlineData currentData, Color targetColor, Color newColor)
        {
            throw new NotImplementedException();
            /*
            int localHeight = CurrentY - 1;

            var nextData = new ScanlineData(ExtendedLeft, ExtendedLeft, localHeight, ScanlineData.Direction.Up, false, false);

            bool canSkipMiddleOfTheLine = CurrentLine.DirectionTheCrawlerIsGoing == ScanlineData.Direction.Down;
            bool dataIsValid = false;
            bool pushedFirstLine = false;

            // Checking for trivial cases
            if (canSkipMiddleOfTheLine && ExtendedLeft == ExtendedRight)
                return;

            int x = ExtendedLeft;
            int y = localHeight;
            for (int movingX = ExtendedLeft; movingX <= ExtendedRight; movingX++)
            {
                x = movingX;

                if (IsValid(x, y))
                {
                    MarkAsInvalid(x, y);

                    if (!dataIsValid)
                    {
                        dataIsValid = true;
                        nextData.Left = movingX;
                    }
                    nextData.Right = movingX;
                }
                else
                {
                    if (dataIsValid)
                    {
                        if (!pushedFirstLine)
                        {
                            nextData.ShouldBeExtendedLeft = nextData.Left == ExtendedLeft;
                            ranges.Push(nextData);
                            pushedFirstLine = true;
                        }
                        else
                        {
                            ranges.Push(nextData);
                        }

                        dataIsValid = false;
                        nextData = new ScanlineData(movingX, movingX, localHeight, ScanlineData.Direction.Up, false, false);
                    }
                }

                if (movingX == CurrentLine.Left && canSkipMiddleOfTheLine)
                {
                    // Skip previously-checked points
                    if (dataIsValid)
                    {
                        ranges.Push(nextData);
                        //nextData = new ScanlineData(movingX, movingX, localHeight, ScanlineData.Direction.Up, false, false);
                        nextData = new ScanlineData(CurrentLine.Right, CurrentLine.Right, localHeight, ScanlineData.Direction.Up, false, false);
                    }
                    dataIsValid = false;
                    movingX = CurrentLine.Right;
                }
            }

            if (dataIsValid && nextData.Right == ExtendedRight)
            {
                nextData.ShouldBeExtendedLeft = (nextData.Left == ExtendedLeft);
                nextData.ShouldBeExtendedRight = true;
                ranges.Push(nextData);
            }
            */
        }
        private ScanlineData CrawRight(ScanlineData currentData, Color targetColor, Color newColor)
        {
            int x = currentData.Right;
            int maximumX = Bitmap.Width - 1;

            // The idea is to find the biggest x value for the current y
            // that still makes IsValid(...) return true
            while (x <= maximumX)
            {
                x++;
                if (IsValid(x, currentData.Y, targetColor))
                {
                    MarkAsInvalid(x, currentData.Y, newColor);
                }
                else
                {
                    // This means increased x one too many times, oughta undo it and stop trying
                    x--;
                    break;
                }
            }

            var newScanline = new ScanlineData(left: currentData.Left,
                right: x,
                y: currentData.Y,
                directionTheCrawlerIsGoing: currentData.DirectionTheCrawlerIsGoing,
                shouldBeExtendedLeft: currentData.ShouldBeExtendedLeft,
                shouldBeExtendedRight: false);
            return newScanline;
        }
        private ScanlineData CrawLeft(ScanlineData currentData, Color targetColor, Color newColor)
        {
            int x = currentData.Left;

            // Bitmap's minimum x value is known to be 0
            int minimumX = 0;

            // The idea is to find the smallest x value for the current y
            // that still makes IsValid(...) return true
            while (x >= minimumX)
            {
                x--;
                if (IsValid(x, currentData.Y, targetColor))
                {
                    MarkAsInvalid(x, currentData.Y, newColor);
                }
                else
                {
                    // This means decreased x one too many times, oughta undo it and stop trying
                    x++;
                    break;
                }
            }

            var newScanline = new ScanlineData(left: x,
                right: currentData.Right,
                y: currentData.Y,
                directionTheCrawlerIsGoing: currentData.DirectionTheCrawlerIsGoing,
                shouldBeExtendedLeft: false,
                shouldBeExtendedRight: currentData.ShouldBeExtendedRight);
            return newScanline;
        }
示例#5
0
        /// <summary>
        /// Checks the points directly below the current line. MarkAsInvalid the valid ones and, if necessary, creates new ScanLineDatas to be extended.checked.
        /// </summary>
        protected void CheckBelow()
        {
            int localHeight = CurrentY + 1;

            var nextData = new ScanlineData(ExtendedLeft, ExtendedLeft, localHeight, ScanlineData.Direction.Down, false, false);

            bool canSkipMiddleOfTheLine = CurrentLine.DirectionTheCrawlerIsGoing == ScanlineData.Direction.Up;
            bool dataIsValid = false;
            bool pushedFirstLine = false;

            // Checking for trivial cases
            if (canSkipMiddleOfTheLine && ExtendedLeft == ExtendedRight) return;

            int x = ExtendedLeft;
            int y = localHeight;
            for (int movingX = ExtendedLeft; movingX <= ExtendedRight; movingX++)
            {
                x = movingX;

                if (IsValid(x, y))
                {
                    MarkAsInvalid(x, y);

                    if (!dataIsValid)
                    {
                        dataIsValid = true;
                        nextData.Left = movingX;
                    }
                    nextData.Right = movingX;
                }
                else
                {
                    if (dataIsValid)
                    {
                        if (!pushedFirstLine)
                        {
                            nextData.ShouldBeExtendedLeft = nextData.Left == ExtendedLeft;
                            ranges.Push(nextData);
                            pushedFirstLine = true;
                        }
                        else
                        {
                            ranges.Push(nextData);
                        }

                        dataIsValid = false;
                        nextData = new ScanlineData(movingX, movingX, localHeight, ScanlineData.Direction.Down, false, false);
                    }
                }

                if (movingX == CurrentLine.Left && canSkipMiddleOfTheLine)
                {
                    // Skip previously-checked points
                    if (dataIsValid)
                    {
                        ranges.Push(nextData);
                        nextData = new ScanlineData(movingX, movingX, localHeight, ScanlineData.Direction.Down, false, false);
                    }
                    dataIsValid = false;
                    movingX = CurrentLine.Right;
                }
            }

            if (dataIsValid && nextData.Right == ExtendedRight)
            {
                nextData.ShouldBeExtendedLeft = (nextData.Left == ExtendedLeft);
                nextData.ShouldBeExtendedRight = true;
                ranges.Push(nextData);
            }

        }
示例#6
0
        /// <summary>
        /// Starts crawling. The crawler will check all points that are connected to this one and mark them as already visited as it goes.
        /// Stops when there are no more points connected to the initial one.
        /// </summary>
        /// <param name="startingX">Ininitial x coordinate.</param>
        /// <param name="startingY">Ininitial y coordinate.</param>
        /// <param name="minimumX">Minimum including value of x.</param>
        /// <param name="minimumY">Minimum including value of Y.</param>
        /// <param name="maximumX">Maximum non-including value of x.</param>
        /// <param name="maximumY">Maximum non-including value of y.</param>
        protected void Crawl(int startingX, int startingY, int minimumX, int minimumY, int maximumX, int maximumY)
        {
            MinimumY = minimumY;
            MaximumY = maximumY;
            MinimumX = minimumX;
            MaximumX = maximumX;

            PreCrawlMethods();

            if (IsValid(startingX, startingY))
                MarkAsInvalid(startingX, startingY);
            else
                return;

            // "Crawls" the startingPoint
            ranges.Push(new ScanlineData(startingX, startingX, startingY, ScanlineData.Direction.None, true, true));

            while (ranges.Count > 0)
            {
                CurrentLine = ranges.Pop();

                ExtendedLeft = CurrentLine.Left;
                ExtendedRight = CurrentLine.Right;
                CurrentY = CurrentLine.Y;

                if (CurrentLine.ShouldBeExtendedLeft)
                    ExtendLeft();

                if (CurrentLine.ShouldBeExtendedRight)
                    ExtendRight();

                /*(if (currentY > ValidArea.Y)                
                    CheckAbove();
                */
                if (CurrentY > MinimumY)
                    CheckAbove();

                /*if (currentY < ValidArea.Bottom - 1)                
                    CheckBelow();                
                */
                if (CurrentY < MaximumY - 1)
                    CheckBelow();
            }

            PostCrawlMethods();
        }