/// <summary>
        /// Creates the tessellation.
        /// </summary>
        /// <param name="tess">The tess.</param>
        /// <returns></returns>
        public static Bitmap createTessellation(Tessellation tess)
        {
            int tessWidth = Math.Abs(tess.getBaseClick().X - tess.getEndClick().X);
            int tessHeight = Math.Abs(tess.getBaseClick().Y - tess.getEndClick().Y);

            // Get the patterns to tile and draw
            Point[][] patterns = tess.getPattern().getPatterns();
            // Determine the number of iterations in the x direction and the number of iterations in the y direction
            // that need to be used in order to cover the entire tessellation area.
            // 2 was added so that I can draw it overlapping the User Controls draw area so that there is no whitespace near edges.

            int iterX = (tess.getBaseClick().Y - tess.getEndClick().Y) / tess.getPattern().iWidth + 6;
            int iterY = (tess.getBaseClick().Y - tess.getEndClick().Y) / tess.getPattern().iHeight + 6;
            tess.getUnfoldingPath().Clear();
            // What divPatWidth and divPatHeight are used for is to determine the area of iterations that this pattern should run through while drawing in order
            // for the pattern to not end while using your mouse to scroll the map beyond the bounds of the picturebox.
            // This method to create a dynamic maps such as this is a necessary so that you are not trying to draw things that are not even visible to the container.
            // Although, there is a bit of an overlap purposely on the left, right and top because many patterns would simply end while scrolling because they are so large jagged.
            int divPatWidth = (-tess.getOffset().X) / tess.getPattern().iWidth;
            int divPatHeight = (-tess.getOffset().Y) / tess.getPattern().iHeight;
            if (divPatWidth > 0)
                divPatWidth = 0;
            if (divPatHeight > 0)
                divPatHeight = 0;
            // Run through the iterations in both directions (it draws the Y direction for each X first).
            for (int i = divPatWidth; i < iterX + divPatWidth; i++)
            {
                int iMultGetPatWidth = i * tess.getPattern().iWidth;
                for (int j = divPatHeight; j < iterY + divPatHeight; j++)
                {
                    int jMultGetPatHeight = j * tess.getPattern().iHeight;
                    for (int k = 0; k < patterns.Count(); k++)
                    {
                        // Draw each pattern
                        Point[] poly = new Point[patterns.ElementAt<Point[]>(k).Count()];
                        bool isShapeCollided = false;
                        for (int l = 0; l < patterns.ElementAt<Point[]>(k).Count(); l++)
                        {
                            Point temp = new Point(iMultGetPatWidth + patterns[k][l].X, tess.getPictureBox().Height - 5 - jMultGetPatHeight - patterns[k][l].Y);
                            // This is applied every other row because some patterns do not populate the map perfectly straight up.
                            // For example, the equilateral pattern must be applied at a slight horizontal offset otherwise the pattern would not match up as we draw
                            if (j % 2 == 1)
                                temp.X -= tess.getPattern().iOffset;
                            // This is applied at every iteration, we will subtract 3 times the width to not mess up the iOffset and give it some overlap to the left
                            temp.X -= tess.getPattern().iWidth * 3 - tess.getOffset().X;
                            temp.Y -= tess.getOffset().Y;
                            poly[l] = temp;

                            // Algorithm for highlighting the shapes that have a collision
                            int tempMod = (int)MathUtilities.mod(l - 1, patterns.ElementAt<Point[]>(k).Count()); // Use tempMod to find the correct vertex to determine a line for the current wall
                            if (!isShapeCollided) // Check if this polygon has been determined as part of the unfolding
                            {
                                if (l > 0)
                                {
                                    // Check the collisions between the vertices of the wall we're examining currently and the vertices of the base and end clicks
                                    if (MathUtilities.isValidIntersect((double)poly[tempMod].X, (double)poly[tempMod].Y, (double)poly[l].X, (double)poly[l].Y, (double)tess.getBaseClick().X + tess.getOffset().X, (double)tess.getBaseClick().Y - tess.getOffset().Y, (double)tess.getEndClick().X + tess.getOffset().X, (double)tess.getEndClick().Y - tess.getOffset().Y))
                                    {
                                        isShapeCollided = true;
                                    }
                                }
                                // Because we didn't check when l is 0, we must come back around after it has been set (on the last iteration) to check that wall we skipped
                                if (l == patterns.ElementAt<Point[]>(k).Count() - 1)
                                {
                                    if (MathUtilities.isValidIntersect((double)poly[l].X, (double)poly[l].Y, (double)poly[0].X, (double)poly[0].Y, (double)tess.getBaseClick().X + tess.getOffset().X, (double)tess.getBaseClick().Y - tess.getOffset().Y, (double)tess.getEndClick().X + tess.getOffset().X, (double)tess.getEndClick().Y - tess.getOffset().Y))
                                    {
                                        isShapeCollided = true;
                                    }
                                }
                            }
                        }
                        if(isShapeCollided)
                            tess.getUnfoldingPath().Add(poly);
                    }
                }
            }

            Bitmap myBitmap = new Bitmap(tessWidth + tess.getPattern().iWidth*2, tessHeight + tess.getPattern().iHeight*2);
            using (Graphics g = Graphics.FromImage(myBitmap))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.Clear(Color.White);

                for (int i = 0; i < tess.getUnfoldingPath().Count; i++)
                {
                    Point[] poly = tess.getUnfoldingPath()[i];
                    for (int j = 0; j < poly.Length; j++)
                    {
                        poly[j].X -= tess.getBaseClick().X > tess.getEndClick().X ? tess.getEndClick().X : tess.getBaseClick().X;
                        poly[j].Y -= tess.getBaseClick().Y > tess.getEndClick().Y ? tess.getEndClick().Y : tess.getBaseClick().Y;
                        poly[j].X += tess.getPattern().iWidth - tess.getOffset().X;
                        poly[j].Y += tess.getPattern().iHeight + tess.getOffset().Y;
                    }
                    g.DrawPolygon(System.Drawing.Pens.Black, poly);
                }
                Point newBaseClick = new Point();
                Point newEndClick = new Point();
                int xOffset = tess.getBaseClick().X > tess.getEndClick().X ? tess.getEndClick().X : tess.getBaseClick().X;
                int yOffset = tess.getBaseClick().Y > tess.getEndClick().Y ? tess.getEndClick().Y : tess.getBaseClick().Y;
                xOffset -= tess.getPattern().iWidth;
                yOffset -= tess.getPattern().iHeight;
                newBaseClick.X = tess.getBaseClick().X - xOffset;
                newBaseClick.Y = tess.getBaseClick().Y - yOffset;
                newEndClick.X = tess.getEndClick().X - xOffset;
                newEndClick.Y = tess.getEndClick().Y - yOffset;
                System.Drawing.Pen myPen = new Pen(System.Drawing.Brushes.DarkBlue, 2);
                g.DrawLine(System.Drawing.Pens.Blue, newBaseClick, newEndClick);

                g.Save();
                return myBitmap;
            }
        }
