Search code examples
c#winformsshapesgraphicspath

GraphicsPath AddArc


I'm trying to create a popup bubble with a round rectangle and a thingy at the bottom which I circled with green on the image bellow:

enter image description here

But as you have guessed this isn't how i want it to look but instead:

enter image description here

I figured out how to draw it as i should but in that case when i add border around my path it separates that little triangle and the round rectangle.

Heres the code I'm working with:

public static GraphicsPath CreateBubblePath(Rectangle rect, int radius)
{
    GraphicsPath p = new GraphicsPath();
    GraphicsPath p2 = new GraphicsPath();
    p.StartFigure();
    p2.StartFigure();

    int pointHeigt = 3 * radius;

    //Top Left Corner
    p.AddArc(rect.X, rect.Y, 2 * radius, 2 * radius, 180, 90);

    //Top Edge
    p.AddLine(rect.X + radius, rect.Y, rect.X + rect.Width - radius, rect.Y);

    //Top Right Corner
    p.AddArc(rect.X + rect.Width - 2 * radius, rect.Y, 2 * radius, 2 * radius, 270, 90);


    //Right Edge
    p.AddLine(rect.X + rect.Width, rect.Y + radius, rect.X + rect.Width, rect.Y + rect.Height - radius - pointHeigt);

    //Bottom Right Corner
    p.AddArc(rect.X + rect.Width - (2 * radius), rect.Y + rect.Height - radius - pointHeigt, 2 * radius, 2 * radius, 0, 90);

    //Bottom Edge 1/2
    //METHOD 1
    p.AddLine(rect.X + rect.Width - radius, rect.Y + rect.Height - 2 * radius, rect.X + (rect.Width / 2) + pointHeigt, rect.Y + rect.Height - 2 * radius);

    p.AddArc(rect.X + (rect.Width / 2), rect.Y + rect.Height - 2 * radius , pointHeigt, pointHeigt, 180, 90);
    p.AddArc(rect.X + (rect.Width / 2) - pointHeigt, rect.Y + rect.Height - 2 * radius, pointHeigt, pointHeigt, 270, 90);

    p.AddLine(rect.X + (rect.Width / 2) - pointHeigt, rect.Y + rect.Height - 2 * radius, rect.X + radius, rect.Y + rect.Height - 2 * radius);

    //METHOD 2///////////////////////////////////////
    //p.AddLine(rect.X + rect.Width - radius, rect.Y + rect.Height - 2 * radius, rect.X + radius, rect.Y + rect.Height - 2 * radius);
    //p2.AddArc(rect.X + (rect.Width / 2), rect.Y + rect.Height - 2 * radius, pointHeigt, pointHeigt, 180, 90);
    //p2.AddArc(rect.X + (rect.Width / 2) - pointHeigt, rect.Y + rect.Height - 2 * radius, pointHeigt, pointHeigt, 270, 90);
    //p2.CloseFigure();
    ////////////////////////////////

    //Bottom Left Corner
    p.AddArc(rect.X, rect.Y + rect.Height - radius - pointHeigt, 2 * radius, 2 * radius, 90, 90);

    //Left Edge
    p.AddLine(rect.X, rect.Y + rect.Height - radius - pointHeigt, rect.X, rect.Y + radius);

    p.CloseFigure();
    //METHOD 2
    //p.AddPath(p2, true);
    return p;
}

Solution

  • I think the angles for the arcs are the problem.

    I changed them to this:

    p.AddArc(rect.X + (rect.Width / 2), rect.Y + rect.Height - 2 * radius, pointHeigt, pointHeigt, 270, -90);
    p.AddArc(rect.X + (rect.Width / 2) - pointHeigt, rect.Y + rect.Height - 2 * radius, pointHeigt, pointHeigt, 0, -90);
    

    And the point on the bottom of the rectangle looks correct now.

    Information about arc's angles can be found on the MSDN page for GraphicsPath.AddArc, in particular in the Remarks section:

    The arc is traced along the perimeter of the ellipse bounded by the specified rectangle. The starting point of the arc is determined by measuring clockwise from the x-axis of the ellipse (at the 0-degree angle) by the number of degrees in the start angle. The endpoint is similarly located by measuring clockwise from the starting point by the number of degrees in the sweep angle. If the sweep angle is greater than 360 degrees or less than -360 degrees, the arc is swept by exactly 360 degrees or -360 degrees, respectively.