Пример #1
0
        private static void Apply(ExplicitOutlineShape target, TileGridElement tile, int xRight, int yTop, bool allLocations)
        {
            // Determine location of the center tile.
            int x = xRight;
            int y = yTop;

            // Determine bounding box of the center tile.
            Rectangle bbox = tile.BoundingBox;

            bbox.X += x;
            bbox.Y += y;

            // Move tile location to the left/top so that the bounding box is just inside of the shape.
            int i = bbox.Right / tile.Width;
            int j = bbox.Bottom / tile.Height;
            int k = (i + j) % 2;

            x      -= i * tile.Width;
            y      -= j * tile.Height;
            bbox.X -= i * tile.Width;
            bbox.Y -= j * tile.Height;

            // Apply the tile in all locations where the bounding box is still inside of the shape.
            for (i = 0; bbox.Left + i * tile.Width < target.XSize; i++)
            {
                for (j = 0; bbox.Top + j * tile.Height < target.YSize; j++)
                {
                    if (allLocations || (i + j + k) % 2 == 0)
                    {
                        tile.Apply(target, x + i * tile.Width, y + j * tile.Height);
                    }
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Apply the tile element in a repeating grid on the whole target shape.
        /// One tile (which will be inverted if invertEveryOtherTile is true) will be placed at the given location.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="xLeft"></param>
        /// <param name="yTop"></param>
        public override void Apply(ExplicitOutlineShape target, int xLeft, int yTop)
        {
            Apply(target, tile, xLeft, yTop, true);

            if (invertEveryOtherTile)
            {
                Apply(target, white, xLeft, yTop, false);
            }
        }
Пример #3
0
        /// <summary>
        /// Create an outline shape from the given character and font family.
        /// </summary>
        /// <param name="xSize">width of the created shape</param>
        /// <param name="ySize">height of the created shape</param>
        /// <param name="centerX">X coordinate, relative to total width; 0.0 = top, 1.0 = bottom</param>
        /// <param name="centerY">Y coordinate, relative to total height; 0.0 = left, 1.0 = right</param>
        /// <param name="shapeSize">size, relative to distance of center from the border; 1.0 will touch the border</param>
        /// <param name="ch"></param>
        /// <param name="fontFamily"></param>
        /// <returns></returns>
        internal static OutlineShape Char(int xSize, int ySize, double centerX, double centerY, double shapeSize, char ch, FontFamily fontFamily)
        {
            ExplicitOutlineShape result = new ExplicitOutlineShape(xSize, ySize);

            double xc, yc, sz;

            ConvertParameters(xSize, ySize, centerX, centerY, shapeSize, out xc, out yc, out sz);
            sz *= 2; // sz is not used as a radius but as the character height

            #region Draw the given character into an image (white on black).

            StringFormat stringFormat = new StringFormat();
            stringFormat.Alignment     = StringAlignment.Center;
            stringFormat.LineAlignment = StringAlignment.Center;

            int      enlargement = 3;
            int      imgXSize = enlargement * xSize, imgYSize = enlargement * ySize;
            Bitmap   img  = new Bitmap(imgXSize, imgYSize);
            Graphics g    = Graphics.FromImage(img);
            Font     font = new Font(fontFamily, (float)(enlargement * sz), FontStyle.Bold);
            g.DrawRectangle(Pens.Black, 0, 0, imgXSize, imgXSize);
            g.DrawString(new string(ch, 1), font, Brushes.White, new RectangleF(0, 0, imgXSize, (int)(1.20 * imgYSize)), stringFormat);

            #endregion

            #region Scale the image so that the covered area is of the requested size.

            int imgXCenter, imgYCenter;
            ScaleImage(ref img, sz, out imgXCenter, out imgYCenter);

            int imgXOffset = imgXCenter - (int)xc;
            int imgYOffset = imgYCenter - (int)yc;

            #endregion

            for (int x = 0; x < xSize; x++)
            {
                for (int y = 0; y < ySize; y++)
                {
                    int imgX = x + imgXOffset, imgY = y + imgYOffset;

                    if (imgX < 0 || imgX >= img.Width || imgY < 0 || imgY >= img.Height)
                    {
                        // result.SetValue(x, y, false);
                    }
                    else if (img.GetPixel(imgX, imgY).GetBrightness() > 0.5)
                    {
                        result.SetValue(x, y, true);
                    }
                }
            }
            return(result);
        }
Пример #4
0
        /// <summary>
        /// Create an outline shape.
        /// </summary>
        /// <param name="r">a source of random numbers</param>
        /// <param name="xSize">width of the created shape</param>
        /// <param name="ySize">height of the created shape</param>
        /// <param name="centerX">X coordinate, relative to total width; 0.0 = top, 1.0 = bottom</param>
        /// <param name="centerY">Y coordinate, relative to total height; 0.0 = left, 1.0 = right</param>
        /// <param name="shapeSize">size, relative to distance of center from the border; 1.0 will touch the border</param>
        /// <returns></returns>
        public static OutlineShape Character(Random r, int xSize, int ySize, double centerX, double centerY, double shapeSize)
        {
            FontFamily fontFamily = new FontFamily("Helvetica");

            char[] shapeCharacters =
            {
                'C', 'O', 'S', 'V', 'X',            // no vertical or horizontal lines
                '3', '6', '8', '9', '?',            // no vertical or horizontal lines
                'K', 'R', 'Z', 'A', 'G',            // some vertical or horizontal lines
            };
            char ch = shapeCharacters[r.Next(shapeCharacters.Length)];

            return(ExplicitOutlineShape.Char(xSize, ySize, centerX, centerY, shapeSize, ch, fontFamily));
        }
Пример #5
0
        /// <summary>
        /// The current GridElement is applied to the given target.
        /// Every set square is inverted.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="xLeft"></param>
        /// <param name="yTop"></param>
        public override void Apply(ExplicitOutlineShape target, int xLeft, int yTop)
        {
            Rectangle bbox = this.BoundingBox;

            for (int x = bbox.Left; x < bbox.Right; x++)
            {
                for (int y = bbox.Top; y < bbox.Bottom; y++)
                {
                    if (this[x, y] == true)
                    {
                        this.Invert(target, x + xLeft, y + yTop);
                    }
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="xSize">The overall shape size.</param>
        /// <param name="ySize">The overall shape size.</param>
        /// <param name="tile">A shape that will be used as the repeating tile pattern.</param>
        private TilesOutlineShape(int xSize, int ySize, ExplicitOutlineShape tile)
            : base(xSize, ySize)
        {
            this.tile         = tile;
            this.xRepetitions = new int[tile.XSize];
            this.yRepetitions = new int[tile.YSize];

            for (int i = 0; i < xRepetitions.Length; i++)
            {
                xRepetitions[i] = 1;
            }
            for (int i = 0; i < yRepetitions.Length; i++)
            {
                yRepetitions[i] = 1;
            }

            UpdateTileSize();
        }
Пример #7
0
        /// <summary>
        /// Builds a pattern from the given bitmap, rotated and scaled.
        /// </summary>
        /// <param name="xSize"></param>
        /// <param name="ySize"></param>
        /// <param name="bitmap"></param>
        /// <param name="rft"></param>
        /// <param name="scale"></param>
        /// <returns></returns>
        private static OutlineShape FromBitmap(int xSize, int ySize, Bitmap bitmap, RotateFlipType rft, int scale)
        {
#if false
            System.Console.Out.WriteLine("[TilesOutlineShape.FromBitmap] " + rft.ToString() + ", x" + scale.ToString());
#endif

#if false
            // Note: Some bitmaps are useless (all black or all white) after the RotateFlip() operation!
            Bitmap template = (Bitmap)bitmap.Clone();
            template.RotateFlip(rft);
            TilesOutlineShape result = new TilesOutlineShape(xSize, ySize, template);
#else
            OutlineShape      tile   = new ExplicitOutlineShape(bitmap).RotatedOrFlipped(rft);
            TilesOutlineShape result = new TilesOutlineShape(xSize, ySize, tile as ExplicitOutlineShape);
#endif
            result.SetRepetitions(scale);

            return(result);
        }
Пример #8
0
        /// <summary>
        /// Returns the largest subset of the template shape whose squares are all connected to each other.
        /// </summary>
        /// <param name="template"></param>
        /// <param name="isReserved">defines the maze's reserved areas</param>
        /// <returns></returns>
        public static OutlineShape ConnectedSubset(OutlineShape template, InsideShapeDelegate isReserved)
        {
            ExplicitOutlineShape result = new ExplicitOutlineShape(template, isReserved);

            #region Scan the shape for connected areas.

            byte subsetId        = 1;
            int  largestAreaSize = 0;
            byte largestAreaId   = 0;

            for (int x = 0; x < result.XSize; x++)
            {
                for (int y = 0; y < result.YSize; y++)
                {
                    if (result.squares[x, y] == 1 && subsetId < byte.MaxValue)
                    {
                        int areaSize = result.FillSubset(x, y, ++subsetId);
                        if (areaSize > largestAreaSize)
                        {
                            largestAreaSize = areaSize;
                            largestAreaId   = subsetId;
                        }
                    }
                }
            }

            #endregion

            #region Leave only the largest subset, eliminate all others.

            for (int x = 0; x < result.XSize; x++)
            {
                for (int y = 0; y < result.YSize; y++)
                {
                    result.SetValue(x, y, (result.squares[x, y] == largestAreaId));
                }
            }

            #endregion

            return(result);
        }
Пример #9
0
        /// <summary>
        /// Create an outline shape.
        /// </summary>
        /// <param name="r">a source of random numbers</param>
        /// <param name="xSize">width of the created shape</param>
        /// <param name="ySize">height of the created shape</param>
        /// <param name="centerX">X coordinate, relative to total width; 0.0 = top, 1.0 = bottom</param>
        /// <param name="centerY">Y coordinate, relative to total height; 0.0 = left, 1.0 = right</param>
        /// <param name="shapeSize">size, relative to distance of center from the border; 1.0 will touch the border</param>
        /// <returns></returns>
        public static OutlineShape Symbol(Random r, int xSize, int ySize, double centerX, double centerY, double shapeSize)
        {
            FontFamily fontFamily = new FontFamily("Times New Roman");

            char[] shapeCharacters =
            {
                //'\u0040',   // @
                '\u03C0',   // pi
                '\u05D0',   // aleph
                '\u263B',   // smiley
                '\u2660',   // spades
                '\u2663',   // clubs
                '\u2665',   // hearts
                '\u2666',   // diamonds
                '\u266A',   // musical note
            };
            char ch = shapeCharacters[r.Next(shapeCharacters.Length)];

            return(ExplicitOutlineShape.Char(xSize, ySize, centerX, centerY, shapeSize, ch, fontFamily));
        }
Пример #10
0
        /// <summary>
        /// Creates a MazeOutlineShape using the given mazeBuilder.
        /// </summary>
        /// <param name="xSize"></param>
        /// <param name="ySize"></param>
        /// <param name="gridWidth"></param>
        /// <param name="mazeBuilder"></param>
        private MazeOutlineShape(int xSize, int ySize, int wallWidth, int gridWidth, MazeShapeBuilder mazeBuilder)
            : base(xSize, ySize)
        {
            this.wallWidth = wallWidth;
            this.gridWidth = gridWidth;

            // Determine dimensions of a maze shape that fits tightly around the real maze.
            int mazeWidth  = (XSize - wallWidth + gridWidth - 1) / gridWidth;
            int mazeHeight = (YSize - wallWidth + gridWidth - 1) / gridWidth;
            int mazeAreaX  = mazeWidth * gridWidth + wallWidth;
            int mazeAreaY  = mazeHeight * gridWidth + wallWidth;

            this.xOffset = -(mazeAreaX - XSize) / 2;
            this.yOffset = -(mazeAreaY - YSize) / 2;

            // Adjust width if the left (and maybe also the right) border would lie on the real maze border.
            if (wallWidth + xOffset > 0)
            {
                mazeWidth += 1;
                mazeAreaX += gridWidth;
                xOffset    = -(mazeAreaX - XSize) / 2;
            }
            if (wallWidth + yOffset > 0)
            {
                mazeHeight += 1;
                mazeAreaY  += gridWidth;
                yOffset     = -(mazeAreaY - YSize) / 2;
            }

            this.maze = mazeBuilder(mazeWidth, mazeHeight);

            this.baseShape = new ExplicitOutlineShape(XSize, YSize);

            PaintBorder();
            PaintWalls();
        }
Пример #11
0
 /// <summary>
 /// Returns this shape, augmented by all totally enclosed areas.
 /// Reserved areas define additional borders around enclosed areas.
 /// </summary>
 /// <param name="isReserved">defines the maze's reserved areas</param>
 /// <returns></returns>
 public OutlineShape Closure(InsideShapeDelegate isReserved)
 {
     return(ExplicitOutlineShape.Closure(this, isReserved));
 }
Пример #12
0
 /// <summary>
 /// Returns this shape, augmented by all totally enclosed areas.
 /// </summary>
 /// <returns></returns>
 public OutlineShape Closure()
 {
     return(ExplicitOutlineShape.Closure(this, null));
 }
Пример #13
0
 /// <summary>
 /// Returns the largest subset of this shape whose squares are all connected to each other.
 /// </summary>
 /// <returns></returns>
 public OutlineShape ConnectedSubset(InsideShapeDelegate isReserved)
 {
     return(ExplicitOutlineShape.ConnectedSubset(this, isReserved));
 }
Пример #14
0
 /// <summary>
 /// The current GridElement is applied to the given target.
 /// Every set square is inverted.
 /// </summary>
 /// <param name="target"></param>
 /// <param name="xLeft"></param>
 /// <param name="yTop"></param>
 public abstract void Apply(ExplicitOutlineShape target, int xLeft, int yTop);
Пример #15
0
 /// <summary>
 /// Inverts the target square at the given coordinates.
 /// </summary>
 /// <param name="target"></param>
 /// <param name="x"></param>
 /// <param name="y"></param>
 protected void Invert(ExplicitOutlineShape target, int x, int y)
 {
     target.SetValue(x, y, !target[x, y]);
 }
Пример #16
0
 private GridOutlineShape(int xSize, int ySize, GridElement tile)
     : base(xSize, ySize)
 {
     this.baseShape = new ExplicitOutlineShape(xSize, ySize);
     this.Apply(tile);
 }
Пример #17
0
        /// <summary>
        /// Returns the template shape, augmented by all totally enclosed areas.
        /// </summary>
        /// <param name="template"></param>
        /// <param name="isReserved">defines the maze's reserved areas</param>
        /// <returns></returns>
        public static OutlineShape Closure(OutlineShape template, InsideShapeDelegate isReserved)
        {
            ExplicitOutlineShape result = new ExplicitOutlineShape(template.Inverse());

            #region Scan and mark the reserved areas.

            if (isReserved != null)
            {
                byte reservedId = 3;

                for (int x = 0; x < result.XSize; x++)
                {
                    for (int y = 0; y < result.YSize; y++)
                    {
                        if (isReserved(x, y))
                        {
                            result.squares[x, y] = reservedId;
                        }
                    }
                }
            }

            #endregion

            #region Scan all outside areas.

            byte outsideId = 2;
            int  x0 = 0, x1 = result.XSize - 1, y0 = 0, y1 = result.YSize - 1;

            for (int x = 0; x < result.XSize; x++)
            {
                if (result.squares[x, y0] == 1)
                {
                    result.FillSubset(x, y0, outsideId);
                }
                if (result.squares[x, y1] == 1)
                {
                    result.FillSubset(x, y1, outsideId);
                }
            }
            for (int y = 0; y < result.YSize; y++)
            {
                if (result.squares[x0, y] == 1)
                {
                    result.FillSubset(x0, y, outsideId);
                }
                if (result.squares[x1, y] == 1)
                {
                    result.FillSubset(x1, y, outsideId);
                }
            }

            #endregion

            #region Add the areas which were not reached.

            for (int x = 0; x < result.XSize; x++)
            {
                for (int y = 0; y < result.YSize; y++)
                {
                    // 0: square is part of the template (not part of its inverse)
                    // 1: square is not part of the template, but was not reached
                    result.SetValue(x, y, (result.squares[x, y] <= 1));
                }
            }

            #endregion

            return(result);
        }