用Java AWT在圆圈中绘制文本(字母的方向应相应)

用Java AWT在圆圈中绘制文本(字母的方向应相应),java,text,geometry,awt,affinetransform,Java,Text,Geometry,Awt,Affinetransform,我正在尝试使用JavaAWT和仿射函数在一个圆圈中绘制一个给定的字符串,其中字母也会沿着圆圈上下颠倒 我从开始时的代码开始,将文本单独绘制成曲线。 我还使用了来自的坐标计算来绘制模拟时钟的数字 下面是我的代码。老实说,为了修复我的代码,我不完全理解这些方法是如何工作的。我一直在尝试尝试使用coords和theta值 import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.Grap

我正在尝试使用JavaAWT和
仿射函数
在一个圆圈中绘制一个给定的字符串,其中字母也会沿着圆圈上下颠倒

我从开始时的代码开始,将文本单独绘制成曲线。
我还使用了来自的坐标计算来绘制模拟时钟的数字

下面是我的代码。老实说,为了修复我的代码,我不完全理解这些方法是如何工作的。我一直在尝试尝试使用
coords
theta

import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;

public class Main extends Panel {
  public static void main(String[] args){
    Frame f = new Frame("Circle Text");
    f.add(new Main());
    f.setSize(750, 750);
    f.setVisible(true);
  }

  private int[] getPointXY(int dist, double rad){
    int[] coord = new int[2];
    coord[0] = (int) (dist * Math.cos(rad) + dist);
    coord[1] = (int) (-dist * Math.sin(rad) + dist);
    return coord;
  }

  @Override
  public void paint(Graphics g){
    Graphics2D g2 = (Graphics2D) g;

    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);

    // Hard-coded for now, using 12 characters for 30 degrees angles (like  a clock)
    String text = "0123456789AB";

    Font font = new Font("Serif", 0, 25);
    FontRenderContext frc = g2.getFontRenderContext();
    g2.translate(200, 200); // Starting position of the text

    GlyphVector gv = font.createGlyphVector(frc, text);
    int length = gv.getNumGlyphs(); // Same as text.length()
    final double toRad = Math.PI / 180;
    for(int i = 0; i < length; i++){
      //Point2D p = gv.getGlyphPosition(i);
      int[] coords = getPointXY(100, -360 / length * i * toRad + Math.PI / 2);
      double theta = 2 * Math.PI / (length + 1) * i;
      AffineTransform at = AffineTransform.getTranslateInstance(coords[0], coords[1]);
      at.rotate(theta);
      Shape glyph = gv.getGlyphOutline(i);
      Shape transformedGlyph = at.createTransformedShape(glyph);
      g2.fill(transformedGlyph);
    }
  }
}

我现在确实有一个圆圈,所以这是一些东西,但不幸的是仍然有三个问题:

  • 第一个字符的起始位置是~4点钟,而不是顶部
  • 角色的顶部与圆圈中心的角度不正确
  • 字符串是逆时针而不是顺时针绘制的
最后一个问题很容易解决,方法是将旋转中的
-2
更改为
2

但是另外两个呢


编辑2:我误读了@MBo关于初始字形集的一小部分答案。它正在工作。与上面的编辑相比,此处生成的代码再次发生更改:

gv.setGlyphPosition(i, new Point(-length / 2, -length / 2));
AffineTransform at = AffineTransform.getTranslateInstance(coords[0], coords[1]);
at.rotate(2 * Math.PI * i / length);

虽然我仍然看到一些较大输入字符串的小问题,所以我将对此进行研究


EDIT3:已经有一段时间了,但我刚刚回到这个问题上,我发现了我对长度66测试用例的错误,我很容易尝试:
360
应该是
360d
,因为如果360不能被长度平均整除,那么
360/length
将使用整数除法。
我现在有了这个,它可以任意长度工作。请注意,该中心并不完全正确,@Mbo提供的答案可能会有所帮助。我唯一的目标是把文字圈起来(长度66)。它在屏幕上的位置和大小其实并不重要

int[] coords = this.getPointXY(r, -360.0 / length * i * toRad + Math.PI / 2);
  gv.setGlyphPosition(i, new Point(0, 0));
  AffineTransform at = AffineTransform.getTranslateInstance(coords[0], coords[1]);
  at.rotate(2 * Math.PI * i / length);
  at.translate(r * Math.cos(Math.PI / 2 - 2 * Math.PI * i / length),
      r * Math.sin(Math.PI / 2 - 2 * Math.PI * i / length));
  at.translate(-FONT_SIZE / 2, 0);

对于位置,初始角度为
Pi/2
,对于字形旋转,初始角度为
0
。 要正确设置旋转和位置,我建议:

  • 将图示符置于坐标原点(0,0)
  • 将其旋转
    -2*Math.PI*i/长度
  • 通过
    r*cos(Math.PI/2-2*Math.PI*i/length)
    r*sin(Math.PI/2-2*Math.PI*i/length)
  • 通过圆心坐标进行平移
步骤:

注意-旋转,然后移动

这种方法可能会产生好的但不是完美的结果。为了获得更好的外观,您可以添加第一步-将glyph平移一半大小,以提供围绕其中心的旋转。因此,顺序:

  • 移位-像素大小/2
  • 轮换
  • 移动到最终位置(相对于零,然后按圆心移动)

所以我使用
双θ=-360/length*I*toRad+Math.PI/2
用于
getPointXY(100,θ)
at.rotate(θ)
调用?如果是那样的话,我会得到。如何使用此θ计算轮廓旋转?另外,
getPointXY
坐标中的
dist
值是否会对计算产生影响,还是只是为了调整大小?Emm,我错了。Pi/2仅用于位置。我会详细说明的。我还是不太明白。我现在有一个圆圈,但仍然有很多问题,比如不同的起始位置和逆时针旋转。我已经对我的帖子进行了编辑,介绍了我是如何解释你答案中最重要的建议的。我将字形放在
0,0
,先旋转它,然后翻译它。编辑:通过将旋转中的
-2
更改为
2
,逆时针方向很容易固定。但是您将图示符放入
坐标中,然后进行零移位,而它必须接近0,0!啊,当然!。。现在我得到了一个几乎正确的结果,所以我只需要应用你答案的第二部分来纠正这个微小的变化。谢谢你。我会给你一个接受的分数或者如果我有任何其他问题。
int[] coords = this.getPointXY(r, -360.0 / length * i * toRad + Math.PI / 2);
  gv.setGlyphPosition(i, new Point(0, 0));
  AffineTransform at = AffineTransform.getTranslateInstance(coords[0], coords[1]);
  at.rotate(2 * Math.PI * i / length);
  at.translate(r * Math.cos(Math.PI / 2 - 2 * Math.PI * i / length),
      r * Math.sin(Math.PI / 2 - 2 * Math.PI * i / length));
  at.translate(-FONT_SIZE / 2, 0);