javaswinggraphicsshapesdrawstring

Draw a String with a specific angle degree in line


I'm drawing a graph with two points of each point having a line with a weight.

for example graph: point "15" to point "16" line with the weight of 1.872 and point "16" to point "15" with the weight of 1.567.

take a look at my graph for now:

enter image description here

I want to draw a String with always parallel (adjacent) to the line.

I calculated the slope for the straight and the angel I did calculate is the arctan of this slope:

I had use this function to rotate the string:

public static void drawRotate(Graphics2D g2d, double x, double y, double angle, String text) {
    g2d.translate((float)x,(float)y);
    g2d.rotate(Math.toRadians(angle));
    g2d.drawString(text,0,0);
    g2d.rotate(-Math.toRadians(angle));
    g2d.translate(-(float)x,-(float)y);
}

With the angle of arctan((y2-y1)/(x2-x1)= the slope of the line ) and it didn't work well.

How can I rotate this String to run parallel always to the line I draw?

My goal: Draw the String like this example

enter image description here


Solution

  • Here is a quick demo to be used as a guide on how it might be done. I omitted some things like the arrowheads since that is just busy work. And I guesstimated on the label positions. I would recommend you read about the three argument version of Graphics.rotate() and RenderingHints and anti-aliasing to smooth the lines.

    You may want to write general methods to facilitate positioning the text and labels based on font size.

    But I believe your primary problem was doing int division when calculating the slope.

    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class GraphicsExample extends JPanel {
        JFrame f = new JFrame("Draw Vector");
        final static int WIDTH = 500;
        final static int HEIGHT = 500;
        String A = "1.567 [B->A]";
        String B = "1.862 [A->B]";
        public static void main(String[] args) {
            SwingUtilities.invokeLater(()-> new GraphicsExample().start());
        }
        public void start() {
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(this);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
        public Dimension getPreferredSize() {
            return new Dimension(WIDTH, HEIGHT);
        }
        
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            int x1= 50;int y1 = 400;
            int x2 = 400; int y2 = 200;
            // copy the graphics context.
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            int diameter = 20;
            drawLine(g2d,x1+diameter/2, y1+diameter/2, x2+diameter/2, y2+diameter/2);
            g2d.setFont(new Font("Arial", Font.PLAIN, 18));
            drawEndPoint(g2d,x1,y1, diameter, "A");
            drawEndPoint(g2d,x2,y2, diameter, "B");
            double angle = Math.atan((double)(y1-y2)/(x1-x2));
            g2d.rotate(angle,x1,y1);
            
            // based on font, this computes the placement of the Strings
            FontMetrics fm = g2d.getFontMetrics();
            int width = SwingUtilities.computeStringWidth(fm, A); // use for both
            g2d.setColor(Color.black);
            g2d.drawString(A, x1 + ((x2-x1) - width)/2, y1);
            g2d.drawString(B, x1 + ((x2-x1) - width)/2, y1+ 30);
            // discard the context.
            g2d.dispose();
        }
        
        public void drawEndPoint(Graphics2D g2d, int x, int y, int diameter, String label) {
            
            g2d.setColor(Color.BLUE);
            g2d.drawString(label, x, y);
            g2d.fillOval(x,y,diameter, diameter);
            g2d.setColor(Color.RED);
            g2d.setStroke(new BasicStroke(2f));
            g2d.drawOval(x,y,diameter, diameter);
        }
        public void drawLine(Graphics2D g2d, int x1, int y1, int x2, int y2) {
            g2d.setColor(Color.RED);
            g2d.setStroke(new BasicStroke(3f));
            g2d.drawLine(x1,y1,x2,y2);
        }
    }
    

    Shows

    enter image description here