I need to convert a two dimensional integer array into a one dimensional byte array. Can anybody help me with this?

Basically I have a 2D array holding all int's of either 0 or 1. 0 for a white pixel and 1 for a black pixel, its supposed to represent an image.

Here are the instructions for it: getPixels() Returns a byte array holding all the pixels, first those from the top row, then those from the next row, and so on so that the pixel at location (x,y) is at index x + y*imageWidth in the array.

This is the code I'm trying to do it with:

Greg Roberts<br />CIS Student<br />University of West Florida

Hint #1: At this point in the code, you've got a particular int from your 2-D array, and all you want to do is put this value into your "pixels" array.

Hint #2: Can you express "i" as a function of "h" and "w"?

"We're kind of on the level of crossword puzzle writers... And no one ever goes to them and gives them an award." ~Joe Strummer sscce.org

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

Hint #1: At this point in the code, you've got a particular int from your 2-D array, and all you want to do is put this value into your "pixels" array.

Hint #2: Can you express "i" as a function of "h" and "w"?[/qb]<hr></blockquote>

Hopefully that code is going through each element in the pixels array and adding the current element of the 2D array into the pixels array. I'm not sure how to express i as a function of h and w. Do I not need to use a for each loop on the pixels array?

How about this:

[ September 19, 2005: Message edited by: Greg Roberts ]

Let's say you're at the beginning: w=0 and h=0. So int a = byteArray[0][0]. Let's suppose this happens to be a "1".

Now your code (in the initial post) loops through the pixels array and sets every element to "1". Obviously, that's not what you want. Instead, you just want to take this single value (a=1) and put it in the appropriate place in the pixels array.

So the question is: If you have element (w, h) from the 2-D array, what should the index be in pixels?

(If you just use h, then every time w increments, you will just keep overwriting the first h elements of pixels.)

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

If the element [w][h] is 0,0 than that element should be at pixels[0]. If it is 0,1 than that value should be placed into pixels[1]. I just need to figure out how to do that. It basically should place all the rows of the 2D array into the pixel array one after another.

Here's the weird part, in the driver program, test 1 passes, but the rest fail. Here is the one that passes:

The next test adds a few points to the image, then runs a simliar test, and it fails, along with all the rest. [ September 19, 2005: Message edited by: Greg Roberts ]

Originally posted by Greg Roberts: If the element [w][h] is 0,0 than that element should be at pixels[0]. If it is 0,1 than that value should be placed into pixels[1]. I just need to figure out how to do that...

Exactly. So what happens when w increments and you hit 1,0? At that point, you've already valued pixels[0] through pixels[h].

PS: For the purpose of testing, you might want to create a simple 2-D array -- containing something more illustrative than zeros and ones. For example, { {11, 12, 13}, {21, 22, 23}, {31, 32, 33} } should demonstrate what's going on.

Originally posted by Greg Roberts: ... But it doesn't seem to work either.

How are you testing it?

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

I'm running the driver program and its still failing everything after test01 (except for test05, which simply tests the class's ability to reject negative and out of bounds numbers).

I would need a class file for "ByteImage" to look at that test driver, but I think your last code for converting the 2-d array to a 1-d array does work, as demonstrated below. If the tests in the driver are failing, it's for some other reason.

PS: Rather than just incrementing a counter for the pixels index, I was thinking of something that related directly to the 2-d array, like (w*height) + h. [ September 19, 2005: Message edited by: marc weber ]

Basically, the different tests in the driver are testing different methods in your class. If a particular driver test fails, then you need to correct the corresponding method in your class. (Your getPixels method is working, so that's not the problem.)

For example, Test02 is failing, so you need to examine your addPoint method. All the driver is telling you is "pass" or "fail," so in order to see what's wrong, you need some code that actually shows what's happening. I modified my test code above to include your addPoint method...

Note that my test array clearly indicates which element is which (rather than all zeros). I changed the point I'm adding to a value of 99 so it stands out. If you look at the output, I think you'll see that it's not adding the point where you might expect it.

Wait a second. There are different ways that getPixels might work, depending on how you envision your x-y plane, and exactly how that plane is represented by a 2-dimensional array.

Consider this: If you have a 3x3 2-dimensional array that getPixels converts to a 1-dimensional array of { a, b, c, d, e, f, g, h, i }, does this mean that your original array was...

ghi def abc or

cfi beh adg or

abc def ghi or

adg beh cfi or...?

You need to consider that the test driver is written with a specific one of these in mind. If your're not consisent with the driver (and you're currently not), then the driver tests will fail.

Along these same lines, where is point 0,0? Is it...

xoo ooo ooo or

ooo ooo xoo or...?

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

This is listed in the project requirements for getPixels()

