예제 #1
0
        //---------------------------------------------------------//
        /// <summary>
        /// Combines two Geometries, offset by the specified amount.
        /// </summary>
        /// <param name="geometry1">The first geometry to combine.</param>
        /// <param name="offset1">The offset of the first geometry relative to the second geometry, specified in puzzle piece units.</param>
        /// <param name="geometry1">The second geometry to combine.</param>
        /// <param name="offset1">The offset of the second geometry relative to the first geometry, specified in puzzle piece units.</param>
        /// <returns>The combined geometry</returns>
        private Geometry CombineGeometries(PuzzlePiece piece1, PuzzlePiece piece2)
        {
            // Get the geometires that will be joined
            Geometry geometry1 = piece1.ClipShape;
            Geometry geometry2 = piece2.ClipShape;

            // Get the offset of each piece relative to the puzzle
            Vector offset1InPixels = GetPieceTopLeftInScreenUnits(piece1);
            Vector offset2InPixels = GetPieceTopLeftInScreenUnits(piece2);

            // Use the offsets determined above to find the offset of each piece relative to the other piece
            // Between the two offsets, only one offset will have a nonzero value for x and y. This could be 
            // the same offset, or different offsets. Possible combinations are (0,0) and (100, 100); (50, 0) 
            // and (0, 75) but not (10, 0) and (15, 0)
            Vector relativeOffset1 = new Vector(Math.Max(0, Math.Round(offset1InPixels.X - offset2InPixels.X)), Math.Max(0, Math.Round(offset1InPixels.Y - offset2InPixels.Y)));
            Vector relativeOffset2 = new Vector(Math.Max(0, Math.Round(offset2InPixels.X - offset1InPixels.X)), Math.Max(0, Math.Round(offset2InPixels.Y - offset1InPixels.Y)));

            // Translate the geometries according to their offsets so they don't overlap when they're joined
            geometry1.Transform = new TranslateTransform(relativeOffset1.X, relativeOffset1.Y);
            geometry2.Transform = new TranslateTransform(relativeOffset2.X, relativeOffset2.Y);

            // Make a new GeometryGroup
            GeometryGroup newGeometry = new GeometryGroup();
            newGeometry.FillRule = FillRule.Nonzero;

            // Add the Geometries to the group
            newGeometry.Children.Add(geometry1);
            newGeometry.Children.Add(geometry2);

            // Flatten the group and return it
            return newGeometry.GetFlattenedPathGeometry();
        }
예제 #2
0
        //---------------------------------------------------------//
        /// <summary>
        /// Calculates the adjustment that must be made to a ScatterViewItem's center when 
        /// its content is replaced with differently sized content so that the piece does not
        /// appear to jump after two pieces are joined.
        /// </summary>
        /// <param name="originalPiece">The original content of the item.</param>
        /// <param name="newPiece">The content that will become the item's content.</param>
        /// <returns>The adjustment that should be applied to that item's center, relative to the puzzle piece.</returns>
        public Vector CalculateJoinCenterAdjustment(PuzzlePiece originalPiece, PuzzlePiece newPiece)
        {
            Vector originalOffset = GetRelativePieceCenterInScreenUnits(originalPiece);
            Vector newOffset = GetRelativePieceCenterInScreenUnits(newPiece);

            double adjustmentX = Math.Ceiling(newOffset.X - originalOffset.X);
            double adjustnemtY = Math.Ceiling(newOffset.Y - originalOffset.Y);

            return new Vector(adjustmentX, adjustnemtY);
        }
