Java - 子像素线精度是否需要 AffineTransform?
我以前从未使用过 Java 绘图方法,因此我决定深入研究并创建一个模拟时钟作为 PoC。除了指针之外,我还画了一个钟面,其中包括分钟/小时的刻度线。我使用简单的正弦/余弦计算来确定圆周围直线的位置。
然而,我注意到由于分钟刻度线非常短,所以线条的角度看起来不对。我确信这是因为 Graphics2D.drawLine()
和 Line2D.double()
方法都无法以亚像素精度进行绘制。
我知道我可以绘制从中心开始的线条,然后用一个圆圈将其遮盖(以创建更长、更准确的线条),但这似乎是一个不优雅且成本高昂的解决方案。我已经对如何执行此操作进行了一些研究,但我遇到的最佳答案是使用 AffineTransform
。我假设我可以使用仅旋转的 AffineTransform,而不是必须执行超级采样。
这是唯一/最好的亚像素精度绘图方法吗?或者有可能更快的解决方案吗?
编辑:我已经为 Graphics2D
对象设置了 RenderingHint
。
根据要求,这里是一些代码(没有完全优化,因为这只是一个 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)
这是绘图的屏幕截图。可能有点难看,但看一下 59 分钟的刻度线。它是完全垂直的。
I've never worked with Java drawing methods before, so I decided to dive in and create an analog clock as a PoC. In addition to the hands, I draw a clock face that includes tick marks for minutes/hours. I use simple sin/cos calculations to determine the position of the lines around the circle.
However, I've noticed that since the minute tick-marks are very short, the angle of the lines looks wrong. I'm certain this is because both Graphics2D.drawLine()
and Line2D.double()
methods cannot draw with subpixel accuracy.
I know I can draw lines originating from the center and masking it out with a circle (to create longer, more accurate lines), but that seems like such an inelegant and costly solution. I've done some research on how to do this, but the best answer I've come across is to use an AffineTransform
. I assume I could use an AffineTransform
with rotation only, as opposed to having to perform a supersampling.
Is this the only/best method of drawing with sub-pixel accuracy? Or is there a potentially faster solution?
Edit: I am already setting a RenderingHint
to the Graphics2D
object.
As requested, here is a little bit of the code (not fully optimized as this was just a 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)
Here's a screenshot of the drawing. It may be somewhat difficult to see, but look at the tick mark for 59 minutes. It is perfectly vertical.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
错误,使用
RenderingHints.VALUE_STROKE_PURE
Graphics2D 对象可以使用形状
Line2D
绘制“子像素”精度。我认为你在这里错过了一些东西。 Graphics2D 对象已经拥有一个 AffineTransform 并将其用于所有绘图操作及其廉价的性能。
但是要告诉您代码中缺少的内容 - 缺少:
下面是一个生成此图片的独立示例:
Wrong, using
RenderingHints.VALUE_STROKE_PURE
the Graphics2D object can draw "subpixel" accuracy with the shapeLine2D
.I think you are missing somthing here. The Graphics2D object already holds a
AffineTransform
and it is using it for all drawing actions and its cheap performance wise.But to get back to you what is missing from your code - this is missing:
Below is a self contained example that produces this picture: