D.N*_*.N. 9 java drawing line affinetransform subpixel
我之前从未使用过Java绘图方法,所以我决定潜入并创建一个模拟时钟作为PoC.除了手之外,我画了一个钟面,包括刻度标记,分钟/小时.我使用简单的sin/cos计算来确定圆周线的位置.
但是,我注意到由于分钟刻度非常短,因此线条的角度看起来不对.我确定这是因为两者Graphics2D.drawLine()和Line2D.double()方法都无法以亚像素精度绘制.
我知道我可以画出来自中心的线条并用圆圈遮住它(以创建更长,更准确的线条),但这似乎是一种不那么优雅和昂贵的解决方案.我已经做过一些关于如何做到这一点的研究,但我遇到的最好的答案是使用一个AffineTransform.我假设我只能使用AffineTransformwith旋转,而不是必须执行超级采样.
这是以亚像素精度绘制的唯一/最佳方法吗?或者是否有更快的解决方案?
编辑:我已经设置RenderingHint的Graphics2D对象.
根据要求,这里有一些代码(没有完全优化,因为这只是一个PoC):
diameter = Math.max(Math.min(pnlOuter.getSize().getWidth(),
pnlOuter.getSize().getHeight()) - 2, MIN_DIAMETER);
for (double radTick = 0d; radTick < 360d; radTick += 6d) {
g2d.draw(new Line2D.Double(
(diameter / 2) + (Math.cos(Math.toRadians(radTick))) * diameter / 2.1d,
(diameter / 2) + (Math.sin(Math.toRadians(radTick))) * diameter / 2.1d,
(diameter / 2) + (Math.cos(Math.toRadians(radTick))) * diameter / 2.05d,
(diameter / 2) + (Math.sin(Math.toRadians(radTick))) * diameter / 2.05d));
} // End for(radTick)
Run Code Online (Sandbox Code Playgroud)
这是图纸的截图.可能有点难以看到,但是看59分钟的刻度线.它是完全垂直的.

Line2D.double()方法无法以子像素精度绘制.
错了,使用RenderingHints.VALUE_STROKE_PUREGraphics2D对象可以在形状上绘制"子像素"精度Line2D.
我假设我只能使用带旋转的AffineTransform,而不必执行超级采样.这是以亚像素精度绘制的唯一/最佳方法吗?或者是否有更快的解决方案?
我想你在这里错过了什么.Graphics2D对象已经拥有了AffineTransform它,它正在将它用于所有绘图操作及其廉价的性能.
但是要回复你的代码中缺少的东西 - 这是缺失的:
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
Run Code Online (Sandbox Code Playgroud)
下面是一个自包含的示例,生成此图片:

public static void main(String[] args) throws Exception {
final JFrame frame = new JFrame("Test");
frame.add(new JComponent() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
System.out.println(g2d.getTransform());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
double dia = Math.min(getWidth(), getHeight()) - 2;
for (int i = 0; i < 60 ; i++) {
double angle = 2 * Math.PI * i / 60;
g2d.draw(new Line2D.Double(
(dia / 2) + Math.cos(angle) * dia / 2.1d,
(dia / 2) + Math.sin(angle) * dia / 2.1d,
(dia / 2) + Math.cos(angle) * dia / 2.05d,
(dia / 2) + Math.sin(angle) * dia / 2.05d));
}
g2d.draw(new Ellipse2D.Double(1, 1, dia - 1, dia - 1));
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1679 次 |
| 最近记录: |