public static BezierCurve CreateVertical(int length, CurveRatio ratio) { BezierCurve curve = CreateHorizontal(length, ratio); curve.Rotate(90); int offsetX = 0 - curve.Points[0].X; int offsetY = 0 - curve.Points[0].Y; return(curve.Translate(offsetX, offsetY)); }
public static BezierCurve CreateHorizontal(int length, CurveRatio ratio) { double curvature = length * CURVE_TENSION; int x1, y1; // First curve's starting point int x2, y2; // First curve's first control point int x3, y3; // First curve's second control point int x4, y4; // First curve's ending point, second curve's starting point int x5, y5; // Second curve's first control point int x6, y6; // Second curve's second control point int x7, y7; // Second curve's ending point // First curve (first curve's ending point is (X4, Y4), which is also second curve's end point x1 = 0; y1 = 0; x2 = x1 + (int)(length * ratio.X2); y2 = y1 + (int)(curvature * ratio.Y2); x3 = x1 + (int)(length * ratio.X3); y3 = y1 - (int)(curvature * ratio.Y3); x4 = x1 + (int)(length * ratio.X4); y4 = y1 - (int)(curvature * ratio.Y4); // Second curve (second curve's ending point is (X4, Y4) ) x7 = x1 + length; y7 = y1; x6 = x7 - (int)(length * ratio.X6); y6 = y7 + (int)(curvature * ratio.Y6); x5 = x7 - (int)(length * ratio.X5); y5 = y7 - (int)(curvature * ratio.Y5); BezierCurve curve = new BezierCurve() { Points = new Point[] { new Point(x1, y1), new Point(x2, y2), new Point(x3, y3), new Point(x4, y4), new Point(x5, y5), new Point(x6, y6), new Point(x7, y7) } }; return(curve); }
public List <PieceCluster> CreateJigsawPuzzle(Size clientSize, Image sourcePicture, int menuStripHeight) { #region Some validation if (sourcePicture == null) { throw new Exception("Please provide source picture."); } if (GameSettings.NUM_ROWS <= 1 || GameSettings.NUM_COLUMNS <= 1) { throw new Exception("GameSettings.NUM_COLUMNS and GameSettings.NUM_ROWS must be at least 2."); } if (GameSettings.NUM_COLUMNS != GameSettings.NUM_ROWS) { throw new Exception("GameSettings.NUM_COLUMNS and GameSettings.NUM_ROWS must be the same."); } #endregion #region Make sure the piece size is not too small int pieceWidth = sourcePicture.Width / GameSettings.NUM_COLUMNS; int pieceHeight = sourcePicture.Height / GameSettings.NUM_ROWS; if (pieceWidth < GameSettings.MIN_PIECE_WIDTH || pieceHeight < GameSettings.MIN_PIECE_HEIGHT) { throw new Exception("The picture is too small. Please select a bigger picture."); } int lastColPieceWidth = pieceWidth + (sourcePicture.Width % GameSettings.NUM_COLUMNS); int lastRowPieceHeight = pieceHeight + (sourcePicture.Height % GameSettings.NUM_ROWS); #endregion #region Construct jigsaw pieces int lastRow = (GameSettings.NUM_ROWS - 1); int lastCol = (GameSettings.NUM_COLUMNS - 1); var clusters = new List <PieceCluster>(); Matrix matrix = new Matrix(); Pen outlinePen = new Pen(Color.Black) { Width = GameSettings.PIECE_OUTLINE_WIDTH, Alignment = PenAlignment.Inset }; var vsets = new List <Vector3>(5); vsets.Add(new Vector3(0.9, 1.1, 0.95)); vsets.Add(new Vector3(1.1, 0.9, 1.05)); vsets.Add(new Vector3(1.13, 0.95, 1.0)); vsets.Add(new Vector3(0.9, 0.9, 1.15)); vsets.Add(new Vector3(0.95, 1.19, 0.95)); int[, ,] mat = new int[GameSettings.NUM_ROWS, GameSettings.NUM_COLUMNS, 4]; int pieceID = 0; Random rnd = new Random((int)(DateTime.Now.Ticks)); for (int row = 0; row < GameSettings.NUM_ROWS; row++) { // Make the top and bottom curves face in the same way or opposite direction. for (int col = 0; col < GameSettings.NUM_COLUMNS; col++) { mat[row, col, RightCurve] = rnd.Next(5); mat[row, col, BottomCurve] = rnd.Next(5); mat[row, col, RightOutty] = rnd.Next(2); mat[row, col, BottomOutty] = rnd.Next(2); GraphicsPath figure = new GraphicsPath(); int offsetX = (col * pieceWidth); int offsetY = (row * pieceHeight); int horizontalCurveLength = (col == lastCol ? lastColPieceWidth : pieceWidth); int verticalCurveLength = (row == lastRow ? lastRowPieceHeight : pieceHeight); #region Top if (row == 0) { int startX = offsetX; int startY = offsetY; int endX = offsetX + horizontalCurveLength; int endY = offsetY; figure.AddLine(startX, startY, endX, endY); } else { var v = vsets[mat[row - 1, col, BottomCurve]]; var crTop = new CurveRatio(v.X, v.Y, 2.0 - v.Z); //var crTop = new CurveRatio(v.X, v.Y, v.Z); BezierCurve topCurve = BezierCurve.CreateHorizontal(horizontalCurveLength, crTop); if (mat[row - 1, col, BottomOutty] > 0) { topCurve.FlipVertical(); } figure.AddBeziers(topCurve.Translate(offsetX, offsetY).Points); } #endregion #region Right if (col == lastCol) { int startX = offsetX + lastColPieceWidth; int startY = offsetY; int endX = offsetX + lastColPieceWidth; int endY = offsetY + verticalCurveLength; figure.AddLine(startX, startY, endX, endY); } else { BezierCurve verticalCurve = BezierCurve.CreateVertical(verticalCurveLength, new CurveRatio(vsets[mat[row, col, RightCurve]])); if (mat[row, col, RightOutty] > 0) { verticalCurve.FlipHorizontal(); } verticalCurve.Translate(offsetX + pieceWidth, offsetY); figure.AddBeziers(verticalCurve.Points); } #endregion #region Bottom if (row == lastRow) { int startX = offsetX; int startY = offsetY + lastRowPieceHeight; int endX = offsetX + horizontalCurveLength; int endY = offsetY + lastRowPieceHeight; figure.AddLine(endX, endY, startX, startY); } else { BezierCurve bottomCurve = BezierCurve.CreateHorizontal(horizontalCurveLength, new CurveRatio(vsets[mat[row, col, BottomCurve]])); bottomCurve.FlipHorizontal(); if (mat[row, col, BottomOutty] > 0) { bottomCurve.FlipVertical(); } bottomCurve.Translate(offsetX + horizontalCurveLength, offsetY + pieceHeight); figure.AddBeziers(bottomCurve.Points); } #endregion #region Left if (col == 0) { int startX = offsetX; int startY = offsetY; int endX = offsetX; int endY = offsetY + verticalCurveLength; figure.AddLine(endX, endY, startX, startY); } else { var v = vsets[mat[row, col - 1, RightCurve]]; var crLeft = new CurveRatio(v.X, v.Y, 2.0 - v.Z); //var crLeft = new CurveRatio(v.X, v.Y, v.Z); BezierCurve verticalCurve = BezierCurve.CreateVertical(verticalCurveLength, crLeft); verticalCurve.FlipVertical(); if (mat[row, col - 1, RightOutty] > 0) { verticalCurve.FlipHorizontal(); } verticalCurve.Translate(offsetX, offsetY + verticalCurveLength); figure.AddBeziers(verticalCurve.Points); } #endregion #region Jigsaw information #region Determine adjacent piece IDs for the current piece List <Coordinate> adjacentCoords = new List <Coordinate> { new Coordinate(col, row - 1), new Coordinate(col + 1, row), new Coordinate(col, row + 1), new Coordinate(col - 1, row) }; List <int> adjacentPieceIDs = DetermineAdjacentPieceIDs(adjacentCoords, GameSettings.NUM_COLUMNS); #endregion #region Construct piece picture Rectangle figureLocation = Rectangle.Truncate(figure.GetBounds()); // Translate the figure to the origin to draw the picture for individual piece matrix.Reset(); matrix.Translate(0 - figureLocation.X, 0 - figureLocation.Y); GraphicsPath translatedFigure = (GraphicsPath)figure.Clone(); translatedFigure.Transform(matrix); Rectangle translatedFigureLocation = Rectangle.Truncate(translatedFigure.GetBounds()); Bitmap piecePicture = new Bitmap(figureLocation.Width, figureLocation.Height); using (Graphics gfx = Graphics.FromImage(piecePicture)) { gfx.FillRectangle(Brushes.White, 0, 0, piecePicture.Width, piecePicture.Height); gfx.ResetClip(); gfx.SetClip(translatedFigure); gfx.DrawImage(sourcePicture, new Rectangle(0, 0, piecePicture.Width, piecePicture.Height), figureLocation, GraphicsUnit.Pixel); if (GameSettings.DRAW_PIECE_OUTLINE) { gfx.SmoothingMode = SmoothingMode.AntiAlias; gfx.DrawPath(outlinePen, translatedFigure); } } // Wanted to do the "bevel edge" effect but too complicated for me. Bitmap modifiedPiecePicture = (Bitmap)piecePicture.Clone(); ImageUtilities.EdgeDetectHorizontal(modifiedPiecePicture); ImageUtilities.EdgeDetectVertical(modifiedPiecePicture); piecePicture = ImageUtilities.AlphaBlendMatrix(modifiedPiecePicture, piecePicture, 200); #endregion #region Piece and cluster information Piece piece = new Piece { ID = pieceID, ClusterID = pieceID, Width = figureLocation.Width, Height = figureLocation.Height, BoardLocation = translatedFigureLocation, SourcePictureLocation = figureLocation, MovableFigure = (GraphicsPath)translatedFigure.Clone(), StaticFigure = (GraphicsPath)figure.Clone(), Picture = (Bitmap)piecePicture.Clone(), AdjacentPieceIDs = adjacentPieceIDs }; PieceCluster cluster = new PieceCluster { ID = pieceID, Width = figureLocation.Width, Height = figureLocation.Height, BoardLocation = translatedFigureLocation, SourcePictureLocation = figureLocation, MovableFigure = (GraphicsPath)translatedFigure.Clone(), StaticFigure = (GraphicsPath)figure.Clone(), Picture = (Bitmap)piecePicture.Clone(), Pieces = new List <Piece> { piece } }; #endregion clusters.Add(cluster); #endregion pieceID++; } } //var ratioLeft = new CurveRatio(1.1, 0.9, 1.05); //var ratioRight = new CurveRatio(1.1, 0.9, 0.95); //var ratioTop = new CurveRatio(0.9, 1.1, 1.0); //var ratioBottom = new CurveRatio(0.9, 1.1, 1.0); //for (int row = 0; row < GameSettings.NUM_ROWS; row++) //{ // // Make the top and bottom curves face in the same way or opposite direction. // bool topCurveFlipVertical = (row % 2 == 0); // bool bottomCurveFlipVertical = (row % 2 != 0); // for (int col = 0; col < GameSettings.NUM_COLUMNS; col++) // { // // Make the left and right curves face in the same way or opposite direction. // bool leftCurveFlipHorizontal = (col % 2 != 0); // bool rightCurveFlipHorizontal = (col % 2 == 0); // // Toggle the facing of left and right curves with each row. // if (row % 2 == 0) // { // leftCurveFlipHorizontal = (col % 2 == 0); // rightCurveFlipHorizontal = (col % 2 != 0); // } // // Toggle the facing of top and bottom curves with each row. // topCurveFlipVertical = !topCurveFlipVertical; // bottomCurveFlipVertical = !bottomCurveFlipVertical; // GraphicsPath figure = new GraphicsPath(); // int offsetX = (col * pieceWidth); // int offsetY = (row * pieceHeight); // int horizontalCurveLength = (col == lastCol ? lastColPieceWidth : pieceWidth); // int verticalCurveLength = (row == lastRow ? lastRowPieceHeight : pieceHeight); // #region Top // if (row == 0) // { // int startX = offsetX; // int startY = offsetY; // int endX = offsetX + horizontalCurveLength; // int endY = offsetY; // figure.AddLine(startX, startY, endX, endY); // } // else // { // BezierCurve topCurve = BezierCurve.CreateHorizontal(horizontalCurveLength, ratioTop); // if (topCurveFlipVertical) // { // topCurve.FlipVertical(); // } // topCurve.Translate(offsetX, offsetY); // figure.AddBeziers(topCurve.Points); // } // #endregion // #region Right // if (col == lastCol) // { // int startX = offsetX + lastColPieceWidth; // int startY = offsetY; // int endX = offsetX + lastColPieceWidth; // int endY = offsetY + verticalCurveLength; // figure.AddLine(startX, startY, endX, endY); // } // else // { // BezierCurve verticalCurve = BezierCurve.CreateVertical(verticalCurveLength, ratioRight); // if (rightCurveFlipHorizontal) // { // verticalCurve.FlipHorizontal(); // } // verticalCurve.Translate(offsetX + pieceWidth, offsetY); // figure.AddBeziers(verticalCurve.Points); // } // #endregion // #region Bottom // if (row == lastRow) // { // int startX = offsetX; // int startY = offsetY + lastRowPieceHeight; // int endX = offsetX + horizontalCurveLength; // int endY = offsetY + lastRowPieceHeight; // figure.AddLine(endX, endY, startX, startY); // } // else // { // BezierCurve bottomCurve = BezierCurve.CreateHorizontal(horizontalCurveLength, ratioBottom); // bottomCurve.FlipHorizontal(); // if (bottomCurveFlipVertical) // { // bottomCurve.FlipVertical(); // } // bottomCurve.Translate(offsetX + horizontalCurveLength, offsetY + pieceHeight); // figure.AddBeziers(bottomCurve.Points); // } // #endregion // #region Left // if (col == 0) // { // int startX = offsetX; // int startY = offsetY; // int endX = offsetX; // int endY = offsetY + verticalCurveLength; // figure.AddLine(endX, endY, startX, startY); // } // else // { // BezierCurve verticalCurve = BezierCurve.CreateVertical(verticalCurveLength, ratioLeft); // verticalCurve.FlipVertical(); // if (leftCurveFlipHorizontal) // { // verticalCurve.FlipHorizontal(); // } // verticalCurve.Translate(offsetX, offsetY + verticalCurveLength); // figure.AddBeziers(verticalCurve.Points); // } // #endregion // #region Jigsaw information // #region Determine adjacent piece IDs for the current piece // List<Coordinate> adjacentCoords = new List<Coordinate> // { // new Coordinate(col, row - 1), // new Coordinate(col + 1, row), // new Coordinate(col, row + 1), // new Coordinate(col - 1, row) // }; // List<int> adjacentPieceIDs = DetermineAdjacentPieceIDs(adjacentCoords, GameSettings.NUM_COLUMNS); // #endregion // #region Construct piece picture // Rectangle figureLocation = Rectangle.Truncate(figure.GetBounds()); // // Translate the figure to the origin to draw the picture for individual piece // matrix.Reset(); // matrix.Translate(0 - figureLocation.X, 0 - figureLocation.Y); // GraphicsPath translatedFigure = (GraphicsPath)figure.Clone(); // translatedFigure.Transform(matrix); // Rectangle translatedFigureLocation = Rectangle.Truncate(translatedFigure.GetBounds()); // Bitmap piecePicture = new Bitmap(figureLocation.Width, figureLocation.Height); // using (Graphics gfx = Graphics.FromImage(piecePicture)) // { // gfx.FillRectangle(Brushes.White, 0, 0, piecePicture.Width, piecePicture.Height); // gfx.ResetClip(); // gfx.SetClip(translatedFigure); // gfx.DrawImage(sourcePicture, new Rectangle(0, 0, piecePicture.Width, piecePicture.Height), // figureLocation, GraphicsUnit.Pixel); // if (GameSettings.DRAW_PIECE_OUTLINE) // { // gfx.SmoothingMode = SmoothingMode.AntiAlias; // gfx.DrawPath(outlinePen, translatedFigure); // } // } // // Wanted to do the "bevel edge" effect but too complicated for me. // Bitmap modifiedPiecePicture = (Bitmap)piecePicture.Clone(); // ImageUtilities.EdgeDetectHorizontal(modifiedPiecePicture); // ImageUtilities.EdgeDetectVertical(modifiedPiecePicture); // piecePicture = ImageUtilities.AlphaBlendMatrix(modifiedPiecePicture, piecePicture, 200); // #endregion // #region Piece and cluster information // Piece piece = new Piece // { // ID = pieceID, // ClusterID = pieceID, // Width = figureLocation.Width, // Height = figureLocation.Height, // BoardLocation = translatedFigureLocation, // SourcePictureLocation = figureLocation, // MovableFigure = (GraphicsPath)translatedFigure.Clone(), // StaticFigure = (GraphicsPath)figure.Clone(), // Picture = (Bitmap)piecePicture.Clone(), // AdjacentPieceIDs = adjacentPieceIDs // }; // PieceCluster cluster = new PieceCluster // { // ID = pieceID, // Width = figureLocation.Width, // Height = figureLocation.Height, // BoardLocation = translatedFigureLocation, // SourcePictureLocation = figureLocation, // MovableFigure = (GraphicsPath)translatedFigure.Clone(), // StaticFigure = (GraphicsPath)figure.Clone(), // Picture = (Bitmap)piecePicture.Clone(), // Pieces = new List<Piece> { piece } // }; // #endregion // clusters.Add(cluster); // #endregion // pieceID++; // } //} #endregion #region Scramble jigsaw pieces Random random = new Random(); int boardWidth = clientSize.Width; int boardHeight = clientSize.Height; foreach (PieceCluster cluster in clusters) { int locationX = random.Next(1, boardWidth); int locationY = random.Next((menuStripHeight + 1), boardHeight); #region Make sure the piece is within client rectangle bounds if ((locationX + cluster.Width) > boardWidth) { locationX = locationX - ((locationX + cluster.Width) - boardWidth); } if ((locationY + cluster.Height) > boardHeight) { locationY = locationY - ((locationY + cluster.Height) - boardHeight); } #endregion for (int index = 0; index < cluster.Pieces.Count; index++) { Piece piece = cluster.Pieces[index]; piece.BoardLocation = new Rectangle(locationX, locationY, piece.Width, piece.Height); matrix.Reset(); matrix.Translate(locationX, locationY); piece.MovableFigure.Transform(matrix); } // Move the figure for cluster piece cluster.BoardLocation = new Rectangle(locationX, locationY, cluster.Width, cluster.Height); matrix.Reset(); matrix.Translate(locationX, locationY); cluster.MovableFigure.Transform(matrix); } return(clusters); }