Domanda

I have a small block of code that is reading Line2D values from an array called lineList (in a different class) and storing them in the new array called list. from here I have been trying to convert all of the line values into Polygon points (a point for each x, y coordinate of a line end).

so far I have it working but its not working for the very first point of the first line in the array (that's what I suspect it is) that is added and I am having trouble finding a solution to this as I have tried including this in the first if statement.

I will greatly appreciate any help that anyone is able to provide for me on this.

Below is the code I am using for adding the points from the Line2D values:

Polygon p = new Polygon();
    ArrayList<Line2D> list = new ArrayList<Line2D>();
    Color pixel;
    boolean firstTime = true;

    list = segmentation.getLineList();

    //loop through lineList and add all x and y coordinates to relative x and y arrays
    for(int i = 0; i < list.size(); i++) {
        if(firstTime == true){
            Line2D line = list.get(i);
            Point2D startPoint = line.getP1();
            Point2D endPoint = line.getP2();
            int startX = (int) startPoint.getX();
            int startY = (int) startPoint.getY();
            int endX = (int) endPoint.getX();
            int endY = (int) endPoint.getY();
            p.addPoint(p.xpoints[i] = startX, p.ypoints[i] = startY);
            p.addPoint(p.xpoints[i] = endX, p.ypoints[i] = endY);
            startPoint = null;
            endPoint = null;
            line = null;
            firstTime = false;
        }
        else {
            Line2D line = list.get(i);
            Point2D endPoint = line.getP2();
            int endX = (int) endPoint.getX();
            int endY = (int) endPoint.getY();
            p.addPoint(p.xpoints[i] =  endX, p.ypoints[i] = endY);
            endPoint = null;
            line = null;    
        }
    }

Below is an example of the first point (lower most point) not being included in the polygon points. enter image description here

È stato utile?

Soluzione

Seems like a lot of duplicated code to me. Before we try any more debugging, let's refactor the code and make it simpler to understand and debug.

Refactoring

The first bit of code we can pull out is the code to add a point to the Polygon. Here's the new method.

protected void addPoint(Polygon p, Point2D point) {
    int x = (int) point.getX();
    int y = (int) point.getY();
    p.addPoint(x, y);
}

Now, I didn't get to this in one refactoring. I first pulled out the end point code, because it was identical. After reflecting on the code some more, I generalized it so I could use it for the start point code.

When I first saw this line of code

 p.addPoint(p.xpoints[i] = startX, p.ypoints[i] = startY);

I thought, WTF? I'd never seen anyone set values in a method call. In a where clause, sure.

After about 5 minutes of thought, I realized that the Polygon class internal values were being set after the execution of the addPoint method. While this might be useful with some other method call, it's not necessary here. The method call can be simplified to

p.addPoint(x, y);

Java developers, if you need yet another reason for making your class variables non-public, this is a real good one. Keeps people from setting your class variables after you've set them in your setter method.

Priming Read

We can get rid of the first time switch, and a lot of code, if we use a little known algorithm called the priming read.

Most for loops have the input statement as the first statement in the loop. The for (String s : stringList) construction of a loop hides the fact that the input statement is the first statement in the loop.

But sometimes, you have a method where you need a priming read. This method is one of those times.

In pseudo code, a priming read works like this.

Read input
for loop
    process input
    read input
end loop
process last input

By using a priming read, I was able to greatly simplify the createPolygon method.

Any Cobol programmer reading this thought, "Yep, the priming read."

Java programmers, keep this priming read idea in your mind. You won't use it that often, but as you see, it greatly reduces the amount of code you need in certain cases.

Refactored Code

public Polygon createPolygon(Segmentation segmentation) {
    Polygon p = new Polygon();
    List<Line2D> list = segmentation.getLineList();
    if (list.size() < 2) return p;

    Line2D line = list.get(0);
    addPoint(p, line.getP1());

    // loop through lineList and add all x and y coordinates to relative x
    // and y arrays
    for (int i = 1; i < list.size(); i++) {
        addPoint(p, line.getP2());
        line = list.get(i);
    }

    addPoint(p, line.getP2());
    return p;
}

protected void addPoint(Polygon p, Point2D point) {
    int x = (int) point.getX();
    int y = (int) point.getY();
    p.addPoint(x, y);
}

I did two additional things to the code.

  1. I added a test for less than 2 lines. Basically, it takes at least 2 lines to create a triangle (polygon). There was no point executing the method for 1 line or zero lines.

  2. I changed the ArrayList reference to List. In Java, it's better to use an interface over a concrete class. Since the only List method we're using in the code is the get method, we can use the interface. The advantage to using the interface is that the createPolygon method doesn't care whether or not the getLineList method returns an ArrayList, a LinkedList, or a custom class that implements List. This makes future modifications easier.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top