///|
pub fn measure_distance(first : Point, second : Point) -> Double {
distance(first, second)
}
///|
pub fn measure_signed_distance(line : Line, point : Point) -> Double {
line.a * point.x + line.b * point.y + line.c
}
///|
pub fn measure_angle(first : Point, second : Point) -> Double {
@math.atan2(second.y - first.y, second.x - first.x)
}
///|
pub fn measure_diameter(circle : Circle) -> Double {
circle.radius * 2.0
}
///|
pub fn measure_radius(points : Array[Point]) -> Circle {
detect_circle_from_points(points)
}
///|
pub fn measure_line(points : Array[Point]) -> Line {
fit_line(points)
}
///|
pub fn line_length(points : Array[Point]) -> Double {
if points.length() < 2 {
0.0
} else {
let mut result = 0.0
for i in 1.. Double {
angle_between_lines(first, second)
}
///|
pub fn parallelism_error(
reference : Line,
candidate : Line,
points : Array[Point],
) -> Double {
if points.is_empty() {
0.0
} else {
let mut maximum = 0.0
for point in points {
maximum = maximum.max(
(reference.distance_to(point) - candidate.distance_to(point)).abs(),
)
}
maximum
}
}
///|
pub fn perpendicularity_error(first : Line, second : Line) -> Double {
(angle_between_lines(first, second) - 1.5707963267948966).abs()
}
///|
pub fn circle_roundness(circle : Circle) -> Double {
circle.rms_error
}
///|
pub fn circular_runout(points : Array[Point], reference : Point) -> Double {
if points.is_empty() {
0.0
} else {
let distances = points.map(fn(point) { distance(point, reference) })
maximum_value(distances) - minimum_value(distances)
}
}
///|
pub fn bounding_width(bounds : Bounds) -> Double {
Double::from_int((bounds.max_x - bounds.min_x + 1).max(0))
}
///|
pub fn bounding_height(bounds : Bounds) -> Double {
Double::from_int((bounds.max_y - bounds.min_y + 1).max(0))
}
///|
pub fn bounding_area(bounds : Bounds) -> Double {
bounding_width(bounds) * bounding_height(bounds)
}
///|
pub fn region_width(mask : BinaryMask) -> Double {
bounding_width(mask.bounds())
}
///|
pub fn region_height(mask : BinaryMask) -> Double {
bounding_height(mask.bounds())
}
///|
pub fn edge_pair_width(edges : Array[EdgePoint], direction : Vector2) -> Double {
if edges.length() < 2 {
0.0
} else {
let axis = direction.normalized()
let mut minimum = axis.dot(
Vector2::Vector2(x=edges[0].point.x, y=edges[0].point.y),
)
let mut maximum = minimum
for edge in edges[1:] {
let value = axis.dot(Vector2::Vector2(x=edge.point.x, y=edge.point.y))
minimum = minimum.min(value)
maximum = maximum.max(value)
}
maximum - minimum
}
}
///|
pub fn repeatability(values : Array[Double]) -> Double {
describe_samples(values).standard_deviation
}
///|
pub fn bias_against_nominal(values : Array[Double], nominal : Double) -> Double {
mean_value(values) - nominal
}
///|
pub fn capability_index(
values : Array[Double],
lower : Double,
upper : Double,
) -> Double {
let summary = describe_samples(values)
let spread = 6.0 * summary.standard_deviation
if spread <= 0.0000000001 {
0.0
} else {
(upper - lower) / spread
}
}
///|
pub fn to_feature_measurement(
name : String,
measurement : Measurement,
confidence : Double,
) -> FeatureMeasurement {
{
name,
value: measurement.value,
unit: measurement.unit,
confidence: clamp_double(confidence, 0.0, 1.0),
decision: measurement.decision,
}
}
///|
pub fn feature_to_measurement(
feature : FeatureMeasurement,
nominal : Double,
lower : Double,
upper : Double,
) -> Measurement {
let tolerance = Tolerance::Tolerance(
nominal~,
lower~,
upper~,
unit=feature.unit,
)
{
name: feature.name,
value: feature.value,
unit: feature.unit,
decision: tolerance.judge(feature.value),
deviation: feature.value - nominal,
}
}
///|
pub fn measurement_passes(measurement : Measurement) -> Bool {
match measurement.decision {
Pass => true
Warn => true
Fail => false
}
}
///|
pub fn measurement_score(
measurement : Measurement,
tolerance : Tolerance,
) -> Double {
let span = tolerance.upper - tolerance.lower
if span <= 0.0 {
0.0
} else {
1.0 - (measurement.value - tolerance.nominal).abs() / span
}
}