Как нарисовать полукруглый текст с помощью Java Graphics2D?

Я хочу нарисовать текст вокруг верхней половины круга с помощью Java Graphics2D. Это можно использовать в Swing, но на самом деле я хочу, чтобы он рисовал круглый логотип в SVG с помощью Apache Batik.


person Guy Smith    schedule 09.01.2019    source источник
comment
Начните с рисования геометрических примитивов   -  person MadProgrammer    schedule 09.01.2019
comment
Возможный дубликат Рисование срезов круга в java? ; Попытка нарисовать дугу с помощью Java   -  person MadProgrammer    schedule 09.01.2019


Ответы (1)


Уловка заключается в использовании GlyphVector. Каждую букву нужно индивидуально перемещать и вращать.

public class HalfCircleDemo {

    @SuppressWarnings("serial")
    private static class DemoPanel extends JPanel { 

        public void paintComponent(Graphics g) {
            super.paintComponent(g);       
            Graphics2D graphics = (Graphics2D) g ; 
            graphics.setPaint(Color.yellow);
            graphics.fill(new Rectangle(0, 0, 100, 100));
            graphics.fill(new Rectangle(100, 100, 200, 200));
            graphics.setPaint(Color.BLACK);
            { /* THIS IS THE SECTION THAT DOES THE WORK  *******************************************/ 
                Font font = graphics.getFont(); 
                FontRenderContext frc = graphics.getFontRenderContext(); 
                GlyphVector glyphVector = font.createGlyphVector(frc, str); 
                int glyphCount = str.length(); 
                int radius = 50 ;
                for (int i=0 ; i<glyphCount ; i++) { 
                    double theta = Math.PI * i / (double) (glyphCount); 
                    AffineTransform transform = AffineTransform.getRotateInstance(theta-halfPi); 
                    Point2D.Double offset = new Point2D.Double(-radius*Math.cos(theta), -radius*Math.sin(theta)); 
                    glyphVector.setGlyphTransform(i, transform);
                    glyphVector.setGlyphPosition(i, offset);
                }
                graphics.drawGlyphVector(glyphVector, 100,  100);
            } /* ***********************************************************************************/ 
        }

        private static final String str = "Hello World, Hello World" ;
        private static final double halfPi = Math.PI / 2 ;

        public DemoPanel() {
            setBorder(BorderFactory.createLineBorder(Color.black));
        }

        public Dimension getPreferredSize() {
            return new Dimension(250,200);
        }  
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame f = new JFrame("Half-circle text demo");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new DemoPanel());
                f.pack();
                f.setVisible(true); 
            }
        });
    }
}

Есть некоторые проблемы с версткой. Они исправлены в разделе кода ниже. Во-первых, в приведенном ниже коде, поскольку текст изначально правильно расположен (разумный межбуквенный интервал) в GlyphVector, мы используем межбуквенные интервалы GlyphVector. Во-вторых, последняя буква должна быть повернута на 180 градусов, чтобы она лежала ровно, но ее положение должно быть меньше 180 (иначе она была бы ниже середины круга). Итак, мы вычисляем две немного разные тэты. В-третьих, мы вычисляем радиус так, чтобы диаметр полукруга был примерно равен длине исходного текста.

        Font font = graphics.getFont(); 
        FontRenderContext frc = graphics.getFontRenderContext(); 
        GlyphVector glyphVector = font.createGlyphVector(frc, str); 
        int glyphCount = str.length(); 
        double pixelLength = glyphVector.getPixelBounds(frc, 0, 0).width ; 
        double pixelLengthShort = glyphVector.getGlyphPosition(glyphCount-1).getX(); 
        double radius = pixelLength / Math.PI ;
        double halfPi = Math.PI / 2 ;
        for (int i=0 ; i<glyphCount ; i++) { 
            double glyphLinearOffset = glyphVector.getGlyphPosition(i).getX();
            double thetaRotation = Math.PI * glyphLinearOffset / (pixelLengthShort); 
            double thetaPosition = Math.PI * glyphLinearOffset / (pixelLength); 
            AffineTransform transform = AffineTransform.getRotateInstance(thetaRotation-halfPi); 
            Point2D.Double offsetVector = new Point2D.Double(-radius*Math.cos(thetaPosition), -radius*Math.sin(thetaPosition)); 
            glyphVector.setGlyphTransform(i, transform);
            glyphVector.setGlyphPosition(i, offsetVector);
        }
        graphics.drawGlyphVector(glyphVector, 100,  100);
person Guy Smith    schedule 09.01.2019