예제 #3
0
        //---------------------------------------------------------//
        /// <summary>
        /// Try to join two puzzle pieces together.
        /// </summary>
        /// <param name="piece1">The first of two pieces to try to join.</param>
        /// <param name="piece2">The second of two pieces to try to join.</param>
        /// <returns>The result of the join.</returns>
        public PuzzlePiece JoinPieces(PuzzlePiece piece1, PuzzlePiece piece2)
        {
            // Combine the viewboxes
            VisualBrush newBrush = new VisualBrush(piece1.ImageBrush.Visual);
            newBrush.Viewbox = Rect.Union(piece1.ImageBrush.Viewbox, piece2.ImageBrush.Viewbox);
            newBrush.ViewboxUnits = BrushMappingMode.RelativeToBoundingBox;

            // Combine the pieces
            HashSet<int> newPieces = new HashSet<int>(piece1.Pieces);
            newPieces.UnionWith(piece2.Pieces);

            // Combine the geometries
            Geometry newGeometry = CombineGeometries(piece1, piece2);

            // Now make them into a piece
            return new PuzzlePiece(newGeometry, newBrush, newPieces);
        }
예제 #4
0
        //---------------------------------------------------------//
        /// <summary>
        /// Gets the center of a specific piece number in a PuzzlePiece
        /// </summary>
        /// <param name="piece">The piece number for which to find the center</param>
        /// <param name="pieceNumber">The piece in which the piece number exists</param>
        /// <returns>The center of the piece numberm in screen units</returns>
        private Vector GetPieceNumberCenterInScreenUnits(PuzzlePiece piece, int pieceNumber)
        {
            Vector pieceOffset = GetPieceTopLeftInPieceUnits(piece);
            Vector pieceNumberOffset = new Vector(GetPieceColumn(pieceNumber), GetPieceRow(pieceNumber));
            Vector pieceCenter = pieceNumberOffset - pieceOffset;
            pieceCenter *= edgeLength;
            pieceCenter += halfEdge;

            if (pieceOffset.X != 0)
            {
                pieceCenter.X += overlap * edgeLength / 2;
            }
            if (pieceOffset.Y != 0)
            {
                pieceCenter.Y += overlap * edgeLength / 2;
            }

            return pieceCenter;
        }
예제 #5
0
 //---------------------------------------------------------//
 /// <summary>
 /// Gets the offset between the center of two pieces.
 /// </summary>
 /// <param name="piece1">The first of the two pieces.</param>
 /// <param name="piece2">The second of the two pieces.</param>
 /// <returns>The offset between the centers of the two pieces, measured in pieces.</returns>
 private Vector GetRelativeCenterOffsetInPieceUnits(PuzzlePiece piece1, PuzzlePiece piece2)
 {
     return GetRelativePieceCenterInScreenUnits(piece2) - GetRelativePieceCenterInScreenUnits(piece1);
 }
예제 #6
0
 //---------------------------------------------------------//
 /// <summary>
 /// Gets the offset from the top left of a PuzzlePiece to that same piece's center
 /// </summary>
 /// <param name="piece">The piece for which to calculate the center</param>
 /// <returns>The center of the piece, measured in screen units</returns>
 private static Vector GetAbsolutePieceCenterInScreenUnits(PuzzlePiece piece)
 {
     return new Vector(Math.Ceiling(piece.ClipShape.Bounds.Width) / 2, Math.Ceiling(piece.ClipShape.Bounds.Height) / 2);
 }
예제 #7
0
 //---------------------------------------------------------//
 /// <summary>
 /// Gets the offset from the top left of the puzzle to the center of a PuzzlePiece.
 /// </summary>
 /// <param name="piece">The piece.</param>
 /// <returns>The offset from the top left of the puzzle to the center of the piece, measured in screen units.</returns>
 private Vector GetRelativePieceCenterInScreenUnits(PuzzlePiece piece)
 {
     Vector PieceCenter = GetAbsolutePieceCenterInScreenUnits(piece);
     Vector PieceOffset = GetPieceTopLeftInScreenUnits(piece);
     return PieceOffset + PieceCenter;
 }
