Jahir Fiquitiva
Jahir Fiquitiva

Reputation: 1509

How to draw a triangle with border with Java Graphics

I'm trying to draw a triangle with a border using the Graphics.drawPolygon() method

The triangle is properly drawn, but how can I calculate the 3 points of the border?

I already did it with a circle, but I can't seem to find a solution for triangle.

A requirement of the instructor as that it cannot use Graphics2D.

My code:

if (xPoints != null && yPoints != null) {
    int[] nXPoints = new int[] { xPoints[0] - borderThickness, xPoints[1] - borderThickness,
            xPoints[2] - borderThickness };
    int[] nYPoints = new int[] { yPoints[0] - borderThickness, yPoints[1] - borderThickness,
            yPoints[2] - borderThickness };

    g.setColor(borderColor);
    g.fillPolygon(nXPoints, nYPoints, 3);

    g.setColor(fillColor);
    g.fillPolygon(xPoints, yPoints, 3);
}

Edit: Expected result

Expected result

Upvotes: 2

Views: 3305

Answers (1)

trashgod
trashgod

Reputation: 205765

Use the Graphics methods drawPolygon() to render the outline and fillPolygon() to fill its interior; both have the required signature, as shown here.

image1

Because "operations that draw the outline of a figure operate by traversing an infinitely thin path between pixels with a pixel-sized pen," cast the graphics context to Graphics2D so that you can use draw() and fill() on the corresponding Shape. This will allow you to specify the outline using setStroke(), illustrated here.

image2

I need it to have a custom thickness…I also don't want to use Graphics2D.

Custom thickness is not supported in the Graphics API. As suggested here, the actual graphics context received by paintComponent() is an instance of Graphics2D, which does support custom stroke geometry.

The things is teacher haven't taught me Graphics2D, so I'm not supposed to use it.

Then simply paint the larger triangle and then the smaller. If this isn't working, then you have an error in you calculation of the larger triangle, and you should edit your question to include a complete example.

I'm looking for a way to do it without Graphics2D…a guy has interpreted the question properly in this comment.

As @Marco13 observes, you need a triangle that is larger than the original one by the borderThickness. You can use AffineTransform to do the scaling. While Graphics can't fill() an arbitrary Shape, such as one created by AffineTransform, it can clip the rendering as required. In the example below, a unit triangle is translated and scaled to the center of an N x N panel; a copy is enlarged by delta. Note how rendering is clipped first to the larger background figure and then to the smaller foreground figure.

GraphicsBorder

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @see https://stackoverflow.com/a/39812618/230513
 */
public class GraphicsBorder {

    private static class GraphicsPanel extends JPanel {

        private static final int N = 256;
        private static final Color FILL = new Color(0x990099);
        private static final Color BORDER = new Color(0x66FFB2);
        private final Shape fore;
        private final Shape back;

        public GraphicsPanel(Polygon polygon, int delta) {
            AffineTransform a1 = new AffineTransform();
            a1.translate(N / 2, N / 2);
            a1.scale(N / 3, N / 3);
            fore = a1.createTransformedShape(polygon);
            AffineTransform a2 = new AffineTransform();
            a2.translate(N / 2, N / 2 - delta / 3);
            a2.scale(N / 3 + delta, N / 3 + delta);
            back = a2.createTransformedShape(polygon);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(BORDER);
            g.setClip(back);
            g.fillRect(0, 0, N, N);
            g.setColor(FILL);
            g.setClip(fore);
            g.fillRect(0, 0, N, N);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(N, N);
        }
    }

    private void display() {
        JFrame f = new JFrame("GraphicsBorder");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Polygon p = new Polygon();
        p.addPoint(0, -1);
        p.addPoint(1, 1);
        p.addPoint(-1, 1);
        f.add(new GraphicsPanel(p, 16));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new GraphicsBorder()::display);
    }
}

Upvotes: 1

Related Questions