使用 Sutherland-Hodgman 算法时多边形裁剪不起作用
Polygon Clipping not working when using Sutherland-Hodgman Algorithm
我正在编写一个程序来创建一个形状像鱼的多边形并用绿色填充它。在 window 内有一些按钮可以移动这条鱼。我只想让 window 内的鱼部分可见,因此我试图实现 Sutherland-Hodgman 算法来执行此操作。
我不确定哪里出错了。我所知道的是,当我接触到 window 的边缘时,我最终会把线转到它们不应该去的地方。
例如:
第一张图是鱼碰到边缘之前,第二张是鱼碰到边缘的时候window:
这是我为实现多边形裁剪的 Sutherland-Hodgman 算法而编写的代码:
int left_most_edge, right_most_edge, scan = 0;
double wxl = 50, wxh = 362, wyl = 246, wyh = 62;
double[][] table = new double[4][200]; //2d array containing:
//[0][-] -> ymax, [1][-] -> ymin, [2][-] -> dx, [3][-] -> x
double[] px = {100, 150, 200, 210, 215, 205, 215, 210, 200, 150}; //contains all x coord.
double[] py = {125, 100, 120, 110, 115, 125, 135, 140, 130, 150}; //contains all y coord.
double[] xout = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
double[] yout = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int outnum;
double[] lastl = new double[2];
double[] lastr = new double[2];
double[] lastt = new double[2];
double[] lastb = new double[2];
boolean drawAgain = false;
public void clipPolygon(Graphics g, int number_entered_edges)
{//clips the polygon so only parts that are in the viewing window get filled
lastl[0] = px[number_entered_edges - 1];
lastl[1] = py[number_entered_edges - 1];
lastr[0] = wxl;
lastb[0] = wxl;
lastt[0] = wxl;
lastr[1] = wyl;
lastb[1] = wyl;
lastt[1] = wyl;
outnum = 0;
for (int i = 0; i < number_entered_edges; i++)
{
clipL(px[i], py[i]);
}//end for
outnum = 0;
for (int i = 0; i < number_entered_edges; i++)
{
clipL(px[i], py[i]);
}//end for
}//end clipPolygon
public void clipL(double x, double y)
{//clips from the left
if ((lastl[0] < wxl && wxl <= x) || (x <= wxl && wxl < lastl[0]))
{
System.out.println("Passed into clipR -> (" + wxl + ", " + ((((y - lastl[1]) * (wxl - x)) / x - lastl[0]) + y) + ")");
System.out.println(y + " - " + lastl[1] + " * " + "(" + wxl + " - " + x + ") / " + x + " - " + lastl[0] + " + " + y + ")");
clipR(wxl, ((((y - lastl[1]) * (wxl - x)) / x - lastl[0]) + y));
drawAgain = true;
}//end if
lastl[0] = x;
lastl[1] = y;
if (wxl < x)
clipR(x, y);
}//end clipL
public void clipR(double x, double y)
{//clips from the right
System.out.println("herro: " + x + ", " + y);
if ((x <= wxh && wxh < lastr[0]) || (lastr[0] < wxh && wxh <= x))
{
clipB(wxh, ((((y - lastr[1]) * (wxh - x)) / x - lastr[0]) + y));
drawAgain = true;
}//end if
lastr[0] = x;
lastr[1] = y;
if (x < wxh)
clipB(x, y);
}//end clipR
public void clipB(double x, double y)
{//clips from the bottom
if ((lastb[1] < wyl && wyl <= y) || (y <= wyl && wyl < lastb[1]))
{
clipT(((((x - lastb[0]) * (wyl - y)) / y - lastb[1]) + x), wyl);
drawAgain = true;
}//end if
lastb[0] = x;
lastb[1] = y;
if (wyl > y)
clipT(x, y);
}//end clipB
public void clipT(double x, double y)
{//clips from the top
if ((lastt[1] > wyh && wyh >= y) || y >= wyh && wyh > lastt[1])
{
store(((((x - lastt[0]) * (wyh - y)) / y - lastt[1]) + x), wyh);
drawAgain = true;
}//end if
lastt[0] = x;
lastt[1] = y;
if (wyh < y)
store(x, y);
}//end clipT
public void store(double x, double y)
{//stores the final coordinates after clipping
xout[outnum] = x;
yout[outnum] = y;
outnum++;
}//end store
public void drawMyPolygon(Graphics g)
{ //draws the polygon
g.setColor(Color.RED);
g.drawLine((int) px[0], (int) py[0], (int) px[1], (int) py[1]);
g.drawLine((int) px[1], (int) py[1], (int) px[2], (int) py[2]);
g.drawLine((int) px[2], (int) py[2], (int) px[3], (int) py[3]);
g.drawLine((int) px[3], (int) py[3], (int) px[4], (int) py[4]);
g.drawLine((int) px[4], (int) py[4], (int) px[5], (int) py[5]);
g.drawLine((int) px[5], (int) py[5], (int) px[6], (int) py[6]);
g.drawLine((int) px[6], (int) py[6], (int) px[7], (int) py[7]);
g.drawLine((int) px[7], (int) py[7], (int) px[8], (int) py[8]);
g.drawLine((int) px[8], (int) py[8], (int) px[9], (int) py[9]);
g.drawLine((int) px[9], (int) py[9], (int) px[0], (int) py[0]);
}//end drawMyPolygon
public void drawNewPolygon(Graphics g)
{ //draw a new polygon with the coordinates of the clipped polygon
g.setColor(Color.RED);
g.drawLine((int) xout[0], (int) yout[0], (int) xout[1], (int) yout[1]);
g.drawLine((int) xout[1], (int) yout[1], (int) xout[2], (int) yout[2]);
g.drawLine((int) xout[2], (int) yout[2], (int) xout[3], (int) yout[3]);
g.drawLine((int) xout[3], (int) yout[3], (int) xout[4], (int) yout[4]);
g.drawLine((int) xout[4], (int) yout[4], (int) xout[5], (int) yout[5]);
g.drawLine((int) xout[5], (int) yout[5], (int) xout[6], (int) yout[6]);
g.drawLine((int) xout[6], (int) yout[6], (int) xout[7], (int) yout[7]);
g.drawLine((int) xout[7], (int) yout[7], (int) xout[8], (int) yout[8]);
g.drawLine((int) xout[8], (int) yout[8], (int) xout[9], (int) yout[9]);
g.drawLine((int) xout[9], (int) yout[9], (int) xout[0], (int) yout[0]);
drawAgain = false;
}//end drawNewPolygon
public void drawMyHorizontalLine(Graphics g, int x1, int y, int x2)
{ //draws the line for filling
g.setColor(Color.GREEN);
g.drawLine(x1, y, x2, y);
}//end drawMyHorizontalLine
public void drawWindow(Graphics g)
{//draws the viewing window
g.setColor(Color.BLACK);
g.drawLine((int)wxl, (int)wyh, (int)wxl, (int)wyl);
g.drawLine((int)wxl, (int)wyh, (int)wxh, (int)wyh);
g.drawLine((int)wxl, (int)wyl, (int)wxh, (int)wyl);
g.drawLine((int)wxh, (int)wyh, (int)wxh, (int)wyl);
}//end drawWindow
@Override
public void paint(Graphics g)
{
super.paint(g);
//draw viewing window
drawWindow(g);
//initialize the edge table to all zeroes
initializeTable();
//clip the polygon
clipPolygon(g, 10);
System.out.println("Coordinates:");
System.out.println("(" + px[0] + ", " + py[0] + ")");
System.out.println("(" + px[1] + ", " + py[1] + ")");
System.out.println("(" + px[2] + ", " + py[2] + ")");
System.out.println("(" + px[3] + ", " + py[3] + ")");
System.out.println("(" + px[4] + ", " + py[4] + ")");
System.out.println("(" + px[5] + ", " + py[5] + ")");
System.out.println("(" + px[6] + ", " + py[6] + ")");
System.out.println("(" + px[7] + ", " + py[7] + ")");
System.out.println("(" + px[8] + ", " + py[8] + ")");
System.out.println("(" + px[9] + ", " + py[9] + ")");
System.out.println("\nStored:");
System.out.println("(" + xout[0] + ", " + yout[0] + ")");
System.out.println("(" + xout[1] + ", " + yout[1] + ")");
System.out.println("(" + xout[2] + ", " + yout[2] + ")");
System.out.println("(" + xout[3] + ", " + yout[3] + ")");
System.out.println("(" + xout[4] + ", " + yout[4] + ")");
System.out.println("(" + xout[5] + ", " + yout[5] + ")");
System.out.println("(" + xout[6] + ", " + yout[6] + ")");
System.out.println("(" + xout[7] + ", " + yout[7] + ")");
System.out.println("(" + xout[8] + ", " + yout[8] + ")");
System.out.println("(" + xout[9] + ", " + yout[9] + ")");
for (int i = 0; i < xout.length; i++)
System.out.println("outnum -> " + outnum);
//draw polygon with red outline
if (drawAgain)
{
fillMyPolygon(g, 10, 10);
drawNewPolygon(g);
}//end if
else
{
fillMyPolygon(g, 10, 10);
drawMyPolygon(g);
}//end else
//set buttons to visible
buttons();
}//end paint
如果您有任何想法或可能需要更多信息,请告诉我。谢谢
算法的问题很简单,就是缺少括号来分隔公式的不同部分,这些公式决定了剪裁线的新坐标。解决后效果很好
我正在编写一个程序来创建一个形状像鱼的多边形并用绿色填充它。在 window 内有一些按钮可以移动这条鱼。我只想让 window 内的鱼部分可见,因此我试图实现 Sutherland-Hodgman 算法来执行此操作。
我不确定哪里出错了。我所知道的是,当我接触到 window 的边缘时,我最终会把线转到它们不应该去的地方。
例如:
第一张图是鱼碰到边缘之前,第二张是鱼碰到边缘的时候window:
这是我为实现多边形裁剪的 Sutherland-Hodgman 算法而编写的代码:
int left_most_edge, right_most_edge, scan = 0;
double wxl = 50, wxh = 362, wyl = 246, wyh = 62;
double[][] table = new double[4][200]; //2d array containing:
//[0][-] -> ymax, [1][-] -> ymin, [2][-] -> dx, [3][-] -> x
double[] px = {100, 150, 200, 210, 215, 205, 215, 210, 200, 150}; //contains all x coord.
double[] py = {125, 100, 120, 110, 115, 125, 135, 140, 130, 150}; //contains all y coord.
double[] xout = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
double[] yout = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int outnum;
double[] lastl = new double[2];
double[] lastr = new double[2];
double[] lastt = new double[2];
double[] lastb = new double[2];
boolean drawAgain = false;
public void clipPolygon(Graphics g, int number_entered_edges)
{//clips the polygon so only parts that are in the viewing window get filled
lastl[0] = px[number_entered_edges - 1];
lastl[1] = py[number_entered_edges - 1];
lastr[0] = wxl;
lastb[0] = wxl;
lastt[0] = wxl;
lastr[1] = wyl;
lastb[1] = wyl;
lastt[1] = wyl;
outnum = 0;
for (int i = 0; i < number_entered_edges; i++)
{
clipL(px[i], py[i]);
}//end for
outnum = 0;
for (int i = 0; i < number_entered_edges; i++)
{
clipL(px[i], py[i]);
}//end for
}//end clipPolygon
public void clipL(double x, double y)
{//clips from the left
if ((lastl[0] < wxl && wxl <= x) || (x <= wxl && wxl < lastl[0]))
{
System.out.println("Passed into clipR -> (" + wxl + ", " + ((((y - lastl[1]) * (wxl - x)) / x - lastl[0]) + y) + ")");
System.out.println(y + " - " + lastl[1] + " * " + "(" + wxl + " - " + x + ") / " + x + " - " + lastl[0] + " + " + y + ")");
clipR(wxl, ((((y - lastl[1]) * (wxl - x)) / x - lastl[0]) + y));
drawAgain = true;
}//end if
lastl[0] = x;
lastl[1] = y;
if (wxl < x)
clipR(x, y);
}//end clipL
public void clipR(double x, double y)
{//clips from the right
System.out.println("herro: " + x + ", " + y);
if ((x <= wxh && wxh < lastr[0]) || (lastr[0] < wxh && wxh <= x))
{
clipB(wxh, ((((y - lastr[1]) * (wxh - x)) / x - lastr[0]) + y));
drawAgain = true;
}//end if
lastr[0] = x;
lastr[1] = y;
if (x < wxh)
clipB(x, y);
}//end clipR
public void clipB(double x, double y)
{//clips from the bottom
if ((lastb[1] < wyl && wyl <= y) || (y <= wyl && wyl < lastb[1]))
{
clipT(((((x - lastb[0]) * (wyl - y)) / y - lastb[1]) + x), wyl);
drawAgain = true;
}//end if
lastb[0] = x;
lastb[1] = y;
if (wyl > y)
clipT(x, y);
}//end clipB
public void clipT(double x, double y)
{//clips from the top
if ((lastt[1] > wyh && wyh >= y) || y >= wyh && wyh > lastt[1])
{
store(((((x - lastt[0]) * (wyh - y)) / y - lastt[1]) + x), wyh);
drawAgain = true;
}//end if
lastt[0] = x;
lastt[1] = y;
if (wyh < y)
store(x, y);
}//end clipT
public void store(double x, double y)
{//stores the final coordinates after clipping
xout[outnum] = x;
yout[outnum] = y;
outnum++;
}//end store
public void drawMyPolygon(Graphics g)
{ //draws the polygon
g.setColor(Color.RED);
g.drawLine((int) px[0], (int) py[0], (int) px[1], (int) py[1]);
g.drawLine((int) px[1], (int) py[1], (int) px[2], (int) py[2]);
g.drawLine((int) px[2], (int) py[2], (int) px[3], (int) py[3]);
g.drawLine((int) px[3], (int) py[3], (int) px[4], (int) py[4]);
g.drawLine((int) px[4], (int) py[4], (int) px[5], (int) py[5]);
g.drawLine((int) px[5], (int) py[5], (int) px[6], (int) py[6]);
g.drawLine((int) px[6], (int) py[6], (int) px[7], (int) py[7]);
g.drawLine((int) px[7], (int) py[7], (int) px[8], (int) py[8]);
g.drawLine((int) px[8], (int) py[8], (int) px[9], (int) py[9]);
g.drawLine((int) px[9], (int) py[9], (int) px[0], (int) py[0]);
}//end drawMyPolygon
public void drawNewPolygon(Graphics g)
{ //draw a new polygon with the coordinates of the clipped polygon
g.setColor(Color.RED);
g.drawLine((int) xout[0], (int) yout[0], (int) xout[1], (int) yout[1]);
g.drawLine((int) xout[1], (int) yout[1], (int) xout[2], (int) yout[2]);
g.drawLine((int) xout[2], (int) yout[2], (int) xout[3], (int) yout[3]);
g.drawLine((int) xout[3], (int) yout[3], (int) xout[4], (int) yout[4]);
g.drawLine((int) xout[4], (int) yout[4], (int) xout[5], (int) yout[5]);
g.drawLine((int) xout[5], (int) yout[5], (int) xout[6], (int) yout[6]);
g.drawLine((int) xout[6], (int) yout[6], (int) xout[7], (int) yout[7]);
g.drawLine((int) xout[7], (int) yout[7], (int) xout[8], (int) yout[8]);
g.drawLine((int) xout[8], (int) yout[8], (int) xout[9], (int) yout[9]);
g.drawLine((int) xout[9], (int) yout[9], (int) xout[0], (int) yout[0]);
drawAgain = false;
}//end drawNewPolygon
public void drawMyHorizontalLine(Graphics g, int x1, int y, int x2)
{ //draws the line for filling
g.setColor(Color.GREEN);
g.drawLine(x1, y, x2, y);
}//end drawMyHorizontalLine
public void drawWindow(Graphics g)
{//draws the viewing window
g.setColor(Color.BLACK);
g.drawLine((int)wxl, (int)wyh, (int)wxl, (int)wyl);
g.drawLine((int)wxl, (int)wyh, (int)wxh, (int)wyh);
g.drawLine((int)wxl, (int)wyl, (int)wxh, (int)wyl);
g.drawLine((int)wxh, (int)wyh, (int)wxh, (int)wyl);
}//end drawWindow
@Override
public void paint(Graphics g)
{
super.paint(g);
//draw viewing window
drawWindow(g);
//initialize the edge table to all zeroes
initializeTable();
//clip the polygon
clipPolygon(g, 10);
System.out.println("Coordinates:");
System.out.println("(" + px[0] + ", " + py[0] + ")");
System.out.println("(" + px[1] + ", " + py[1] + ")");
System.out.println("(" + px[2] + ", " + py[2] + ")");
System.out.println("(" + px[3] + ", " + py[3] + ")");
System.out.println("(" + px[4] + ", " + py[4] + ")");
System.out.println("(" + px[5] + ", " + py[5] + ")");
System.out.println("(" + px[6] + ", " + py[6] + ")");
System.out.println("(" + px[7] + ", " + py[7] + ")");
System.out.println("(" + px[8] + ", " + py[8] + ")");
System.out.println("(" + px[9] + ", " + py[9] + ")");
System.out.println("\nStored:");
System.out.println("(" + xout[0] + ", " + yout[0] + ")");
System.out.println("(" + xout[1] + ", " + yout[1] + ")");
System.out.println("(" + xout[2] + ", " + yout[2] + ")");
System.out.println("(" + xout[3] + ", " + yout[3] + ")");
System.out.println("(" + xout[4] + ", " + yout[4] + ")");
System.out.println("(" + xout[5] + ", " + yout[5] + ")");
System.out.println("(" + xout[6] + ", " + yout[6] + ")");
System.out.println("(" + xout[7] + ", " + yout[7] + ")");
System.out.println("(" + xout[8] + ", " + yout[8] + ")");
System.out.println("(" + xout[9] + ", " + yout[9] + ")");
for (int i = 0; i < xout.length; i++)
System.out.println("outnum -> " + outnum);
//draw polygon with red outline
if (drawAgain)
{
fillMyPolygon(g, 10, 10);
drawNewPolygon(g);
}//end if
else
{
fillMyPolygon(g, 10, 10);
drawMyPolygon(g);
}//end else
//set buttons to visible
buttons();
}//end paint
如果您有任何想法或可能需要更多信息,请告诉我。谢谢
算法的问题很简单,就是缺少括号来分隔公式的不同部分,这些公式决定了剪裁线的新坐标。解决后效果很好