使用我的多边形填充算法填充多边形会出现越界错误

Filling in polygon with my polygon fill algorithm give an out of bounds error

我正在创建一个程序,它需要绘制一个多边形,然后用绿色填充多边形。我目前编写的算法存在问题,因为它只填充多边形的上半部分,然后出现 IndexOutOfBounds 错误。

这是我的算法代码:

public class FillPolygon
{
    int left_most_edge, right_most_edge, scan = 0;
    double[] xcoord;
    double[][] table = new double[4][200];  //2d array containing: 
                                            //[0][-] -> ymax, [1][-] -> ymin, [2][-] -> dx, [3][-] -> x

    public void initializeTable()
    {
        int i, j;

        for (i = 0; i < 4; i++)
        {
            for (j = 0; j < 200; j++)
            {
                table[i][j] = 0;
            }//end for
        }//end for
    }//end initializeTable

    public void help(int i)
    {
        double helpX, helpDX, helpYMax, helpYMin;
        for (int j = i - 1; j >= 0; j--)
        {
            if ((table[1][j] == table[1][j + 1] && table[3][j] > table[3][j + 1]) || table[1][j] > table[1][j + 1])
            {
                helpYMax = table[0][j];
                table[0][j] = table[0][j + 1];
                table[0][j + 1] = helpYMax;

                helpYMin = table[1][j];
                table[1][j] = table[1][j + 1];
                table[1][j + 1] = helpYMin;

                helpDX = table[2][j];
                table[2][j] = table[2][j + 1];
                table[2][j + 1] = helpDX;

                helpX = table[3][j];
                table[3][j] = table[3][j + 1];
                table[3][j + 1] = helpX;
            }//end if
        }//end for
    }//end help

    public double max (double x, double y)
    { //determines the greater of two values
        double max;
        if (x > y)
            max = x;
        else
            max = y;
        return max;
    }//end max

    public void edgeInsert(double xStart, double yStart, double xEnd, double yEnd, int number_entered_edges)
    {
        int j = number_entered_edges - 1; //removing the - 1 removes line on left side
        double x;

        if (yStart > yEnd)
        {
            table[0][j] = yStart;
            table[1][j] = yEnd;
        }//end if
        else
        {
            table[0][j] = yEnd;
            table[1][j] = yStart;
        }//end else

        if (table[1][j] == xStart)
            x = xStart;
        else
            x = xEnd;

        if (table[0][j] == yStart)
            table[2][j] = -(-(xEnd - xStart) / (yEnd - yStart));
        else
            table[2][j] = -(xEnd - xStart) / (yEnd - yStart);

        table[3][j] = x + table[2][j] / 2;

        help(j);
    }//end edgeInsert

    public void loadTable(int number_vertices, int number_entered_edges,
                    double[] px, double[] py)
    { //take the x and y coordinats and build an edge table based off of them
        int k;
        double xStart, yStart, xEnd, yEnd;

        xStart = px[number_vertices - 1];
        yStart = trunc(py[number_vertices - 1]) + 0.5;

        //start off with no edges in edge table
        number_entered_edges = 0;
        for (k = 0; k < number_vertices; k++)
        {
            xEnd = px[k];
            yEnd = trunc(py[k]) + 0.5;
            System.out.println("x: " + xEnd + " y: " + yEnd);
            if (yStart == yEnd)
            {
                xStart = xEnd;
            }//end if
            else
            {
                //add edge to edge table
                number_entered_edges++;
                edgeInsert(xStart, yStart, xEnd, yEnd, number_entered_edges);

                yStart = yEnd;
                xStart = xEnd;
            }//end else
        }//end for
        scan = (int)trunc(table[1][0]); //start at the top of the polygon
    }//end loadTable

    public void include(int number_entered_edges)
    { //pushing the right most edge
        while ((right_most_edge + 1 < number_entered_edges) && (table[1][right_most_edge + 1] < scan))
        {
            right_most_edge++;
        }//end while
    }//end include

    public void exclude()
    { //excluding edges that we no longer care about
        for (int i = left_most_edge; i <= right_most_edge; i++)
        {
            if (table[0][i] < scan)
            {
                left_most_edge++;
                for (int j = i; j >= left_most_edge; j--)
                {
                    table[0][j] = table[0][j - 1];
                    table[2][j] = table[2][j - 1];
                    table[3][j] = table[3][j - 1];
                }//end for
            }//end if
        }//end for
    }//end exclude

    public void updateX()
    { //increment x based on dx
        for (int i = left_most_edge; i <= right_most_edge; i++)
        {
            table[3][i] += table[2][i];
        }//end for
    }//end updateX

