3

These days I am working on a Paint App in Windows Form. I created my own variation of TaW's code for live painting on picturebox:

enum ArtMode { HandDraw, Erase, Line, Rectangle, Ellipse, Circle, AutoPainter }
class ArtManager
{
    Pen pen;
    public void Draw(PaintEventArgs G, List<ArtAction> actions)
    {          
        foreach (ArtAction da in actions)
        {
            pen = new Pen(da.color, da.width);
            if (da.points.Count > 1)
            {
                if (da.artMode == ArtMode.HandDraw)
                    G.Graphics.DrawCurve(pen, da.points.ToArray());
                else if (da.artMode == ArtMode.Erase)
                    G.Graphics.DrawCurve(new Pen(da.color, da.width), da.points.ToArray()); 
                else if (da.artMode == ArtMode.Line)
                    G.Graphics.DrawLine(pen, da.points[0], da.points[da.points.Count - 1]);
                else if (da.artMode == ArtMode.Rectangle)
                    G.Graphics.DrawRectangle(pen, Math.Min(da.points[0].X, da.points[da.points.Count - 1].X), Math.Min(da.points[0].Y, da.points[da.points.Count - 1].Y), Math.Abs(da.points[0].X - da.points[da.points.Count - 1].X), Math.Abs(da.points[0].Y - da.points[da.points.Count - 1].Y));
                else if (da.artMode == ArtMode.Ellipse)
                {
                    Rectangle rect = new Rectangle((int)Math.Min(da.points[0].X, da.points[da.points.Count - 1].X), (int)Math.Min(da.points[0].Y, da.points[da.points.Count - 1].Y), (int)Math.Abs(da.points[0].X - da.points[da.points.Count - 1].X), (int)Math.Abs(da.points[0].Y - da.points[da.points.Count - 1].Y));
                    G.Graphics.DrawEllipse(pen, rect);
                }
                else if (da.artMode == ArtMode.Circle)
                {
                    Rectangle rect = new Rectangle((int)Math.Min(da.points[0].X, da.points[da.points.Count - 1].X), (int)Math.Min(da.points[0].Y, da.points[da.points.Count - 1].Y), (int)Math.Abs(da.points[0].Y - da.points[da.points.Count - 1].Y), (int)Math.Abs(da.points[0].Y - da.points[da.points.Count - 1].Y));
                    G.Graphics.DrawEllipse(pen, rect);
                }
            }
        }           
    }
}

class ArtAction
{
    public Color color;
    public float width;
    public ArtMode artMode;
    public List<PointF> points;

    public ArtAction(Color color, float width ,ArtMode artMode)
    {
        this.color = color;
        this.width = width;
        this.artMode = artMode;
        points = new List<PointF>();
    }
}   

Form's code:

    Pen pen;
    ArtMode artMode;

    List<ArtAction> actions = new List<ArtAction>();
    ArtManager artManager = new ArtManager();
    int i = 0;

    private void canvas_MouseDown(object sender, MouseEventArgs e)
    {
        //Setting pen
        pen.Width = float.Parse(BrushSizeCB.SelectedItem.ToString());
        pen.Color = HandDraw_ColorIndic.BackColor;

        if (artMode == ArtMode.HandDraw)            
            actions.Add(new ArtAction(pen.Color, pen.Width, ArtMode.HandDraw));                                     
        else if (artMode == ArtMode.Erase)            
            actions.Add(new ArtAction(Color.White, pen.Width, ArtMode.Erase));            
        else if (artMode == ArtMode.Line)            
            actions.Add(new ArtAction(pen.Color, pen.Width, ArtMode.Line));            
        else if (artMode == ArtMode.Rectangle)           
            actions.Add(new ArtAction(pen.Color, pen.Width, ArtMode.Rectangle));            
        else if (artMode == ArtMode.Ellipse)            
            actions.Add(new ArtAction(pen.Color, pen.Width, ArtMode.Ellipse));            
        else if (artMode == ArtMode.Circle)           
            actions.Add(new ArtAction(pen.Color, pen.Width, ArtMode.Circle));                                           
    }
    
    private void canvas_MouseMove(object sender, MouseEventArgs e)
    {
        Cordinates_X.Text = "X: " + e.X;
        Cordinates_Y.Text = "Y: " + e.Y;

        if (e.Button == MouseButtons.Left)
        {
            actions[i].points.Add(e.Location);
            canvas.Invalidate();
        }              
    }

    private void canvas_MouseUp(object sender, MouseEventArgs e)
    {
        i++;
    }

    private void canvas_Paint(object sender, PaintEventArgs e)
    {            
        artManager.Draw(e, actions);
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    } 

The results I get for HandDraw(free-form line) are not what I expected... The curves have thorns. With smaller pen width the problem is smaller but at larger numbers the problem is worse: Image1, Image2 The issue gets even worse when there a lot of stuff on the canvas.

Any suggetions on how to fix this?

TaW
  • 53,122
  • 8
  • 69
  • 111
MrAkazaas
  • 31
  • 1
  • 1
    Try using one of the overloads of `DrawCurve()` that accepts a `tension` parameter, and play around with different values for `tension`, starting with `0.0f`. – Matthew Watson Jan 12 '21 at 14:05
  • 1
    You need to set the miter lmit; start by setting the miter width to the 1/2 of the pen width. There are more properties you may want play with or even offer to the user to build a palette of custom pens.. – TaW Jan 13 '21 at 00:16
  • By setting the tension to 0 it nearly fixed the problem. There was still problem at the 'corners' of the line. Adjusting the LineJoin fixed this. Problem solved. 0.0f Tension + LineJoin to Round! – MrAkazaas Jan 14 '21 at 07:50

0 Answers0