Как нарисовать полукруглый текст с помощью Java Graphics2D? - PullRequest
0 голосов
/ 09 января 2019

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

1 Ответ

0 голосов
/ 10 января 2019

Хитрость в том, чтобы использовать 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);
...