Search code examples
javaawtgraphics2d

Graphics2D.drawPolyline() vs Graphics2D.drawLine()


Is there any benefit to calling drawPolyline() versus iterating through each line and calling drawLine() in the Graphics2D class?

For example:

graphics2d.drawPolyline(xPoints, yPoints, nPoints);

versus:

for (MyBean line : myBeans) {
    graphics2d.drawLine(line.getX1Point(), line.getY1Point(), line.getX2Point(), line.getY2Point());     
}

Is the first a convenience method for the second?

Fairly new to AWT. (I realize that the first one may be more concise.)

Edit: I call BufferedImage.createGraphics() for the implementation of Graphics2D.


Solution

  • There is an important difference: With drawPolyline you are drawing a single polyline. With drawLine you are drawing individual lines. So far, so obvious. But what does it mean?

    The difference mainly shows up when assigning a "non-trivial" Stroke to the graphics object - usually, a certain BasicStroke. This receives several parameters in the constructor. The important one regarding your question is the join parameter. It can be JOIN_BEVEL, JOIN_METER and JOIN_ROUND. It determines how two connected lines are joined. And this, obviously, can only be applied when it is known that the lines are connected, which is only the case in the drawPolyline call. It simply can not be applied for individual drawLine calls.

    The following is a screenshot showing this difference. It uses a stroke with a witdh of 15 and a join=BasicStroke.JOIN_ROUND. The left part is drawn with drawPolyline, and the right one is drawn as individual lines:

    DrawLineVsDrawPolyline01

    But you should not usually not use drawPolyline anyhow...

    ... because it is somehow out-dated and has several shortcomings. First of all, it is a hassle to create the arrays that are required for calling it. And importantly, it only accepts int[] arrays.

    The whole Java 2D painting infrastructure was originally focussing on int coordinates, like in Graphics#drawLine(int,int,int,int). This has been generalized, and the Graphics2D methods allow a much greater flexibility here. So the usual way to draw a polyline nowadays would be to create a Shape object containing the polyline. In most cases, this will be a Path2D instance:

    Path2D path = new Path2D.Double();
    path.moveTo(x0,y0);
    path.lineTo(x1,y1);
    path.lineTo(x2,y2);
    ...
    graphics2D.draw(path);
    

    However, just for reference, here is the code that was used to create the above image:

    import java.awt.BasicStroke;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class DrawLineVsDrawPolyline
    {
        public static void main(String[] args)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    createAndShowGUI();
                }
            });
        }
       
        private static void createAndShowGUI()
        {
            JFrame f = new JFrame("");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.getContentPane().setLayout(new BorderLayout());
           
            class Line
            {
                int x1, y1, x2, y2;
                Line(int x1, int y1, int x2, int y2)
                {
                    this.x1 = x1;
                    this.y1 = y1;
                    this.x2 = x2;
                    this.y2 = y2;
                }
                public int getX1Point()
                {
                    return x1;
                }
                public int getY1Point()
                {
                    return y1;
                }
                public int getX2Point()
                {
                    return x2;
                }
                public int getY2Point()
                {
                    return y2;
                }
            }
            int xPoints[] = new int[] { 100, 150, 200 };
            int yPoints[] = new int[] { 100, 250, 100 };
            int nPoints = xPoints.length;
            List<Line> lines = new ArrayList<Line>();
            for (int i0=0; i0<nPoints-1; i0++)
            {
                int i1 = i0+1;
                int x1 = xPoints[i0];
                int y1 = yPoints[i0];
                int x2 = xPoints[i1];
                int y2 = yPoints[i1];
                lines.add(new Line(x1,y1,x2,y2));
            }
            
            JPanel panel = new JPanel()
            {
                @Override
                protected void paintComponent(Graphics gr) 
                {
                    super.paintComponent(gr);
                    Graphics2D g = (Graphics2D)gr;
                    
                    g.setColor(Color.RED);
                    g.setStroke(new BasicStroke(20.0f, 
                        BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
    
                    g.drawPolyline(xPoints, yPoints, nPoints);
                    
                    g.translate(200, 0);
                    
                    for (Line line : lines) {
                        g.drawLine(
                            line.getX1Point(), line.getY1Point(), 
                            line.getX2Point(), line.getY2Point());     
                    }
                    
                }
            };
            f.getContentPane().add(panel, BorderLayout.CENTER);
            
            f.setSize(500,500);
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
        
    }