mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
BitMatrix
This commit is contained in:
@@ -1,537 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.common;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Represents a 2D 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 1-D array of 32-bit ints. However, each row begins
|
|
||||||
* with a new int. This is done intentionally so that we can copy out a row into a BitArray very
|
|
||||||
* efficiently.</p>
|
|
||||||
*
|
|
||||||
* <p>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 implements Cloneable {
|
|
||||||
|
|
||||||
private int width;
|
|
||||||
private int height;
|
|
||||||
private int rowSize;
|
|
||||||
private int[] bits;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty square {@code BitMatrix}.
|
|
||||||
*
|
|
||||||
* @param dimension height and width
|
|
||||||
*/
|
|
||||||
public BitMatrix(int dimension) {
|
|
||||||
this(dimension, dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty {@code BitMatrix}.
|
|
||||||
*
|
|
||||||
* @param width bit matrix width
|
|
||||||
* @param height bit matrix height
|
|
||||||
*/
|
|
||||||
public BitMatrix(int width, int height) {
|
|
||||||
if (width < 1 || height < 1) {
|
|
||||||
throw new IllegalArgumentException("Both dimensions must be greater than 0");
|
|
||||||
}
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.rowSize = (width + 31) / 32;
|
|
||||||
bits = new int[rowSize * height];
|
|
||||||
}
|
|
||||||
|
|
||||||
private BitMatrix(int width, int height, int rowSize, int[] bits) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.rowSize = rowSize;
|
|
||||||
this.bits = bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interprets a 2D array of booleans as a {@code BitMatrix}, where "true" means an "on" bit.
|
|
||||||
*
|
|
||||||
* @param image bits of the image, as a row-major 2D array. Elements are arrays representing rows
|
|
||||||
* @return {@code BitMatrix} representation of image
|
|
||||||
*/
|
|
||||||
public static BitMatrix parse(boolean[][] image) {
|
|
||||||
int height = image.length;
|
|
||||||
int width = image[0].length;
|
|
||||||
BitMatrix bits = new BitMatrix(width, height);
|
|
||||||
for (int i = 0; i < height; i++) {
|
|
||||||
boolean[] imageI = image[i];
|
|
||||||
for (int j = 0; j < width; j++) {
|
|
||||||
if (imageI[j]) {
|
|
||||||
bits.set(j, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BitMatrix parse(String stringRepresentation, String setString, String unsetString) {
|
|
||||||
if (stringRepresentation == null) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean[] bits = new boolean[stringRepresentation.length()];
|
|
||||||
int bitsPos = 0;
|
|
||||||
int rowStartPos = 0;
|
|
||||||
int rowLength = -1;
|
|
||||||
int nRows = 0;
|
|
||||||
int pos = 0;
|
|
||||||
while (pos < stringRepresentation.length()) {
|
|
||||||
if (stringRepresentation.charAt(pos) == '\n' ||
|
|
||||||
stringRepresentation.charAt(pos) == '\r') {
|
|
||||||
if (bitsPos > rowStartPos) {
|
|
||||||
if (rowLength == -1) {
|
|
||||||
rowLength = bitsPos - rowStartPos;
|
|
||||||
} else if (bitsPos - rowStartPos != rowLength) {
|
|
||||||
throw new IllegalArgumentException("row lengths do not match");
|
|
||||||
}
|
|
||||||
rowStartPos = bitsPos;
|
|
||||||
nRows++;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
} else if (stringRepresentation.startsWith(setString, pos)) {
|
|
||||||
pos += setString.length();
|
|
||||||
bits[bitsPos] = true;
|
|
||||||
bitsPos++;
|
|
||||||
} else if (stringRepresentation.startsWith(unsetString, pos)) {
|
|
||||||
pos += unsetString.length();
|
|
||||||
bits[bitsPos] = false;
|
|
||||||
bitsPos++;
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"illegal character encountered: " + stringRepresentation.substring(pos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no EOL at end?
|
|
||||||
if (bitsPos > rowStartPos) {
|
|
||||||
if (rowLength == -1) {
|
|
||||||
rowLength = bitsPos - rowStartPos;
|
|
||||||
} else if (bitsPos - rowStartPos != rowLength) {
|
|
||||||
throw new IllegalArgumentException("row lengths do not match");
|
|
||||||
}
|
|
||||||
nRows++;
|
|
||||||
}
|
|
||||||
|
|
||||||
BitMatrix matrix = new BitMatrix(rowLength, nRows);
|
|
||||||
for (int i = 0; i < bitsPos; i++) {
|
|
||||||
if (bits[i]) {
|
|
||||||
matrix.set(i % rowLength, i / rowLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <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 x, int y) {
|
|
||||||
int offset = y * rowSize + (x / 32);
|
|
||||||
return ((bits[offset] >>> (x & 0x1f)) & 1) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Sets the given bit to true.</p>
|
|
||||||
*
|
|
||||||
* @param x The horizontal component (i.e. which column)
|
|
||||||
* @param y The vertical component (i.e. which row)
|
|
||||||
*/
|
|
||||||
public void set(int x, int y) {
|
|
||||||
int offset = y * rowSize + (x / 32);
|
|
||||||
bits[offset] |= 1 << (x & 0x1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unset(int x, int y) {
|
|
||||||
int offset = y * rowSize + (x / 32);
|
|
||||||
bits[offset] &= ~(1 << (x & 0x1f));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Flips the given bit.</p>
|
|
||||||
*
|
|
||||||
* @param x The horizontal component (i.e. which column)
|
|
||||||
* @param y The vertical component (i.e. which row)
|
|
||||||
*/
|
|
||||||
public void flip(int x, int y) {
|
|
||||||
int offset = y * rowSize + (x / 32);
|
|
||||||
bits[offset] ^= 1 << (x & 0x1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Flips every bit in the matrix.</p>
|
|
||||||
*/
|
|
||||||
public void flip() {
|
|
||||||
int max = bits.length;
|
|
||||||
for (int i = 0; i < max; i++) {
|
|
||||||
bits[i] = ~bits[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding
|
|
||||||
* mask bit is set.
|
|
||||||
*
|
|
||||||
* @param mask XOR mask
|
|
||||||
*/
|
|
||||||
public void xor(BitMatrix mask) {
|
|
||||||
if (width != mask.width || height != mask.height || rowSize != mask.rowSize) {
|
|
||||||
throw new IllegalArgumentException("input matrix dimensions do not match");
|
|
||||||
}
|
|
||||||
BitArray rowArray = new BitArray(width);
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
int offset = y * rowSize;
|
|
||||||
int[] row = mask.getRow(y, rowArray).getBitArray();
|
|
||||||
for (int x = 0; x < rowSize; x++) {
|
|
||||||
bits[offset + x] ^= row[x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all bits (sets to false).
|
|
||||||
*/
|
|
||||||
public void clear() {
|
|
||||||
int max = bits.length;
|
|
||||||
for (int i = 0; i < max; i++) {
|
|
||||||
bits[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Sets a square region of the bit matrix to true.</p>
|
|
||||||
*
|
|
||||||
* @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 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 right = left + width;
|
|
||||||
int bottom = top + height;
|
|
||||||
if (bottom > this.height || right > this.width) {
|
|
||||||
throw new IllegalArgumentException("The region must fit inside the matrix");
|
|
||||||
}
|
|
||||||
for (int y = top; y < bottom; y++) {
|
|
||||||
int offset = y * rowSize;
|
|
||||||
for (int x = left; x < right; x++) {
|
|
||||||
bits[offset + (x / 32)] |= 1 << (x & 0x1f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A fast method to retrieve one row of data from the matrix as a BitArray.
|
|
||||||
*
|
|
||||||
* @param y The row to retrieve
|
|
||||||
* @param row An optional caller-allocated BitArray, will be allocated if null or too small
|
|
||||||
* @return The resulting BitArray - this reference should always be used even when passing
|
|
||||||
* your own row
|
|
||||||
*/
|
|
||||||
public BitArray getRow(int y, BitArray row) {
|
|
||||||
if (row == null || row.getSize() < width) {
|
|
||||||
row = new BitArray(width);
|
|
||||||
} else {
|
|
||||||
row.clear();
|
|
||||||
}
|
|
||||||
int offset = y * rowSize;
|
|
||||||
for (int x = 0; x < rowSize; x++) {
|
|
||||||
row.setBulk(x * 32, bits[offset + x]);
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param y row to set
|
|
||||||
* @param row {@link BitArray} to copy from
|
|
||||||
*/
|
|
||||||
public void setRow(int y, BitArray row) {
|
|
||||||
System.arraycopy(row.getBitArray(), 0, bits, y * rowSize, rowSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifies this {@code BitMatrix} to represent the same but rotated the given degrees (0, 90, 180, 270)
|
|
||||||
*
|
|
||||||
* @param degrees number of degrees to rotate through counter-clockwise (0, 90, 180, 270)
|
|
||||||
*/
|
|
||||||
public void rotate(int degrees) {
|
|
||||||
switch (degrees % 360) {
|
|
||||||
case 0:
|
|
||||||
return;
|
|
||||||
case 90:
|
|
||||||
rotate90();
|
|
||||||
return;
|
|
||||||
case 180:
|
|
||||||
rotate180();
|
|
||||||
return;
|
|
||||||
case 270:
|
|
||||||
rotate90();
|
|
||||||
rotate180();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("degrees must be a multiple of 0, 90, 180, or 270");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees
|
|
||||||
*/
|
|
||||||
public void rotate180() {
|
|
||||||
BitArray topRow = new BitArray(width);
|
|
||||||
BitArray bottomRow = new BitArray(width);
|
|
||||||
int maxHeight = (height + 1) / 2;
|
|
||||||
for (int i = 0; i < maxHeight; i++) {
|
|
||||||
topRow = getRow(i, topRow);
|
|
||||||
int bottomRowIndex = height - 1 - i;
|
|
||||||
bottomRow = getRow(bottomRowIndex, bottomRow);
|
|
||||||
topRow.reverse();
|
|
||||||
bottomRow.reverse();
|
|
||||||
setRow(i, bottomRow);
|
|
||||||
setRow(bottomRowIndex, topRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifies this {@code BitMatrix} to represent the same but rotated 90 degrees counterclockwise
|
|
||||||
*/
|
|
||||||
public void rotate90() {
|
|
||||||
int newWidth = height;
|
|
||||||
int newHeight = width;
|
|
||||||
int newRowSize = (newWidth + 31) / 32;
|
|
||||||
int[] newBits = new int[newRowSize * newHeight];
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
int offset = y * rowSize + (x / 32);
|
|
||||||
if (((bits[offset] >>> (x & 0x1f)) & 1) != 0) {
|
|
||||||
int newOffset = (newHeight - 1 - x) * newRowSize + (y / 32);
|
|
||||||
newBits[newOffset] |= 1 << (y & 0x1f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
width = newWidth;
|
|
||||||
height = newHeight;
|
|
||||||
rowSize = newRowSize;
|
|
||||||
bits = newBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is useful in detecting the enclosing rectangle of a 'pure' barcode.
|
|
||||||
*
|
|
||||||
* @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white
|
|
||||||
*/
|
|
||||||
public int[] getEnclosingRectangle() {
|
|
||||||
int left = width;
|
|
||||||
int top = height;
|
|
||||||
int right = -1;
|
|
||||||
int bottom = -1;
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x32 = 0; x32 < rowSize; x32++) {
|
|
||||||
int theBits = bits[y * rowSize + x32];
|
|
||||||
if (theBits != 0) {
|
|
||||||
if (y < top) {
|
|
||||||
top = y;
|
|
||||||
}
|
|
||||||
if (y > bottom) {
|
|
||||||
bottom = y;
|
|
||||||
}
|
|
||||||
if (x32 * 32 < left) {
|
|
||||||
int bit = 0;
|
|
||||||
while ((theBits << (31 - bit)) == 0) {
|
|
||||||
bit++;
|
|
||||||
}
|
|
||||||
if ((x32 * 32 + bit) < left) {
|
|
||||||
left = x32 * 32 + bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (x32 * 32 + 31 > right) {
|
|
||||||
int bit = 31;
|
|
||||||
while ((theBits >>> bit) == 0) {
|
|
||||||
bit--;
|
|
||||||
}
|
|
||||||
if ((x32 * 32 + bit) > right) {
|
|
||||||
right = x32 * 32 + bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (right < left || bottom < top) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new int[] {left, top, right - left + 1, bottom - top + 1};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is useful in detecting a corner of a 'pure' barcode.
|
|
||||||
*
|
|
||||||
* @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white
|
|
||||||
*/
|
|
||||||
public int[] getTopLeftOnBit() {
|
|
||||||
int bitsOffset = 0;
|
|
||||||
while (bitsOffset < bits.length && bits[bitsOffset] == 0) {
|
|
||||||
bitsOffset++;
|
|
||||||
}
|
|
||||||
if (bitsOffset == bits.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int y = bitsOffset / rowSize;
|
|
||||||
int x = (bitsOffset % rowSize) * 32;
|
|
||||||
|
|
||||||
int theBits = bits[bitsOffset];
|
|
||||||
int bit = 0;
|
|
||||||
while ((theBits << (31 - bit)) == 0) {
|
|
||||||
bit++;
|
|
||||||
}
|
|
||||||
x += bit;
|
|
||||||
return new int[] {x, y};
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getBottomRightOnBit() {
|
|
||||||
int bitsOffset = bits.length - 1;
|
|
||||||
while (bitsOffset >= 0 && bits[bitsOffset] == 0) {
|
|
||||||
bitsOffset--;
|
|
||||||
}
|
|
||||||
if (bitsOffset < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int y = bitsOffset / rowSize;
|
|
||||||
int x = (bitsOffset % rowSize) * 32;
|
|
||||||
|
|
||||||
int theBits = bits[bitsOffset];
|
|
||||||
int bit = 31;
|
|
||||||
while ((theBits >>> bit) == 0) {
|
|
||||||
bit--;
|
|
||||||
}
|
|
||||||
x += bit;
|
|
||||||
|
|
||||||
return new int[] {x, y};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The width of the matrix
|
|
||||||
*/
|
|
||||||
public int getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The height of the matrix
|
|
||||||
*/
|
|
||||||
public int getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The row size of the matrix
|
|
||||||
*/
|
|
||||||
public int getRowSize() {
|
|
||||||
return rowSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof BitMatrix)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
BitMatrix other = (BitMatrix) o;
|
|
||||||
return width == other.width && height == other.height && rowSize == other.rowSize &&
|
|
||||||
Arrays.equals(bits, other.bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int hash = width;
|
|
||||||
hash = 31 * hash + width;
|
|
||||||
hash = 31 * hash + height;
|
|
||||||
hash = 31 * hash + rowSize;
|
|
||||||
hash = 31 * hash + Arrays.hashCode(bits);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string representation using "X" for set and " " for unset bits
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return toString("X ", " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param setString representation of a set bit
|
|
||||||
* @param unsetString representation of an unset bit
|
|
||||||
* @return string representation of entire matrix utilizing given strings
|
|
||||||
*/
|
|
||||||
public String toString(String setString, String unsetString) {
|
|
||||||
return buildToString(setString, unsetString, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param setString representation of a set bit
|
|
||||||
* @param unsetString representation of an unset bit
|
|
||||||
* @param lineSeparator newline character in string representation
|
|
||||||
* @return string representation of entire matrix utilizing given strings and line separator
|
|
||||||
* @deprecated call {@link #toString(String,String)} only, which uses \n line separator always
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public String toString(String setString, String unsetString, String lineSeparator) {
|
|
||||||
return buildToString(setString, unsetString, lineSeparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buildToString(String setString, String unsetString, String lineSeparator) {
|
|
||||||
StringBuilder result = new StringBuilder(height * (width + 1));
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
result.append(get(x, y) ? setString : unsetString);
|
|
||||||
}
|
|
||||||
result.append(lineSeparator);
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BitMatrix clone() {
|
|
||||||
return new BitMatrix(width, height, rowSize, bits.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -713,3 +713,602 @@ impl DetectorRXingResult {
|
|||||||
return self.points;
|
return self.points;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 ZXing authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package com.google.zxing.common;
|
||||||
|
|
||||||
|
// import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Represents a 2D 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 1-D array of 32-bit ints. However, each row begins
|
||||||
|
* with a new int. This is done intentionally so that we can copy out a row into a BitArray very
|
||||||
|
* efficiently.</p>
|
||||||
|
*
|
||||||
|
* <p>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)
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct BitMatrix {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
rowSize: usize,
|
||||||
|
bits: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitMatrix {
|
||||||
|
/**
|
||||||
|
* Creates an empty square {@code BitMatrix}.
|
||||||
|
*
|
||||||
|
* @param dimension height and width
|
||||||
|
*/
|
||||||
|
pub fn with_single_dimension(dimension: u32) -> Self {
|
||||||
|
Self::new(dimension, dimension)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty {@code BitMatrix}.
|
||||||
|
*
|
||||||
|
* @param width bit matrix width
|
||||||
|
* @param height bit matrix height
|
||||||
|
*/
|
||||||
|
pub fn new(width: u32, height: u32) -> Result<Self, IllegalArgumentException> {
|
||||||
|
if width < 1 || height < 1 {
|
||||||
|
return Err(IllegalArgumentException::new(
|
||||||
|
"Both dimensions must be greater than 0",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
rowSize: (width + 31) / 32,
|
||||||
|
bits: vec![0; ((width + 31) / 32) * height],
|
||||||
|
})
|
||||||
|
// this.width = width;
|
||||||
|
// this.height = height;
|
||||||
|
// this.rowSize = (width + 31) / 32;
|
||||||
|
// bits = new int[rowSize * height];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_all_data(&self, width: u32, height: u32, rowSize: usize, bits: Vec<u32>) -> Self {
|
||||||
|
Self {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
rowSize,
|
||||||
|
bits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interprets a 2D array of booleans as a {@code BitMatrix}, where "true" means an "on" bit.
|
||||||
|
*
|
||||||
|
* @param image bits of the image, as a row-major 2D array. Elements are arrays representing rows
|
||||||
|
* @return {@code BitMatrix} representation of image
|
||||||
|
*/
|
||||||
|
pub fn parse(image: &[[bool]]) -> Self {
|
||||||
|
let height = image.len();
|
||||||
|
let width = image[0].len();
|
||||||
|
let bits = BitMatrix::new(width, height).unwrap();
|
||||||
|
for i in 0..height {
|
||||||
|
//for (int i = 0; i < height; i++) {
|
||||||
|
let imageI = image[i];
|
||||||
|
for j in 0..width {
|
||||||
|
//for (int j = 0; j < width; j++) {
|
||||||
|
if imageI[j] {
|
||||||
|
bits.set(j, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(
|
||||||
|
stringRepresentation: &str,
|
||||||
|
setString: &str,
|
||||||
|
unsetString: &str,
|
||||||
|
) -> Result<Self, IllegalArgumentException> {
|
||||||
|
// cannot pass nulls in rust
|
||||||
|
// if (stringRepresentation == null) {
|
||||||
|
// throw new IllegalArgumentException();
|
||||||
|
// }
|
||||||
|
|
||||||
|
let bits = Vec::with_capacity(stringRepresentation.length());
|
||||||
|
let bitsPos = 0;
|
||||||
|
let rowStartPos = 0;
|
||||||
|
let rowLength = -1;
|
||||||
|
let nRows = 0;
|
||||||
|
let pos = 0;
|
||||||
|
while pos < stringRepresentation.length() {
|
||||||
|
if stringRepresentation.charAt(pos) == '\n' || stringRepresentation.charAt(pos) == '\r'
|
||||||
|
{
|
||||||
|
if bitsPos > rowStartPos {
|
||||||
|
if rowLength == -1 {
|
||||||
|
rowLength = bitsPos - rowStartPos;
|
||||||
|
} else if bitsPos - rowStartPos != rowLength {
|
||||||
|
return Err(IllegalArgumentException::new("row lengths do not match"));
|
||||||
|
}
|
||||||
|
rowStartPos = bitsPos;
|
||||||
|
nRows += 1;
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
} else if stringRepresentation.startsWith(setString, pos) {
|
||||||
|
pos += setString.length();
|
||||||
|
bits[bitsPos] = true;
|
||||||
|
bitsPos += 1;
|
||||||
|
} else if stringRepresentation.startsWith(unsetString, pos) {
|
||||||
|
pos += unsetString.length();
|
||||||
|
bits[bitsPos] = false;
|
||||||
|
bitsPos += 1;
|
||||||
|
} else {
|
||||||
|
return Err(IllegalArgumentException::new(&format!(
|
||||||
|
"illegal character encountered: {}",
|
||||||
|
stringRepresentation.substring(pos)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no EOL at end?
|
||||||
|
if bitsPos > rowStartPos {
|
||||||
|
if rowLength == -1 {
|
||||||
|
rowLength = bitsPos - rowStartPos;
|
||||||
|
} else if bitsPos - rowStartPos != rowLength {
|
||||||
|
return Err(IllegalArgumentException::new("row lengths do not match"));
|
||||||
|
}
|
||||||
|
nRows += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let matrix = BitMatrix::new(rowLength, nRows);
|
||||||
|
for i in 0..bitsPos {
|
||||||
|
//for (int i = 0; i < bitsPos; i++) {
|
||||||
|
if bits[i] {
|
||||||
|
matrix.set(i % rowLength, i / rowLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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
|
||||||
|
*/
|
||||||
|
pub fn get(&self, x: u32, y: u32) -> bool {
|
||||||
|
let offset = y * self.rowSize + (x / 32);
|
||||||
|
return ((self.bits[offset] >> (x & 0x1f)) & 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the given bit to true.</p>
|
||||||
|
*
|
||||||
|
* @param x The horizontal component (i.e. which column)
|
||||||
|
* @param y The vertical component (i.e. which row)
|
||||||
|
*/
|
||||||
|
pub fn set(&self, x: u32, y: u32) {
|
||||||
|
let offset = y * self.rowSize + (x / 32);
|
||||||
|
self.bits[offset] |= 1 << (x & 0x1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unset(&self, x: u32, y: u32) {
|
||||||
|
let offset = y * self.rowSize + (x / 32);
|
||||||
|
self.bits[offset] &= !(1 << (x & 0x1f));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Flips the given bit.</p>
|
||||||
|
*
|
||||||
|
* @param x The horizontal component (i.e. which column)
|
||||||
|
* @param y The vertical component (i.e. which row)
|
||||||
|
*/
|
||||||
|
pub fn flip(&self, x: u32, y: u32) {
|
||||||
|
let offset = y * self.rowSize + (x / 32);
|
||||||
|
self.bits[offset] ^= 1 << (x & 0x1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Flips every bit in the matrix.</p>
|
||||||
|
*/
|
||||||
|
pub fn flip(&self) {
|
||||||
|
let max = self.bits.len();
|
||||||
|
for i in 0..max {
|
||||||
|
//for (int i = 0; i < max; i++) {
|
||||||
|
self.bits[i] = !self.bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding
|
||||||
|
* mask bit is set.
|
||||||
|
*
|
||||||
|
* @param mask XOR mask
|
||||||
|
*/
|
||||||
|
pub fn xor(&self, mask: &BitMatrix) -> Result<(), IllegalArgumentException> {
|
||||||
|
if self.width != mask.width || self.height != mask.height || self.rowSize != mask.rowSize {
|
||||||
|
return Err(IllegalArgumentException::new(
|
||||||
|
"input matrix dimensions do not match",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let rowArray = BitArray::with_size(self.width);
|
||||||
|
for y in 0..self.height {
|
||||||
|
//for (int y = 0; y < height; y++) {
|
||||||
|
let offset = y * self.rowSize;
|
||||||
|
let row = mask.getRow(y, self.rowArray).getBitArray();
|
||||||
|
for x in 0..self.rowSize {
|
||||||
|
//for (int x = 0; x < rowSize; x++) {
|
||||||
|
self.bits[offset + x] ^= row[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all bits (sets to false).
|
||||||
|
*/
|
||||||
|
pub fn clear(&self) {
|
||||||
|
let max = self.bits.len();
|
||||||
|
for i in 0..max {
|
||||||
|
//for (int i = 0; i < max; i++) {
|
||||||
|
self.bits[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets a square region of the bit matrix to true.</p>
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
pub fn setRegion(
|
||||||
|
&self,
|
||||||
|
left: u32,
|
||||||
|
top: u32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
) -> Result<(), IllegalArgumentException> {
|
||||||
|
if top < 0 || left < 0 {
|
||||||
|
return Err(IllegalArgumentException::new(
|
||||||
|
"Left and top must be nonnegative",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if height < 1 || width < 1 {
|
||||||
|
return Err(IllegalArgumentException::new(
|
||||||
|
"Height and width must be at least 1",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let right = left + width;
|
||||||
|
let bottom = top + height;
|
||||||
|
if bottom > self.height || right > self.width {
|
||||||
|
return Err(IllegalArgumentException::new(
|
||||||
|
"The region must fit inside the matrix",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for y in top..bottom {
|
||||||
|
//for (int y = top; y < bottom; y++) {
|
||||||
|
let offset = y * self.rowSize;
|
||||||
|
for x in left..right {
|
||||||
|
//for (int x = left; x < right; x++) {
|
||||||
|
self.bits[offset + (x / 32)] |= 1 << (x & 0x1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fast method to retrieve one row of data from the matrix as a BitArray.
|
||||||
|
*
|
||||||
|
* @param y The row to retrieve
|
||||||
|
* @param row An optional caller-allocated BitArray, will be allocated if null or too small
|
||||||
|
* @return The resulting BitArray - this reference should always be used even when passing
|
||||||
|
* your own row
|
||||||
|
*/
|
||||||
|
pub fn getRow(&self, y: u32, row: &BitArray) -> BitArray {
|
||||||
|
let rw: BitArray = if row.getSize() < self.width {
|
||||||
|
row = &BitArray::with_size(self.width)
|
||||||
|
} else {
|
||||||
|
row.clear();
|
||||||
|
row
|
||||||
|
};
|
||||||
|
|
||||||
|
let offset = y * self.rowSize;
|
||||||
|
for x in 0..self.rowSize {
|
||||||
|
//for (int x = 0; x < rowSize; x++) {
|
||||||
|
rw.setBulk(x * 32, self.bits[offset + x]);
|
||||||
|
}
|
||||||
|
return rw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param y row to set
|
||||||
|
* @param row {@link BitArray} to copy from
|
||||||
|
*/
|
||||||
|
pub fn setRow(&self, y: u32, row: &BitArray) {
|
||||||
|
return self.bits[y * self.rowSize..self.rowSize]
|
||||||
|
.clone_from_slice(&row.getBitArray()[0..self.rowSize]);
|
||||||
|
//System.arraycopy(row.getBitArray(), 0, self.bits, y * self.rowSize, self.rowSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies this {@code BitMatrix} to represent the same but rotated the given degrees (0, 90, 180, 270)
|
||||||
|
*
|
||||||
|
* @param degrees number of degrees to rotate through counter-clockwise (0, 90, 180, 270)
|
||||||
|
*/
|
||||||
|
pub fn rotate(&self, degrees: u32) -> Result<(), IllegalArgumentException> {
|
||||||
|
match degrees % 360 {
|
||||||
|
0 => Ok(()),
|
||||||
|
90 => {
|
||||||
|
self.rotate90();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
180 => {
|
||||||
|
self.rotate180();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
270 => {
|
||||||
|
self.rotate90();
|
||||||
|
self.rotate180();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(IllegalArgumentException::new(
|
||||||
|
"degrees must be a multiple of 0, 90, 180, or 270",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees
|
||||||
|
*/
|
||||||
|
pub fn rotate180(&self) {
|
||||||
|
let mut topRow = BitArray::with_size(self.width);
|
||||||
|
let mut bottomRow = BitArray::with_size(self.width);
|
||||||
|
let mut maxHeight = (self.height + 1) / 2;
|
||||||
|
for i in 0..maxHeight {
|
||||||
|
//for (int i = 0; i < maxHeight; i++) {
|
||||||
|
topRow = self.getRow(i, &topRow);
|
||||||
|
let bottomRowIndex = self.height - 1 - i;
|
||||||
|
bottomRow = self.getRow(bottomRowIndex, &bottomRow);
|
||||||
|
topRow.reverse();
|
||||||
|
bottomRow.reverse();
|
||||||
|
self.setRow(i, &bottomRow);
|
||||||
|
self.setRow(bottomRowIndex, &topRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies this {@code BitMatrix} to represent the same but rotated 90 degrees counterclockwise
|
||||||
|
*/
|
||||||
|
pub fn rotate90(&self) {
|
||||||
|
let mut newWidth = self.height;
|
||||||
|
let mut newHeight = self.width;
|
||||||
|
let mut newRowSize = (newWidth + 31) / 32;
|
||||||
|
let mut newBits = Vec::with_capacity(newRowSize * newHeight);
|
||||||
|
|
||||||
|
for y in 0..self.height {
|
||||||
|
//for (int y = 0; y < height; y++) {
|
||||||
|
for x in 0..self.width {
|
||||||
|
//for (int x = 0; x < width; x++) {
|
||||||
|
let offset = y * self.rowSize + (x / 32);
|
||||||
|
if ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 {
|
||||||
|
let newOffset = (newHeight - 1 - x) * newRowSize + (y / 32);
|
||||||
|
newBits[newOffset] |= 1 << (y & 0x1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.width = newWidth;
|
||||||
|
self.height = newHeight;
|
||||||
|
self.rowSize = newRowSize;
|
||||||
|
self.bits = newBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is useful in detecting the enclosing rectangle of a 'pure' barcode.
|
||||||
|
*
|
||||||
|
* @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white
|
||||||
|
*/
|
||||||
|
pub fn getEnclosingRectangle(&self) -> Option<Vec<u32>> {
|
||||||
|
let left = self.width;
|
||||||
|
let top = self.height;
|
||||||
|
let right = -1;
|
||||||
|
let bottom = -1;
|
||||||
|
|
||||||
|
for y in 0..self.height {
|
||||||
|
//for (int y = 0; y < height; y++) {
|
||||||
|
for x32 in 0..self.rowSize {
|
||||||
|
//for (int x32 = 0; x32 < rowSize; x32++) {
|
||||||
|
let theBits = self.bits[y * self.rowSize + x32];
|
||||||
|
if theBits != 0 {
|
||||||
|
if y < top {
|
||||||
|
top = y;
|
||||||
|
}
|
||||||
|
if y > bottom {
|
||||||
|
bottom = y;
|
||||||
|
}
|
||||||
|
if x32 * 32 < left {
|
||||||
|
let bit = 0;
|
||||||
|
while (theBits << (31 - bit)) == 0 {
|
||||||
|
bit += 1;
|
||||||
|
}
|
||||||
|
if (x32 * 32 + bit) < left {
|
||||||
|
left = x32 * 32 + bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if x32 * 32 + 31 > right {
|
||||||
|
let bit = 31;
|
||||||
|
while (theBits >> bit) == 0 {
|
||||||
|
bit -= 1;
|
||||||
|
}
|
||||||
|
if (x32 * 32 + bit) > right {
|
||||||
|
right = x32 * 32 + bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if right < left || bottom < top {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(vec![left, top, right - left + 1, bottom - top + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is useful in detecting a corner of a 'pure' barcode.
|
||||||
|
*
|
||||||
|
* @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white
|
||||||
|
*/
|
||||||
|
pub fn getTopLeftOnBit(&self) -> Option<Vec<u32>> {
|
||||||
|
let bitsOffset = 0;
|
||||||
|
while bitsOffset < self.bits.length && self.bits[bitsOffset] == 0 {
|
||||||
|
bitsOffset += 1;
|
||||||
|
}
|
||||||
|
if bitsOffset == self.bits.length {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let y = bitsOffset / self.rowSize;
|
||||||
|
let x = (bitsOffset % self.rowSize) * 32;
|
||||||
|
|
||||||
|
let theBits = self.bits[bitsOffset];
|
||||||
|
let bit = 0;
|
||||||
|
while (theBits << (31 - bit)) == 0 {
|
||||||
|
bit += 1;
|
||||||
|
}
|
||||||
|
x += bit;
|
||||||
|
return Some(vec![x, y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getBottomRightOnBit(&self) -> Option<Vec<u32>> {
|
||||||
|
let bitsOffset = self.bits.length - 1;
|
||||||
|
while bitsOffset >= 0 && self.bits[bitsOffset] == 0 {
|
||||||
|
bitsOffset -= 1;
|
||||||
|
}
|
||||||
|
if bitsOffset < 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let y = bitsOffset / self.rowSize;
|
||||||
|
let x = (bitsOffset % self.rowSize) * 32;
|
||||||
|
|
||||||
|
let theBits = self.bits[bitsOffset];
|
||||||
|
let bit = 31;
|
||||||
|
while (theBits >> bit) == 0 {
|
||||||
|
bit -= 1;
|
||||||
|
}
|
||||||
|
x += bit;
|
||||||
|
|
||||||
|
return Some(vec![x, y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The width of the matrix
|
||||||
|
*/
|
||||||
|
pub fn getWidth(&self) -> u32 {
|
||||||
|
return self.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The height of the matrix
|
||||||
|
*/
|
||||||
|
pub fn getHeight(&self) -> u32 {
|
||||||
|
return self.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The row size of the matrix
|
||||||
|
*/
|
||||||
|
pub fn getRowSize(&self) -> usize {
|
||||||
|
return self.rowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public boolean equals(Object o) {
|
||||||
|
// if (!(o instanceof BitMatrix)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// BitMatrix other = (BitMatrix) o;
|
||||||
|
// return width == other.width && height == other.height && rowSize == other.rowSize &&
|
||||||
|
// Arrays.equals(bits, other.bits);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public int hashCode() {
|
||||||
|
// int hash = width;
|
||||||
|
// hash = 31 * hash + width;
|
||||||
|
// hash = 31 * hash + height;
|
||||||
|
// hash = 31 * hash + rowSize;
|
||||||
|
// hash = 31 * hash + Arrays.hashCode(bits);
|
||||||
|
// return hash;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param setString representation of a set bit
|
||||||
|
* @param unsetString representation of an unset bit
|
||||||
|
* @return string representation of entire matrix utilizing given strings
|
||||||
|
*/
|
||||||
|
pub fn toString(&self, setString: &str, unsetString: &str) -> String {
|
||||||
|
return self.buildToString(setString, unsetString, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param setString representation of a set bit
|
||||||
|
* @param unsetString representation of an unset bit
|
||||||
|
* @param lineSeparator newline character in string representation
|
||||||
|
* @return string representation of entire matrix utilizing given strings and line separator
|
||||||
|
* @deprecated call {@link #toString(String,String)} only, which uses \n line separator always
|
||||||
|
*/
|
||||||
|
// @Deprecated
|
||||||
|
// public String toString(String setString, String unsetString, String lineSeparator) {
|
||||||
|
// return buildToString(setString, unsetString, lineSeparator);
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn buildToString(&self, setString: &str, unsetString: &str, lineSeparator: &str) -> String {
|
||||||
|
let result = String::with_capacity(self.height * (self.width + 1));
|
||||||
|
for y in 0..self.height {
|
||||||
|
//for (int y = 0; y < height; y++) {
|
||||||
|
for x in 0..self.width {
|
||||||
|
//for (int x = 0; x < width; x++) {
|
||||||
|
result.push_str(if self.get(x, y) {
|
||||||
|
setString
|
||||||
|
} else {
|
||||||
|
unsetString
|
||||||
|
});
|
||||||
|
}
|
||||||
|
result.push_str(lineSeparator);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public BitMatrix clone() {
|
||||||
|
// return new BitMatrix(width, height, rowSize, bits.clone());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BitMatrix {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.toString("X ", " "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user