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

@@ -68,8 +68,8 @@ impl<'a> Detector<'_> {
let bottomRight = points[2];
let topRight = points[3];
let mut dimensionTop = self.transitionsBetween(&topLeft, &topRight) + 1;
let mut dimensionRight = self.transitionsBetween(&bottomRight, &topRight) + 1;
let mut dimensionTop = self.transitionsBetween(topLeft, topRight) + 1;
let mut dimensionRight = self.transitionsBetween(bottomRight, topRight) + 1;
if (dimensionTop & 0x01) == 1 {
dimensionTop += 1;
}
@@ -85,10 +85,10 @@ impl<'a> Detector<'_> {
let bits = Self::sampleGrid(
self.image,
&topLeft,
&bottomLeft,
&bottomRight,
&topRight,
topLeft,
bottomLeft,
bottomRight,
topRight,
dimensionTop,
dimensionRight,
)?;
@@ -135,10 +135,10 @@ impl<'a> Detector<'_> {
let pointC = cornerPoints[3];
let pointD = cornerPoints[2];
let trAB = self.transitionsBetween(&pointA, &pointB);
let trBC = self.transitionsBetween(&pointB, &pointC);
let trCD = self.transitionsBetween(&pointC, &pointD);
let trDA = self.transitionsBetween(&pointD, &pointA);
let trAB = self.transitionsBetween(pointA, pointB);
let trBC = self.transitionsBetween(pointB, pointC);
let trCD = self.transitionsBetween(pointC, pointD);
let trDA = self.transitionsBetween(pointD, pointA);
// 0..3
// : :
@@ -183,11 +183,11 @@ impl<'a> Detector<'_> {
// Transition detection on the edge is not stable.
// 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 pointCs = Self::shiftPoint(pointC, pointB, (tr + 1) * 4);
let trBA = self.transitionsBetween(&pointBs, &pointA);
let trCD = self.transitionsBetween(&pointCs, &pointD);
let trBA = self.transitionsBetween(pointBs, pointA);
let trCD = self.transitionsBetween(pointCs, pointD);
// 0..3
// | :
@@ -222,13 +222,13 @@ impl<'a> Detector<'_> {
let pointD = points[3];
// shift points for safe transition detection.
let mut trTop = self.transitionsBetween(&pointA, &pointD);
let mut trRight = self.transitionsBetween(&pointB, &pointD);
let mut trTop = self.transitionsBetween(pointA, pointD);
let mut trRight = self.transitionsBetween(pointB, pointD);
let pointAs = Self::shiftPoint(pointA, pointB, (trRight + 1) * 4);
let pointCs = Self::shiftPoint(pointC, pointB, (trTop + 1) * 4);
trTop = self.transitionsBetween(&pointAs, &pointD);
trRight = self.transitionsBetween(&pointCs, &pointD);
trTop = self.transitionsBetween(pointAs, pointD);
trRight = self.transitionsBetween(pointCs, pointD);
let candidate1 = RXingResultPoint::new(
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),
);
if !self.isValid(&candidate1) {
if self.isValid(&candidate2) {
if !self.isValid(candidate1) {
if self.isValid(candidate2) {
return Some(candidate2);
}
return None;
}
if !self.isValid(&candidate2) {
if !self.isValid(candidate2) {
return Some(candidate1);
}
let sumc1 = self.transitionsBetween(&pointAs, &candidate1)
+ self.transitionsBetween(&pointCs, &candidate1);
let sumc2 = self.transitionsBetween(&pointAs, &candidate2)
+ self.transitionsBetween(&pointCs, &candidate2);
let sumc1 = self.transitionsBetween(pointAs, candidate1)
+ self.transitionsBetween(pointCs, candidate1);
let sumc2 = self.transitionsBetween(pointAs, candidate2)
+ self.transitionsBetween(pointCs, candidate2);
if sumc1 > sumc2 {
Some(candidate1)
@@ -274,16 +274,16 @@ impl<'a> Detector<'_> {
let mut pointD = points[3];
// calculate pseudo dimensions
let mut dimH = self.transitionsBetween(&pointA, &pointD) + 1;
let mut dimV = self.transitionsBetween(&pointC, &pointD) + 1;
let mut dimH = self.transitionsBetween(pointA, pointD) + 1;
let mut dimV = self.transitionsBetween(pointC, pointD) + 1;
// shift points for safe dimension detection
let mut pointAs = Self::shiftPoint(pointA, pointB, dimV * 4);
let mut pointCs = Self::shiftPoint(pointC, pointB, dimH * 4);
// calculate more precise dimensions
dimH = self.transitionsBetween(&pointAs, &pointD) + 1;
dimV = self.transitionsBetween(&pointCs, &pointD) + 1;
dimH = self.transitionsBetween(pointAs, pointD) + 1;
dimV = self.transitionsBetween(pointCs, pointD) + 1;
if (dimH & 0x01) == 1 {
dimH += 1;
}
@@ -316,7 +316,7 @@ impl<'a> Detector<'_> {
[pointAs, pointBs, pointCs, pointDs]
}
fn isValid(&self, p: &RXingResultPoint) -> bool {
fn isValid(&self, p: RXingResultPoint) -> bool {
p.getX() >= 0.0
&& p.getX() <= self.image.getWidth() as f32 - 1.0
&& p.getY() > 0.0
@@ -325,10 +325,10 @@ impl<'a> Detector<'_> {
fn sampleGrid(
image: &BitMatrix,
topLeft: &RXingResultPoint,
bottomLeft: &RXingResultPoint,
bottomRight: &RXingResultPoint,
topRight: &RXingResultPoint,
topLeft: RXingResultPoint,
bottomLeft: RXingResultPoint,
bottomRight: RXingResultPoint,
topRight: RXingResultPoint,
dimensionX: u32,
dimensionY: u32,
) -> 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.
*/
fn transitionsBetween(&self, from: &RXingResultPoint, to: &RXingResultPoint) -> u32 {
fn transitionsBetween(&self, from: RXingResultPoint, to: RXingResultPoint) -> u32 {
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
let mut fromX = from.getX().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); }
fn testAt(&self, p: &RXingResultPoint) -> Value; //const
// {
// return img->isIn(p) ? Value{img->get(p)} : Value{};
// }
fn testAt(&self, p: RXingResultPoint) -> Value; //const
// {
// 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()
}
fn whiteAt(&self, pos: &RXingResultPoint) -> bool {
fn whiteAt(&self, pos: RXingResultPoint) -> bool {
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 isBlack(&self) -> bool; // { return blackAt(p); }
fn isWhite(&self) -> bool; // { return whiteAt(p); }
@@ -46,30 +46,30 @@ pub trait BitMatrixCursor {
fn turnRight(&mut self); //noexcept { d = right(); }
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);
// return testAt(p + d) != v ? v : Value();
// }
fn edgeAtFront(&self) -> Value {
return self.edgeAt_point(self.front());
return self.edgeAt_point(*self.front());
}
fn edgeAtBack(&self) -> Value {
self.edgeAt_point(&self.back())
self.edgeAt_point(self.back())
}
fn edgeAtLeft(&self) -> Value {
self.edgeAt_point(&self.left())
self.edgeAt_point(self.left())
}
fn edgeAtRight(&self) -> Value {
self.edgeAt_point(&self.right())
self.edgeAt_point(self.right())
}
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(&self, dir:&RXingResultPoint);// { d = dir; }
fn setDirection(&mut self, dir: RXingResultPoint); // { d = bresenhamDirection(dir); }
// fn setDirection(&self, dir: RXingResultPoint);// { d = dir; }
fn step(&mut self, s: Option<f32>) -> bool; // DEF to 1
// {
@@ -77,7 +77,7 @@ pub trait BitMatrixCursor {
// return isIn(p);
// }
fn movedBy<T: BitMatrixCursor>(self, d: &RXingResultPoint) -> Self;
fn movedBy<T: BitMatrixCursor>(self, d: RXingResultPoint) -> Self;
// {
// auto res = *this;
// res.p += d;

View File

@@ -76,7 +76,7 @@ fn Scan(
// follow left leg upwards
t.turnRight();
t.state = 1;
CHECK!(t.traceLine(&t.right(), lineL)?);
CHECK!(t.traceLine(t.right(), lineL)?);
CHECK!(t.traceCorner(&mut t.right(), &mut tl)?);
lineL.reverse();
let mut tlTracer = t;
@@ -84,19 +84,19 @@ fn Scan(
// follow left leg downwards
t = startTracer.clone();
t.state = 1;
t.setDirection(&tlTracer.right());
CHECK!(t.traceLine(&t.left(), lineL)?);
t.setDirection(tlTracer.right());
CHECK!(t.traceLine(t.left(), lineL)?);
if !lineL.isValid() {
t.updateDirectionFromOrigin(&tl);
t.updateDirectionFromOrigin(tl);
}
let up = t.back();
CHECK!(t.traceCorner(&mut t.left(), &mut bl)?);
// follow bottom leg right
t.state = 2;
CHECK!(t.traceLine(&t.left(), lineB)?);
CHECK!(t.traceLine(t.left(), lineB)?);
if !lineB.isValid() {
t.updateDirectionFromOrigin(&bl);
t.updateDirectionFromOrigin(bl);
}
let right = *t.front();
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:
// follow top row right 'half way' (4 gaps), see traceGaps break condition with 'invalid' line
tlTracer.setDirection(&right);
tlTracer.setDirection(right);
CHECK!(tlTracer.traceGaps(
&tlTracer.right(),
tlTracer.right(),
lineT,
maxStepSize,
&mut DMRegressionLine::default()
@@ -124,9 +124,9 @@ fn Scan(
maxStepSize = std::cmp::min(lineT.length() as i32 / 3, (lenL / 5.0) as i32) * 2;
// follow up until we reach the top line
t.setDirection(&up);
t.setDirection(up);
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)?);
let lenT = distance(&tl, &tr) - 1.0;
@@ -140,7 +140,7 @@ fn Scan(
);
// 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
// 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
};
};
splitDouble(lineT.modules(&tl, &tr)?, &mut dimT, &mut fracT);
splitDouble(lineR.modules(&br, &tr)?, &mut dimR, &mut fracR);
splitDouble(lineT.modules(tl, tr)?, &mut dimT, &mut fracT);
splitDouble(lineR.modules(br, tr)?, &mut dimR, &mut fracR);
// #ifdef PRINT_DEBUG
// 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));
let movedTowardsBy = |a: &RXingResultPoint,
b1: &RXingResultPoint,
b2: &RXingResultPoint,
let movedTowardsBy = |a: RXingResultPoint,
b1: RXingResultPoint,
b2: RXingResultPoint,
d: f32|
-> RXingResultPoint {
*a + d * RXingResultPoint::normalized(
RXingResultPoint::normalized(*b1 - *a) + RXingResultPoint::normalized(*b2 - *a),
a + d * RXingResultPoint::normalized(
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
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
// inclined toward the center anyway.
movedTowardsBy(&tr, &br, &tl, 0.3),
movedTowardsBy(&br, &bl, &tr, 0.5),
movedTowardsBy(&bl, &tl, &br, 0.5),
movedTowardsBy(tr, br, tl, 0.3),
movedTowardsBy(br, bl, tr, 0.5),
movedTowardsBy(bl, tl, br, 0.5),
);
let grid_sampler = DefaultGridSampler::default();
@@ -303,7 +303,7 @@ pub fn detect(
y: (image.getHeight() / 2) as f32,
}; //PointF(image.width() / 2, image.height() / 2);
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 {
history.borrow_mut().clear(0);

View File

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

View File

@@ -31,7 +31,7 @@ pub struct EdgeTracer<'a> {
// }
impl BitMatrixCursor for EdgeTracer<'_> {
fn testAt(&self, p: &RXingResultPoint) -> Value {
fn testAt(&self, p: RXingResultPoint) -> Value {
if self.img.isIn(p, 0) {
Value::from(self.img.get_point(p))
} 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)
}
fn isInSelf(&self) -> bool {
self.isIn(&self.p)
self.isIn(self.p)
}
fn isBlack(&self) -> bool {
self.blackAt(&self.p)
self.blackAt(self.p)
}
fn isWhite(&self) -> bool {
self.whiteAt(&self.p)
self.whiteAt(self.p)
}
fn front(&self) -> &RXingResultPoint {
@@ -96,28 +96,28 @@ impl BitMatrixCursor for EdgeTracer<'_> {
self.d = self.direction(dir)
}
fn edgeAt_point(&self, d: &RXingResultPoint) -> Value {
let v = self.testAt(&self.p);
if self.testAt(&(self.p + *d)) != v {
fn edgeAt_point(&self, d: RXingResultPoint) -> Value {
let v = self.testAt(self.p);
if self.testAt(self.p + d) != v {
v
} else {
Value::Invalid
}
}
fn setDirection(&mut self, dir: &RXingResultPoint) {
self.d = RXingResultPoint::bresenhamDirection(dir)
fn setDirection(&mut self, dir: RXingResultPoint) {
self.d = dir.bresenhamDirection();
}
fn step(&mut self, s: Option<f32>) -> bool {
let s = if let Some(s) = s { s } else { 1.0 };
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;
res.p += *d;
res.p += d;
res
}
@@ -135,11 +135,11 @@ impl BitMatrixCursor for EdgeTracer<'_> {
let backup = if let Some(b) = backup { b } else { false };
// TODO: provide an alternative and faster out-of-bounds check than isIn() inside testAt()
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() {
steps += 1;
let v = self.testAt(&(self.p + steps * self.d));
let v = self.testAt(self.p + steps * self.d);
if lv != v {
lv = v;
nth -= 1;
@@ -167,11 +167,11 @@ impl<'a> EdgeTracer<'_> {
fn traceStep(
&mut self,
dEdge: &RXingResultPoint,
dEdge: RXingResultPoint,
maxStepSize: i32,
goodDirection: bool,
) -> Result<StepResult, Exceptions> {
let dEdge = RXingResultPoint::mainDirection(*dEdge);
let dEdge = RXingResultPoint::mainDirection(dEdge);
for breadth in 1..=(if maxStepSize == 1 {
2
} else if goodDirection {
@@ -189,19 +189,19 @@ impl<'a> EdgeTracer<'_> {
+ (if i & 1 > 0 { (i + 1) / 2 } else { -i / 2 }) * dEdge;
// dbg!(pEdge);
if !self.blackAt(&(pEdge + dEdge)) {
if !self.blackAt(pEdge + dEdge) {
continue;
}
// found black pixel -> go 'outward' until we hit the b/w border
for _j in 0..(std::cmp::max(maxStepSize, 3)) {
// 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 self.p == RXingResultPoint::centered(&pEdge) {
if self.p == pEdge.centered() {
return Err(Exceptions::IllegalStateException(None));
}
self.p = RXingResultPoint::centered(&pEdge);
self.p = pEdge.centered();
// if (self.history && maxStepSize == 1) {
if let Some(history) = &self.history {
@@ -222,12 +222,12 @@ impl<'a> EdgeTracer<'_> {
return Ok(StepResult::Found);
}
pEdge = pEdge - dEdge;
if self.blackAt(&(pEdge - self.d)) {
if self.blackAt(pEdge - self.d) {
pEdge = pEdge - self.d;
}
// dbg!(pEdge);
if !self.isIn(&pEdge) {
if !self.isIn(pEdge) {
break;
}
}
@@ -239,9 +239,9 @@ impl<'a> EdgeTracer<'_> {
Ok(StepResult::OpenEnd)
}
pub fn updateDirectionFromOrigin(&mut self, origin: &RXingResultPoint) -> bool {
pub fn updateDirectionFromOrigin(&mut self, origin: RXingResultPoint) -> bool {
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 RXingResultPoint::dot(self.d, old_d) < 0.0 {
return false;
@@ -260,24 +260,24 @@ impl<'a> EdgeTracer<'_> {
pub fn traceLine<T: RegressionLine>(
&mut self,
dEdge: &RXingResultPoint,
dEdge: RXingResultPoint,
line: &mut T,
) -> Result<bool, Exceptions> {
line.setDirectionInward(dEdge);
loop {
// log(self.p);
line.add(&self.p)?;
line.add(self.p)?;
if line.points().len() % 50 == 10 {
if !line.evaluate_max_distance(None, None) {
return Ok(false);
}
if !self.updateDirectionFromOrigin(
&(self.p - line.project(&self.p)
self.p - line.project(self.p)
+ **line
.points()
.first()
.as_ref()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?),
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
) {
return Ok(false);
}
@@ -291,7 +291,7 @@ impl<'a> EdgeTracer<'_> {
pub fn traceGaps<T: RegressionLine>(
&mut self,
dEdge: &RXingResultPoint,
dEdge: RXingResultPoint,
line: &mut T,
maxStepSize: i32,
finishLine: &mut T,
@@ -325,14 +325,14 @@ impl<'a> EdgeTracer<'_> {
// if we drifted too far outside of the code, break
if line.isValid()
&& line.signedDistance(&self.p) < -5.0
&& (!line.evaluate_max_distance(None, None) || line.signedDistance(&self.p) < -5.0)
&& line.signedDistance(self.p) < -5.0
&& (!line.evaluate_max_distance(None, None) || line.signedDistance(self.p) < -5.0)
{
return Ok(false);
}
// 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.
// 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
@@ -350,7 +350,7 @@ impl<'a> EdgeTracer<'_> {
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:
// consider a 90deg corner, rotated 45deg. we step away perpendicular from the line and get
// back projected where we left off the line.
@@ -362,14 +362,14 @@ impl<'a> EdgeTracer<'_> {
line.project(
line.points()
.last()
.as_ref()
.copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
),
) < 1.0
{
np += self.d;
}
self.p = RXingResultPoint::centered(&np);
self.p = RXingResultPoint::centered(np);
} else {
let stepLengthInMainDir = if line.points().is_empty() {
0.0
@@ -380,10 +380,11 @@ impl<'a> EdgeTracer<'_> {
- line
.points()
.last()
.copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
)
};
line.add(&self.p)?;
line.add(self.p)?;
if stepLengthInMainDir > 1.0 {
gaps += 1;
@@ -392,11 +393,12 @@ impl<'a> EdgeTracer<'_> {
return Ok(false);
}
if !self.updateDirectionFromOrigin(
&(self.p - line.project(&self.p)
+ *line
self.p - line.project(self.p)
+ line
.points()
.first()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?),
.copied()
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
) {
return Ok(false);
}
@@ -418,7 +420,7 @@ impl<'a> EdgeTracer<'_> {
if finishLine.isValid() {
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())?;
@@ -428,7 +430,7 @@ impl<'a> EdgeTracer<'_> {
{
return Ok(stepResult == StepResult::OpenEnd
&& finishLine.isValid()
&& (finishLine.signedDistance(&self.p)) as i32 <= maxStepSize + 1);
&& (finishLine.signedDistance(self.p)) as i32 <= maxStepSize + 1);
}
} //while (true);
}
@@ -442,10 +444,10 @@ impl<'a> EdgeTracer<'_> {
// log(p);
*corner = self.p;
std::mem::swap(&mut self.d, dir);
self.traceStep(&(-1.0 * dir), 2, false)?;
self.traceStep(-1.0 * (*dir), 2, false)?;
// #ifdef PRINT_DEBUG
// printf("turn: %.0f x %.0f -> %.2f, %.2f\n", p.x, p.y, d.x, d.y);
// #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 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() };
@@ -186,14 +186,14 @@ pub fn RotatedCorners(q: &Quadrilateral, n: Option<i32>, mirror: Option<bool>) -
}
#[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
let mut pos = 0;
let mut neg = 0;
for i in 0..q.0.len()
// 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;
} else {
pos += 1;

View File

@@ -13,7 +13,7 @@ pub trait RegressionLine {
// fn intersect<T: RegressionLine, T2: RegressionLine>(&self, l1: &T, l2: &T2)
// -> 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);
// 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 evaluateSelf(&mut self) -> bool;
fn distance(&self, a: &RXingResultPoint, b: &RXingResultPoint) -> f32 {
crate::result_point_utils::distance(a, b)
fn distance(&self, a: RXingResultPoint, b: RXingResultPoint) -> f32 {
crate::result_point_utils::distance(&a, &b)
}
// 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 isValid(&self) -> bool; //const { return !std::isnan(a); }
fn normal(&self) -> RXingResultPoint; //const { return isValid() ? PointF(a, b) : _directionInward; }
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 project(&self, p: &RXingResultPoint) -> RXingResultPoint {
*p - self.normal() * self.signedDistance(p)
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 project(&self, p: RXingResultPoint) -> RXingResultPoint {
p - self.normal() * self.signedDistance(p)
}
fn reset(&mut self);
@@ -76,16 +76,16 @@ pub trait RegressionLine {
// a = b = c = NAN;
// }
fn add(&mut self, p: &RXingResultPoint) -> Result<(), Exceptions>; //{
// assert(_directionInward != PointF());
// _points.push_back(p);
// if (_points.size() == 1)
// c = dot(normal(), p);
// }
fn add(&mut self, p: RXingResultPoint) -> Result<(), Exceptions>; //{
// assert(_directionInward != PointF());
// _points.push_back(p);
// if (_points.size() == 1)
// c = dot(normal(), p);
// }
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_max_distance(