    public void sortOnX()
    { //sorting x values from least to greatest in edge table
        int l = 0;
        double t;
        xcoord = new double[right_most_edge - left_most_edge + 1];

        for (int i = left_most_edge; i <= right_most_edge; i++)
        {
            xcoord[l] = table[3][i];
            for(int j = l - 1; j >= 0; j--)
            {
                if (xcoord[j] > xcoord[j + 1])
                {
                    t = xcoord[j];
                    xcoord[j] = xcoord[j + 1];
                    xcoord[j + 1] = t;
                }//end if
            }//end for

            l++;
        }//end for
    }//end sortOnX

    public void fillScan(Graphics g)
    { //determines the line to be drawn for filling
        for (int i = 0; i < xcoord.length; i += 2)
        {
                drawMyHorizontalLine(g, (int)Math.round(xcoord[i]), scan, (int)Math.round(xcoord[i + 1]));
        }//end for
    }//end fillScan

    public double trunc(double num)
    { //trucates the number passed in to remove any decimal
        double rem;
        if ((num % 2) == 0)
            return num;
        else
        {
            rem = num % 2;
            return num - rem;
        }//end else
    }//end trunc

    public void drawMyPolygon(Graphics g)
    { //draws the polygon
        g.setColor(Color.RED);
        g.drawLine(100, 125, 150, 100); //from (100, 125) to (150, 100)
        g.drawLine(150, 100, 250, 200); //from (150, 100) to (250, 200)
        g.drawLine(250, 200, 300, 150); //from (250, 200) to (300, 150)
        g.drawLine(300, 150, 250, 100); //from (300, 150) to (250, 100)
        g.drawLine(250, 100, 150, 200); //from (250, 100) to (150, 200)
        g.drawLine(150, 200, 100, 200); //from (150, 200) to (100, 200)
        g.drawLine(100, 200, 100, 125); //from (100, 125) to (100, 125)
    }//end drawMyPolygon

    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 fillMyPolygon(Graphics g, int number_vertices, int number_entered_edges, double[] px, double[] py)
    { //called methods to deal with edge table and fill the polygon
        if (number_entered_edges < 3 || number_entered_edges > 200)
        {
            System.out.println("Polygon size error");
        }//end if
        else
        {
            loadTable(number_vertices, number_entered_edges, px, py);
            while (left_most_edge < number_entered_edges)
            {
                scan++;
                exclude();
                updateX();
                include(number_entered_edges);
                sortOnX();
                fillScan(g);
            }//end while
        }//end else
    }//end fillMyPolygon



}//end FillPolygon

@Override
public void paint(Graphics g)
{
    FillPolygon f = new FillPolygon();
    double[] px = new double[7]; //contains all x coord.
    double[] py = new double[7]; //contains all y coord.

    //populate x coord.
    px[0] = 100;
    px[1] = 150;
    px[2] = 250;
    px[3] = 300;
    px[4] = 250;
    px[5] = 150;
    px[6] = 100;

    //populate y coord.
    py[0] = 125;
    py[1] = 100;
    py[2] = 200;
    py[3] = 150;
    py[4] = 100;
    py[5] = 200;
    py[6] = 200;

    f.initializeTable();
    f.fillMyPolygon(g, 7, 7, px, py); //begin filling the polygon
    f.drawMyPolygon(g); //draw polygon with red outline
}//end paint

我不知道为什么会收到错误消息或如何停止它。错误发生在我的行 "drawMyHorizontalLine(g, (int)Math.round(xcoord[i]), scan, (int)Math.round(xcoord[i + 1]));"

非常感谢您的帮助。谢谢

这是因为 i + 1for 循环的最后一次迭代中超出了 xcoord 数组的范围。

我按如下方式更改了您的 fillScan() 方法,它似乎表现得更好(从 i = 1 开始并在循环内使用 i - 1,而不是 i + 1 ).

    public void fillScan(Graphics g) {
        for (int i = 1; i < xcoord.length; i++) {
            drawMyHorizontalLine(g, (int) Math.round(xcoord[i-1]),
                                scan, (int) Math.round(xcoord[i]));
        }
    }

这个循环是你的问题。您一次遍历数组的两个位置 (i+= 2),但您一直这样做直到 i < xcoord.length。

所以当i == (xcoord.length - 1)时,即xcoord[i]是数组的最后一个元素,在你调用drawMyHorizo​​ntalLine的方法中,xcoord[i + 1]会过去数组的末尾。

public void fillScan(Graphics g)
{ //determines the line to be drawn for filling
    for (int i = 0; i < xcoord.length; i += 2)
    {
        drawMyHorizontalLine(g, (int)Math.round(xcoord[i]), scan, (int)Math.round(xcoord[i + 1]));
    }//end for
}//end fillScan

要修复此循环,只需更改为 for(...; i < xcoord.length-1 ;i += 2)。只要数组中剩余两个元素,就一次移动两个元素。

这应该可以解决您的越界错误,不确定您的多边形是否只填充了一半。我不太理解你的多边形表示。