mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
partial test complete
This commit is contained in:
@@ -147,7 +147,7 @@ impl BitSource {
|
|||||||
// Next read whole bytes
|
// Next read whole bytes
|
||||||
if num_bits > 0 {
|
if num_bits > 0 {
|
||||||
while num_bits >= 8 {
|
while num_bits >= 8 {
|
||||||
result = (result << 8) | self.bytes[self.byte_offset] as u32;
|
result = (result << 8) | self.bytes[byte_offset] as u32;
|
||||||
// result = ((result as u16) << 8) as u8 | (self.bytes[self.byte_offset]);
|
// result = ((result as u16) << 8) as u8 | (self.bytes[self.byte_offset]);
|
||||||
byte_offset += 1;
|
byte_offset += 1;
|
||||||
num_bits -= 8;
|
num_bits -= 8;
|
||||||
@@ -158,7 +158,7 @@ impl BitSource {
|
|||||||
let bits_to_not_read = 8 - num_bits;
|
let bits_to_not_read = 8 - num_bits;
|
||||||
let mask = (0xFF >> bits_to_not_read) << bits_to_not_read;
|
let mask = (0xFF >> bits_to_not_read) << bits_to_not_read;
|
||||||
result = (result << num_bits)
|
result = (result << num_bits)
|
||||||
| ((self.bytes[self.byte_offset] & mask) as u32 >> bits_to_not_read);
|
| ((self.bytes[byte_offset] & mask) as u32 >> bits_to_not_read);
|
||||||
bit_offset += num_bits;
|
bit_offset += num_bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ pub fn CollectRingPoints(
|
|||||||
edgeIndex: i32,
|
edgeIndex: i32,
|
||||||
backup: bool,
|
backup: bool,
|
||||||
) -> Vec<Point> {
|
) -> Vec<Point> {
|
||||||
let centerI = center.round();
|
let centerI = center.floor();
|
||||||
let radius = range;
|
let radius = range;
|
||||||
let mut cur = EdgeTracer::new(image, centerI, point(0.0, 1.0));
|
let mut cur = EdgeTracer::new(image, centerI, point(0.0, 1.0));
|
||||||
if cur.stepToEdge(Some(edgeIndex), Some(radius), Some(backup)) == 0 {
|
if cur.stepToEdge(Some(edgeIndex), Some(radius), Some(backup)) == 0 {
|
||||||
@@ -362,17 +362,20 @@ pub fn FitQadrilateralToPoints(center: Point, points: &mut [Point]) -> Option<Qu
|
|||||||
let dist2Center = |a, b| Point::distance(a, center) < Point::distance(b, center);
|
let dist2Center = |a, b| Point::distance(a, center) < Point::distance(b, center);
|
||||||
// rotate points such that the first one is the furthest away from the center (hence, a corner)
|
// rotate points such that the first one is the furthest away from the center (hence, a corner)
|
||||||
|
|
||||||
let max_by_pred = |a: &Point, b: &Point| {
|
let max_by_pred = |a: &&Point, b: &&Point| {
|
||||||
if dist2Center(*a, *b) {
|
let da = Point::distance(**a, center);
|
||||||
std::cmp::Ordering::Greater
|
let db = Point::distance(**b, center);
|
||||||
} else {
|
da.partial_cmp(&db).unwrap()
|
||||||
std::cmp::Ordering::Less
|
// if dist2Center(**a, **b) {
|
||||||
}
|
// std::cmp::Ordering::Greater
|
||||||
|
// } else {
|
||||||
|
// std::cmp::Ordering::Less
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
let max = points.iter().copied().max_by(max_by_pred)?;
|
let max = points.iter().max_by(max_by_pred)?;
|
||||||
|
|
||||||
let pos = points.iter().position(|e| *e == max)?;
|
let pos = points.iter().position(|e| e == max)?;
|
||||||
|
|
||||||
points.rotate_left(pos);
|
points.rotate_left(pos);
|
||||||
// std::rotate(points.begin(), std::max_element(points.begin(), points.end(), dist2Center), points.end());
|
// std::rotate(points.begin(), std::max_element(points.begin(), points.end(), dist2Center), points.end());
|
||||||
@@ -380,9 +383,8 @@ pub fn FitQadrilateralToPoints(center: Point, points: &mut [Point]) -> Option<Qu
|
|||||||
let mut corners = [Point::default(); 4];
|
let mut corners = [Point::default(); 4];
|
||||||
corners[0] = points[0];
|
corners[0] = points[0];
|
||||||
// find the oposite corner by looking for the farthest point near the oposite point
|
// find the oposite corner by looking for the farthest point near the oposite point
|
||||||
points[(points.len() * 3 / 8)..=(points.len() * 5 / 8)]
|
corners[2] = *points[(points.len() * 3 / 8)..=(points.len() * 5 / 8)]
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
|
||||||
.max_by(max_by_pred)?;
|
.max_by(max_by_pred)?;
|
||||||
// corners[2] = std::max_element(&points[Size(points) * 3 / 8], &points[Size(points) * 5 / 8], dist2Center);
|
// 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
|
// find the two in between corners by looking for the points farthest from the long diagonal
|
||||||
@@ -390,11 +392,14 @@ pub fn FitQadrilateralToPoints(center: Point, points: &mut [Point]) -> Option<Qu
|
|||||||
let dist2Diagonal = /*[l = RegressionLine(*corners[0], *corners[2])]*/| a, b| { l.distance_single(a) < l.distance_single(b) };
|
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| {
|
let diagonal_max_by_pred = |p1: &Point, p2: &Point| {
|
||||||
if dist2Diagonal(*p1, *p2) {
|
let d1 = l.distance_single(*p1);
|
||||||
std::cmp::Ordering::Greater
|
let d2 = l.distance_single(*p2);
|
||||||
} else {
|
d1.partial_cmp(&d2).unwrap()
|
||||||
std::cmp::Ordering::Less
|
// if dist2Diagonal(*p1, *p2) {
|
||||||
}
|
// std::cmp::Ordering::Greater
|
||||||
|
// } else {
|
||||||
|
// std::cmp::Ordering::Less
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
corners[1] = points[(points.len() / 8)..=(points.len() * 3 / 8)]
|
corners[1] = points[(points.len() / 8)..=(points.len() * 3 / 8)]
|
||||||
.iter()
|
.iter()
|
||||||
@@ -407,11 +412,19 @@ pub fn FitQadrilateralToPoints(center: Point, points: &mut [Point]) -> Option<Qu
|
|||||||
.max_by(diagonal_max_by_pred)?;
|
.max_by(diagonal_max_by_pred)?;
|
||||||
// corners[3] = std::max_element(&points[Size(points) * 5 / 8], &points[Size(points) * 7 / 8], dist2Diagonal);
|
// corners[3] = std::max_element(&points[Size(points) * 5 / 8], &points[Size(points) * 7 / 8], dist2Diagonal);
|
||||||
|
|
||||||
|
let corner_positions = [0, points.iter().position(|p| *p == corners[1])?, points.iter().position(|p| *p == corners[2])?, points.iter().position(|p| *p == corners[3])?];
|
||||||
|
|
||||||
|
// let lines = [
|
||||||
|
// 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),
|
||||||
|
// ];
|
||||||
let lines = [
|
let lines = [
|
||||||
RegressionLine::with_two_points(corners[0] + 1.0, corners[1]),
|
RegressionLine::with_point_slice(&points[corner_positions[0] + 1.. corner_positions[1]]),
|
||||||
RegressionLine::with_two_points(corners[1] + 1.0, corners[2]),
|
RegressionLine::with_point_slice(&points[corner_positions[1] + 1.. corner_positions[2]]),
|
||||||
RegressionLine::with_two_points(corners[2] + 1.0, corners[3]),
|
RegressionLine::with_point_slice(&points[corner_positions[2] + 1.. corner_positions[3]]),
|
||||||
RegressionLine::with_two_points(corners[3] + 1.0, *points.last()? + 1.0),
|
RegressionLine::with_point_slice(&points[corner_positions[3] + 1.. points.len()]),
|
||||||
];
|
];
|
||||||
// std::array lines{RegressionLine{corners[0] + 1, corners[1]}, RegressionLine{corners[1] + 1, corners[2]},
|
// 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}};
|
// RegressionLine{corners[2] + 1, corners[3]}, RegressionLine{corners[3] + 1, &points.back() + 1}};
|
||||||
@@ -428,6 +441,44 @@ pub fn FitQadrilateralToPoints(center: Point, points: &mut [Point]) -> Option<Qu
|
|||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn fit_quadralateral_to_points(center: Point, points: Vec<Point>) -> Option<Quadrilateral> {
|
||||||
|
// let dist2center = |a, b| Point::distance(a, center) < Point::distance(b, center);
|
||||||
|
|
||||||
|
// // Rotate points such that the first one is the furthest away from the center (hence, a corner)
|
||||||
|
// let mut points = points;
|
||||||
|
// points.rotate_left(points.iter().position(|p| dist2center(p, center)).unwrap());
|
||||||
|
|
||||||
|
// let mut corners = [&points[0]; 4];
|
||||||
|
// corners[0] = &points[0];
|
||||||
|
|
||||||
|
// // Find the opposite corner by looking for the farthest point near the opposite point
|
||||||
|
// let opposite_corner = points.iter().take(points.len() / 2).max_by(|p| dist2center(p, corners[0]));
|
||||||
|
// corners[2] = opposite_corner;
|
||||||
|
|
||||||
|
// // Find the two in between corners by looking for the points farthest from the long diagonal
|
||||||
|
// let dist2diagonal = |l: &RegressionLine, a| l.distance(a);
|
||||||
|
// corners[1] = points.iter().take(points.len() / 2).max_by(|p| dist2diagonal(&RegressionLine(*corners[0], *corners[2]), *p));
|
||||||
|
// corners[3] = points.iter().skip(points.len() / 2).max_by(|p| dist2diagonal(&RegressionLine(*corners[0], *corners[2]), *p));
|
||||||
|
|
||||||
|
// let lines = [
|
||||||
|
// RegressionLine::new(corners[0], corners[1]),
|
||||||
|
// RegressionLine::new(corners[1], corners[2]),
|
||||||
|
// RegressionLine::new(corners[2], corners[3]),
|
||||||
|
// RegressionLine::new(corners[3], corners[0]),
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// if lines.iter().any(|l| !l.is_valid()) {
|
||||||
|
// return None;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let mut res = QuadrilateralF::new();
|
||||||
|
// for i in 0..4 {
|
||||||
|
// res[i] = intersect(lines[i], lines[(i + 1) % 4]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Some(res)
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn QuadrilateralIsPlausibleSquare(q: &Quadrilateral, lineIndex: usize) -> bool {
|
pub fn QuadrilateralIsPlausibleSquare(q: &Quadrilateral, lineIndex: usize) -> bool {
|
||||||
let mut m;
|
let mut m;
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ impl<'a> FastEdgeToEdgeCounter<'a> {
|
|||||||
steps += 1;
|
steps += 1;
|
||||||
if steps > maxSteps {
|
if steps > maxSteps {
|
||||||
if maxSteps == self.stepsToBorder {
|
if maxSteps == self.stepsToBorder {
|
||||||
break false;
|
break;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ impl<'a> FastEdgeToEdgeCounter<'a> {
|
|||||||
// if !(self.under_arry[idx_pt]
|
// if !(self.under_arry[idx_pt]
|
||||||
// == self.under_arry[self.p as usize])
|
// == self.under_arry[self.p as usize])
|
||||||
if !(self.under_arry.get_index(idx_pt) == self.under_arry.get_index(self.p as usize)) {
|
if !(self.under_arry.get_index(idx_pt) == self.under_arry.get_index(self.p as usize)) {
|
||||||
break true;
|
break;
|
||||||
}
|
}
|
||||||
} // while (p[steps * stride] == p[0]);
|
} // while (p[steps * stride] == p[0]);
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ use crate::{Exceptions, Point};
|
|||||||
pub struct Matrix<T: Default + Clone + Copy> {
|
pub struct Matrix<T: Default + Clone + Copy> {
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
data: Vec<T>,
|
data: Vec<Option<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Clone + Copy> Matrix<T> {
|
impl<T: Default + Clone + Copy> Matrix<T> {
|
||||||
pub fn with_data(width: usize, height: usize, data: Vec<T>) -> Result<Matrix<T>> {
|
pub fn with_data(width: usize, height: usize, data: Vec<Option<T>>) -> Result<Matrix<T>> {
|
||||||
if (width != 0 && data.len() / width as usize != height as usize) {
|
if width != 0 && data.len() / width as usize != height as usize {
|
||||||
return Err(Exceptions::illegal_argument_with(
|
return Err(Exceptions::illegal_argument_with(
|
||||||
"invalid size: width * height is too big",
|
"invalid size: width * height is too big",
|
||||||
));
|
));
|
||||||
@@ -31,7 +31,7 @@ impl<T: Default + Clone + Copy> Matrix<T> {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
data: vec![T::default(); width * height],
|
data: vec![None; width * height],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,13 +66,15 @@ impl<T: Default + Clone + Copy> Matrix<T> {
|
|||||||
pub fn get(&self, x: usize, y: usize) -> Option<T> {
|
pub fn get(&self, x: usize, y: usize) -> Option<T> {
|
||||||
if x >= self.width || y >= self.height {
|
if x >= self.width || y >= self.height {
|
||||||
None
|
None
|
||||||
|
} else if let Some(Some(d)) = self.data.get(Self::get_offset(x, y, self.width)){
|
||||||
|
Some(*d)
|
||||||
}else {
|
}else {
|
||||||
Some(self.data[Self::get_offset(x, y, self.width)])
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, x: usize, y: usize, value: T) -> T {
|
pub fn set(&mut self, x: usize, y: usize, value: T) -> T {
|
||||||
self.data[Self::get_offset(x, y, self.width)] = value;
|
self.data[Self::get_offset(x, y, self.width)] = Some(value);
|
||||||
self.get(x, y).unwrap()
|
self.get(x, y).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +86,7 @@ impl<T: Default + Clone + Copy> Matrix<T> {
|
|||||||
self.set(p.x as usize, p.y as usize, value)
|
self.set(p.x as usize, p.y as usize, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data(&self) -> &[T] {
|
pub fn data(&self) -> &[Option<T>] {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,10 +99,10 @@ impl<T: Default + Clone + Copy> Matrix<T> {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn clear_with(&mut self, value: T) {
|
pub fn clear_with(&mut self, value: T) {
|
||||||
self.data.fill(value)
|
self.data.fill(Some(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.data.fill(T::default())
|
self.data.fill(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,4 +228,9 @@ impl RegressionLine {
|
|||||||
new_rl.evaluate(&[point1, point2]);
|
new_rl.evaluate(&[point1, point2]);
|
||||||
new_rl
|
new_rl
|
||||||
}
|
}
|
||||||
|
pub fn with_point_slice(points: &[Point]) -> Self {
|
||||||
|
let mut new_rl = RegressionLine::default();
|
||||||
|
new_rl.evaluate(points);
|
||||||
|
new_rl
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,11 +35,14 @@ pub fn CorrectErrors(codewordBytes: &mut [u8], numDataCodewords: u32) -> Result<
|
|||||||
let rs = ReedSolomonDecoder::new(get_predefined_genericgf(
|
let rs = ReedSolomonDecoder::new(get_predefined_genericgf(
|
||||||
PredefinedGenericGF::QrCodeField256,
|
PredefinedGenericGF::QrCodeField256,
|
||||||
));
|
));
|
||||||
if rs.decode(&mut codewordsInts, numECCodewords)? != 0
|
|
||||||
// if (!ReedSolomonDecode(GenericGF::QRCodeField256(), codewordsInts, numECCodewords))
|
rs.decode(&mut codewordsInts, numECCodewords)?;
|
||||||
{
|
|
||||||
return Ok(false);
|
// if rs.decode(&mut codewordsInts, numECCodewords)? != 0
|
||||||
}
|
// // if (!ReedSolomonDecode(GenericGF::QRCodeField256(), codewordsInts, numECCodewords))
|
||||||
|
// {
|
||||||
|
// return Ok(false);
|
||||||
|
// }
|
||||||
|
|
||||||
// Copy back into array of bytes -- only need to worry about the bytes that were data
|
// Copy back into array of bytes -- only need to worry about the bytes that were data
|
||||||
// We don't care about errors in the error-correction codewords
|
// We don't care about errors in the error-correction codewords
|
||||||
@@ -298,9 +301,9 @@ pub fn DecodeBitStream(
|
|||||||
let modeBitLength = Mode::get_codec_mode_bits_length(version);
|
let modeBitLength = Mode::get_codec_mode_bits_length(version);
|
||||||
|
|
||||||
let res = (|| {
|
let res = (|| {
|
||||||
while (!IsEndOfStream(&mut bits, version)?) {
|
while !IsEndOfStream(&mut bits, version)? {
|
||||||
let mode: Mode;
|
let mode: Mode;
|
||||||
if (modeBitLength == 0) {
|
if modeBitLength == 0 {
|
||||||
mode = Mode::NUMERIC; // MicroQRCode version 1 is always NUMERIC and modeBitLength is 0
|
mode = Mode::NUMERIC; // MicroQRCode version 1 is always NUMERIC and modeBitLength is 0
|
||||||
} else {
|
} else {
|
||||||
mode = Mode::CodecModeForBits(
|
mode = Mode::CodecModeForBits(
|
||||||
@@ -309,7 +312,7 @@ pub fn DecodeBitStream(
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match (mode) {
|
match mode {
|
||||||
Mode::FNC1_FIRST_POSITION => {
|
Mode::FNC1_FIRST_POSITION => {
|
||||||
// if (!result.empty()) // uncomment to enforce specification
|
// if (!result.empty()) // uncomment to enforce specification
|
||||||
// throw FormatError("GS1 Indicator (FNC1 in first position) at illegal position");
|
// throw FormatError("GS1 Indicator (FNC1 in first position) at illegal position");
|
||||||
@@ -317,14 +320,14 @@ pub fn DecodeBitStream(
|
|||||||
result.symbology.aiFlag = AIFlag::GS1; // In Alphanumeric mode undouble doubled '%' and treat single '%' as <GS>
|
result.symbology.aiFlag = AIFlag::GS1; // In Alphanumeric mode undouble doubled '%' and treat single '%' as <GS>
|
||||||
}
|
}
|
||||||
Mode::FNC1_SECOND_POSITION => {
|
Mode::FNC1_SECOND_POSITION => {
|
||||||
if (!result.is_empty()) {
|
if !result.is_empty() {
|
||||||
return Err(Exceptions::format_with("AIM Application Indicator (FNC1 in second position) at illegal position"));
|
return Err(Exceptions::format_with("AIM Application Indicator (FNC1 in second position) at illegal position"));
|
||||||
// throw FormatError("AIM Application Indicator (FNC1 in second position) at illegal position");
|
// throw FormatError("AIM Application Indicator (FNC1 in second position) at illegal position");
|
||||||
}
|
}
|
||||||
result.symbology.modifier = b'5'; // As above
|
result.symbology.modifier = b'5'; // As above
|
||||||
// ISO/IEC 18004:2015 7.4.8.3 AIM Application Indicator (FNC1 in second position), "00-99" or "A-Za-z"
|
// ISO/IEC 18004:2015 7.4.8.3 AIM Application Indicator (FNC1 in second position), "00-99" or "A-Za-z"
|
||||||
let appInd = bits.readBits(8)?;
|
let appInd = bits.readBits(8)?;
|
||||||
if (appInd < 100)
|
if appInd < 100
|
||||||
// "00-09"
|
// "00-09"
|
||||||
{
|
{
|
||||||
result +=
|
result +=
|
||||||
@@ -367,7 +370,7 @@ pub fn DecodeBitStream(
|
|||||||
// "Normal" QR code modes:
|
// "Normal" QR code modes:
|
||||||
// How many characters will follow, encoded in this mode?
|
// How many characters will follow, encoded in this mode?
|
||||||
let count = bits.readBits(mode.CharacterCountBits(version) as usize)?;
|
let count = bits.readBits(mode.CharacterCountBits(version) as usize)?;
|
||||||
match (mode) {
|
match mode {
|
||||||
Mode::NUMERIC => DecodeNumericSegment(&mut bits, count, &mut result)?,
|
Mode::NUMERIC => DecodeNumericSegment(&mut bits, count, &mut result)?,
|
||||||
Mode::ALPHANUMERIC => {
|
Mode::ALPHANUMERIC => {
|
||||||
DecodeAlphanumericSegment(&mut bits, count, &mut result)?
|
DecodeAlphanumericSegment(&mut bits, count, &mut result)?
|
||||||
|
|||||||
@@ -714,8 +714,8 @@ pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result<QRCodeDetect
|
|||||||
let y0 = apM[y];
|
let y0 = apM[y];
|
||||||
let y1 = apM[y + 1];
|
let y1 = apM[y + 1];
|
||||||
rois.push(SamplerControl {
|
rois.push(SamplerControl {
|
||||||
p0: point_i(x0 - u32::from(x == 0) * 6, x1 + u32::from(x == N - 1) * 7),
|
p0: point_i(x0 - u32::from(x == 0) * 6, y0 - u32::from(y == 0) * 6),
|
||||||
p1: point_i(y0 - u32::from(y == 0) * 6, y1 + u32::from(y == N - 1) * 7),
|
p1: point_i(x1 + u32::from(x == N - 1) * 7, y1 + u32::from(y == N - 1) * 7),
|
||||||
transform: PerspectiveTransform::quadrilateralToQuadrilateral(
|
transform: PerspectiveTransform::quadrilateralToQuadrilateral(
|
||||||
Quadrilateral::rectangle_from_xy(
|
Quadrilateral::rectangle_from_xy(
|
||||||
x0 as f32, x1 as f32, y0 as f32, y1 as f32, None,
|
x0 as f32, x1 as f32, y0 as f32, y1 as f32, None,
|
||||||
|
|||||||
@@ -280,6 +280,13 @@ impl Point {
|
|||||||
y: self.y.round(),
|
y: self.y.round(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn floor(self) -> Self {
|
||||||
|
Self {
|
||||||
|
x: self.x.floor(),
|
||||||
|
y: self.y.floor()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&(f32, f32)> for Point {
|
impl From<&(f32, f32)> for Point {
|
||||||
|
|||||||
Reference in New Issue
Block a user