///|
pub fn safe_pixel(image : GrayImage, point : Point, default : Double) -> Double {
if image.inside(point.x.floor().to_int(), point.y.floor().to_int()) {
image.sample_bilinear(point)
} else {
default
}
}
///|
pub fn safe_bounds(width : Int, height : Int, bounds : Bounds) -> Bounds {
{
min_x: bounds.min_x.clamp(min=0, max=width.max(0)),
min_y: bounds.min_y.clamp(min=0, max=height.max(0)),
max_x: bounds.max_x.clamp(min=-1, max=width - 1),
max_y: bounds.max_y.clamp(min=-1, max=height - 1),
}
}
///|
pub fn bounds_from_center(center : Point, width : Int, height : Int) -> Bounds {
let half_width = width.max(0) / 2
let half_height = height.max(0) / 2
{
min_x: center.x.to_int() - half_width,
min_y: center.y.to_int() - half_height,
max_x: center.x.to_int() + half_width,
max_y: center.y.to_int() + half_height,
}
}
///|
pub fn bounds_intersection(first : Bounds, second : Bounds) -> Bounds {
{
min_x: first.min_x.max(second.min_x),
min_y: first.min_y.max(second.min_y),
max_x: first.max_x.min(second.max_x),
max_y: first.max_y.min(second.max_y),
}
}
///|
pub fn bounds_union(first : Bounds, second : Bounds) -> Bounds {
{
min_x: first.min_x.min(second.min_x),
min_y: first.min_y.min(second.min_y),
max_x: first.max_x.max(second.max_x),
max_y: first.max_y.max(second.max_y),
}
}
///|
pub fn bounds_is_empty(bounds : Bounds) -> Bool {
bounds.max_x < bounds.min_x || bounds.max_y < bounds.min_y
}
///|
pub fn bounds_contains(bounds : Bounds, point : Point) -> Bool {
point.x >= Double::from_int(bounds.min_x) &&
point.x <= Double::from_int(bounds.max_x) &&
point.y >= Double::from_int(bounds.min_y) &&
point.y <= Double::from_int(bounds.max_y)
}
///|
pub fn vector_to_string(vector : Vector2) -> String {
"(" + vector.x.to_string() + ", " + vector.y.to_string() + ")"
}
///|
pub fn point_to_string(point : Point) -> String {
"(" + point.x.to_string() + ", " + point.y.to_string() + ")"
}
///|
pub fn line_to_string(line : Line) -> String {
line.a.to_string() +
"x + " +
line.b.to_string() +
"y + " +
line.c.to_string() +
" = 0"
}
///|
pub fn circle_to_string(circle : Circle) -> String {
"center=" +
point_to_string(circle.center) +
"; radius=" +
circle.radius.to_string() +
"; rms=" +
circle.rms_error.to_string()
}
///|
pub fn transform_to_string(transform : AffineTransform) -> String {
"[" +
transform.a.to_string() +
"," +
transform.b.to_string() +
";" +
transform.c.to_string() +
"," +
transform.d.to_string() +
";" +
transform.tx.to_string() +
"," +
transform.ty.to_string() +
"]"
}
///|
pub fn unit_convert(value : Double, source : String, target : String) -> Double {
if source == target {
value
} else if source == "mm" && target == "um" {
value * 1000.0
} else if source == "um" && target == "mm" {
value / 1000.0
} else if source == "in" && target == "mm" {
value * 25.4
} else if source == "mm" && target == "in" {
value / 25.4
} else if source == "px" || target == "px" {
value
} else {
value
}
}
///|
pub fn convert_measurement_unit(
measurement : Measurement,
target : String,
) -> Measurement {
{
..measurement,
value: unit_convert(measurement.value, measurement.unit, target),
unit: target,
}
}
///|
pub fn convert_tolerance_unit(
tolerance : Tolerance,
target : String,
) -> Tolerance {
{
nominal: unit_convert(tolerance.nominal, tolerance.unit, target),
lower: unit_convert(tolerance.lower, tolerance.unit, target),
upper: unit_convert(tolerance.upper, tolerance.unit, target),
unit: target,
}
}
///|
pub fn image_scale_values(image : GrayImage, factor : Double) -> GrayImage {
let result = image.copy()
for i in 0.. GrayImage {
let result = image.copy()
for i in 0.. GrayImage {
let result = image.copy()
for i in 0.. Double {
mean_value(patch_difference(first, second).pixels)
}
///|
pub fn image_difference_maximum(
first : GrayImage,
second : GrayImage,
) -> Double {
maximum_value(patch_difference(first, second).pixels)
}
///|
pub fn image_equal_with_tolerance(
first : GrayImage,
second : GrayImage,
tolerance : Double,
) -> Bool {
first.width == second.width &&
first.height == second.height &&
image_difference_maximum(first, second) <= tolerance.max(0.0)
}
///|
pub fn measurement_equal_with_tolerance(
first : Measurement,
second : Measurement,
tolerance : Double,
) -> Bool {
first.name == second.name &&
first.unit == second.unit &&
approx_equal(first.value, second.value, tolerance~)
}
///|
pub fn report_measurement_count(report : MeasurementReport) -> Int {
report.measurements.length()
}