mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-25 20:02:34 +00:00
port concentric finder (no test)
This commit is contained in:
@@ -78,12 +78,12 @@ pub trait BitMatrixCursor {
|
||||
// }
|
||||
|
||||
fn movedBy<T: BitMatrixCursor>(self, d: Point) -> Self;
|
||||
fn turnedBack(&self) -> Self;// { return {*img, p, back()}; }
|
||||
// {
|
||||
// auto res = *this;
|
||||
// res.p += d;
|
||||
// return res;
|
||||
// }
|
||||
fn turnedBack(&self) -> Self; // { return {*img, p, back()}; }
|
||||
// {
|
||||
// auto res = *this;
|
||||
// res.p += d;
|
||||
// return res;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief stepToEdge advances cursor to one step behind the next (or n-th) edge.
|
||||
|
||||
@@ -9,7 +9,8 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
BitMatrixCursor, DMRegressionLine, EdgeTracer, FastEdgeToEdgeCounter, Pattern, RegressionLine,
|
||||
BitMatrixCursor, EdgeTracer, FastEdgeToEdgeCounter, Pattern, RegressionLine,
|
||||
RegressionLineTrait,
|
||||
};
|
||||
|
||||
pub fn CenterFromEnd<const N: usize, T: Into<f32> + std::iter::Sum<T> + Copy>(
|
||||
@@ -378,7 +379,7 @@ pub fn FitQadrilateralToPoints(center: Point, points: &mut [Point]) -> Option<Qu
|
||||
.max_by(max_by_pred)?;
|
||||
// corners[2] = std::max_element(&points[Size(points) * 3 / 8], &points[Size(points) * 5 / 8], dist2Center);
|
||||
// find the two in between corners by looking for the points farthest from the long diagonal
|
||||
let l = DMRegressionLine::with_two_points(corners[0], corners[2]);
|
||||
let l = RegressionLine::with_two_points(corners[0], corners[2]);
|
||||
let dist2Diagonal = /*[l = RegressionLine(*corners[0], *corners[2])]*/| a, b| { l.distance_single(a) < l.distance_single(b) };
|
||||
|
||||
let diagonal_max_by_pred = |p1: &Point, p2: &Point| {
|
||||
@@ -400,10 +401,10 @@ pub fn FitQadrilateralToPoints(center: Point, points: &mut [Point]) -> Option<Qu
|
||||
// corners[3] = std::max_element(&points[Size(points) * 5 / 8], &points[Size(points) * 7 / 8], dist2Diagonal);
|
||||
|
||||
let lines = [
|
||||
DMRegressionLine::with_two_points((corners[0] + 1.0), corners[1]),
|
||||
DMRegressionLine::with_two_points((corners[1] + 1.0), corners[2]),
|
||||
DMRegressionLine::with_two_points((corners[2] + 1.0), corners[3]),
|
||||
DMRegressionLine::with_two_points((corners[3] + 1.0), (*points.last()? + 1.0)),
|
||||
RegressionLine::with_two_points((corners[0] + 1.0), corners[1]),
|
||||
RegressionLine::with_two_points((corners[1] + 1.0), corners[2]),
|
||||
RegressionLine::with_two_points((corners[2] + 1.0), corners[3]),
|
||||
RegressionLine::with_two_points((corners[3] + 1.0), (*points.last()? + 1.0)),
|
||||
];
|
||||
// std::array lines{RegressionLine{corners[0] + 1, corners[1]}, RegressionLine{corners[1] + 1, corners[2]},
|
||||
// RegressionLine{corners[2] + 1, corners[3]}, RegressionLine{corners[3] + 1, &points.back() + 1}};
|
||||
@@ -414,7 +415,7 @@ pub fn FitQadrilateralToPoints(center: Point, points: &mut [Point]) -> Option<Qu
|
||||
let mut res = Quadrilateral::default();
|
||||
for i in 0..4 {
|
||||
// for (int i = 0; i < 4; ++i) {
|
||||
res[i] = DMRegressionLine::intersect(&lines[i], &lines[(i + 1) % 4])?;
|
||||
res[i] = RegressionLine::intersect(&lines[i], &lines[(i + 1) % 4])?;
|
||||
}
|
||||
|
||||
Some(res)
|
||||
@@ -483,42 +484,61 @@ pub fn FindConcentricPatternCorners(
|
||||
#[derive(Default)]
|
||||
pub struct ConcentricPattern {
|
||||
p: Point,
|
||||
size: usize,
|
||||
size: i32,
|
||||
}
|
||||
|
||||
pub fn LocateConcentricPattern<const RELAXED_THRESHOLD:bool, const LEN: usize,
|
||||
const SUM: usize,
|
||||
T: BitMatrixCursor>( image:&BitMatrix, pattern:&Pattern<LEN>, center:Point, range:i32) -> Option<ConcentricPattern>
|
||||
{
|
||||
let mut cur = EdgeTracer::new(image, center, Point::default());
|
||||
let mut minSpread = image.getWidth() as i32;
|
||||
pub fn LocateConcentricPattern<
|
||||
const RELAXED_THRESHOLD: bool,
|
||||
const LEN: usize,
|
||||
const SUM: usize,
|
||||
T: BitMatrixCursor,
|
||||
>(
|
||||
image: &BitMatrix,
|
||||
pattern: &Pattern<LEN>,
|
||||
center: Point,
|
||||
range: i32,
|
||||
) -> Option<ConcentricPattern> {
|
||||
let mut cur = EdgeTracer::new(image, center, Point::default());
|
||||
let mut minSpread = image.getWidth() as i32;
|
||||
let mut maxSpread = 0_i32;
|
||||
for d in [point(0.0,1.0), point(1.0,0.0)] {
|
||||
// for (auto d : {PointI{0, 1}, {1, 0}}) {
|
||||
for d in [point(0.0, 1.0), point(1.0, 0.0)] {
|
||||
// for (auto d : {PointI{0, 1}, {1, 0}}) {
|
||||
cur.setDirection(d); // THIS COULD POSSIBLY BE WRONG, WE MIGHT MEAN TO CLONE cur EACH RUN?
|
||||
let spread = CheckSymmetricPattern(&mut cur, pattern, range, true);
|
||||
if (!(spread != 0))
|
||||
{return None}
|
||||
UpdateMinMax(&mut minSpread, &mut maxSpread, spread);
|
||||
}
|
||||
let spread =
|
||||
CheckSymmetricPattern::<RELAXED_THRESHOLD, LEN, SUM, _>(&mut cur, pattern, range, true);
|
||||
if (!(spread != 0)) {
|
||||
return None;
|
||||
}
|
||||
UpdateMinMax(&mut minSpread, &mut maxSpread, spread);
|
||||
}
|
||||
|
||||
//#if 1
|
||||
for d in [point(1.0,1.0), point(1.0,-1.0)] {
|
||||
// for (auto d : {PointI{1, 1}, {1, -1}}) {
|
||||
cur.setDirection(d);// THIS COULD POSSIBLY BE WRONG, WE MIGHT MEAN TO CLONE cur EACH RUN?
|
||||
let spread = CheckSymmetricPattern(&mut cur, pattern, range * 2, false);
|
||||
if (!(spread != 0))
|
||||
{return None}
|
||||
UpdateMinMax(&mut minSpread, &mut maxSpread, spread);
|
||||
}
|
||||
//#endif
|
||||
//#if 1
|
||||
for d in [point(1.0, 1.0), point(1.0, -1.0)] {
|
||||
// for (auto d : {PointI{1, 1}, {1, -1}}) {
|
||||
cur.setDirection(d); // THIS COULD POSSIBLY BE WRONG, WE MIGHT MEAN TO CLONE cur EACH RUN?
|
||||
let spread = CheckSymmetricPattern::<RELAXED_THRESHOLD, LEN, SUM, _>(
|
||||
&mut cur,
|
||||
pattern,
|
||||
range * 2,
|
||||
false,
|
||||
);
|
||||
if (!(spread != 0)) {
|
||||
return None;
|
||||
}
|
||||
UpdateMinMax(&mut minSpread, &mut maxSpread, spread);
|
||||
}
|
||||
//#endif
|
||||
|
||||
if (maxSpread > 5 * minSpread)
|
||||
{return None}
|
||||
if (maxSpread > 5 * minSpread) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let newCenter = FinetuneConcentricPatternCenter(image, cur.p(), range, pattern.len() as u32)?;
|
||||
let newCenter = FinetuneConcentricPatternCenter(image, cur.p(), range, pattern.len() as u32)?;
|
||||
|
||||
Some(ConcentricPattern{*newCenter, (maxSpread + minSpread) / 2})
|
||||
Some(ConcentricPattern {
|
||||
p: newCenter,
|
||||
size: (maxSpread + minSpread) / 2,
|
||||
})
|
||||
}
|
||||
|
||||
fn UpdateMinMax<T: Ord + Copy>(min: &mut T, max: &mut T, val: T) {
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use crate::common::Result;
|
||||
use crate::{Exceptions, Point, point};
|
||||
use crate::{Exceptions, Point};
|
||||
|
||||
use super::{
|
||||
util::{float_max, float_min},
|
||||
RegressionLine,
|
||||
};
|
||||
use super::RegressionLineTrait;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DMRegressionLine {
|
||||
@@ -30,7 +27,7 @@ impl Default for DMRegressionLine {
|
||||
}
|
||||
}
|
||||
|
||||
impl RegressionLine for DMRegressionLine {
|
||||
impl RegressionLineTrait for DMRegressionLine {
|
||||
fn points(&self) -> &[Point] {
|
||||
&self.points
|
||||
}
|
||||
@@ -136,14 +133,14 @@ impl RegressionLine for DMRegressionLine {
|
||||
let Some(mut min) = self.points.first().copied() else { return false };
|
||||
let Some(mut max) = self.points.first().copied() else { return false };
|
||||
for p in &self.points {
|
||||
min.x = float_min(min.x, p.x);
|
||||
min.y = float_min(min.y, p.y);
|
||||
max.x = float_max(max.x, p.x);
|
||||
max.y = float_max(max.y, p.y);
|
||||
min.x = f32::min(min.x, p.x);
|
||||
min.y = f32::min(min.y, p.y);
|
||||
max.x = f32::max(max.x, p.x);
|
||||
max.y = f32::max(max.y, p.y);
|
||||
}
|
||||
let diff = max - min;
|
||||
let len = diff.maxAbsComponent();
|
||||
let steps = float_min(diff.x.abs(), diff.y.abs());
|
||||
let steps = f32::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
|
||||
}
|
||||
@@ -226,12 +223,6 @@ impl RegressionLine for DMRegressionLine {
|
||||
}
|
||||
|
||||
impl DMRegressionLine {
|
||||
pub fn with_two_points(point1: Point, point2: Point) -> Self {
|
||||
let mut new_rl = DMRegressionLine::default();
|
||||
new_rl.evaluate(&[point1, point2]);
|
||||
new_rl
|
||||
}
|
||||
|
||||
// template <typename Container, typename Filter>
|
||||
fn average<T>(c: &[f64], f: T) -> f64
|
||||
where
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
Exceptions, Point,
|
||||
};
|
||||
|
||||
use super::{BitMatrixCursor, Direction, RegressionLine, StepResult, Value};
|
||||
use super::{BitMatrixCursor, Direction, RegressionLineTrait, StepResult, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EdgeTracer<'a> {
|
||||
@@ -142,9 +142,9 @@ impl BitMatrixCursor for EdgeTracer<'_> {
|
||||
*/
|
||||
fn stepToEdge(&mut self, nth: Option<i32>, range: Option<i32>, backup: Option<bool>) -> i32 {
|
||||
let mut nth = nth.unwrap_or(1); //if let Some(nth) = nth { nth } else { 1 };
|
||||
let range = range.unwrap_or(0);//if let Some(r) = range { r } else { 0 };
|
||||
let backup = backup.unwrap_or(false);//if let Some(b) = backup { b } else { false };
|
||||
// TODO: provide an alternative and faster out-of-bounds check than isIn() inside testAt()
|
||||
let range = range.unwrap_or(0); //if let Some(r) = range { r } else { 0 };
|
||||
let backup = backup.unwrap_or(false); //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);
|
||||
|
||||
@@ -166,7 +166,6 @@ impl BitMatrixCursor for EdgeTracer<'_> {
|
||||
fn p(&self) -> Point {
|
||||
self.p
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<'a> EdgeTracer<'_> {
|
||||
@@ -271,7 +270,11 @@ impl<'a> EdgeTracer<'_> {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn traceLine<T: RegressionLine>(&mut self, dEdge: Point, line: &mut T) -> Result<bool> {
|
||||
pub fn traceLine<T: RegressionLineTrait>(
|
||||
&mut self,
|
||||
dEdge: Point,
|
||||
line: &mut T,
|
||||
) -> Result<bool> {
|
||||
line.setDirectionInward(dEdge);
|
||||
loop {
|
||||
// log(self.p);
|
||||
@@ -298,7 +301,7 @@ impl<'a> EdgeTracer<'_> {
|
||||
} // while (true);
|
||||
}
|
||||
|
||||
pub fn traceGaps<T: RegressionLine>(
|
||||
pub fn traceGaps<T: RegressionLineTrait>(
|
||||
&mut self,
|
||||
dEdge: Point,
|
||||
line: &mut T,
|
||||
|
||||
@@ -2,39 +2,37 @@ use super::BitMatrixCursor;
|
||||
|
||||
pub struct FastEdgeToEdgeCounter {
|
||||
// const uint8_t* p = nullptr;
|
||||
// int stride = 0;
|
||||
// int stepsToBorder = 0;
|
||||
// int stride = 0;
|
||||
// int stepsToBorder = 0;
|
||||
}
|
||||
|
||||
impl FastEdgeToEdgeCounter
|
||||
{
|
||||
impl FastEdgeToEdgeCounter {
|
||||
pub fn new<T: BitMatrixCursor>(cur: &T) -> Self {
|
||||
todo!()
|
||||
// stride = cur.d.y * cur.img->width() + cur.d.x;
|
||||
// p = cur.img->row(cur.p.y).begin() + cur.p.x;
|
||||
// p = cur.img->row(cur.p.y).begin() + cur.p.x;
|
||||
|
||||
// int maxStepsX = cur.d.x ? (cur.d.x > 0 ? cur.img->width() - 1 - cur.p.x : cur.p.x) : INT_MAX;
|
||||
// int maxStepsY = cur.d.y ? (cur.d.y > 0 ? cur.img->height() - 1 - cur.p.y : cur.p.y) : INT_MAX;
|
||||
// stepsToBorder = std::min(maxStepsX, maxStepsY);
|
||||
// int maxStepsX = cur.d.x ? (cur.d.x > 0 ? cur.img->width() - 1 - cur.p.x : cur.p.x) : INT_MAX;
|
||||
// int maxStepsY = cur.d.y ? (cur.d.y > 0 ? cur.img->height() - 1 - cur.p.y : cur.p.y) : INT_MAX;
|
||||
// stepsToBorder = std::min(maxStepsX, maxStepsY);
|
||||
}
|
||||
|
||||
pub fn stepToNextEdge(&self, range: i32) -> i32
|
||||
{
|
||||
pub fn stepToNextEdge(&self, range: i32) -> i32 {
|
||||
todo!()
|
||||
// int maxSteps = std::min(stepsToBorder, range);
|
||||
// int steps = 0;
|
||||
// do {
|
||||
// if (++steps > maxSteps) {
|
||||
// if (maxSteps == stepsToBorder)
|
||||
// break;
|
||||
// else
|
||||
// return 0;
|
||||
// }
|
||||
// } while (p[steps * stride] == p[0]);
|
||||
// int maxSteps = std::min(stepsToBorder, range);
|
||||
// int steps = 0;
|
||||
// do {
|
||||
// if (++steps > maxSteps) {
|
||||
// if (maxSteps == stepsToBorder)
|
||||
// break;
|
||||
// else
|
||||
// return 0;
|
||||
// }
|
||||
// } while (p[steps * stride] == p[0]);
|
||||
|
||||
// p += steps * stride;
|
||||
// stepsToBorder -= steps;
|
||||
// p += steps * stride;
|
||||
// stepsToBorder -= steps;
|
||||
|
||||
// return steps;
|
||||
}
|
||||
}
|
||||
// return steps;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,21 +3,23 @@ pub mod concentric_finder;
|
||||
pub mod direction;
|
||||
pub mod dm_regression_line;
|
||||
pub mod edge_tracer;
|
||||
pub mod fast_edge_to_edge_counter;
|
||||
pub mod pattern;
|
||||
pub mod regression_line;
|
||||
pub mod regression_line_trait;
|
||||
pub mod step_result;
|
||||
pub mod util;
|
||||
pub mod value;
|
||||
pub mod fast_edge_to_edge_counter;
|
||||
|
||||
pub use bitmatrix_cursor::*;
|
||||
pub use concentric_finder::*;
|
||||
pub use direction::*;
|
||||
pub use dm_regression_line::*;
|
||||
pub use edge_tracer::*;
|
||||
pub use fast_edge_to_edge_counter::*;
|
||||
pub use pattern::*;
|
||||
pub use regression_line::*;
|
||||
pub use regression_line_trait::*;
|
||||
pub use step_result::*;
|
||||
pub use util::*;
|
||||
pub use value::*;
|
||||
pub use fast_edge_to_edge_counter::*;
|
||||
|
||||
@@ -8,19 +8,19 @@ use crate::{common::Result, Exceptions};
|
||||
pub type PatternType = u16;
|
||||
pub type Pattern<const N: usize> = [PatternType; N];
|
||||
|
||||
#[derive(Default,Debug)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct PatternRow(Vec<PatternType>);
|
||||
|
||||
// pub struct PatternRow<T: std::iter::Sum + Into<f32> + Into<usize> + Copy>(Vec<T>);
|
||||
|
||||
impl PatternRow {
|
||||
pub fn new( v: Vec<PatternType>) -> Self {
|
||||
Self(v)
|
||||
}
|
||||
pub fn new(v: Vec<PatternType>) -> Self {
|
||||
Self(v)
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
pub fn into_pattern_view(&self) -> PatternView {
|
||||
PatternView::new(self)
|
||||
@@ -534,7 +534,7 @@ pub fn NormalizedPattern<'a, const LEN: usize, const SUM: usize>(
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum Color {
|
||||
White = 0,
|
||||
Black = 1
|
||||
Black = 1,
|
||||
}
|
||||
|
||||
impl<T: Into<PatternType>> From<T> for Color {
|
||||
@@ -546,11 +546,14 @@ impl<T: Into<PatternType>> From<T> for Color {
|
||||
}
|
||||
}
|
||||
|
||||
fn GetPatternRow<T: Into<PatternType> + Copy + Default + From<T>>(b_row: &[T], p_row: &mut PatternRow) {
|
||||
fn GetPatternRow<T: Into<PatternType> + Copy + Default + From<T>>(
|
||||
b_row: &[T],
|
||||
p_row: &mut PatternRow,
|
||||
) {
|
||||
p_row.0.clear();
|
||||
|
||||
if Color::from(p_row.0.first().copied().unwrap_or_default()) == Color::Black {
|
||||
// first
|
||||
// first
|
||||
p_row.0.push(0);
|
||||
}
|
||||
|
||||
@@ -567,7 +570,7 @@ fn GetPatternRow<T: Into<PatternType> + Copy + Default + From<T>>(b_row: &[T], p
|
||||
current_color = this_color;
|
||||
}
|
||||
|
||||
count +=1 ;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if count != 0 {
|
||||
@@ -577,7 +580,6 @@ fn GetPatternRow<T: Into<PatternType> + Copy + Default + From<T>>(b_row: &[T], p
|
||||
if current_color == Color::Black {
|
||||
p_row.0.push(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -591,7 +593,7 @@ mod tests {
|
||||
fn all_white() {
|
||||
for s in 1..=N {
|
||||
// for (int s = 1; s <= N; ++s) {
|
||||
let t_in:Vec<PatternType> = vec![0; s];
|
||||
let t_in: Vec<PatternType> = vec![0; s];
|
||||
// std::vector<uint8_t> in(s, 0);
|
||||
let mut pr = PatternRow::default();
|
||||
GetPatternRow(&t_in, &mut pr);
|
||||
@@ -620,7 +622,7 @@ mod tests {
|
||||
fn black_white() {
|
||||
for s in 1..=N {
|
||||
// for (int s = 1; s <= N; ++s) {
|
||||
let mut t_in : Vec<PatternType> = vec![0; N];
|
||||
let mut t_in: Vec<PatternType> = vec![0; N];
|
||||
t_in[..s].copy_from_slice(&vec![1; s]);
|
||||
// std::fill_n(in.data(), s, 0xff);
|
||||
let mut pr = PatternRow::default();
|
||||
@@ -652,11 +654,16 @@ mod tests {
|
||||
#[test]
|
||||
fn basic_pattern_view() {
|
||||
let mut p_row = PatternRow::default();
|
||||
GetPatternRow(&vec![0_u16,1,0,1,0,0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1], &mut p_row);
|
||||
GetPatternRow(
|
||||
&vec![
|
||||
0_u16, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
||||
],
|
||||
&mut p_row,
|
||||
);
|
||||
|
||||
let mut pv = PatternView::new(&p_row);
|
||||
|
||||
assert_eq!(pv.data().0,p_row.0);
|
||||
assert_eq!(pv.data().0, p_row.0);
|
||||
|
||||
assert_eq!(pv[0], 1_u16);
|
||||
assert_eq!(pv[1], 1_u16);
|
||||
@@ -667,6 +674,6 @@ mod tests {
|
||||
assert!(pv.shift(1));
|
||||
assert_eq!(pv.index(), 1);
|
||||
assert!(pv.skipPair());
|
||||
assert_eq!(pv.index(),3);
|
||||
assert_eq!(pv.index(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,147 +1,231 @@
|
||||
use crate::common::Result;
|
||||
use crate::{Point, point};
|
||||
use crate::{Exceptions, Point};
|
||||
|
||||
pub trait RegressionLine {
|
||||
// points: Vec<Point>,
|
||||
// direction_inward: Point,
|
||||
use super::RegressionLineTrait;
|
||||
|
||||
// }
|
||||
// impl RegressionLine {
|
||||
#[derive(Clone)]
|
||||
pub struct RegressionLine {
|
||||
points: Vec<Point>,
|
||||
direction_inward: Point,
|
||||
pub(super) a: f32,
|
||||
pub(super) b: f32,
|
||||
pub(super) c: f32,
|
||||
// std::vector<PointF> _points;
|
||||
// PointF _directionInward;
|
||||
// PointF::value_t a = NAN, b = NAN, c = NAN;
|
||||
}
|
||||
|
||||
fn intersect<T: RegressionLine, T2: RegressionLine>( l1: &T, l2: &T2)
|
||||
-> Option<Point>{
|
||||
if !(l1.isValid() && l2.isValid()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let d = l1.a() * l2.b() - l1.b() * l2.a();
|
||||
let x = (l1.c() * l2.b() - l1.b() * l2.c()) / d;
|
||||
let y = (l1.a() * l2.c() - l1.c() * l2.a()) / d;
|
||||
|
||||
Some(point(x, y))
|
||||
impl Default for RegressionLine {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
points: Default::default(),
|
||||
direction_inward: Default::default(),
|
||||
a: f32::NAN,
|
||||
b: f32::NAN,
|
||||
c: f32::NAN,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fn evaluate_begin_end(&self, begin: Point, end: Point) -> bool;// {
|
||||
// {
|
||||
// let mean = std::accumulate(begin, end, PointF()) / std::distance(begin, end);
|
||||
// PointF::value_t sumXX = 0, sumYY = 0, sumXY = 0;
|
||||
// for (auto p = begin; p != end; ++p) {
|
||||
// auto d = *p - mean;
|
||||
// sumXX += d.x * d.x;
|
||||
// sumYY += d.y * d.y;
|
||||
// sumXY += d.x * d.y;
|
||||
// }
|
||||
// if (sumYY >= sumXX) {
|
||||
// auto l = std::sqrt(sumYY * sumYY + sumXY * sumXY);
|
||||
// a = +sumYY / l;
|
||||
// b = -sumXY / l;
|
||||
// } else {
|
||||
// auto l = std::sqrt(sumXX * sumXX + sumXY * sumXY);
|
||||
// a = +sumXY / l;
|
||||
// b = -sumXX / l;
|
||||
// }
|
||||
// if (dot(_directionInward, normal()) < 0) {
|
||||
// a = -a;
|
||||
// b = -b;
|
||||
// }
|
||||
// c = dot(normal(), mean); // (a*mean.x + b*mean.y);
|
||||
// return dot(_directionInward, normal()) > 0.5f; // angle between original and new direction is at most 60 degree
|
||||
// }
|
||||
|
||||
fn evaluate(&mut self, points: &[Point]) -> bool; // { return self.evaluate_begin_end(&points.front(), &points.back() + 1); }
|
||||
fn evaluateSelf(&mut self) -> bool;
|
||||
|
||||
// RegressionLine() { _points.reserve(16); } // arbitrary but plausible start size (tiny performance improvement)
|
||||
|
||||
// template<typename T> RegressionLine(PointT<T> a, PointT<T> b)
|
||||
// {
|
||||
// evaluate(std::vector{a, b});
|
||||
// }
|
||||
|
||||
// template<typename T> RegressionLine(const PointT<T>* b, const PointT<T>* e)
|
||||
// {
|
||||
// evaluate(b, e);
|
||||
// }
|
||||
|
||||
fn points(&self) -> &[Point]; //const { return _points; }
|
||||
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) -> Point; //const { return isValid() ? PointF(a, b) : _directionInward; }
|
||||
fn signedDistance(&self, p: Point) -> f32; //const { return dot(normal(), p) - c; }
|
||||
fn distance_single(&self, p: Point) -> f32; //const { return std::abs(signedDistance(PointF(p))); }
|
||||
fn project(&self, p: Point) -> Point {
|
||||
p - self.normal() * self.signedDistance(p)
|
||||
impl RegressionLineTrait for RegressionLine {
|
||||
fn points(&self) -> &[Point] {
|
||||
&self.points
|
||||
}
|
||||
|
||||
fn reset(&mut self);
|
||||
// {
|
||||
// _points.clear();
|
||||
// _directionInward = {};
|
||||
// a = b = c = NAN;
|
||||
// }
|
||||
fn length(&self) -> u32 {
|
||||
if self.points.len() >= 2 {
|
||||
Point::distance(*self.points.first().unwrap(), *self.points.last().unwrap()) as u32
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&mut self, p: Point) -> Result<()>; //{
|
||||
// assert(_directionInward != PointF());
|
||||
// _points.push_back(p);
|
||||
// if (_points.size() == 1)
|
||||
// c = dot(normal(), p);
|
||||
// }
|
||||
fn isValid(&self) -> bool {
|
||||
!self.a.is_nan()
|
||||
}
|
||||
|
||||
fn pop_back(&mut self); // { _points.pop_back(); }
|
||||
fn normal(&self) -> Point {
|
||||
if self.isValid() {
|
||||
Point {
|
||||
x: self.a,
|
||||
y: self.b,
|
||||
}
|
||||
} else {
|
||||
self.direction_inward
|
||||
}
|
||||
}
|
||||
|
||||
fn setDirectionInward(&mut self, d: Point); //{ _directionInward = normalized(d); }
|
||||
fn signedDistance(&self, p: Point) -> f32 {
|
||||
Point::dot(self.normal(), p) - self.c
|
||||
}
|
||||
|
||||
fn distance_single(&self, p: Point) -> f32 {
|
||||
(self.signedDistance(p)).abs()
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.points.clear();
|
||||
self.direction_inward = Point { x: 0.0, y: 0.0 };
|
||||
self.a = f32::NAN;
|
||||
self.b = f32::NAN;
|
||||
self.c = f32::NAN;
|
||||
}
|
||||
|
||||
fn add(&mut self, p: Point) -> Result<()> {
|
||||
if self.direction_inward == Point::default() {
|
||||
return Err(Exceptions::ILLEGAL_STATE);
|
||||
}
|
||||
self.points.push(p);
|
||||
if self.points.len() == 1 {
|
||||
self.c = Point::dot(self.normal(), p);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop_back(&mut self) {
|
||||
self.points.pop();
|
||||
}
|
||||
|
||||
fn setDirectionInward(&mut self, d: Point) {
|
||||
self.direction_inward = Point::normalized(d);
|
||||
}
|
||||
|
||||
// fn evaluate(&self, double maxSignedDist = -1, bool updatePoints = false) -> bool
|
||||
fn evaluate_max_distance(
|
||||
&mut self,
|
||||
maxSignedDist: Option<f64>,
|
||||
updatePoints: Option<bool>,
|
||||
) -> bool;
|
||||
// {
|
||||
// bool ret = evaluate(_points);
|
||||
// if (maxSignedDist > 0) {
|
||||
// auto points = _points;
|
||||
// while (true) {
|
||||
// auto old_points_size = points.size();
|
||||
// // remove points that are further 'inside' than maxSignedDist or further 'outside' than 2 x maxSignedDist
|
||||
// auto end = std::remove_if(points.begin(), points.end(), [this, maxSignedDist](auto p) {
|
||||
// auto sd = this->signedDistance(p);
|
||||
// return sd > maxSignedDist || sd < -2 * maxSignedDist;
|
||||
// });
|
||||
// points.erase(end, points.end());
|
||||
// if (old_points_size == points.size())
|
||||
// break;
|
||||
// // #ifdef PRINT_DEBUG
|
||||
// // printf("removed %zu points\n", old_points_size - points.size());
|
||||
// // #endif
|
||||
// ret = evaluate(points);
|
||||
// }
|
||||
) -> bool {
|
||||
let maxSignedDist = if let Some(m) = maxSignedDist { m } else { -1.0 };
|
||||
let updatePoints = if let Some(u) = updatePoints { u } else { false };
|
||||
|
||||
// if (updatePoints)
|
||||
// _points = std::move(points);
|
||||
// }
|
||||
// return ret;
|
||||
// }
|
||||
let mut ret = self.evaluateSelf();
|
||||
if maxSignedDist > 0.0 {
|
||||
let mut points = self.points.clone();
|
||||
loop {
|
||||
let old_points_size = points.len();
|
||||
// remove points that are further 'inside' than maxSignedDist or further 'outside' than 2 x maxSignedDist
|
||||
// auto end = std::remove_if(points.begin(), points.end(), [this, maxSignedDist](auto p) {
|
||||
// auto sd = this->signedDistance(p);
|
||||
// return sd > maxSignedDist || sd < -2 * maxSignedDist;
|
||||
// });
|
||||
// points.erase(end, points.end());
|
||||
points.retain(|&p| {
|
||||
let sd = self.signedDistance(p) as f64;
|
||||
!(sd > maxSignedDist || sd < -2.0 * maxSignedDist)
|
||||
});
|
||||
if old_points_size == points.len() {
|
||||
break;
|
||||
}
|
||||
// #ifdef PRINT_DEBUG
|
||||
// printf("removed %zu points\n", old_points_size - points.size());
|
||||
// #endif
|
||||
ret = self.evaluate(&points);
|
||||
}
|
||||
|
||||
fn isHighRes(&self) -> bool; //const
|
||||
// {
|
||||
// PointF min = _points.front(), max = _points.front();
|
||||
// for (auto p : _points) {
|
||||
// min.x = std::min(min.x, p.x);
|
||||
// min.y = std::min(min.y, p.y);
|
||||
// max.x = std::max(max.x, p.x);
|
||||
// max.y = std::max(max.y, p.y);
|
||||
// }
|
||||
// auto diff = max - min;
|
||||
// auto len = maxAbsComponent(diff);
|
||||
// auto steps = std::min(std::abs(diff.x), std::abs(diff.y));
|
||||
// // due to aliasing we get bad extrapolations if the line is short and too close to vertical/horizontal
|
||||
// return steps > 2 || len > 50;
|
||||
// }
|
||||
fn a(&self) -> f32;
|
||||
fn b(&self) -> f32;
|
||||
fn c(&self) -> f32;
|
||||
if updatePoints {
|
||||
self.points = points;
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn isHighRes(&self) -> bool {
|
||||
let Some(mut min) = self.points.first().copied() else { return false };
|
||||
let Some(mut max) = self.points.first().copied() else { return false };
|
||||
for p in &self.points {
|
||||
min.x = f32::min(min.x, p.x);
|
||||
min.y = f32::min(min.y, p.y);
|
||||
max.x = f32::max(max.x, p.x);
|
||||
max.y = f32::max(max.y, p.y);
|
||||
}
|
||||
let diff = max - min;
|
||||
let len = diff.maxAbsComponent();
|
||||
let steps = f32::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
|
||||
}
|
||||
|
||||
fn evaluate(&mut self, points: &[Point]) -> bool {
|
||||
let mean = points.iter().sum::<Point>() / points.len() as f32;
|
||||
|
||||
let mut sumXX = 0.0;
|
||||
let mut sumYY = 0.0;
|
||||
let mut sumXY = 0.0;
|
||||
for p in points {
|
||||
// for (auto p = begin; p != end; ++p) {
|
||||
let d = *p - mean;
|
||||
sumXX += d.x * d.x;
|
||||
sumYY += d.y * d.y;
|
||||
sumXY += d.x * d.y;
|
||||
}
|
||||
if sumYY >= sumXX {
|
||||
let l = (sumYY * sumYY + sumXY * sumXY).sqrt();
|
||||
self.a = sumYY / l;
|
||||
self.b = -sumXY / l;
|
||||
} else {
|
||||
let l = (sumXX * sumXX + sumXY * sumXY).sqrt();
|
||||
self.a = sumXY / l;
|
||||
self.b = -sumXX / l;
|
||||
}
|
||||
if Point::dot(self.direction_inward, self.normal()) < 0.0 {
|
||||
// if (dot(_directionInward, normal()) < 0) {
|
||||
self.a = -self.a;
|
||||
self.b = -self.b;
|
||||
}
|
||||
self.c = Point::dot(self.normal(), mean); // (a*mean.x + b*mean.y);
|
||||
Point::dot(self.direction_inward, self.normal()) > 0.5
|
||||
// angle between original and new direction is at most 60 degree
|
||||
}
|
||||
|
||||
fn evaluateSelf(&mut self) -> bool {
|
||||
let mean = self.points.iter().sum::<Point>() / self.points.len() as f32;
|
||||
|
||||
let mut sumXX = 0.0;
|
||||
let mut sumYY = 0.0;
|
||||
let mut sumXY = 0.0;
|
||||
for p in &self.points {
|
||||
// for (auto p = begin; p != end; ++p) {
|
||||
let d = *p - mean;
|
||||
sumXX += d.x * d.x;
|
||||
sumYY += d.y * d.y;
|
||||
sumXY += d.x * d.y;
|
||||
}
|
||||
if sumYY >= sumXX {
|
||||
let l = (sumYY * sumYY + sumXY * sumXY).sqrt();
|
||||
self.a = sumYY / l;
|
||||
self.b = -sumXY / l;
|
||||
} else {
|
||||
let l = (sumXX * sumXX + sumXY * sumXY).sqrt();
|
||||
self.a = sumXY / l;
|
||||
self.b = -sumXX / l;
|
||||
}
|
||||
if Point::dot(self.direction_inward, self.normal()) < 0.0 {
|
||||
// if (dot(_directionInward, normal()) < 0) {
|
||||
self.a = -self.a;
|
||||
self.b = -self.b;
|
||||
}
|
||||
self.c = Point::dot(self.normal(), mean); // (a*mean.x + b*mean.y);
|
||||
Point::dot(self.direction_inward, self.normal()) > 0.5
|
||||
// angle between original and new direction is at most 60 degree
|
||||
}
|
||||
|
||||
fn a(&self) -> f32 {
|
||||
self.a
|
||||
}
|
||||
|
||||
fn b(&self) -> f32 {
|
||||
self.b
|
||||
}
|
||||
|
||||
fn c(&self) -> f32 {
|
||||
self.c
|
||||
}
|
||||
}
|
||||
|
||||
impl RegressionLine {
|
||||
pub fn with_two_points(point1: Point, point2: Point) -> Self {
|
||||
let mut new_rl = RegressionLine::default();
|
||||
new_rl.evaluate(&[point1, point2]);
|
||||
new_rl
|
||||
}
|
||||
}
|
||||
|
||||
149
src/common/cpp_essentials/regression_line_trait.rs
Normal file
149
src/common/cpp_essentials/regression_line_trait.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
use crate::common::Result;
|
||||
use crate::{point, Point};
|
||||
|
||||
pub trait RegressionLineTrait {
|
||||
// points: Vec<Point>,
|
||||
// direction_inward: Point,
|
||||
|
||||
// }
|
||||
// impl RegressionLine {
|
||||
// std::vector<PointF> _points;
|
||||
// PointF _directionInward;
|
||||
// PointF::value_t a = NAN, b = NAN, c = NAN;
|
||||
|
||||
fn intersect<T: RegressionLineTrait, T2: RegressionLineTrait>(
|
||||
l1: &T,
|
||||
l2: &T2,
|
||||
) -> Option<Point> {
|
||||
if !(l1.isValid() && l2.isValid()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let d = l1.a() * l2.b() - l1.b() * l2.a();
|
||||
let x = (l1.c() * l2.b() - l1.b() * l2.c()) / d;
|
||||
let y = (l1.a() * l2.c() - l1.c() * l2.a()) / d;
|
||||
|
||||
Some(point(x, y))
|
||||
}
|
||||
|
||||
// fn evaluate_begin_end(&self, begin: Point, end: Point) -> bool;// {
|
||||
// {
|
||||
// let mean = std::accumulate(begin, end, PointF()) / std::distance(begin, end);
|
||||
// PointF::value_t sumXX = 0, sumYY = 0, sumXY = 0;
|
||||
// for (auto p = begin; p != end; ++p) {
|
||||
// auto d = *p - mean;
|
||||
// sumXX += d.x * d.x;
|
||||
// sumYY += d.y * d.y;
|
||||
// sumXY += d.x * d.y;
|
||||
// }
|
||||
// if (sumYY >= sumXX) {
|
||||
// auto l = std::sqrt(sumYY * sumYY + sumXY * sumXY);
|
||||
// a = +sumYY / l;
|
||||
// b = -sumXY / l;
|
||||
// } else {
|
||||
// auto l = std::sqrt(sumXX * sumXX + sumXY * sumXY);
|
||||
// a = +sumXY / l;
|
||||
// b = -sumXX / l;
|
||||
// }
|
||||
// if (dot(_directionInward, normal()) < 0) {
|
||||
// a = -a;
|
||||
// b = -b;
|
||||
// }
|
||||
// c = dot(normal(), mean); // (a*mean.x + b*mean.y);
|
||||
// return dot(_directionInward, normal()) > 0.5f; // angle between original and new direction is at most 60 degree
|
||||
// }
|
||||
|
||||
fn evaluate(&mut self, points: &[Point]) -> bool; // { return self.evaluate_begin_end(&points.front(), &points.back() + 1); }
|
||||
fn evaluateSelf(&mut self) -> bool;
|
||||
|
||||
// RegressionLine() { _points.reserve(16); } // arbitrary but plausible start size (tiny performance improvement)
|
||||
|
||||
// template<typename T> RegressionLine(PointT<T> a, PointT<T> b)
|
||||
// {
|
||||
// evaluate(std::vector{a, b});
|
||||
// }
|
||||
|
||||
// template<typename T> RegressionLine(const PointT<T>* b, const PointT<T>* e)
|
||||
// {
|
||||
// evaluate(b, e);
|
||||
// }
|
||||
|
||||
fn points(&self) -> &[Point]; //const { return _points; }
|
||||
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) -> Point; //const { return isValid() ? PointF(a, b) : _directionInward; }
|
||||
fn signedDistance(&self, p: Point) -> f32; //const { return dot(normal(), p) - c; }
|
||||
fn distance_single(&self, p: Point) -> f32; //const { return std::abs(signedDistance(PointF(p))); }
|
||||
fn project(&self, p: Point) -> Point {
|
||||
p - self.normal() * self.signedDistance(p)
|
||||
}
|
||||
|
||||
fn reset(&mut self);
|
||||
// {
|
||||
// _points.clear();
|
||||
// _directionInward = {};
|
||||
// a = b = c = NAN;
|
||||
// }
|
||||
|
||||
fn add(&mut self, p: Point) -> Result<()>; //{
|
||||
// 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: Point); //{ _directionInward = normalized(d); }
|
||||
|
||||
// fn evaluate(&self, double maxSignedDist = -1, bool updatePoints = false) -> bool
|
||||
fn evaluate_max_distance(
|
||||
&mut self,
|
||||
maxSignedDist: Option<f64>,
|
||||
updatePoints: Option<bool>,
|
||||
) -> bool;
|
||||
// {
|
||||
// bool ret = evaluate(_points);
|
||||
// if (maxSignedDist > 0) {
|
||||
// auto points = _points;
|
||||
// while (true) {
|
||||
// auto old_points_size = points.size();
|
||||
// // remove points that are further 'inside' than maxSignedDist or further 'outside' than 2 x maxSignedDist
|
||||
// auto end = std::remove_if(points.begin(), points.end(), [this, maxSignedDist](auto p) {
|
||||
// auto sd = this->signedDistance(p);
|
||||
// return sd > maxSignedDist || sd < -2 * maxSignedDist;
|
||||
// });
|
||||
// points.erase(end, points.end());
|
||||
// if (old_points_size == points.size())
|
||||
// break;
|
||||
// // #ifdef PRINT_DEBUG
|
||||
// // printf("removed %zu points\n", old_points_size - points.size());
|
||||
// // #endif
|
||||
// ret = evaluate(points);
|
||||
// }
|
||||
|
||||
// if (updatePoints)
|
||||
// _points = std::move(points);
|
||||
// }
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
fn isHighRes(&self) -> bool; //const
|
||||
// {
|
||||
// PointF min = _points.front(), max = _points.front();
|
||||
// for (auto p : _points) {
|
||||
// min.x = std::min(min.x, p.x);
|
||||
// min.y = std::min(min.y, p.y);
|
||||
// max.x = std::max(max.x, p.x);
|
||||
// max.y = std::max(max.y, p.y);
|
||||
// }
|
||||
// auto diff = max - min;
|
||||
// auto len = maxAbsComponent(diff);
|
||||
// auto steps = std::min(std::abs(diff.x), std::abs(diff.y));
|
||||
// // due to aliasing we get bad extrapolations if the line is short and too close to vertical/horizontal
|
||||
// return steps > 2 || len > 50;
|
||||
// }
|
||||
fn a(&self) -> f32;
|
||||
fn b(&self) -> f32;
|
||||
fn c(&self) -> f32;
|
||||
}
|
||||
@@ -1,34 +1,19 @@
|
||||
use crate::common::Result;
|
||||
use crate::{Exceptions, Point};
|
||||
|
||||
use super::{DMRegressionLine, Direction, RegressionLine};
|
||||
use super::{Direction, RegressionLineTrait};
|
||||
|
||||
#[inline(always)]
|
||||
pub fn float_min<T: PartialOrd>(a: T, b: T) -> T {
|
||||
if a > b {
|
||||
b
|
||||
} else {
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn float_max<T: PartialOrd>(a: T, b: T) -> T {
|
||||
if a < b {
|
||||
b
|
||||
} else {
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn intersect(l1: &DMRegressionLine, l2: &DMRegressionLine) -> Result<Point> {
|
||||
pub fn intersect<T: RegressionLineTrait, T2: RegressionLineTrait>(
|
||||
l1: &T,
|
||||
l2: &T2,
|
||||
) -> Result<Point> {
|
||||
if !(l1.isValid() && l2.isValid()) {
|
||||
return Err(Exceptions::ILLEGAL_STATE);
|
||||
}
|
||||
let d = l1.a * l2.b - l1.b * l2.a;
|
||||
let x = (l1.c * l2.b - l1.b * l2.c) / d;
|
||||
let y = (l1.a * l2.c - l1.c * l2.a) / d;
|
||||
let d = l1.a() * l2.b() - l1.b() * l2.a();
|
||||
let x = (l1.c() * l2.b() - l1.b() * l2.c()) / d;
|
||||
let y = (l1.a() * l2.c() - l1.c() * l2.a()) / d;
|
||||
Ok(Point { x, y })
|
||||
}
|
||||
|
||||
|
||||
@@ -209,26 +209,31 @@ impl Quadrilateral {
|
||||
!(x || y)
|
||||
}
|
||||
|
||||
pub fn blend(a: &Quadrilateral, b:&Quadrilateral) -> Self {
|
||||
pub fn blend(a: &Quadrilateral, b: &Quadrilateral) -> Self {
|
||||
let c = a[0];
|
||||
let dist2First = | a, b| { Point::distance(a, c) < Point::distance(b, c) };
|
||||
// rotate points such that the the two topLeft points are closest to each other
|
||||
let min_element = b.0.iter().copied().min_by(|a,b| {
|
||||
match dist2First(*a,*b) {
|
||||
true => std::cmp::Ordering::Less,
|
||||
false => std::cmp::Ordering::Greater,
|
||||
let dist2First = |a, b| Point::distance(a, c) < Point::distance(b, c);
|
||||
// rotate points such that the the two topLeft points are closest to each other
|
||||
let min_element =
|
||||
b.0.iter()
|
||||
.copied()
|
||||
.min_by(|a, b| match dist2First(*a, *b) {
|
||||
true => std::cmp::Ordering::Less,
|
||||
false => std::cmp::Ordering::Greater,
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let offset =
|
||||
b.0.iter()
|
||||
.position(|v| *v == min_element)
|
||||
.unwrap_or_default();
|
||||
// let offset = std::min_element(b.begin(), b.end(), dist2First) - b.begin();
|
||||
|
||||
let mut res = Quadrilateral::default();
|
||||
for i in 0..4 {
|
||||
// for (int i = 0; i < 4; ++i){
|
||||
res[i] = (a[i] + b[(i + offset) % 4]) / 2.0;
|
||||
}
|
||||
}).unwrap_or_default();
|
||||
let offset = b.0.iter().position(|v| *v == min_element).unwrap_or_default();
|
||||
// let offset = std::min_element(b.begin(), b.end(), dist2First) - b.begin();
|
||||
|
||||
let mut res= Quadrilateral::default();
|
||||
for i in 0..4 {
|
||||
// for (int i = 0; i < 4; ++i){
|
||||
res[i] = (a[i] + b[(i + offset) % 4]) / 2.0;
|
||||
}
|
||||
|
||||
res
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,4 +255,4 @@ impl std::ops::IndexMut<usize> for Quadrilateral {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
&mut self.0[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,12 @@ macro_rules! CHECK {
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, DefaultGridSampler, GridSampler, Quadrilateral, Result},
|
||||
common::{
|
||||
cpp_essentials::RegressionLineTrait, BitMatrix, DefaultGridSampler, GridSampler,
|
||||
Quadrilateral, Result,
|
||||
},
|
||||
datamatrix::detector::{
|
||||
zxing_cpp_detector::{util::intersect, BitMatrixCursor, RegressionLine},
|
||||
zxing_cpp_detector::{util::intersect, BitMatrixCursor},
|
||||
DatamatrixDetectorResult,
|
||||
},
|
||||
point,
|
||||
|
||||
Reference in New Issue
Block a user