Java Graphics.fillPolygon:如何同时渲染右边缘和下边缘?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7701097/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 21:03:22  来源:igfitidea点击:

Java Graphics.fillPolygon: How to also render right and bottom edges?

javagraphicspolygongraphics2dedges

提问by Timothy Miller

When drawing polygons, Java2D leaves off the right and bottom edges. I understand why this is done. However, I would like to draw something that includes those edges. One thing that occurred to me was to follow fillPolygonwith drawPolygonwith the same coordinates, but this appears to leave a gap. (See the little triangular image at the bottom.) There are two possibilities, but I can't tell which. To enable antialiasing, I'm doing this:

绘制多边形时,Java2D 会保留右侧和底部边缘。我明白为什么要这样做。但是,我想画一些包含这些边缘的东西。这发生在我身上的一件事是遵循fillPolygondrawPolygon具有相同的坐标,但是这似乎留下一个缺口。(见底部的小三角形图像。)有两种可能性,但我不知道是哪一种。为了启用抗锯齿,我这样做:

renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
                  RenderingHints.VALUE_ANTIALIAS_ON);
renderHints.put(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(renderHints);

One possibility is that the antialiasing is not being done on the alpha channel, so the gap is caused by overdraw. In that case, if the alpha channel were what was being antialiased, the edges would abut properly. The other possibility is that there is just a gap here.

一种可能性是在 alpha 通道上没有进行抗锯齿处理,因此间隙是由过度绘制引起的。在这种情况下,如果 alpha 通道是被抗锯齿的通道,边缘就会正确地邻接。另一种可能是这里只是有一个缺口。

How can I fix this?

我怎样才能解决这个问题?

Also, I'm not sure, but it appears that the polygon outline may actually be TOO BIG. That is, it may be going further out than the right and bottom edges that I want to include.

另外,我不确定,但看起来多边形轮廓实际上可能太大了。也就是说,它可能比我想要包含的右侧和底部边缘更远。

Thanks.

谢谢。

enter image description here

在此处输入图片说明

-- UPDATE --

- 更新 -

Based on a very nice suggestion by Hovercraft Full of Eels, I have made a compilable example:

基于 Hovercraft Full of Eels 的一个非常好的建议,我做了一个可编译的例子:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

public class polygon {
   private static final int WIDTH = 20;

   public static void main(String[] args) {
      BufferedImage img = new BufferedImage(WIDTH, WIDTH, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      int[] xPoints = {WIDTH / 3, (2*WIDTH) / 3, WIDTH / 3};
      int[] yPoints = {0, WIDTH / 2, WIDTH};
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setColor(Color.green);
      g2.drawLine(0, WIDTH-1, WIDTH, WIDTH-1);
      g2.drawLine(0, 0, WIDTH, 0);
      g2.drawLine(WIDTH/3, 0, WIDTH/3, WIDTH);
      g2.drawLine((2*WIDTH/3), 0, (2*WIDTH/3), WIDTH);
      g2.setColor(Color.black);
      g2.drawPolygon(xPoints, yPoints, xPoints.length);
      g2.setColor(Color.black);
      g2.fillPolygon(xPoints, yPoints, xPoints.length);
      g2.dispose();

      ImageIcon icon = new ImageIcon(img);
      JLabel label = new JLabel(icon);

      JOptionPane.showMessageDialog(null, label);
   }
}

If you leave the filled polygon red, you get the image below (zoomed by 500%), which shows that the polygon does not extend all the way to the right edge. That is, the vertical green line is corresponds to x=(2*WIDTH)/2, and although the red polygon includes that coordinate, it does not paint any pixels there.

如果将填充的多边形保留为红色,则会得到下图(放大 500%),这表明多边形并未一直延伸到右边缘。也就是说,垂直绿线对应于x=(2*WIDTH)/2,虽然红色多边形包含该坐标,但它并未在那里绘制任何像素。

enter image description here

在此处输入图片说明

To see the gap problem, I changed redin the program to black. In this image, you can see a subtle gap on the lower right side, where the outline drawn by drawPolygondoes not quite meet up with what was drawn with fillPolygon.

为了看gap问题,我red在程序里改成black. 在这张图片中,您可以看到右下方有一个细微的差距,其中由 绘制的轮廓与用 绘制的轮廓drawPolygon不太吻合fillPolygon

enter image description here

在此处输入图片说明

采纳答案by Hovercraft Full Of Eels

Show us your code for your drawing in a simple compilable runnable program. For instance when I try to imitate your image and used RenderingHints, it seemed to produce an appropriate sized image with complete right/bottom edges:

在一个简单的可编译可运行程序中向我们展示您的绘图代码。例如,当我尝试模仿您的图像并使用 RenderingHints 时,它似乎生成了具有完整右/下边缘的适当大小的图像:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Foo002 {
   private static final int WIDTH = 20;

   public static void main(String[] args) {
      BufferedImage img = new BufferedImage(WIDTH, WIDTH,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      int[] xPoints = { WIDTH / 3, (2 * WIDTH) / 3, WIDTH / 3 };
      int[] yPoints = { 0, WIDTH / 2, WIDTH };
      g2.setColor(Color.black);
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setRenderingHint(RenderingHints.KEY_RENDERING,
            RenderingHints.VALUE_RENDER_QUALITY);
      g2.fillPolygon(xPoints, yPoints, xPoints.length);
      g2.dispose();

      ImageIcon icon = new ImageIcon(img);
      JLabel label = new JLabel(icon);
      label.setBorder(BorderFactory.createLineBorder(Color.black));
      JPanel panel = new JPanel();
      panel.add(label);

      JOptionPane.showMessageDialog(null, panel);
   }
}

If you can show us a similar program that reproduces your problem, then we can give you better help.

如果您可以向我们展示一个类似的程序来重现您的问题,那么我们可以为您提供更好的帮助。

回答by trashgod

I like the convenience of ImageIcon, shown by @HFOE, but this variation may make it a little easier to see what's happening. From the GraphicsAPI,

我喜欢ImageIcon@HFOE 显示的 便利性,但这种变化可能会让您更容易了解正在发生的事情。从GraphicsAPI,

Operations that draw the outline of a figure operate by traversing an infinitely thin path between pixels with a pixel-sized pen that hangs down and to the right of the anchor point on the path. Operations that fill a figure operate by filling the interior of that infinitely thin path.

绘制图形轮廓的操作通过使用垂悬在路径上的锚点右侧的像素大小的笔遍历像素之间的无限细路径来操作。填充图形的操作通过填充无限细路径的内部来操作。

In contrast, Graphics2Dmust follow more complex rules for antialiasing, which allow it to "draw outside the lines."

相比之下,Graphics2D必须遵循更复杂的抗锯齿规则,这允许它“在线条之外绘制”。

PixelView

像素视图

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @see http://stackoverflow.com/questions/7701097 */
public class PixelView extends JPanel {

    private static final int SIZE = 20;
    private static final int SCALE = 16;
    private BufferedImage img;

    public PixelView(Color fill) {
        this.setBackground(Color.white);
        this.setPreferredSize(new Dimension(SCALE * SIZE, SCALE * SIZE));
        img = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        int[] xPoints = {SIZE / 3, (2 * SIZE) / 3, SIZE / 3};
        int[] yPoints = {0, SIZE / 2, SIZE};
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.green);
        g2.drawLine(0, SIZE - 1, SIZE, SIZE - 1);
        g2.drawLine(0, 0, SIZE, 0);
        g2.drawLine(SIZE / 3, 0, SIZE / 3, SIZE);
        g2.drawLine((2 * SIZE / 3), 0, (2 * SIZE / 3), SIZE);
        g2.setColor(Color.black);
        g2.drawPolygon(xPoints, yPoints, xPoints.length);
        g2.setColor(fill);
        g2.fillPolygon(xPoints, yPoints, xPoints.length);
        g2.dispose();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
    }

    private static void display() {
        JFrame f = new JFrame("PixelView");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(new GridLayout(1, 0));
        f.add(new PixelView(Color.black));
        f.add(new PixelView(Color.red));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                display();
            }
        });
    }
}