예제 #8
0
 //---------------------------------------------------------//
 /// <summary>
 /// Gets a piece's top left relative to the puzzle.
 /// </summary>
 /// <param name="piece">The puzzle piece.</param>
 /// <returns>A vector that reprsents the top left of the piece, measured in screen units.</returns>
 private Vector GetPieceTopLeftInScreenUnits(PuzzlePiece piece)
 {
     Vector pieceOffset = GetPieceTopLeftInPieceUnits(piece);
     return new Vector(Math.Max(0, edgeLength * (pieceOffset.X - overlap)), Math.Max(0, edgeLength * (pieceOffset.Y - overlap)));
 }
예제 #9
0
        //---------------------------------------------------------//
        /// <summary>
        /// Gets a piece's top left relative to the puzzle.
        /// </summary>
        /// <param name="piece">The puzzle piece.</param>
        /// <returns>A vector that reprsents the top left of the piece, measured in pieces.</returns>
        private Vector GetPieceTopLeftInPieceUnits(PuzzlePiece piece)
        {
            Vector offset = new Vector(int.MaxValue, int.MaxValue);
            foreach (int i in piece.Pieces)
            {
                int row = GetPieceRow(i);
                int col = GetPieceColumn(i);

                if (col < offset.X)
                {
                    offset.X = col;
                }
                if (row < offset.Y )
                {
                    offset.Y = row;
                }
            }
            
            return offset;
        }
예제 #10
0
        //---------------------------------------------------------//
        /// <summary>
        /// Creates puzzle pieces from a visual, and adds them into the ScatterView.
        /// </summary>
        /// <param name="visual"></param>
        void LoadVisualAsPuzzle(Visual visual, Direction fromDirection)
        {
            // The more columns/rows, the less each piece needs to overlap
            float rowOverlap = PuzzleManager.Overlap / rowCount;
            float colOverlap = PuzzleManager.Overlap / colCount;

            puzzleBrush = new VisualBrush(visual);

            // Tell the puzzle manager to load a puzzle with the specified dimensions
            puzzleManager.LoadPuzzle(colCount, rowCount);

            for (int row = 0; row < rowCount; row++)
            {
                for (int column = 0; column < colCount; column++)
                {
                    // Calculate the size of the rectangle that will be used to create a viewbox into the puzzle image.
                    // The size is specified as a percentage of the total image size.
                    float boxLeft = (float) column / (float)colCount;
                    float boxTop = (float) row / (float)rowCount;
                    float boxWidth = 1f / colCount;
                    float boxHeight = 1f / rowCount;

                    // Items in column 0 don't have any male puzzle parts on their side, all others do
                    if (column != 0)
                    {
                        boxLeft -= colOverlap;
                        boxWidth += colOverlap;
                    }

                    // Items in row 0 don't have any male puzzle parts on their top, all others do
                    if (row != 0)
                    {
                        boxTop -= rowOverlap;
                        boxHeight += rowOverlap;
                    }

                    // Make a visual brush based on the rectangle that was just calculated.
                    VisualBrush itemBrush = new VisualBrush(visual);
                    itemBrush.Viewbox = new Rect(boxLeft, boxTop, boxWidth, boxHeight);
                    itemBrush.ViewboxUnits = BrushMappingMode.RelativeToBoundingBox;

                    // Get the shape of the piece
                    Geometry shape = GetPieceGeometry(column, row);

                    // Put the brush into a puzzle piece
                    PuzzlePiece piece = new PuzzlePiece( column + (colCount * row), shape, itemBrush);

                    // Add the PuzzlePiece to a ScatterViewItem
                    SSC.ScatterViewItem item = new SSC.ScatterViewItem();
                    item.Content = piece;

                    // Set the initial size of the item and prevent it from being resized
                    item.Width = Math.Round(piece.ClipShape.Bounds.Width, 0);
                    item.Height = Math.Round(piece.ClipShape.Bounds.Height, 0);
                    item.CanScale = false;

                    // Set the item's data context so it can use the piece's shape
                    Binding binding = new Binding();
                    binding.Source = piece;
                    item.SetBinding(ScatterViewItem.DataContextProperty, binding);

                    // Animate the item into view
                    AddPiece(item, fromDirection);
                }
            }
        }