コード例 #1
0
    public FilledRegion Apply(FillData data)
    {
        //Get the space between each shell. In most cases it should be 1.
        //In the case of a very large room, it could be 2.
        //Played around with a graphing calculator to get a good function that reflects this.
        int    minSpace = 1, maxSpace = 2;
        double coefficient        = Math.Sqrt(maxSpace - minSpace) / (data.BeingFilled.Area - MinArea);
        int    spaceBetweenShells = (int)Math.Round(Math.Pow(coefficient * (data.BeingFilled.Area - MinArea), 2.0) + 1.0, 0);

        //Make sure my function is valid.
        if (spaceBetweenShells < 1 || spaceBetweenShells > 2)
        {
            throw new InvalidOperationException("Oops!");
        }

        //Continuously fill in smaller and smaller shells centered around the region center.
        Region shell   = new Region(data.BeingFilled.TopLeft.Right.Below, data.BeingFilled.BottomRight.Left.Above, true);
        sbyte  holeDir = 1;

        //Smallest-allowable shell is 3x3, which means a region of width/height 2.
        while (shell.Area > 4)
        {
            //Fill in the perimeter.
            data.FillPerimeter(true, shell);

            //Clear the hole.
            if (holeDir < 0)
            {
                data.SetMapAt(shell.LeftMid, false);
            }
            else
            {
                data.SetMapAt(shell.RightMid, false);
            }

            //Flip the side the next hole will be on.
            holeDir *= -1;

            //Shrink the shell.
            for (int i = 0; i < spaceBetweenShells; ++i)
            {
                shell = new Region(shell.TopLeft.Right.Below, shell.BottomRight.Left.Above, false);
            }
        }

        return(new ConcentricSquaresRegion(data.BeingFilled, new Region(shell.TopLeft.Left.Above, shell.BottomRight.Right.Below)));
    }
コード例 #2
0
    public FilledRegion Apply(FillData data)
    {
        Region clearArea = new Region(data.BeingFilled.Center.Left.Above, data.BeingFilled.Center.Right.Below);

        //Fill the inner ring.
        //Move from each corner of the X to the center.
        Location counter;
        Location center = data.BeingFilled.Center;
        bool     moveHorizontally;
        bool     horizontalBias = data.BeingFilled.Width > data.BeingFilled.Height;

        //Fill in the center.
        data.FillRegion(true, new Region(clearArea.TopLeft.Above.Left, clearArea.BottomRight.Below.Right));
        for (int i = 0; i < 4; ++i)
        {
            //Get the point to start from.
            switch (i)
            {
            case 0:
                counter = data.BeingFilled.TopLeft.Right.Below;
                data.SetMapAt(counter, false);
                break;

            case 1:
                counter = data.BeingFilled.TopRight.Left.Below;
                data.SetMapAt(counter, false);
                break;

            case 2:
                counter = data.BeingFilled.BottomLeft.Right.Above;
                data.SetMapAt(counter, false);
                break;

            case 3:
                counter = data.BeingFilled.BottomRight.Left.Above;
                data.SetMapAt(counter, false);
                break;

            default: throw new InvalidOperationException();
            }

            //Clear a path to the center.
            while (!clearArea.Touches(counter, true, true, true))
            {
                //Get which direction to move in.
                float relativeDistX = Math.Abs(counter.X - center.X) / (float)data.BeingFilled.Width;
                float relativeDistY = Math.Abs(counter.Y - center.Y) / (float)data.BeingFilled.Height;
                if (relativeDistX > relativeDistY)
                {
                    moveHorizontally = true;
                }
                else if (relativeDistX < relativeDistY)
                {
                    moveHorizontally = false;
                }
                else
                {
                    moveHorizontally = horizontalBias;
                }

                //Move that direction, add the region, and fill part of the X after moving.
                if (moveHorizontally)
                {
                    int amount = Math.Sign(center.X - counter.X);

                    counter.X += amount;
                    data.SetMapAt(counter, false);

                    data.SetMapAt(new Location(counter.X + amount, counter.Y), true);
                    if (counter.Y > 1 && counter.Y < data.BeingFilled.Bottom - 1)
                    {
                        data.SetMapAt(new Location(counter.X, counter.Y + Math.Sign(counter.Y - center.Y)), true);
                    }
                }
                else
                {
                    int amount = Math.Sign(center.Y - counter.Y);

                    counter.Y += amount;
                    data.SetMapAt(counter, false);

                    data.SetMapAt(new Location(counter.X, counter.Y + amount), true);
                    if (counter.X > 1 && counter.X < data.BeingFilled.Right - 1)
                    {
                        data.SetMapAt(new Location(counter.X + Math.Sign(counter.X - center.X), counter.Y), true);
                    }
                }
            }

            //Keep the center clear.
            data.FillRegion(false, clearArea);
        }

        //Just to be safe, clear the perimeter at the end.
        data.FillPerimeter(false, data.BeingFilled);

        return(new XRegion(data.BeingFilled, data.Map));
    }