如何使用线条填充三角形?
How to fill a triangle using lines?
我正在尝试使用水平线填充三角形,但我无法弄清楚我当前的方法有什么问题。在有人说只使用 fillPolygon 之前,我不能使用它。我需要用线来填充它。
它似乎在某些情况下工作正常,而在其他情况下则完全崩溃。
应该是这样的。但是后来我尝试将我的方法应用于旋转的 3D 立方体并且...
我不知道出了什么问题。另外,红色边框也是我的三角形方法之一。这些工作完美,填充三角形和轮廓三角形输入了相同的顶点。
public void filledTri(int x1,int y1,int x2,int y2,int x3,int y3){
int[] xs = {x1,x2,x3};
int[] ys = {y1,y2,y3};
//Sort vertices in vertical order so A/1 is highest and C/3 is lowest
int I,tempx,tempy;
for(int i=1;i<3;i++){
I = i-1;
tempx = xs[i];
tempy = ys[i];
while(I>=0&&tempy<ys[I]){
xs[I+1] = xs[I];
ys[I+1] = ys[I];
I--;
}
xs[I+1] = tempx;
ys[I+1] = tempy;
}
//Set left and right edges
linepts ab = new linepts(xs[0],ys[0],xs[1],ys[1]),
ac = new linepts(xs[0],ys[0],xs[2],ys[2]);
linepts[] lines = {ab.getEndX() < ac.getEndX() ? ab : ac,
ab.getEndX() > ac.getEndX() ? ab : ac,
new linepts(xs[1],ys[1],xs[2],ys[2])};
//Fill triangle
int startY = ys[0],endY = ys[2];
for(int y=startY;y<=endY;y++){
if(y>ys[1])
horizontalLine((int)Math.round(lines[2].getX(y)),
y,
(int)Math.round(lines[1].getX(y)));
else
horizontalLine((int)Math.round(lines[0].getX(y)),
y,
(int)Math.round(lines[1].getX(y)));
}
getX(int y) 获取直线穿过 y 值的 x 坐标。如果它是一条水平线,它只是 returns 线的起点 x
A点屏幕最高值最低,B点居中,C点屏幕最低值最高
如果有帮助,我正在使用 jframe 上的缓冲图像来绘制它。
我没有仔细检查你的代码,但我可以告诉你,你并不总是加入相关方面的交集。
您可以进行如下操作:
对于给定的扫描线(一些Y
),
比较三个边的端点坐标成对(Y0-Y1
,Y1-Y2
,Y2-Y0
),
将有零条或两条横跨Y
;使用条件 (Yi > Y) != (Yi+1 > Y)
(索引对 3 取模),不使用其他条件,
对于横跨 Y
的边,计算交点。
您将从 min(Y0, Y1, Y2)
扫描到 max(Y0, Y1, Y2)
,每次都加入两个路口。
我在 Software Renderer tutorial. It is explained in this and this 集中看过你在做什么。
他所做的是扫描最长的时间以获取该行上的每个像素,它存储最小 X 值和最大 X 值(由其他 2 行给出)。他最初是为特定的三角形制作的,但后来他升级了代码以接受通用三角形。
这是一个很好的图表来解释:
我假设您遇到的情况是因为将 3D 三角形投影到 2D 三角形(裁剪、三角形获得无限坐标,或者因为您的程序不能很好地处理空三角形。
一种方法是在图像上绘制线条,然后在 TexturePaint
中使用该图像填充 Shape
(本例中为三角形)。
它可能看起来像这样:(如果您使用包含一条红线的单个图像,将其放在随机的 BG 颜色上,并使用平滑的 1.5 像素描边将形状本身绘制为蓝色)。
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.*;
public class LinesFillShape {
private JComponent ui = null;
LinesFillShape() {
initUI();
}
public final void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(new JLabel(new ImageIcon(getImage())));
}
private void drawPolygon(Graphics2D g, int sz, Random r) {
int[] xpoints = {
r.nextInt(sz), r.nextInt(sz), r.nextInt(sz)
};
int[] ypoints = {
r.nextInt(sz), r.nextInt(sz), r.nextInt(sz)
};
Polygon p = new Polygon(xpoints, ypoints, 3);
Color bg = new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255));
g.setColor(bg);
g.fill(p);
g.setPaint(
new TexturePaint(getTexture(),
new Rectangle2D.Double(0, 0, 8, 8)));
g.fill(p);
g.setStroke(new BasicStroke(1.5f));
g.setColor(Color.BLUE);
g.draw(p);
}
private BufferedImage getImage() {
int sz = 600;
BufferedImage bi = new BufferedImage(sz, sz, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Random r = new Random();
drawPolygon(g, sz, r);
drawPolygon(g, sz, r);
drawPolygon(g, sz, r);
g.dispose();
return bi;
}
private BufferedImage getTexture() {
BufferedImage bi = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.setColor(Color.RED);
// TODO: something more interesting here..
g.drawLine(0, 0, 0, 8);
g.dispose();
return bi;
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
LinesFillShape o = new LinesFillShape();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
我正在尝试使用水平线填充三角形,但我无法弄清楚我当前的方法有什么问题。在有人说只使用 fillPolygon 之前,我不能使用它。我需要用线来填充它。 它似乎在某些情况下工作正常,而在其他情况下则完全崩溃。
应该是这样的。但是后来我尝试将我的方法应用于旋转的 3D 立方体并且...
我不知道出了什么问题。另外,红色边框也是我的三角形方法之一。这些工作完美,填充三角形和轮廓三角形输入了相同的顶点。
public void filledTri(int x1,int y1,int x2,int y2,int x3,int y3){
int[] xs = {x1,x2,x3};
int[] ys = {y1,y2,y3};
//Sort vertices in vertical order so A/1 is highest and C/3 is lowest
int I,tempx,tempy;
for(int i=1;i<3;i++){
I = i-1;
tempx = xs[i];
tempy = ys[i];
while(I>=0&&tempy<ys[I]){
xs[I+1] = xs[I];
ys[I+1] = ys[I];
I--;
}
xs[I+1] = tempx;
ys[I+1] = tempy;
}
//Set left and right edges
linepts ab = new linepts(xs[0],ys[0],xs[1],ys[1]),
ac = new linepts(xs[0],ys[0],xs[2],ys[2]);
linepts[] lines = {ab.getEndX() < ac.getEndX() ? ab : ac,
ab.getEndX() > ac.getEndX() ? ab : ac,
new linepts(xs[1],ys[1],xs[2],ys[2])};
//Fill triangle
int startY = ys[0],endY = ys[2];
for(int y=startY;y<=endY;y++){
if(y>ys[1])
horizontalLine((int)Math.round(lines[2].getX(y)),
y,
(int)Math.round(lines[1].getX(y)));
else
horizontalLine((int)Math.round(lines[0].getX(y)),
y,
(int)Math.round(lines[1].getX(y)));
}
getX(int y) 获取直线穿过 y 值的 x 坐标。如果它是一条水平线,它只是 returns 线的起点 x
A点屏幕最高值最低,B点居中,C点屏幕最低值最高
如果有帮助,我正在使用 jframe 上的缓冲图像来绘制它。
我没有仔细检查你的代码,但我可以告诉你,你并不总是加入相关方面的交集。
您可以进行如下操作:
对于给定的扫描线(一些Y
),
比较三个边的端点坐标成对(
Y0-Y1
,Y1-Y2
,Y2-Y0
),将有零条或两条横跨
Y
;使用条件(Yi > Y) != (Yi+1 > Y)
(索引对 3 取模),不使用其他条件,对于横跨
Y
的边,计算交点。
您将从 min(Y0, Y1, Y2)
扫描到 max(Y0, Y1, Y2)
,每次都加入两个路口。
我在 Software Renderer tutorial. It is explained in this and this 集中看过你在做什么。
他所做的是扫描最长的时间以获取该行上的每个像素,它存储最小 X 值和最大 X 值(由其他 2 行给出)。他最初是为特定的三角形制作的,但后来他升级了代码以接受通用三角形。
这是一个很好的图表来解释:
我假设您遇到的情况是因为将 3D 三角形投影到 2D 三角形(裁剪、三角形获得无限坐标,或者因为您的程序不能很好地处理空三角形。
一种方法是在图像上绘制线条,然后在 TexturePaint
中使用该图像填充 Shape
(本例中为三角形)。
它可能看起来像这样:(如果您使用包含一条红线的单个图像,将其放在随机的 BG 颜色上,并使用平滑的 1.5 像素描边将形状本身绘制为蓝色)。
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.*;
public class LinesFillShape {
private JComponent ui = null;
LinesFillShape() {
initUI();
}
public final void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(new JLabel(new ImageIcon(getImage())));
}
private void drawPolygon(Graphics2D g, int sz, Random r) {
int[] xpoints = {
r.nextInt(sz), r.nextInt(sz), r.nextInt(sz)
};
int[] ypoints = {
r.nextInt(sz), r.nextInt(sz), r.nextInt(sz)
};
Polygon p = new Polygon(xpoints, ypoints, 3);
Color bg = new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255));
g.setColor(bg);
g.fill(p);
g.setPaint(
new TexturePaint(getTexture(),
new Rectangle2D.Double(0, 0, 8, 8)));
g.fill(p);
g.setStroke(new BasicStroke(1.5f));
g.setColor(Color.BLUE);
g.draw(p);
}
private BufferedImage getImage() {
int sz = 600;
BufferedImage bi = new BufferedImage(sz, sz, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Random r = new Random();
drawPolygon(g, sz, r);
drawPolygon(g, sz, r);
drawPolygon(g, sz, r);
g.dispose();
return bi;
}
private BufferedImage getTexture() {
BufferedImage bi = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.setColor(Color.RED);
// TODO: something more interesting here..
g.drawLine(0, 0, 0, 8);
g.dispose();
return bi;
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
LinesFillShape o = new LinesFillShape();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}