Returns a byte array holding all the pixels, first those from the top row, then those from the next row, and so on so that the pixel at location (x,y) is at index x + y*imageWidth in the array.

Should return a byte array that contains {1,1,1,1,0,0,0,0,1,1,1,1}, right?

I see that this is what getPixels is supposed to do. But how exactly it does this depends on how these "rows" and "columns" are stored in your 2-dimensional array. For example, suppose you have a 2-d array like this (using characters instead of zeros and ones so we can keep track of exactly what's where)...

{ {a, b, c}, {d, e, f}, {g, h, i}, {j, k, l} }

Now, does this 2-d array represent 4 columns and 3 rows? Or is it 3 rows and 4 columns? In other words, do we have array[x][y] or array[y][x]? This isn't so obvious, because the way I would interpret this visually is...

cfil behk adgj

Why? First, I'm using array[x][y] -- that is, an array that holds arrays representing columns (not rows). Second, I assume that as y increases, the corresponding position should move upward (not downward).

BUT this does not appear to be the way the test driver is written. Instead, the driver appears to be using an x-y system in which an increase in y implies downward movement. Specifically, the point (0,2) is actually indicated by "a" in this arrangement...

cfil behk adgj

Now, looking at your code, I think that your 2-d array uses a [y][x] structure, with height first and then width. Also, an increase in y appears to indicate downward movement. This is good because it's consistent with how the driver seems to work, but it also means that the getPixels method needs a second look.

I'm sorry if this is getting too confusing, so to make a long story short, I think you just need to switch your h and w loops to keep things in order...

[ September 19, 2005: Message edited by: marc weber ]

Originally posted by marc weber: I see that this is what getPixels is supposed to do. But how exactly it does this depends on how these "rows" and "columns" are stored in your 2-dimensional array. For example, suppose you have a 2-d array like this (using characters instead of zeros and ones so we can keep track of exactly what's where)...

{ {a, b, c}, {d, e, f}, {g, h, i}, {j, k, l} }

Now, does this 2-d array represent 4 columns and 3 rows? Or is it 3 rows and 4 columns? In other words, do we have array[x][y] or array[y][x]? This isn't so obvious, because the way I would interpret this visually is...

cfil behk adgj

Why? First, I'm using array[x][y] -- that is, an array that holds arrays representing columns (not rows). Second, I assume that as y increases, the corresponding position should move upward (not downward). [ September 19, 2005: Message edited by: marc weber ]

That's interesting because I would interpret this array as

abc def ghi klm

I see it this way because of my mathematical background. Typically in Linear Algebra, array[i][j] in interpreted as the element in the i-th row and the j-th column where row numbers start at the top and increase as you move down and column numbers start at the left and increase as you move right. The main difference I have with the typical mathemetician is that I will start number both rows and columns at 0 instead of 1.

I'm not mentioning this just because its the right way I mention it because as Marc points out, the interpretation of rows and columns is left up to your imagination (or the teacher's instructions). It is a good idea to understand exactly how this is specified.

However, this may be a moot point since as Marc also pointed out, you need to be aware of what each test is doing. I suggest that you add some more System.out.println() calls to see exactly what is going on in the code.

Well you were right about switching h and w in this method. Tests 2 and 3 now pass. Now all I need to look at is how it draws lines and triangles in the array. I don't think I've coded that right. I've got it marking the two endpoints and then marking all points in between, but that can't be right.

I think that would do this: 1,1,1,1 1,1,1,1 1,1,1,0 0,0,0,0

When its supposed to do this: 1,0,0,0 0,1,0,0 0,0,1,0 0,0,0,0

Also, my shiftImage methods don't seem to be working. I'm going through the array and for each element, if it is not on the edge, I'm setting it equal to zero, adding 1 to the width or height, and setting the new coordinate equal to 1. If the element is on the edge, I'm just setting it equal to zero, so it doesn't go out of bounds. For some reason, this isn't working. [ September 20, 2005: Message edited by: Greg Roberts ]

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

Something else as well. In my tests to make sure x and y are >=0 and making sure (xStart,yStart) and (xEnd,yEnd) are not the same point, I'm having a problem. By itself, xStart can equal yStart and xEnd can equal yEnd, as in (0,0 and 3,3) but combined, if (xStart,yStart) and (xEnd,yEnd) are the same point, it should reject the line, as in (1,1 and 1,1). But I'm not sure how to explain that in code. Here is what I have written:

But this is rejecting the points (0,0),(3,3) which is a valid point.

Originally posted by Layne Lund: ... I see it this way because of my mathematical background...

Hmmm, that's interesting. I majored in mathematics, and I thought that was the reason for my interpretation. But I was thinking in terms of a Cartesian system rather than a linear matrix. Now that you point this out, I see the logic in that interpretation.

A big part of the learning process is relating new information to something you already know. But when it comes to abstract concepts like this, different people are likely to conceptualize in very different ways (hence the challenge in teaching these things).

Bottom line: If you're modeling something with a Java multi-dimensional array (which is perhaps a dubious proposition in the first place), you need to be very specific about how you envision it working.

Layne Lund
Ranch Hand

Joined: Dec 06, 2001
Posts: 3061

posted

0

Originally posted by marc weber:

Hmmm, that's interesting. I majored in mathematics, and I thought that was the reason for my interpretation. But I was thinking in terms of a Cartesian system rather than a linear matrix.

Yup, the difference between the traditional Cartesian system and the way matrix elements are referenced throws a lot of beginning students in a Linear Algebra class. It definitely confuses me at times even though I know the differences. Of course, the moral of the story is to make sure the exact representation is totally clear and precise.

Originally posted by Greg Roberts: ... I've got it marking the two endpoints and then marking all points in between, but that can't be right...

I think you see why it's not working. You need to identify the points on the line in relation to the endpoints.

In the diagram below, suppose you have endpoints "a" and "b." Based on this, you need to determine the location of points "1" and "2." If we assume that x coordinates go from left to right, and y coordinates go from top to bottom, then a is at (1, 1) and b is at (4, 4). Point 1 is at (2, 2) and point 2 is at (3, 3). Do you see the pattern?

(This is a diagonal case. I expect that you also need to account for horizontal and vertical cases.)

Originally posted by Greg Roberts: ...if (xStart,yStart) and (xEnd,yEnd) are the same point, it should reject the line...

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

Originally posted by marc weber:

But the problem is, its looking at them as individual int's, instead of looking at the whole picture, which is that they are pairs of int's that represent a point in a coordinate system. xStart can be the same as xEnd, -or- yStart can equal yEnd, but if xStart, yStart, xEnd, and yEnd are all the same, then the start and end points on the graph would be the same point, representing a point instead of a line.

[ September 20, 2005: Message edited by: marc weber ]

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

Still failing.

Here is the code I have for the method:

I know, I haven't addressed the way it draws the line yet, but I'm still trying to get the checks to work. I've tried grouping the "same point" checks together, but it won't work. Its rejecting the line (0,2) (4,2) because yStart and yEnd are the same integer.

Originally posted by marc weber: Sorry, I got that wrong. It should be...

[ September 20, 2005: Message edited by: marc weber ]

Assuming that the endpoints of the line are (xStart, yStart) and (xEnd, yEnd), you had it right the first time. You shouldn't compare x-coordinates to y-coordinates.

Layne

Layne Lund
Ranch Hand

Joined: Dec 06, 2001
Posts: 3061

posted

0

Originally posted by Greg Roberts: <hr></blockquote>

But the problem is, its looking at them as individual int's, instead of looking at the whole picture, which is that they are pairs of int's that represent a point in a coordinate system. xStart can be the same as xEnd, -or- yStart can equal yEnd, but if xStart, yStart, xEnd, and yEnd are all the same, then the start and end points on the graph would be the same point, representing a point instead of a line.[/QB]

So let's look at some examples. The following are legal assuming that the array is large enough:

(1, 0) and (1, 5) // this makes a vertical line (assuming traditional Cartesian coordinates are used) (2, 5) and (5, 5) // this makes a horizontal line

But these are NOT legal:

(1, 1) and (1, 1) (2, 4) and (2, 4)

Note that the last example does not have all four coordinates the same, but looking at the numbers in pairs, they are the same point.

So, following Marc's example, what does it mean for two points to be the same. Perhaps you will do something like this:

Now what does it mean for two points to be different (i.e. NOT the same)? If you can understand this, then you might see why your original check is not correct.

Originally posted by Layne Lund: ...Assuming that the endpoints of the line are (xStart, yStart) and (xEnd, yEnd), you had it right the first time. You shouldn't compare x-coordinates to y-coordinates...

You're absolutely right. I definitely wasn't thinking.

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

if((xStart != xEnd)&&(yStart != xEnd))

If either check failes, it skips to else{ I need to figure out how to code it so that it only skips to else of BOTH checks fail. Java ignores parentheses. If it didn't, simple grouping would solve the problem. If xStart == xEnd it fails the entire check. How can I make it so that both checks must fail for it to skip to else?

Originally posted by Greg Roberts: if((xStart != xEnd)&&(yStart != xEnd))

In English, this says: If ((x coordinates are different) AND (y coordinates are different)).

If your 2 points are the same, this will catch it by evaluating to false. But it will also evaluate to false for certain cases of valid input.

For example, if you have a vertical line, then the x coordinates would be the same. The first comparison would return false (because we're asserting that they're different). The second comparison wouldn't evaluate due to short-circuiting. The evaluation would be false.

Similiarly, if you have a horizontal line, then the y coordinates would be the same. The first comparison would return true, but the second would return false. So the evaluation would again be false.

Now, to make up for my previous error, let me be clear (and hopefully correct) here. In English, you want something like: If it's NOT true that the points are the same, then proceed. Or in other words: If it's NOT true that ((x coordinates are the same) AND (y coordinates are the same)) then proceed.

Or, in Java, if( !((xStart == xEnd) && (yStart == yEnd)) ) {... [ September 21, 2005: Message edited by: marc weber ]

I'll be darn, the elusive piece of code has finally shown itself. That line works! It adds the line as it should, but is now failing because I'm drawing the lines incorrectly. I see what you said earlier about the pattern for diagonal lines, but how would I run a check to see if the line is vertical, horizontal, or diagonal and then tell it how to proceed form there? Also, my shift image methods are not working, but I'm looking at those....

Edit: come to think of it, the shiftImage methods might be working, but I won't know because they're failing as a result of addLine and addTriangle not working right.

Thanks for the help so far! [ September 22, 2005: Message edited by: Greg Roberts ]

Originally posted by Greg Roberts: ...how would I run a check to see if the line is vertical, horizontal, or diagonal and then tell it how to proceed form there? ...

Once you've eliminated cases in which both points are the same...

If the x coordinates are the same, you have a vertical line.

If the y coordinates are the same, you have a horizontal line.

These special cases are easy to draw, because one of the coordinates remains fixed, and all you need to do is increment along the other axis.

The catch is: If you're drawing between yStart and yEnd, you first need to determine which of these values is greater than the other, because that will dictate whether you increment or decrement.

When it comes to diagonals, I have a question: Do you need to deal only with "perfect" diagonals -- for example, 0,0 to 5,5? Or are you expected to be able to draw lines of any slope, like 0,0 to 2,5?

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

Only "perfect" diagonals.

Here are the diagonal cases:

Both on same array: line (0,1)(2,3) line (3,3)(5,1) Here is what it should look like:

Both on same array: line (0,0)(3,3) line (3,0)(0,3) Here's what it should look like: (before shift)

The first pair just draws them, the second pair draws them and then shifts them.

[ September 22, 2005: Message edited by: Greg Roberts ] [ September 22, 2005: Message edited by: Greg Roberts ]

I would consider how a function is graphed: As you move along the x axis from xStart to xEnd (or perhaps in the other direction, depending on which value is greater), you determine the corresponding y value.

Note that the slopes of "perfect" diagonals, (yEnd-yStart)/(xEnd-xStart), will always be 1 or -1. And the sign of this number will probably determine how you go about drawing it -- that is, whether you increment or decrement in your code.

Layne Lund
Ranch Hand

Joined: Dec 06, 2001
Posts: 3061

posted

0

Originally posted by marc weber: I would consider how a function is graphed: As you move along the x axis from xStart to xEnd (or perhaps in the other direction, depending on which value is greater), you determine the corresponding y value.

Note that the slopes of "perfect" diagonals, (yEnd-yStart)/(xEnd-xStart), will always be 1 or -1. And the sign of this number will probably determine how you go about drawing it -- that is, whether you increment or decrement in your code.

I think it might help if you understand the algebra that marc describes here. Do you know how to find the equation of a line if you are given two points? If you can find such an equation, do you also know how to find a y value that corresponds to a given x value? If you can do all this by hand, then I would suggest that you write a method that simulates this procedure. You can pass it the (x, y) values for the start and end point and then an x value. The method will return the corresponding y value. With such a method in hand, you can easily add any line to your array of "pixels".

Layne

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

I see what you're saying about using algebra in the drawLine method, I'm just unsure about where to go from here.

I decided to factor out the code for drawing a line because I'll be re-using it to draw triangles in the other method

Here is the method I'm working on:

[ September 23, 2005: Message edited by: Greg Roberts ]

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

Okay, here is drawLine as it stands. When I read through the code, it should work in my head, but the tests are still failing....

Greg Roberts
Ranch Hand

Joined: Feb 05, 2005
Posts: 72

posted

0

Problems, problems, problems......

I'm getting a "StackOverFlowError" in the output. Its getting stuck in one of the loops in the drawLine method. Do you see any logic errors in that method?

First, the conventional definition of slope might lead you astray in this context. Remember, we're not using a typical x-y system. Instead, the y values are reversed -- meaning that as y increases, the point moves downward rather than upward.

Second, as we move from xStart to xEnd, we are not necessarily increasing, because we don't know in which order the user entered the points. For example, consider drawLine(9, 9, 2, 2). Therefore, a for loop constructed as (int i = xStart; i < xEnd; i++) could be a very dangerous thing.

subject: Converting a two dimensional int array into a byte array