Example #2
0
        /// <summary>
        /// Centralized method to handle the instantiation of all Shapes and Tessellations.
        /// </summary>
        /// <param name="shape">Used to determine which shape to instantiate.</param>
        /// <param name="ratio">Optional parameter that defaults to 0. (Only used for rectangle)</param>
        /// <returns>
        /// Returns a Control array of length 2, the first element being the instance of the Shape
        /// and the second being the instance of the Tessellation.
        /// </returns>
        private void instantiateShapes(out Shape instShape, out Tessellation instTess, int shape, double ratio = 0d)
        {
            // Checks for the default tabPage that is added as a placeholder, and removes it if a shape is being created.
            if (tabControl1.TabPages.Contains(tabPage1))
            {
                tabControl1.TabPages.Remove(tabPage1);
            }
            Shape tempShape = null;
            Tessellation tempTess = null;
            // Each switch case sets the lastTab field, adds the Shape instance to the shapes List, adds the Tessellation instance to the tessellations List,
            // adds the Shape to the tabControl and sets the ContextMenu of that tab to the context menu field in the Shape base class.
            switch (shape)
            {
                case 0:
                    tempShape = new Equilateral();
                    EventSource.output("Equilateral Triangle tab created.");
                    tempTess = new EquilateralTess();
                    tempTess.Name = "Equilateral" + (tempShape.getShapeCount() - 1);
                    break;
                case 1:
                    tempShape = new IsosTri90();
                    EventSource.output("90 Isosceles Triangle tab created.");
                    tempTess = new IsosTri90Tess();
                    tempTess.Name = "IsosTri90" + (tempShape.getShapeCount() - 1);
                    break;
                case 2:
                    tempShape = new IsosTri120();
                    EventSource.output("120 Isosceles Triangle tab created.");
                    tempTess = new IsosTri120Tess();
                    tempTess.Name = "IsosTri120" + (tempShape.getShapeCount() - 1);
                    break;
                case 3:
                    tempShape = new Tri3060();
                    EventSource.output("30-60-90 Triangle tab created.");
                    tempTess = new Tri3060Tess();
                    tempTess.Name = "Tri3060" + (tempShape.getShapeCount() - 1);
                    break;
                case 4:
                    tempShape = new Hexagon();
                    EventSource.output("120 Hexagon tab created.");
                    tempTess = new HexagonTess();
                    tempTess.Name = "Hexagon" + (tempShape.getShapeCount() - 1);
                    break;
                case 5:
                    tempShape = new Rhombus();
                    EventSource.output("60-120 Rhombus tab created.");
                    tempTess = new RhombusTess();
                    tempTess.Name = "Rhombus" + (tempShape.getShapeCount() - 1);
                    break;
                case 6:
                    tempShape = new Kite();
                    EventSource.output("60-90-120 Kite tab created.");
                    tempTess = new KiteTess();
                    tempTess.Name = "Kite" + (tempShape.getShapeCount() - 1);
                    break;
                case 7:
                    tempShape = new Rect(ratio);
                    EventSource.output("Rectangle tab created.");
                    tempTess = new RectTess(ratio);
                    tempTess.Name = "Rectangle" + (tempShape.getShapeCount() - 1);
                    break;
                default:
                    break;
            }

            // The order for this must remain the same, the Shape and Tessellation instances must be added to the Lists before they are added to the Controls
            // because it triggers an event for the tabControl when a new Control is added, and the lastTab must be configured correctly for it.
            if (shapes.Count() != 0)
                lastTab = (Shape)tabControl1.SelectedTab;
            shapes.Add(tempShape);
            tessellations.Add(tempTess);
            tabControl1.TabPages.Add(tempShape);
            instShape = tempShape;
            instTess = tempTess;
        }
Example #3
0
 /// <summary>
 /// Triggers the methods subscribed to the tessellate event
 /// </summary>
 /// <param name="newTess"></param>
 public static void updateTess(Tessellation newTess)
 {
     tessellate(newTess, new Events("Tessellation parameters have been changed."));
 }