remove indirection for RxingResultPoint

Previously, the struct was passed around everywhere as a
reference. It only holds two floats, so there's no real
need for indirection. Now it's being passed as a value.
This commit is contained in:
Vukašin Stepanović
2023-02-15 14:42:07 +00:00
parent 145cf704fe
commit 6b7099a03b
12 changed files with 229 additions and 267 deletions

View File

@@ -94,10 +94,10 @@ impl<'a> Detector<'_> {
// 4. Sample the grid // 4. Sample the grid
let bits = self.sample_grid( let bits = self.sample_grid(
self.image, self.image,
&bulls_eye_corners[self.shift as usize % 4], bulls_eye_corners[self.shift as usize % 4],
&bulls_eye_corners[(self.shift as usize + 1) % 4], bulls_eye_corners[(self.shift as usize + 1) % 4],
&bulls_eye_corners[(self.shift as usize + 2) % 4], bulls_eye_corners[(self.shift as usize + 2) % 4],
&bulls_eye_corners[(self.shift as usize + 3) % 4], bulls_eye_corners[(self.shift as usize + 3) % 4],
)?; )?;
// 5. Get the corners of the matrix. // 5. Get the corners of the matrix.
@@ -122,10 +122,10 @@ impl<'a> Detector<'_> {
&mut self, &mut self,
bulls_eye_corners: &[RXingResultPoint], bulls_eye_corners: &[RXingResultPoint],
) -> Result<(), Exceptions> { ) -> Result<(), Exceptions> {
if !self.is_valid(&bulls_eye_corners[0]) if !self.is_valid(bulls_eye_corners[0])
|| !self.is_valid(&bulls_eye_corners[1]) || !self.is_valid(bulls_eye_corners[1])
|| !self.is_valid(&bulls_eye_corners[2]) || !self.is_valid(bulls_eye_corners[2])
|| !self.is_valid(&bulls_eye_corners[3]) || !self.is_valid(bulls_eye_corners[3])
{ {
return Err(Exceptions::NotFoundException(Some( return Err(Exceptions::NotFoundException(Some(
"no valid points".to_owned(), "no valid points".to_owned(),
@@ -134,10 +134,10 @@ impl<'a> Detector<'_> {
let length = 2 * self.nb_center_layers; let length = 2 * self.nb_center_layers;
// Get the bits around the bull's eye // Get the bits around the bull's eye
let sides = [ let sides = [
self.sample_line(&bulls_eye_corners[0], &bulls_eye_corners[1], length), // Right side self.sample_line(bulls_eye_corners[0], bulls_eye_corners[1], length), // Right side
self.sample_line(&bulls_eye_corners[1], &bulls_eye_corners[2], length), // Bottom self.sample_line(bulls_eye_corners[1], bulls_eye_corners[2], length), // Bottom
self.sample_line(&bulls_eye_corners[2], &bulls_eye_corners[3], length), // Left side self.sample_line(bulls_eye_corners[2], bulls_eye_corners[3], length), // Left side
self.sample_line(&bulls_eye_corners[3], &bulls_eye_corners[0], length), // Top self.sample_line(bulls_eye_corners[3], bulls_eye_corners[0], length), // Top
]; ];
// bullsEyeCorners[shift] is the corner of the bulls'eye that has three // bullsEyeCorners[shift] is the corner of the bulls'eye that has three
@@ -500,10 +500,10 @@ impl<'a> Detector<'_> {
fn sample_grid( fn sample_grid(
&self, &self,
image: &BitMatrix, image: &BitMatrix,
top_left: &RXingResultPoint, top_left: RXingResultPoint,
top_right: &RXingResultPoint, top_right: RXingResultPoint,
bottom_right: &RXingResultPoint, bottom_right: RXingResultPoint,
bottom_left: &RXingResultPoint, bottom_left: RXingResultPoint,
) -> Result<BitMatrix, Exceptions> { ) -> Result<BitMatrix, Exceptions> {
let sampler = DefaultGridSampler::default(); let sampler = DefaultGridSampler::default();
let dimension = self.get_dimension(); let dimension = self.get_dimension();
@@ -542,7 +542,7 @@ impl<'a> Detector<'_> {
* @param size number of bits * @param size number of bits
* @return the array of bits as an int (first bit is high-order bit of result) * @return the array of bits as an int (first bit is high-order bit of result)
*/ */
fn sample_line(&self, p1: &RXingResultPoint, p2: &RXingResultPoint, size: u32) -> u32 { fn sample_line(&self, p1: RXingResultPoint, p2: RXingResultPoint, size: u32) -> u32 {
let mut result = 0; let mut result = 0;
let d = Self::distance(p1, p2); let d = Self::distance(p1, p2);
@@ -724,7 +724,7 @@ impl<'a> Detector<'_> {
x >= 0 && x < self.image.getWidth() as i32 && y >= 0 && y < self.image.getHeight() as i32 x >= 0 && x < self.image.getWidth() as i32 && y >= 0 && y < self.image.getHeight() as i32
} }
fn is_valid(&self, point: &RXingResultPoint) -> bool { fn is_valid(&self, point: RXingResultPoint) -> bool {
let x = MathUtils::round(point.getX()); let x = MathUtils::round(point.getX());
let y = MathUtils::round(point.getY()); let y = MathUtils::round(point.getY());
self.is_valid_points(x, y) self.is_valid_points(x, y)
@@ -734,7 +734,7 @@ impl<'a> Detector<'_> {
MathUtils::distance(a.get_x(), a.get_y(), b.get_x(), b.get_y()) MathUtils::distance(a.get_x(), a.get_y(), b.get_x(), b.get_y())
} }
fn distance(a: &RXingResultPoint, b: &RXingResultPoint) -> f32 { fn distance(a: RXingResultPoint, b: RXingResultPoint) -> f32 {
MathUtils::distance(a.getX(), a.getY(), b.getX(), b.getY()) MathUtils::distance(a.getX(), a.getY(), b.getX(), b.getY())
} }

View File

@@ -212,7 +212,7 @@ impl BitMatrix {
((self.bits[offset] >> (x & 0x1f)) & 1) != 0 ((self.bits[offset] >> (x & 0x1f)) & 1) != 0
} }
pub fn get_point(&self, point: &RXingResultPoint) -> bool { pub fn get_point(&self, point: RXingResultPoint) -> bool {
self.get(point.x as u32, point.y as u32) self.get(point.x as u32, point.y as u32)
// let offset = self.get_offset(point.y as u32, point.x as u32); // let offset = self.get_offset(point.y as u32, point.x as u32);
// ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 // ((self.bits[offset] >> (x & 0x1f)) & 1) != 0
@@ -700,7 +700,7 @@ impl BitMatrix {
new_bm new_bm
} }
pub fn isIn(&self, p: &RXingResultPoint, b: i32) -> bool { pub fn isIn(&self, p: RXingResultPoint, b: i32) -> bool {
b as f32 <= p.x b as f32 <= p.x
&& p.x < self.getWidth() as f32 - b as f32 && p.x < self.getWidth() as f32 - b as f32
&& b as f32 <= p.y && b as f32 <= p.y

View File

@@ -280,7 +280,7 @@ impl<'a> WhiteRectangleDetector<'_> {
return Err(Exceptions::NotFoundException(None)); return Err(Exceptions::NotFoundException(None));
} }
Ok(self.center_edges(&y.unwrap(), &z.unwrap(), &x.unwrap(), &t.unwrap())) Ok(self.center_edges(y.unwrap(), z.unwrap(), x.unwrap(), t.unwrap()))
} else { } else {
Err(Exceptions::NotFoundException(None)) Err(Exceptions::NotFoundException(None))
} }
@@ -322,10 +322,10 @@ impl<'a> WhiteRectangleDetector<'_> {
*/ */
fn center_edges( fn center_edges(
&self, &self,
y: &RXingResultPoint, y: RXingResultPoint,
z: &RXingResultPoint, z: RXingResultPoint,
x: &RXingResultPoint, x: RXingResultPoint,
t: &RXingResultPoint, t: RXingResultPoint,
) -> [RXingResultPoint; 4] { ) -> [RXingResultPoint; 4] {
// //
// t t // t t

View File

@@ -68,8 +68,8 @@ impl<'a> Detector<'_> {
let bottomRight = points[2]; let bottomRight = points[2];
let topRight = points[3]; let topRight = points[3];
let mut dimensionTop = self.transitionsBetween(&topLeft, &topRight) + 1; let mut dimensionTop = self.transitionsBetween(topLeft, topRight) + 1;
let mut dimensionRight = self.transitionsBetween(&bottomRight, &topRight) + 1; let mut dimensionRight = self.transitionsBetween(bottomRight, topRight) + 1;
if (dimensionTop & 0x01) == 1 { if (dimensionTop & 0x01) == 1 {
dimensionTop += 1; dimensionTop += 1;
} }
@@ -85,10 +85,10 @@ impl<'a> Detector<'_> {
let bits = Self::sampleGrid( let bits = Self::sampleGrid(
self.image, self.image,
&topLeft, topLeft,
&bottomLeft, bottomLeft,
&bottomRight, bottomRight,
&topRight, topRight,
dimensionTop, dimensionTop,
dimensionRight, dimensionRight,
)?; )?;
@@ -135,10 +135,10 @@ impl<'a> Detector<'_> {
let pointC = cornerPoints[3]; let pointC = cornerPoints[3];
let pointD = cornerPoints[2]; let pointD = cornerPoints[2];
let trAB = self.transitionsBetween(&pointA, &pointB); let trAB = self.transitionsBetween(pointA, pointB);
let trBC = self.transitionsBetween(&pointB, &pointC); let trBC = self.transitionsBetween(pointB, pointC);
let trCD = self.transitionsBetween(&pointC, &pointD); let trCD = self.transitionsBetween(pointC, pointD);
let trDA = self.transitionsBetween(&pointD, &pointA); let trDA = self.transitionsBetween(pointD, pointA);
// 0..3 // 0..3
// : : // : :
@@ -183,11 +183,11 @@ impl<'a> Detector<'_> {
// Transition detection on the edge is not stable. // Transition detection on the edge is not stable.
// To safely detect, shift the points to the module center. // To safely detect, shift the points to the module center.
let tr = self.transitionsBetween(&pointA, &pointD); let tr = self.transitionsBetween(pointA, pointD);
let pointBs = Self::shiftPoint(pointB, pointC, (tr + 1) * 4); let pointBs = Self::shiftPoint(pointB, pointC, (tr + 1) * 4);
let pointCs = Self::shiftPoint(pointC, pointB, (tr + 1) * 4); let pointCs = Self::shiftPoint(pointC, pointB, (tr + 1) * 4);
let trBA = self.transitionsBetween(&pointBs, &pointA); let trBA = self.transitionsBetween(pointBs, pointA);
let trCD = self.transitionsBetween(&pointCs, &pointD); let trCD = self.transitionsBetween(pointCs, pointD);
// 0..3 // 0..3
// | : // | :
@@ -222,13 +222,13 @@ impl<'a> Detector<'_> {
let pointD = points[3]; let pointD = points[3];
// shift points for safe transition detection. // shift points for safe transition detection.
let mut trTop = self.transitionsBetween(&pointA, &pointD); let mut trTop = self.transitionsBetween(pointA, pointD);
let mut trRight = self.transitionsBetween(&pointB, &pointD); let mut trRight = self.transitionsBetween(pointB, pointD);
let pointAs = Self::shiftPoint(pointA, pointB, (trRight + 1) * 4); let pointAs = Self::shiftPoint(pointA, pointB, (trRight + 1) * 4);
let pointCs = Self::shiftPoint(pointC, pointB, (trTop + 1) * 4); let pointCs = Self::shiftPoint(pointC, pointB, (trTop + 1) * 4);
trTop = self.transitionsBetween(&pointAs, &pointD); trTop = self.transitionsBetween(pointAs, pointD);
trRight = self.transitionsBetween(&pointCs, &pointD); trRight = self.transitionsBetween(pointCs, pointD);
let candidate1 = RXingResultPoint::new( let candidate1 = RXingResultPoint::new(
pointD.getX() + (pointC.getX() - pointB.getX()) / (trTop as f32 + 1.0), pointD.getX() + (pointC.getX() - pointB.getX()) / (trTop as f32 + 1.0),
@@ -239,20 +239,20 @@ impl<'a> Detector<'_> {
pointD.getY() + (pointA.getY() - pointB.getY()) / (trRight as f32 + 1.0), pointD.getY() + (pointA.getY() - pointB.getY()) / (trRight as f32 + 1.0),
); );
if !self.isValid(&candidate1) { if !self.isValid(candidate1) {
if self.isValid(&candidate2) { if self.isValid(candidate2) {
return Some(candidate2); return Some(candidate2);
} }
return None; return None;
} }
if !self.isValid(&candidate2) { if !self.isValid(candidate2) {
return Some(candidate1); return Some(candidate1);
} }
let sumc1 = self.transitionsBetween(&pointAs, &candidate1) let sumc1 = self.transitionsBetween(pointAs, candidate1)
+ self.transitionsBetween(&pointCs, &candidate1); + self.transitionsBetween(pointCs, candidate1);
let sumc2 = self.transitionsBetween(&pointAs, &candidate2) let sumc2 = self.transitionsBetween(pointAs, candidate2)
+ self.transitionsBetween(&pointCs, &candidate2); + self.transitionsBetween(pointCs, candidate2);
if sumc1 > sumc2 { if sumc1 > sumc2 {
Some(candidate1) Some(candidate1)
@@ -274,16 +274,16 @@ impl<'a> Detector<'_> {
let mut pointD = points[3]; let mut pointD = points[3];
// calculate pseudo dimensions // calculate pseudo dimensions
let mut dimH = self.transitionsBetween(&pointA, &pointD) + 1; let mut dimH = self.transitionsBetween(pointA, pointD) + 1;
let mut dimV = self.transitionsBetween(&pointC, &pointD) + 1; let mut dimV = self.transitionsBetween(pointC, pointD) + 1;
// shift points for safe dimension detection // shift points for safe dimension detection
let mut pointAs = Self::shiftPoint(pointA, pointB, dimV * 4); let mut pointAs = Self::shiftPoint(pointA, pointB, dimV * 4);
let mut pointCs = Self::shiftPoint(pointC, pointB, dimH * 4); let mut pointCs = Self::shiftPoint(pointC, pointB, dimH * 4);
// calculate more precise dimensions // calculate more precise dimensions
dimH = self.transitionsBetween(&pointAs, &pointD) + 1; dimH = self.transitionsBetween(pointAs, pointD) + 1;
dimV = self.transitionsBetween(&pointCs, &pointD) + 1; dimV = self.transitionsBetween(pointCs, pointD) + 1;
if (dimH & 0x01) == 1 { if (dimH & 0x01) == 1 {
dimH += 1; dimH += 1;
} }
@@ -316,7 +316,7 @@ impl<'a> Detector<'_> {
[pointAs, pointBs, pointCs, pointDs] [pointAs, pointBs, pointCs, pointDs]
} }
fn isValid(&self, p: &RXingResultPoint) -> bool { fn isValid(&self, p: RXingResultPoint) -> bool {
p.getX() >= 0.0 p.getX() >= 0.0
&& p.getX() <= self.image.getWidth() as f32 - 1.0 && p.getX() <= self.image.getWidth() as f32 - 1.0
&& p.getY() > 0.0 && p.getY() > 0.0
@@ -325,10 +325,10 @@ impl<'a> Detector<'_> {
fn sampleGrid( fn sampleGrid(
image: &BitMatrix, image: &BitMatrix,
topLeft: &RXingResultPoint, topLeft: RXingResultPoint,
bottomLeft: &RXingResultPoint, bottomLeft: RXingResultPoint,
bottomRight: &RXingResultPoint, bottomRight: RXingResultPoint,
topRight: &RXingResultPoint, topRight: RXingResultPoint,
dimensionX: u32, dimensionX: u32,
dimensionY: u32, dimensionY: u32,
) -> Result<BitMatrix, Exceptions> { ) -> Result<BitMatrix, Exceptions> {
@@ -360,7 +360,7 @@ impl<'a> Detector<'_> {
/** /**
* Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. * Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
*/ */
fn transitionsBetween(&self, from: &RXingResultPoint, to: &RXingResultPoint) -> u32 { fn transitionsBetween(&self, from: RXingResultPoint, to: RXingResultPoint) -> u32 {
// See QR Code Detector, sizeOfBlackWhiteBlackRun() // See QR Code Detector, sizeOfBlackWhiteBlackRun()
let mut fromX = from.getX().floor() as i32; let mut fromX = from.getX().floor() as i32;
let mut fromY = from.getY().floor() as i32; let mut fromY = from.getY().floor() as i32;

View File

@@ -16,19 +16,19 @@ pub trait BitMatrixCursor {
// BitMatrixCursor(const BitMatrix& image, POINT p, POINT d) : img(&image), p(p) { setDirection(d); } // BitMatrixCursor(const BitMatrix& image, POINT p, POINT d) : img(&image), p(p) { setDirection(d); }
fn testAt(&self, p: &RXingResultPoint) -> Value; //const fn testAt(&self, p: RXingResultPoint) -> Value; //const
// { // {
// return img->isIn(p) ? Value{img->get(p)} : Value{}; // return img->isIn(p) ? Value{img->get(p)} : Value{};
// } // }
fn blackAt(&self, pos: &RXingResultPoint) -> bool { fn blackAt(&self, pos: RXingResultPoint) -> bool {
self.testAt(pos).isBlack() self.testAt(pos).isBlack()
} }
fn whiteAt(&self, pos: &RXingResultPoint) -> bool { fn whiteAt(&self, pos: RXingResultPoint) -> bool {
self.testAt(pos).isWhite() self.testAt(pos).isWhite()
} }
fn isIn(&self, p: &RXingResultPoint) -> bool; // { return img->isIn(p); } fn isIn(&self, p: RXingResultPoint) -> bool; // { return img->isIn(p); }
fn isInSelf(&self) -> bool; // { return self.isIn(p); } fn isInSelf(&self) -> bool; // { return self.isIn(p); }
fn isBlack(&self) -> bool; // { return blackAt(p); } fn isBlack(&self) -> bool; // { return blackAt(p); }
fn isWhite(&self) -> bool; // { return whiteAt(p); } fn isWhite(&self) -> bool; // { return whiteAt(p); }
@@ -46,30 +46,30 @@ pub trait BitMatrixCursor {
fn turnRight(&mut self); //noexcept { d = right(); } fn turnRight(&mut self); //noexcept { d = right(); }
fn turn(&mut self, dir: Direction); //noexcept { d = direction(dir); } fn turn(&mut self, dir: Direction); //noexcept { d = direction(dir); }
fn edgeAt_point(&self, d: &RXingResultPoint) -> Value; fn edgeAt_point(&self, d: RXingResultPoint) -> Value;
// { // {
// Value v = testAt(p); // Value v = testAt(p);
// return testAt(p + d) != v ? v : Value(); // return testAt(p + d) != v ? v : Value();
// } // }
fn edgeAtFront(&self) -> Value { fn edgeAtFront(&self) -> Value {
return self.edgeAt_point(self.front()); return self.edgeAt_point(*self.front());
} }
fn edgeAtBack(&self) -> Value { fn edgeAtBack(&self) -> Value {
self.edgeAt_point(&self.back()) self.edgeAt_point(self.back())
} }
fn edgeAtLeft(&self) -> Value { fn edgeAtLeft(&self) -> Value {
self.edgeAt_point(&self.left()) self.edgeAt_point(self.left())
} }
fn edgeAtRight(&self) -> Value { fn edgeAtRight(&self) -> Value {
self.edgeAt_point(&self.right()) self.edgeAt_point(self.right())
} }
fn edgeAt_direction(&self, dir: Direction) -> Value { fn edgeAt_direction(&self, dir: Direction) -> Value {
self.edgeAt_point(&self.direction(dir)) self.edgeAt_point(self.direction(dir))
} }
fn setDirection(&mut self, dir: &RXingResultPoint); // { d = bresenhamDirection(dir); } fn setDirection(&mut self, dir: RXingResultPoint); // { d = bresenhamDirection(dir); }
// fn setDirection(&self, dir:&RXingResultPoint);// { d = dir; } // fn setDirection(&self, dir: RXingResultPoint);// { d = dir; }
fn step(&mut self, s: Option<f32>) -> bool; // DEF to 1 fn step(&mut self, s: Option<f32>) -> bool; // DEF to 1
// { // {
@@ -77,7 +77,7 @@ pub trait BitMatrixCursor {
// return isIn(p); // return isIn(p);
// } // }
fn movedBy<T: BitMatrixCursor>(self, d: &RXingResultPoint) -> Self; fn movedBy<T: BitMatrixCursor>(self, d: RXingResultPoint) -> Self;
// { // {
// auto res = *this; // auto res = *this;
// res.p += d; // res.p += d;

View File

@@ -76,7 +76,7 @@ fn Scan(
// follow left leg upwards // follow left leg upwards
t.turnRight(); t.turnRight();
t.state = 1; t.state = 1;
CHECK!(t.traceLine(&t.right(), lineL)?); CHECK!(t.traceLine(t.right(), lineL)?);
CHECK!(t.traceCorner(&mut t.right(), &mut tl)?); CHECK!(t.traceCorner(&mut t.right(), &mut tl)?);
lineL.reverse(); lineL.reverse();
let mut tlTracer = t; let mut tlTracer = t;
@@ -84,19 +84,19 @@ fn Scan(
// follow left leg downwards // follow left leg downwards
t = startTracer.clone(); t = startTracer.clone();
t.state = 1; t.state = 1;
t.setDirection(&tlTracer.right()); t.setDirection(tlTracer.right());
CHECK!(t.traceLine(&t.left(), lineL)?); CHECK!(t.traceLine(t.left(), lineL)?);
if !lineL.isValid() { if !lineL.isValid() {
t.updateDirectionFromOrigin(&tl); t.updateDirectionFromOrigin(tl);
} }
let up = t.back(); let up = t.back();
CHECK!(t.traceCorner(&mut t.left(), &mut bl)?); CHECK!(t.traceCorner(&mut t.left(), &mut bl)?);
// follow bottom leg right // follow bottom leg right
t.state = 2; t.state = 2;
CHECK!(t.traceLine(&t.left(), lineB)?); CHECK!(t.traceLine(t.left(), lineB)?);
if !lineB.isValid() { if !lineB.isValid() {
t.updateDirectionFromOrigin(&bl); t.updateDirectionFromOrigin(bl);
} }
let right = *t.front(); let right = *t.front();
CHECK!(t.traceCorner(&mut t.left(), &mut br)?); CHECK!(t.traceCorner(&mut t.left(), &mut br)?);
@@ -109,9 +109,9 @@ fn Scan(
// at this point we found a plausible L-shape and are now looking for the b/w pattern at the top and right: // at this point we found a plausible L-shape and are now looking for the b/w pattern at the top and right:
// follow top row right 'half way' (4 gaps), see traceGaps break condition with 'invalid' line // follow top row right 'half way' (4 gaps), see traceGaps break condition with 'invalid' line
tlTracer.setDirection(&right); tlTracer.setDirection(right);
CHECK!(tlTracer.traceGaps( CHECK!(tlTracer.traceGaps(
&tlTracer.right(), tlTracer.right(),
lineT, lineT,
maxStepSize, maxStepSize,
&mut DMRegressionLine::default() &mut DMRegressionLine::default()
@@ -124,9 +124,9 @@ fn Scan(
maxStepSize = std::cmp::min(lineT.length() as i32 / 3, (lenL / 5.0) as i32) * 2; maxStepSize = std::cmp::min(lineT.length() as i32 / 3, (lenL / 5.0) as i32) * 2;
// follow up until we reach the top line // follow up until we reach the top line
t.setDirection(&up); t.setDirection(up);
t.state = 3; t.state = 3;
CHECK!(t.traceGaps(&t.left(), lineR, maxStepSize, lineT)?); CHECK!(t.traceGaps(t.left(), lineR, maxStepSize, lineT)?);
CHECK!(t.traceCorner(&mut t.left(), &mut tr)?); CHECK!(t.traceCorner(&mut t.left(), &mut tr)?);
let lenT = distance(&tl, &tr) - 1.0; let lenT = distance(&tl, &tr) - 1.0;
@@ -140,7 +140,7 @@ fn Scan(
); );
// continue top row right until we cross the right line // continue top row right until we cross the right line
CHECK!(tlTracer.traceGaps(&tlTracer.right(), lineT, maxStepSize, lineR)?); CHECK!(tlTracer.traceGaps(tlTracer.right(), lineT, maxStepSize, lineR)?);
// #ifdef PRINT_DEBUG // #ifdef PRINT_DEBUG
// printf("L: %.1f, %.1f ^ %.1f, %.1f > %.1f, %.1f (%d : %d : %d : %d)\n", bl.x, bl.y, // printf("L: %.1f, %.1f ^ %.1f, %.1f > %.1f, %.1f (%d : %d : %d : %d)\n", bl.x, bl.y,
@@ -173,8 +173,8 @@ fn Scan(
f64::INFINITY f64::INFINITY
}; };
}; };
splitDouble(lineT.modules(&tl, &tr)?, &mut dimT, &mut fracT); splitDouble(lineT.modules(tl, tr)?, &mut dimT, &mut fracT);
splitDouble(lineR.modules(&br, &tr)?, &mut dimR, &mut fracR); splitDouble(lineR.modules(br, tr)?, &mut dimR, &mut fracR);
// #ifdef PRINT_DEBUG // #ifdef PRINT_DEBUG
// printf("L: %.1f, %.1f ^ %.1f, %.1f > %.1f, %.1f ^> %.1f, %.1f\n", bl.x, bl.y, // printf("L: %.1f, %.1f ^ %.1f, %.1f > %.1f, %.1f ^> %.1f, %.1f\n", bl.x, bl.y,
@@ -197,24 +197,24 @@ fn Scan(
CHECK!((10..=144).contains(&dimT) && (8..=144).contains(&dimR)); CHECK!((10..=144).contains(&dimT) && (8..=144).contains(&dimR));
let movedTowardsBy = |a: &RXingResultPoint, let movedTowardsBy = |a: RXingResultPoint,
b1: &RXingResultPoint, b1: RXingResultPoint,
b2: &RXingResultPoint, b2: RXingResultPoint,
d: f32| d: f32|
-> RXingResultPoint { -> RXingResultPoint {
*a + d * RXingResultPoint::normalized( a + d * RXingResultPoint::normalized(
RXingResultPoint::normalized(*b1 - *a) + RXingResultPoint::normalized(*b2 - *a), RXingResultPoint::normalized(b1 - a) + RXingResultPoint::normalized(b2 - a),
) )
}; };
// shrink shape by half a pixel to go from center of white pixel outside of code to the edge between white and black // shrink shape by half a pixel to go from center of white pixel outside of code to the edge between white and black
let sourcePoints = Quadrilateral::with_points( let sourcePoints = Quadrilateral::with_points(
movedTowardsBy(&tl, &tr, &bl, 0.5), movedTowardsBy(tl, tr, bl, 0.5),
// move the tr point a little less because the jagged top and right line tend to be statistically slightly // move the tr point a little less because the jagged top and right line tend to be statistically slightly
// inclined toward the center anyway. // inclined toward the center anyway.
movedTowardsBy(&tr, &br, &tl, 0.3), movedTowardsBy(tr, br, tl, 0.3),
movedTowardsBy(&br, &bl, &tr, 0.5), movedTowardsBy(br, bl, tr, 0.5),
movedTowardsBy(&bl, &tl, &br, 0.5), movedTowardsBy(bl, tl, br, 0.5),
); );
let grid_sampler = DefaultGridSampler::default(); let grid_sampler = DefaultGridSampler::default();
@@ -303,7 +303,7 @@ pub fn detect(
y: (image.getHeight() / 2) as f32, y: (image.getHeight() / 2) as f32,
}; //PointF(image.width() / 2, image.height() / 2); }; //PointF(image.width() / 2, image.height() / 2);
let startPos = let startPos =
RXingResultPoint::centered(&(center - center * dir + MIN_SYMBOL_SIZE as i32 / 2 * dir)); RXingResultPoint::centered(center - center * dir + MIN_SYMBOL_SIZE as i32 / 2 * dir);
if let Some(history) = &mut history { if let Some(history) = &mut history {
history.borrow_mut().clear(0); history.borrow_mut().clear(0);

View File

@@ -58,11 +58,11 @@ impl RegressionLine for DMRegressionLine {
} }
} }
fn signedDistance(&self, p: &RXingResultPoint) -> f32 { fn signedDistance(&self, p: RXingResultPoint) -> f32 {
RXingResultPoint::dot(self.normal(), *p) - self.c RXingResultPoint::dot(self.normal(), p) - self.c
} }
fn distance_single(&self, p: &RXingResultPoint) -> f32 { fn distance_single(&self, p: RXingResultPoint) -> f32 {
(self.signedDistance(p)).abs() (self.signedDistance(p)).abs()
} }
@@ -74,13 +74,13 @@ impl RegressionLine for DMRegressionLine {
self.c = f32::NAN; self.c = f32::NAN;
} }
fn add(&mut self, p: &RXingResultPoint) -> Result<(), Exceptions> { fn add(&mut self, p: RXingResultPoint) -> Result<(), Exceptions> {
if self.direction_inward == RXingResultPoint::default() { if self.direction_inward == RXingResultPoint::default() {
return Err(Exceptions::IllegalStateException(None)); return Err(Exceptions::IllegalStateException(None));
} }
self.points.push(*p); self.points.push(p);
if self.points.len() == 1 { if self.points.len() == 1 {
self.c = RXingResultPoint::dot(self.normal(), *p); self.c = RXingResultPoint::dot(self.normal(), p);
} }
Ok(()) Ok(())
} }
@@ -89,8 +89,8 @@ impl RegressionLine for DMRegressionLine {
self.points.pop(); self.points.pop();
} }
fn setDirectionInward(&mut self, d: &RXingResultPoint) { fn setDirectionInward(&mut self, d: RXingResultPoint) {
self.direction_inward = RXingResultPoint::normalized(*d); self.direction_inward = RXingResultPoint::normalized(d);
} }
fn evaluate_max_distance( fn evaluate_max_distance(
@@ -112,7 +112,7 @@ impl RegressionLine for DMRegressionLine {
// return sd > maxSignedDist || sd < -2 * maxSignedDist; // return sd > maxSignedDist || sd < -2 * maxSignedDist;
// }); // });
// points.erase(end, points.end()); // points.erase(end, points.end());
points.retain(|p| { points.retain(|&p| {
let sd = self.signedDistance(p) as f64; let sd = self.signedDistance(p) as f64;
!(sd > maxSignedDist || sd < -2.0 * maxSignedDist) !(sd > maxSignedDist || sd < -2.0 * maxSignedDist)
}); });
@@ -142,8 +142,8 @@ impl RegressionLine for DMRegressionLine {
max.y = float_max(max.y, p.y); max.y = float_max(max.y, p.y);
} }
let diff = max - min; let diff = max - min;
let len = RXingResultPoint::maxAbsComponent(&diff); let len = diff.maxAbsComponent();
let steps = float_min((diff.x).abs(), (diff.y).abs()); let steps = float_min(diff.x.abs(), diff.y.abs());
// due to aliasing we get bad extrapolations if the line is short and too close to vertical/horizontal // due to aliasing we get bad extrapolations if the line is short and too close to vertical/horizontal
steps > 2.0 || len > 50.0 steps > 2.0 || len > 50.0
} }
@@ -237,8 +237,8 @@ impl DMRegressionLine {
pub fn modules( pub fn modules(
&mut self, &mut self,
beg: &RXingResultPoint, beg: RXingResultPoint,
end: &RXingResultPoint, end: RXingResultPoint,
) -> Result<f64, Exceptions> { ) -> Result<f64, Exceptions> {
if self.points.len() <= 3 { if self.points.len() <= 3 {
return Err(Exceptions::IllegalStateException(None)); return Err(Exceptions::IllegalStateException(None));
@@ -257,26 +257,27 @@ impl DMRegressionLine {
for i in 1..self.points.len() { for i in 1..self.points.len() {
// for (size_t i = 1; i < _points.size(); ++i) // for (size_t i = 1; i < _points.size(); ++i)
gapSizes.push(self.distance( gapSizes.push(self.distance(
&self.project(&self.points[i]), self.project(self.points[i]),
&self.project(&self.points[i - 1]), self.project(self.points[i - 1]),
) as f64); ) as f64);
} }
// calculate the (expected average) distance of two adjacent pixels // calculate the (expected average) distance of two adjacent pixels
let unitPixelDist = RXingResultPoint::length(RXingResultPoint::bresenhamDirection( let unitPixelDist = RXingResultPoint::length(RXingResultPoint::bresenhamDirection(
&(*self self.points
.points
.last() .last()
.copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))? .ok_or(Exceptions::IndexOutOfBoundsException(None))?
- *self - self
.points .points
.first() .first()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?), .copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
)) as f64; )) as f64;
// calculate the width of 2 modules (first black pixel to first black pixel) // calculate the width of 2 modules (first black pixel to first black pixel)
let mut sumFront: f64 = let mut sumFront: f64 =
self.distance(beg, &self.project(&self.points[0])) as f64 - unitPixelDist; self.distance(beg, self.project(self.points[0])) as f64 - unitPixelDist;
let mut sumBack: f64 = 0.0; // (last black pixel to last black pixel) let mut sumBack: f64 = 0.0; // (last black pixel to last black pixel)
for dist in gapSizes { for dist in gapSizes {
// for (auto dist : gapSizes) { // for (auto dist : gapSizes) {
@@ -294,9 +295,10 @@ impl DMRegressionLine {
sumFront sumFront
+ self.distance( + self.distance(
end, end,
&self.project( self.project(
self.points self.points
.last() .last()
.copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?, .ok_or(Exceptions::IndexOutOfBoundsException(None))?,
), ),
) as f64, ) as f64,

View File

@@ -31,7 +31,7 @@ pub struct EdgeTracer<'a> {
// } // }
impl BitMatrixCursor for EdgeTracer<'_> { impl BitMatrixCursor for EdgeTracer<'_> {
fn testAt(&self, p: &RXingResultPoint) -> Value { fn testAt(&self, p: RXingResultPoint) -> Value {
if self.img.isIn(p, 0) { if self.img.isIn(p, 0) {
Value::from(self.img.get_point(p)) Value::from(self.img.get_point(p))
} else { } else {
@@ -39,20 +39,20 @@ impl BitMatrixCursor for EdgeTracer<'_> {
} }
} }
fn isIn(&self, p: &RXingResultPoint) -> bool { fn isIn(&self, p: RXingResultPoint) -> bool {
self.img.isIn(p, 0) self.img.isIn(p, 0)
} }
fn isInSelf(&self) -> bool { fn isInSelf(&self) -> bool {
self.isIn(&self.p) self.isIn(self.p)
} }
fn isBlack(&self) -> bool { fn isBlack(&self) -> bool {
self.blackAt(&self.p) self.blackAt(self.p)
} }
fn isWhite(&self) -> bool { fn isWhite(&self) -> bool {
self.whiteAt(&self.p) self.whiteAt(self.p)
} }
fn front(&self) -> &RXingResultPoint { fn front(&self) -> &RXingResultPoint {
@@ -96,28 +96,28 @@ impl BitMatrixCursor for EdgeTracer<'_> {
self.d = self.direction(dir) self.d = self.direction(dir)
} }
fn edgeAt_point(&self, d: &RXingResultPoint) -> Value { fn edgeAt_point(&self, d: RXingResultPoint) -> Value {
let v = self.testAt(&self.p); let v = self.testAt(self.p);
if self.testAt(&(self.p + *d)) != v { if self.testAt(self.p + d) != v {
v v
} else { } else {
Value::Invalid Value::Invalid
} }
} }
fn setDirection(&mut self, dir: &RXingResultPoint) { fn setDirection(&mut self, dir: RXingResultPoint) {
self.d = RXingResultPoint::bresenhamDirection(dir) self.d = dir.bresenhamDirection();
} }
fn step(&mut self, s: Option<f32>) -> bool { fn step(&mut self, s: Option<f32>) -> bool {
let s = if let Some(s) = s { s } else { 1.0 }; let s = if let Some(s) = s { s } else { 1.0 };
self.p += self.d * s; self.p += self.d * s;
self.isIn(&self.p) self.isIn(self.p)
} }
fn movedBy<T: BitMatrixCursor>(self, d: &RXingResultPoint) -> Self { fn movedBy<T: BitMatrixCursor>(self, d: RXingResultPoint) -> Self {
let mut res = self; let mut res = self;
res.p += *d; res.p += d;
res res
} }
@@ -135,11 +135,11 @@ impl BitMatrixCursor for EdgeTracer<'_> {
let backup = if let Some(b) = backup { b } else { false }; let backup = if let Some(b) = backup { b } else { false };
// TODO: provide an alternative and faster out-of-bounds check than isIn() inside testAt() // TODO: provide an alternative and faster out-of-bounds check than isIn() inside testAt()
let mut steps = 0; let mut steps = 0;
let mut lv = self.testAt(&self.p); let mut lv = self.testAt(self.p);
while nth > 0 && (range <= 0 || steps < range) && lv.isValid() { while nth > 0 && (range <= 0 || steps < range) && lv.isValid() {
steps += 1; steps += 1;
let v = self.testAt(&(self.p + steps * self.d)); let v = self.testAt(self.p + steps * self.d);
if lv != v { if lv != v {
lv = v; lv = v;
nth -= 1; nth -= 1;
@@ -167,11 +167,11 @@ impl<'a> EdgeTracer<'_> {
fn traceStep( fn traceStep(
&mut self, &mut self,
dEdge: &RXingResultPoint, dEdge: RXingResultPoint,
maxStepSize: i32, maxStepSize: i32,
goodDirection: bool, goodDirection: bool,
) -> Result<StepResult, Exceptions> { ) -> Result<StepResult, Exceptions> {
let dEdge = RXingResultPoint::mainDirection(*dEdge); let dEdge = RXingResultPoint::mainDirection(dEdge);
for breadth in 1..=(if maxStepSize == 1 { for breadth in 1..=(if maxStepSize == 1 {
2 2
} else if goodDirection { } else if goodDirection {
@@ -189,19 +189,19 @@ impl<'a> EdgeTracer<'_> {
+ (if i & 1 > 0 { (i + 1) / 2 } else { -i / 2 }) * dEdge; + (if i & 1 > 0 { (i + 1) / 2 } else { -i / 2 }) * dEdge;
// dbg!(pEdge); // dbg!(pEdge);
if !self.blackAt(&(pEdge + dEdge)) { if !self.blackAt(pEdge + dEdge) {
continue; continue;
} }
// found black pixel -> go 'outward' until we hit the b/w border // found black pixel -> go 'outward' until we hit the b/w border
for _j in 0..(std::cmp::max(maxStepSize, 3)) { for _j in 0..(std::cmp::max(maxStepSize, 3)) {
// for (int j = 0; j < std::max(maxStepSize, 3) && isIn(pEdge); ++j) { // for (int j = 0; j < std::max(maxStepSize, 3) && isIn(pEdge); ++j) {
if self.whiteAt(&pEdge) { if self.whiteAt(pEdge) {
// if we are not making any progress, we still have another endless loop bug // if we are not making any progress, we still have another endless loop bug
if self.p == RXingResultPoint::centered(&pEdge) { if self.p == pEdge.centered() {
return Err(Exceptions::IllegalStateException(None)); return Err(Exceptions::IllegalStateException(None));
} }
self.p = RXingResultPoint::centered(&pEdge); self.p = pEdge.centered();
// if (self.history && maxStepSize == 1) { // if (self.history && maxStepSize == 1) {
if let Some(history) = &self.history { if let Some(history) = &self.history {
@@ -222,12 +222,12 @@ impl<'a> EdgeTracer<'_> {
return Ok(StepResult::Found); return Ok(StepResult::Found);
} }
pEdge = pEdge - dEdge; pEdge = pEdge - dEdge;
if self.blackAt(&(pEdge - self.d)) { if self.blackAt(pEdge - self.d) {
pEdge = pEdge - self.d; pEdge = pEdge - self.d;
} }
// dbg!(pEdge); // dbg!(pEdge);
if !self.isIn(&pEdge) { if !self.isIn(pEdge) {
break; break;
} }
} }
@@ -239,9 +239,9 @@ impl<'a> EdgeTracer<'_> {
Ok(StepResult::OpenEnd) Ok(StepResult::OpenEnd)
} }
pub fn updateDirectionFromOrigin(&mut self, origin: &RXingResultPoint) -> bool { pub fn updateDirectionFromOrigin(&mut self, origin: RXingResultPoint) -> bool {
let old_d = self.d; let old_d = self.d;
self.setDirection(&(self.p - origin)); self.setDirection(self.p - origin);
// if the new direction is pointing "backward", i.e. angle(new, old) > 90 deg -> break // if the new direction is pointing "backward", i.e. angle(new, old) > 90 deg -> break
if RXingResultPoint::dot(self.d, old_d) < 0.0 { if RXingResultPoint::dot(self.d, old_d) < 0.0 {
return false; return false;
@@ -260,24 +260,24 @@ impl<'a> EdgeTracer<'_> {
pub fn traceLine<T: RegressionLine>( pub fn traceLine<T: RegressionLine>(
&mut self, &mut self,
dEdge: &RXingResultPoint, dEdge: RXingResultPoint,
line: &mut T, line: &mut T,
) -> Result<bool, Exceptions> { ) -> Result<bool, Exceptions> {
line.setDirectionInward(dEdge); line.setDirectionInward(dEdge);
loop { loop {
// log(self.p); // log(self.p);
line.add(&self.p)?; line.add(self.p)?;
if line.points().len() % 50 == 10 { if line.points().len() % 50 == 10 {
if !line.evaluate_max_distance(None, None) { if !line.evaluate_max_distance(None, None) {
return Ok(false); return Ok(false);
} }
if !self.updateDirectionFromOrigin( if !self.updateDirectionFromOrigin(
&(self.p - line.project(&self.p) self.p - line.project(self.p)
+ **line + **line
.points() .points()
.first() .first()
.as_ref() .as_ref()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?), .ok_or(Exceptions::IndexOutOfBoundsException(None))?,
) { ) {
return Ok(false); return Ok(false);
} }
@@ -291,7 +291,7 @@ impl<'a> EdgeTracer<'_> {
pub fn traceGaps<T: RegressionLine>( pub fn traceGaps<T: RegressionLine>(
&mut self, &mut self,
dEdge: &RXingResultPoint, dEdge: RXingResultPoint,
line: &mut T, line: &mut T,
maxStepSize: i32, maxStepSize: i32,
finishLine: &mut T, finishLine: &mut T,
@@ -325,14 +325,14 @@ impl<'a> EdgeTracer<'_> {
// if we drifted too far outside of the code, break // if we drifted too far outside of the code, break
if line.isValid() if line.isValid()
&& line.signedDistance(&self.p) < -5.0 && line.signedDistance(self.p) < -5.0
&& (!line.evaluate_max_distance(None, None) || line.signedDistance(&self.p) < -5.0) && (!line.evaluate_max_distance(None, None) || line.signedDistance(self.p) < -5.0)
{ {
return Ok(false); return Ok(false);
} }
// if we are drifting towards the inside of the code, pull the current position back out onto the line // if we are drifting towards the inside of the code, pull the current position back out onto the line
if line.isValid() && line.signedDistance(&self.p) > 3.0 { if line.isValid() && line.signedDistance(self.p) > 3.0 {
// The current direction d and the line we are tracing are supposed to be roughly parallel. // The current direction d and the line we are tracing are supposed to be roughly parallel.
// In case the 'go outward' step in traceStep lead us astray, we might end up with a line // In case the 'go outward' step in traceStep lead us astray, we might end up with a line
// that is almost perpendicular to d. Then the back-projection below can result in an // that is almost perpendicular to d. Then the back-projection below can result in an
@@ -350,7 +350,7 @@ impl<'a> EdgeTracer<'_> {
return Ok(false); return Ok(false);
} }
let mut np = line.project(&self.p); let mut np = line.project(self.p);
// make sure we are making progress even when back-projecting: // make sure we are making progress even when back-projecting:
// consider a 90deg corner, rotated 45deg. we step away perpendicular from the line and get // consider a 90deg corner, rotated 45deg. we step away perpendicular from the line and get
// back projected where we left off the line. // back projected where we left off the line.
@@ -362,14 +362,14 @@ impl<'a> EdgeTracer<'_> {
line.project( line.project(
line.points() line.points()
.last() .last()
.as_ref() .copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?, .ok_or(Exceptions::IndexOutOfBoundsException(None))?,
), ),
) < 1.0 ) < 1.0
{ {
np += self.d; np += self.d;
} }
self.p = RXingResultPoint::centered(&np); self.p = RXingResultPoint::centered(np);
} else { } else {
let stepLengthInMainDir = if line.points().is_empty() { let stepLengthInMainDir = if line.points().is_empty() {
0.0 0.0
@@ -380,10 +380,11 @@ impl<'a> EdgeTracer<'_> {
- line - line
.points() .points()
.last() .last()
.copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?, .ok_or(Exceptions::IndexOutOfBoundsException(None))?,
) )
}; };
line.add(&self.p)?; line.add(self.p)?;
if stepLengthInMainDir > 1.0 { if stepLengthInMainDir > 1.0 {
gaps += 1; gaps += 1;
@@ -392,11 +393,12 @@ impl<'a> EdgeTracer<'_> {
return Ok(false); return Ok(false);
} }
if !self.updateDirectionFromOrigin( if !self.updateDirectionFromOrigin(
&(self.p - line.project(&self.p) self.p - line.project(self.p)
+ *line + line
.points() .points()
.first() .first()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?), .copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
) { ) {
return Ok(false); return Ok(false);
} }
@@ -418,7 +420,7 @@ impl<'a> EdgeTracer<'_> {
if finishLine.isValid() { if finishLine.isValid() {
maxStepSize = maxStepSize =
std::cmp::min(maxStepSize, (finishLine.signedDistance(&self.p)) as i32); std::cmp::min(maxStepSize, (finishLine.signedDistance(self.p)) as i32);
} }
let stepResult = self.traceStep(dEdge, maxStepSize, line.isValid())?; let stepResult = self.traceStep(dEdge, maxStepSize, line.isValid())?;
@@ -428,7 +430,7 @@ impl<'a> EdgeTracer<'_> {
{ {
return Ok(stepResult == StepResult::OpenEnd return Ok(stepResult == StepResult::OpenEnd
&& finishLine.isValid() && finishLine.isValid()
&& (finishLine.signedDistance(&self.p)) as i32 <= maxStepSize + 1); && (finishLine.signedDistance(self.p)) as i32 <= maxStepSize + 1);
} }
} //while (true); } //while (true);
} }
@@ -442,10 +444,10 @@ impl<'a> EdgeTracer<'_> {
// log(p); // log(p);
*corner = self.p; *corner = self.p;
std::mem::swap(&mut self.d, dir); std::mem::swap(&mut self.d, dir);
self.traceStep(&(-1.0 * dir), 2, false)?; self.traceStep(-1.0 * (*dir), 2, false)?;
// #ifdef PRINT_DEBUG // #ifdef PRINT_DEBUG
// printf("turn: %.0f x %.0f -> %.2f, %.2f\n", p.x, p.y, d.x, d.y); // printf("turn: %.0f x %.0f -> %.2f, %.2f\n", p.x, p.y, d.x, d.y);
// #endif // #endif
Ok(self.isIn(corner) && self.isIn(&self.p)) Ok(self.isIn(*corner) && self.isIn(self.p))
} }
} }

View File

@@ -126,7 +126,7 @@ pub fn IsConvex(poly: &Quadrilateral) -> bool {
{ {
let d1 = poly.0[(i + 2) % N] - poly.0[(i + 1) % N]; let d1 = poly.0[(i + 2) % N] - poly.0[(i + 1) % N];
let d2 = poly.0[i] - poly.0[(i + 1) % N]; let d2 = poly.0[i] - poly.0[(i + 1) % N];
let cp = RXingResultPoint::cross(&d1, &d2); let cp = d1.cross(d2);
m = if m.abs() > cp { cp } else { m.abs() }; m = if m.abs() > cp { cp } else { m.abs() };
@@ -186,14 +186,14 @@ pub fn RotatedCorners(q: &Quadrilateral, n: Option<i32>, mirror: Option<bool>) -
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn IsInside(p: &RXingResultPoint, q: &Quadrilateral) -> bool { pub fn IsInside(p: RXingResultPoint, q: &Quadrilateral) -> bool {
// Test if p is on the same side (right or left) of all polygon segments // Test if p is on the same side (right or left) of all polygon segments
let mut pos = 0; let mut pos = 0;
let mut neg = 0; let mut neg = 0;
for i in 0..q.0.len() for i in 0..q.0.len()
// for (int i = 0; i < Size(q); ++i) // for (int i = 0; i < Size(q); ++i)
{ {
if RXingResultPoint::cross(&(*p - q.0[i]), &(q.0[(i + 1) % q.0.len()] - q.0[i])) < 0.0 { if RXingResultPoint::cross(p - q.0[i], q.0[(i + 1) % q.0.len()] - q.0[i]) < 0.0 {
neg += 1; neg += 1;
} else { } else {
pos += 1; pos += 1;

View File

@@ -13,7 +13,7 @@ pub trait RegressionLine {
// fn intersect<T: RegressionLine, T2: RegressionLine>(&self, l1: &T, l2: &T2) // fn intersect<T: RegressionLine, T2: RegressionLine>(&self, l1: &T, l2: &T2)
// -> RXingResultPoint; // -> RXingResultPoint;
// fn evaluate_begin_end(&self, begin:&RXingResultPoint, end:&RXingResultPoint) -> bool;// { // fn evaluate_begin_end(&self, begin: RXingResultPoint, end: RXingResultPoint) -> bool;// {
// { // {
// let mean = std::accumulate(begin, end, PointF()) / std::distance(begin, end); // let mean = std::accumulate(begin, end, PointF()) / std::distance(begin, end);
// PointF::value_t sumXX = 0, sumYY = 0, sumXY = 0; // PointF::value_t sumXX = 0, sumYY = 0, sumXY = 0;
@@ -43,8 +43,8 @@ pub trait RegressionLine {
fn evaluate(&mut self, points: &[RXingResultPoint]) -> bool; // { return self.evaluate_begin_end(&points.front(), &points.back() + 1); } fn evaluate(&mut self, points: &[RXingResultPoint]) -> bool; // { return self.evaluate_begin_end(&points.front(), &points.back() + 1); }
fn evaluateSelf(&mut self) -> bool; fn evaluateSelf(&mut self) -> bool;
fn distance(&self, a: &RXingResultPoint, b: &RXingResultPoint) -> f32 { fn distance(&self, a: RXingResultPoint, b: RXingResultPoint) -> f32 {
crate::result_point_utils::distance(a, b) crate::result_point_utils::distance(&a, &b)
} }
// RegressionLine() { _points.reserve(16); } // arbitrary but plausible start size (tiny performance improvement) // RegressionLine() { _points.reserve(16); } // arbitrary but plausible start size (tiny performance improvement)
@@ -63,10 +63,10 @@ pub trait RegressionLine {
fn length(&self) -> u32; //const { return _points.size() >= 2 ? int(distance(_points.front(), _points.back())) : 0; } fn length(&self) -> u32; //const { return _points.size() >= 2 ? int(distance(_points.front(), _points.back())) : 0; }
fn isValid(&self) -> bool; //const { return !std::isnan(a); } fn isValid(&self) -> bool; //const { return !std::isnan(a); }
fn normal(&self) -> RXingResultPoint; //const { return isValid() ? PointF(a, b) : _directionInward; } fn normal(&self) -> RXingResultPoint; //const { return isValid() ? PointF(a, b) : _directionInward; }
fn signedDistance(&self, p: &RXingResultPoint) -> f32; //const { return dot(normal(), p) - c; } fn signedDistance(&self, p: RXingResultPoint) -> f32; //const { return dot(normal(), p) - c; }
fn distance_single(&self, p: &RXingResultPoint) -> f32; //const { return std::abs(signedDistance(PointF(p))); } fn distance_single(&self, p: RXingResultPoint) -> f32; //const { return std::abs(signedDistance(PointF(p))); }
fn project(&self, p: &RXingResultPoint) -> RXingResultPoint { fn project(&self, p: RXingResultPoint) -> RXingResultPoint {
*p - self.normal() * self.signedDistance(p) p - self.normal() * self.signedDistance(p)
} }
fn reset(&mut self); fn reset(&mut self);
@@ -76,16 +76,16 @@ pub trait RegressionLine {
// a = b = c = NAN; // a = b = c = NAN;
// } // }
fn add(&mut self, p: &RXingResultPoint) -> Result<(), Exceptions>; //{ fn add(&mut self, p: RXingResultPoint) -> Result<(), Exceptions>; //{
// assert(_directionInward != PointF()); // assert(_directionInward != PointF());
// _points.push_back(p); // _points.push_back(p);
// if (_points.size() == 1) // if (_points.size() == 1)
// c = dot(normal(), p); // c = dot(normal(), p);
// } // }
fn pop_back(&mut self); // { _points.pop_back(); } fn pop_back(&mut self); // { _points.pop_back(); }
fn setDirectionInward(&mut self, d: &RXingResultPoint); //{ _directionInward = normalized(d); } fn setDirectionInward(&mut self, d: RXingResultPoint); //{ _directionInward = normalized(d); }
// fn evaluate(&self, double maxSignedDist = -1, bool updatePoints = false) -> bool // fn evaluate(&self, double maxSignedDist = -1, bool updatePoints = false) -> bool
fn evaluate_max_distance( fn evaluate_max_distance(

View File

@@ -68,7 +68,7 @@ pub fn decode(
leftRowIndicatorColumn = Some(getRowIndicatorColumn( leftRowIndicatorColumn = Some(getRowIndicatorColumn(
image, image,
boundingBox.clone(), boundingBox.clone(),
imageTopLeft.as_ref().unwrap(), imageTopLeft.unwrap(),
true, true,
minCodewordWidth, minCodewordWidth,
maxCodewordWidth, maxCodewordWidth,
@@ -78,7 +78,7 @@ pub fn decode(
rightRowIndicatorColumn = Some(getRowIndicatorColumn( rightRowIndicatorColumn = Some(getRowIndicatorColumn(
image, image,
boundingBox.clone(), boundingBox.clone(),
imageTopRight.as_ref().unwrap(), imageTopRight.unwrap(),
false, false,
minCodewordWidth, minCodewordWidth,
maxCodewordWidth, maxCodewordWidth,
@@ -358,7 +358,7 @@ fn getBarcodeMetadata<T: DetectionRXingResultRowIndicatorColumn>(
fn getRowIndicatorColumn<'a>( fn getRowIndicatorColumn<'a>(
image: &BitMatrix, image: &BitMatrix,
boundingBox: Rc<BoundingBox>, boundingBox: Rc<BoundingBox>,
startPoint: &RXingResultPoint, startPoint: RXingResultPoint,
leftToRight: bool, leftToRight: bool,
minCodewordWidth: u32, minCodewordWidth: u32,
maxCodewordWidth: u32, maxCodewordWidth: u32,

View File

@@ -18,22 +18,26 @@ pub struct RXingResultPoint {
pub(crate) x: f32, pub(crate) x: f32,
pub(crate) y: f32, pub(crate) y: f32,
} }
impl Hash for RXingResultPoint { impl Hash for RXingResultPoint {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.x.to_string().hash(state); self.x.to_string().hash(state);
self.y.to_string().hash(state); self.y.to_string().hash(state);
} }
} }
impl PartialEq for RXingResultPoint { impl PartialEq for RXingResultPoint {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y self.x == other.x && self.y == other.y
} }
} }
impl Eq for RXingResultPoint {} impl Eq for RXingResultPoint {}
impl RXingResultPoint { impl RXingResultPoint {
pub const fn new(x: f32, y: f32) -> Self { pub const fn new(x: f32, y: f32) -> Self {
Self { x, y } Self { x, y }
} }
pub const fn with_single(x: f32) -> Self { pub const fn with_single(x: f32) -> Self {
Self { x, y: x } Self { x, y: x }
} }
@@ -47,12 +51,8 @@ impl std::ops::AddAssign for RXingResultPoint {
} }
impl<'a> Sum<&'a RXingResultPoint> for RXingResultPoint { impl<'a> Sum<&'a RXingResultPoint> for RXingResultPoint {
fn sum<I: Iterator<Item = &'a RXingResultPoint>>(iter: I) -> Self { fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
let mut add = RXingResultPoint { x: 0.0, y: 0.0 }; iter.fold(Self::default(), |acc, &p| acc + p)
for n in iter {
add += *n;
}
add
} }
} }
@@ -65,7 +65,7 @@ impl ResultPoint for RXingResultPoint {
self.y self.y
} }
fn into_rxing_result_point(self) -> RXingResultPoint { fn into_rxing_result_point(self) -> Self {
self self
} }
} }
@@ -77,7 +77,7 @@ impl fmt::Display for RXingResultPoint {
} }
impl std::ops::Sub<RXingResultPoint> for RXingResultPoint { impl std::ops::Sub<RXingResultPoint> for RXingResultPoint {
type Output = RXingResultPoint; type Output = Self;
fn sub(self, rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output {
Self { Self {
@@ -87,19 +87,8 @@ impl std::ops::Sub<RXingResultPoint> for RXingResultPoint {
} }
} }
impl std::ops::Sub<&RXingResultPoint> for RXingResultPoint {
type Output = RXingResultPoint;
fn sub(self, rhs: &Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl std::ops::Neg for RXingResultPoint { impl std::ops::Neg for RXingResultPoint {
type Output = RXingResultPoint; type Output = Self;
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Self { Self {
@@ -110,9 +99,9 @@ impl std::ops::Neg for RXingResultPoint {
} }
impl std::ops::Add<RXingResultPoint> for RXingResultPoint { impl std::ops::Add<RXingResultPoint> for RXingResultPoint {
type Output = RXingResultPoint; type Output = Self;
fn add(self, rhs: RXingResultPoint) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
Self { Self {
x: self.x + rhs.x, x: self.x + rhs.x,
y: self.y + rhs.y, y: self.y + rhs.y,
@@ -121,9 +110,9 @@ impl std::ops::Add<RXingResultPoint> for RXingResultPoint {
} }
impl std::ops::Mul<RXingResultPoint> for RXingResultPoint { impl std::ops::Mul<RXingResultPoint> for RXingResultPoint {
type Output = RXingResultPoint; type Output = Self;
fn mul(self, rhs: RXingResultPoint) -> Self::Output { fn mul(self, rhs: Self) -> Self::Output {
Self { Self {
x: self.x * rhs.x, x: self.x * rhs.x,
y: self.y * rhs.y, y: self.y * rhs.y,
@@ -132,7 +121,7 @@ impl std::ops::Mul<RXingResultPoint> for RXingResultPoint {
} }
impl std::ops::Mul<f32> for RXingResultPoint { impl std::ops::Mul<f32> for RXingResultPoint {
type Output = RXingResultPoint; type Output = Self;
fn mul(self, rhs: f32) -> Self::Output { fn mul(self, rhs: f32) -> Self::Output {
Self { Self {
@@ -143,7 +132,7 @@ impl std::ops::Mul<f32> for RXingResultPoint {
} }
impl std::ops::Mul<i32> for RXingResultPoint { impl std::ops::Mul<i32> for RXingResultPoint {
type Output = RXingResultPoint; type Output = Self;
fn mul(self, rhs: i32) -> Self::Output { fn mul(self, rhs: i32) -> Self::Output {
Self { Self {
@@ -157,7 +146,7 @@ impl std::ops::Mul<RXingResultPoint> for i32 {
type Output = RXingResultPoint; type Output = RXingResultPoint;
fn mul(self, rhs: RXingResultPoint) -> Self::Output { fn mul(self, rhs: RXingResultPoint) -> Self::Output {
RXingResultPoint { Self::Output {
x: rhs.x * self as f32, x: rhs.x * self as f32,
y: rhs.y * self as f32, y: rhs.y * self as f32,
} }
@@ -168,29 +157,7 @@ impl std::ops::Mul<RXingResultPoint> for f32 {
type Output = RXingResultPoint; type Output = RXingResultPoint;
fn mul(self, rhs: RXingResultPoint) -> Self::Output { fn mul(self, rhs: RXingResultPoint) -> Self::Output {
RXingResultPoint { Self::Output {
x: rhs.x * self,
y: rhs.y * self,
}
}
}
impl std::ops::Mul<&RXingResultPoint> for f32 {
type Output = RXingResultPoint;
fn mul(self, rhs: &RXingResultPoint) -> Self::Output {
RXingResultPoint {
x: rhs.x * self,
y: rhs.y * self,
}
}
}
impl std::ops::Mul<&mut RXingResultPoint> for f32 {
type Output = RXingResultPoint;
fn mul(self, rhs: &mut RXingResultPoint) -> Self::Output {
RXingResultPoint {
x: rhs.x * self, x: rhs.x * self,
y: rhs.y * self, y: rhs.y * self,
} }
@@ -209,66 +176,57 @@ impl std::ops::Div<f32> for RXingResultPoint {
} }
impl RXingResultPoint { impl RXingResultPoint {
pub fn dot(a: RXingResultPoint, b: RXingResultPoint) -> f32 { pub fn dot(self, p: Self) -> f32 {
a.x * b.x + a.y * b.y self.x * p.x + self.y * p.y
} }
pub fn cross(a: &RXingResultPoint, b: &RXingResultPoint) -> f32 { pub fn cross(self, p: Self) -> f32 {
a.x * b.y - b.x * a.y self.x * p.y - p.x * self.y
} }
/// L1 norm /// L1 norm
pub fn sumAbsComponent(p: &RXingResultPoint) -> f32 { pub fn sumAbsComponent(self) -> f32 {
(p.x).abs() + (p.y).abs() self.x.abs() + self.y.abs()
} }
/// L2 norm /// L2 norm
pub fn length(p: RXingResultPoint) -> f32 { pub fn length(self) -> f32 {
(Self::dot(p, p)).sqrt() Self::dot(self, self).sqrt()
} }
/// L-inf norm /// L-inf norm
pub fn maxAbsComponent(p: &RXingResultPoint) -> f32 { pub fn maxAbsComponent(self) -> f32 {
let a = (p.x).abs(); f32::max(self.x.abs(), self.y.abs())
let b = (p.y).abs();
if a > b {
a
} else {
b
}
// return std::cmp::max((p.x).abs(), (p.y).abs());
} }
pub fn distance(a: RXingResultPoint, b: RXingResultPoint) -> f32 { pub fn distance(self, p: Self) -> f32 {
Self::length(a - b) Self::length(self - p)
} }
/// Calculate a floating point pixel coordinate representing the 'center' of the pixel. /// Calculate a floating point pixel coordinate representing the 'center' of the pixel.
/// This is sort of the inverse operation of the PointI(PointF) conversion constructor. /// This is sort of the inverse operation of the PointI(PointF) conversion constructor.
/// See also the documentation of the GridSampler API. /// See also the documentation of the GridSampler API.
#[inline(always)] #[inline(always)]
pub fn centered(p: &RXingResultPoint) -> RXingResultPoint { pub fn centered(self) -> Self {
RXingResultPoint { Self {
x: (p.x).floor() + 0.5, x: self.x.floor() + 0.5,
y: (p.y).floor() + 0.5, y: self.y.floor() + 0.5,
} }
} }
pub fn normalized(d: RXingResultPoint) -> RXingResultPoint { pub fn normalized(self) -> Self {
d / Self::length(d) self / Self::length(self)
} }
pub fn bresenhamDirection(d: &RXingResultPoint) -> RXingResultPoint { pub fn bresenhamDirection(self) -> Self {
*d / Self::maxAbsComponent(d) self / Self::maxAbsComponent(self)
} }
pub fn mainDirection(d: RXingResultPoint) -> RXingResultPoint { pub fn mainDirection(self) -> Self {
if (d.x).abs() > (d.y).abs() { if self.x.abs() > self.y.abs() {
Self::new(d.x, 0.0) Self::new(self.x, 0.0)
} else { } else {
Self::new(0.0, d.y) Self::new(0.0, self.y)
} }
} }
} }