用Java AWT在圆圈中绘制文本(字母的方向应相应)
我正在尝试使用JavaAWT和用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
仿射函数在一个圆圈中绘制一个给定的字符串,其中字母也会沿着圆圈上下颠倒
我从开始时的代码开始,将文本单独绘制成曲线。
我还使用了来自的坐标计算来绘制模拟时钟的数字
下面是我的代码。老实说,为了修复我的代码,我不完全理解这些方法是如何工作的。我一直在尝试尝试使用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);