Continuing with the x, y coordinate push, BitMatrix is now standardized. I also converted DataMask back to i, j for now to be consistent with the rest of the QR module, and made sure all the tests still pass.

git-svn-id: https://zxing.googlecode.com/svn/trunk@977 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
dswitkin 2009-06-22 19:52:51 +00:00
parent 4b7e5e6461
commit 7fec06465a
12 changed files with 87 additions and 89 deletions

View file

@ -17,20 +17,16 @@
package com.google.zxing.common;
/**
* <p>Represnts a square matrix of bits. In function arguments below, i is the row position
* and j the column position of a bit. The top left bit corresponds to i = 0 and j = 0.</p>
* <p>Represents a square matrix of bits. In function arguments below, and throughout the common
* module, x is the column position, and y is the row position. The ordering is always x, y.
* The origin is at the top-left.</p>
*
* <p>Internally the bits are represented in a compact 1-D array of 32-bit ints. The
* ordering of bits is column-major; that is the bits in this array correspond to
* j=0 and i=0..dimension-1 first, then j=1 and i=0..dimension-1, etc.</p>
*
* <p>Within each int, less-signficant bits correspond to lower values of i and higher rows.
* That is, the top-left bit is the least significant bit of the first int.</p>
*
* <p>This class is a convenient wrapper around this representation, but also exposes the internal
* array for efficient access and manipulation.</p>
* <p>Internally the bits are represented in a compact 1-D array of 32-bit ints.
* The ordering of bits is row-major. Within each int, the least significant bits are used first,
* meaning they represent lower x values. This is compatible with BitArray's implementation.</p>
*
* @author Sean Owen
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class BitMatrix {
@ -51,63 +47,65 @@ public final class BitMatrix {
}
/**
* @param i row offset
* @param j column offset
* <p>Gets the requested bit, where true means black.</p>
*
* @param x The horizontal component (i.e. which column)
* @param y The vertical component (i.e. which row)
* @return value of given bit in matrix
*/
public boolean get(int i, int j) {
int offset = i + dimension * j;
public boolean get(int x, int y) {
int offset = y * dimension + x;
return ((bits[offset >> 5] >>> (offset & 0x1F)) & 0x01) != 0;
}
/**
* <p>Sets the given bit to true.</p>
*
* @param i row offset
* @param j column offset
* @param x The horizontal component (i.e. which column)
* @param y The vertical component (i.e. which row)
*/
public void set(int i, int j) {
int offset = i + dimension * j;
public void set(int x, int y) {
int offset = y * dimension + x;
bits[offset >> 5] |= 1 << (offset & 0x1F);
}
/**
* <p>Flips the given bit.</p>
*
* @param i row offset
* @param j column offset
* @param x The horizontal component (i.e. which column)
* @param y The vertical component (i.e. which row)
*/
public void flip(int i, int j) {
int offset = i + dimension * j;
public void flip(int x, int y) {
int offset = y * dimension + x;
bits[offset >> 5] ^= 1 << (offset & 0x1F);
}
/**
* <p>Sets a square region of the bit matrix to true.</p>
*
* @param topI row offset of region's top-left corner (inclusive)
* @param leftJ column offset of region's top-left corner (inclusive)
* @param height height of region
* @param width width of region
* @param left The horizontal position to begin at (inclusive)
* @param top The vertical position to begin at (inclusive)
* @param width The width of the region
* @param height The height of the region
*/
public void setRegion(int topI, int leftJ, int height, int width) {
if (topI < 0 || leftJ < 0) {
throw new IllegalArgumentException("topI and leftJ must be nonnegative");
public void setRegion(int left, int top, int width, int height) {
if (top < 0 || left < 0) {
throw new IllegalArgumentException("left and top must be nonnegative");
}
if (height < 1 || width < 1) {
throw new IllegalArgumentException("height and width must be at least 1");
}
int maxJ = leftJ + width;
int maxI = topI + height;
if (maxI > dimension || maxJ > dimension) {
int right = left + width;
int bottom = top + height;
if (bottom > dimension || right > dimension) {
throw new IllegalArgumentException(
"topI + height and leftJ + width must be <= matrix dimension");
"top + height and left + width must be <= matrix dimension");
}
for (int j = leftJ; j < maxJ; j++) {
int jOffset = dimension * j;
for (int i = topI; i < maxI; i++) {
int offset = i + jOffset;
bits[offset >> 5] |= 1 << (offset & 0x1F);
for (int y = top; y < bottom; y++) {
int yoffset = dimension * y;
for (int x = left; x < right; x++) {
int xoffset = yoffset + x;
bits[xoffset >> 5] |= 1 << (xoffset & 0x1F);
}
}
}
@ -121,9 +119,9 @@ public final class BitMatrix {
public String toString() {
StringBuffer result = new StringBuffer(dimension * (dimension + 1));
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
result.append(get(i, j) ? "X " : " ");
for (int y = 0; y < dimension; y++) {
for (int x = 0; x < dimension; x++) {
result.append(get(x, y) ? "X " : " ");
}
result.append('\n');
}

View file

@ -56,7 +56,7 @@ public final class DefaultGridSampler extends GridSampler {
for (int j = 0; j < max; j += 2) {
if (image.isBlack((int) points[j], (int) points[j + 1])) {
// Black(-ish) pixel
bits.set(i, j >> 1);
bits.set(j >> 1, i);
}
}
} catch (ArrayIndexOutOfBoundsException aioobe) {

View file

@ -138,7 +138,7 @@ public final class DataMatrixReader implements Reader {
int iOffset = borderWidth + i * moduleSize;
for (int j = 0; j < dimension; j++) {
if (image.isBlack(borderWidth + j * moduleSize, iOffset)) {
bits.set(i, j);
bits.set(j, i);
}
}
}

View file

@ -118,7 +118,7 @@ final class BitMatrixParser {
} else {
// Sweep upward diagonally to the right
do {
if ((row < numRows) && (column >= 0) && !readMappingMatrix.get(row, column)) {
if ((row < numRows) && (column >= 0) && !readMappingMatrix.get(column, row)) {
result[resultOffset++] = (byte) readUtah(row, column, numRows, numColumns);
}
row -= 2;
@ -129,7 +129,7 @@ final class BitMatrixParser {
// Sweep downward diagonally to the left
do {
if ((row >= 0) && (column < numColumns) && !readMappingMatrix.get(row, column)) {
if ((row >= 0) && (column < numColumns) && !readMappingMatrix.get(column, row)) {
result[resultOffset++] = (byte) readUtah(row, column, numRows, numColumns);
}
row += 2;
@ -165,8 +165,8 @@ final class BitMatrixParser {
column += numColumns;
row += 4 - ((numColumns + 4) & 0x07);
}
readMappingMatrix.set(row, column);
return mappingBitMatrix.get(row, column);
readMappingMatrix.set(column, row);
return mappingBitMatrix.get(column, row);
}
/**
@ -432,9 +432,9 @@ final class BitMatrixParser {
int writeRowOffset = dataRegionRowOffset + i;
for (int j = 0; j < dataRegionSizeColumns; ++j) {
int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
if (bitMatrix.get(readRowOffset, readColumnOffset)) {
if (bitMatrix.get(readColumnOffset, readRowOffset)) {
int writeColumnOffset = dataRegionColumnOffset + j;
bitMatrixWithoutAlignment.set(writeRowOffset, writeColumnOffset);
bitMatrixWithoutAlignment.set(writeColumnOffset, writeRowOffset);
}
}
}

View file

@ -51,7 +51,7 @@ public final class Decoder {
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
if (image[i][j]) {
bits.set(i, j);
bits.set(j, i);
}
}
}

View file

@ -143,7 +143,7 @@ public class QRCodeReader implements Reader {
int iOffset = borderWidth + i * moduleSize;
for (int j = 0; j < dimension; j++) {
if (image.isBlack(borderWidth + j * moduleSize, iOffset)) {
bits.set(i, j);
bits.set(j, i);
}
}
}

View file

@ -141,7 +141,7 @@ final class BitMatrixParser {
}
private int copyBit(int i, int j, int versionBits) {
return bitMatrix.get(i, j) ? (versionBits << 1) | 0x1 : versionBits << 1;
return bitMatrix.get(j, i) ? (versionBits << 1) | 0x1 : versionBits << 1;
}
/**
@ -182,11 +182,11 @@ final class BitMatrixParser {
int i = readingUp ? dimension - 1 - count : count;
for (int col = 0; col < 2; col++) {
// Ignore bits covered by the function pattern
if (!functionPattern.get(i, j - col)) {
if (!functionPattern.get(j - col, i)) {
// Read a bit
bitsRead++;
currentByte <<= 1;
if (bitMatrix.get(i, j - col)) {
if (bitMatrix.get(j - col, i)) {
currentByte |= 1;
}
// If we've made a whole byte, save it off

View file

@ -56,16 +56,16 @@ abstract class DataMask {
* @param dimension dimension of QR Code, represented by bits, being unmasked
*/
final void unmaskBitMatrix(BitMatrix bits, int dimension) {
for (int y = 0; y < dimension; y++) {
for (int x = 0; x < dimension; x++) {
if (isMasked(x, y)) {
bits.flip(x, y);
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
if (isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}
abstract boolean isMasked(int x, int y);
abstract boolean isMasked(int i, int j);
/**
* @param reference a value between 0 and 7 indicating one of the eight possible
@ -83,8 +83,8 @@ abstract class DataMask {
* 000: mask bits for which (x + y) mod 2 == 0
*/
private static class DataMask000 extends DataMask {
boolean isMasked(int x, int y) {
return ((x + y) & 0x01) == 0;
boolean isMasked(int i, int j) {
return ((i + j) & 0x01) == 0;
}
}
@ -92,8 +92,8 @@ abstract class DataMask {
* 001: mask bits for which x mod 2 == 0
*/
private static class DataMask001 extends DataMask {
boolean isMasked(int x, int y) {
return (x & 0x01) == 0;
boolean isMasked(int i, int j) {
return (i & 0x01) == 0;
}
}
@ -101,8 +101,8 @@ abstract class DataMask {
* 010: mask bits for which y mod 3 == 0
*/
private static class DataMask010 extends DataMask {
boolean isMasked(int x, int y) {
return y % 3 == 0;
boolean isMasked(int i, int j) {
return j % 3 == 0;
}
}
@ -110,8 +110,8 @@ abstract class DataMask {
* 011: mask bits for which (x + y) mod 3 == 0
*/
private static class DataMask011 extends DataMask {
boolean isMasked(int x, int y) {
return (x + y) % 3 == 0;
boolean isMasked(int i, int j) {
return (i + j) % 3 == 0;
}
}
@ -119,8 +119,8 @@ abstract class DataMask {
* 100: mask bits for which (x/2 + y/3) mod 2 == 0
*/
private static class DataMask100 extends DataMask {
boolean isMasked(int x, int y) {
return (((x >>> 1) + (y/3)) & 0x01) == 0;
boolean isMasked(int i, int j) {
return (((i >>> 1) + (j /3)) & 0x01) == 0;
}
}
@ -128,8 +128,8 @@ abstract class DataMask {
* 101: mask bits for which xy mod 2 + xy mod 3 == 0
*/
private static class DataMask101 extends DataMask {
boolean isMasked(int x, int y) {
int temp = x * y;
boolean isMasked(int i, int j) {
int temp = i * j;
return (temp & 0x01) + (temp % 3) == 0;
}
}
@ -138,18 +138,18 @@ abstract class DataMask {
* 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0
*/
private static class DataMask110 extends DataMask {
boolean isMasked(int x, int y) {
int temp = x * y;
boolean isMasked(int i, int j) {
int temp = i * j;
return (((temp & 0x01) + (temp % 3)) & 0x01) == 0;
}
}
/**
* 111: mask bits for which ((i+j)mod 2 + ij mod 3) mod 2 == 0
* 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0
*/
private static class DataMask111 extends DataMask {
boolean isMasked(int x, int y) {
return ((((x + y) & 0x01) + ((x * y) % 3)) & 0x01) == 0;
boolean isMasked(int i, int j) {
return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0;
}
}
}

View file

@ -51,7 +51,7 @@ public final class Decoder {
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
if (image[i][j]) {
bits.set(i, j);
bits.set(j, i);
}
}
}

View file

@ -147,9 +147,9 @@ public final class Version {
// Top left finder pattern + separator + format
bitMatrix.setRegion(0, 0, 9, 9);
// Top right finder pattern + separator + format
bitMatrix.setRegion(0, dimension - 8, 9, 8);
// Bottom left finder pattern + separator + format
bitMatrix.setRegion(dimension - 8, 0, 8, 9);
// Bottom left finder pattern + separator + format
bitMatrix.setRegion(0, dimension - 8, 9, 8);
// Alignment patterns
int max = alignmentPatternCenters.length;
@ -160,20 +160,20 @@ public final class Version {
// No alignment patterns near the three finder paterns
continue;
}
bitMatrix.setRegion(i, alignmentPatternCenters[y] - 2, 5, 5);
bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5);
}
}
// Vertical timing pattern
bitMatrix.setRegion(9, 6, dimension - 17, 1);
// Horizontal timing pattern
bitMatrix.setRegion(6, 9, 1, dimension - 17);
// Horizontal timing pattern
bitMatrix.setRegion(9, 6, dimension - 17, 1);
if (versionNumber > 6) {
// Version info, top right
bitMatrix.setRegion(0, dimension - 11, 6, 3);
// Version info, bottom left
bitMatrix.setRegion(dimension - 11, 0, 3, 6);
// Version info, bottom left
bitMatrix.setRegion(0, dimension - 11, 6, 3);
}
return bitMatrix;

View file

@ -29,13 +29,13 @@ public final class BitMatrixTestCase extends TestCase {
for (int i = 0; i < 33; i++) {
for (int j = 0; j < 33; j++) {
if (i * j % 3 == 0) {
matrix.set(i, j);
matrix.set(j, i);
}
}
}
for (int i = 0; i < 33; i++) {
for (int j = 0; j < 33; j++) {
assertEquals(i * j % 3 == 0, matrix.get(i, j));
assertEquals(i * j % 3 == 0, matrix.get(j, i));
}
}
}
@ -45,7 +45,7 @@ public final class BitMatrixTestCase extends TestCase {
matrix.setRegion(1, 1, 3, 3);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
assertEquals(i >= 1 && i <= 3 && j >= 1 && j <= 3, matrix.get(i, j));
assertEquals(i >= 1 && i <= 3 && j >= 1 && j <= 3, matrix.get(j, i));
}
}
}

View file

@ -105,7 +105,7 @@ public final class DataMaskTestCase extends TestCase {
assertEquals(
"(" + i + ',' + j + ')',
condition.isMasked(i, j),
bits.get(i, j));
bits.get(j, i));
}
}
}