feat: initial commit - massive-cloud point cloud processing system

This commit is contained in:
2026-05-27 09:51:42 +00:00
commit 16811100d1
391 changed files with 78338 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
# Default configuration for coupler panel measurement pipeline.
# All numeric units in mm / degree unless otherwise stated.
# Override fields by passing a dict or a YAML path with the same nested shape.
schema_version: "1.0"
# --- CAD parsing & GT extraction --------------------------------------------
cad:
# OpenCASCADE tessellation quality.
linear_deflection_mm: 0.5
angular_deflection_rad: 0.1
# Hole topology classification.
# The four locating holes are expected to be small and equal-radius;
# the central pass-through hole is expected to be much larger.
locating_hole_radius_mm: [4.0, 12.0] # [min, max] of expected locating hole radius
central_hole_radius_min_mm: 20.0 # any circle larger than this is treated as the centre hole
rectangle_aspect_tol: 0.15 # tolerance for "the 4 hole centres form a rectangle"
# --- Sampling ---------------------------------------------------------------
sampling:
method: poisson_disk # uniform_area | poisson_disk | adaptive | grid_spacing
# Use either spacing_mm OR num_points; if both set, spacing_mm wins.
spacing_mm: 1.0
num_points: 100000
seed: 42
adaptive:
curvature_weight: 1.0
min_spacing_factor: 0.25 # smallest spacing = spacing_mm * factor
max_spacing_factor: 4.0
# --- Simulated scan (optional) ----------------------------------------------
scan_simulator:
enabled: false
view_origin: [10000.0, 0.0, 0.0] # camera position in CAD frame, mm
hpr_radius_mm: 50000.0 # hidden-point-removal radius
# --- Panel deflection injection (the SIGNAL the algorithm should measure) --
# This rotates the panel (and its 4 locating holes) by a known small angle.
# After running the pipeline, theta_right_deg / theta_ref_deg in the result
# should match these values within the algorithm's recovery accuracy.
panel_deflection:
enabled: false
theta_right_deg: 0.0 # atan2(n_y, n_x) target (rotation around z)
theta_ref_deg: 0.0 # atan2(n_z, n_x) target (rotation around -y)
# --- Synthetic noise --------------------------------------------------------
# Realistic LIDAR / structured-light noise on a ~2 m × 2 m panel is ≈ 50-80
# µm = 0.05-0.08 mm. Larger sigma is mostly to test robustness, not to
# match a real sensor.
noise:
enabled: true
sigma_mm: 0.05
mode: isotropic # isotropic | along_normal
seed: 43
# --- Synthetic scan-pose perturbation ---------------------------------------
# Mounting / scanner-stage jitter. 4-hole Kabsch should cancel this; if it
# leaks into the final angles that's a registration error, not a measurement
# of panel deflection. Set rotation_deg=0, translation_mm=0 for "ideal pose"
# experiments that isolate the deflection-recovery accuracy.
transform:
enabled: true
rotation_deg: 0.5 # magnitude; axis is randomised
rotation_axis: random # random | x | y | z | [ax, ay, az]
translation_mm: 2.0 # magnitude; direction is randomised
translation_dir: random
seed: 44
# --- Denoise pipeline -------------------------------------------------------
# Steps are executed in the listed order. Set steps to [] to disable.
denoise:
steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 0.5
- type: statistical
nb_neighbors: 30
std_ratio: 2.0
- type: radius
nb_points: 8
radius_mm: 2.0
# Optional MLS smoothing (requires open3d ≥ 0.18 with ml extras).
smoothing:
enabled: false
search_radius_mm: 2.0
polynomial_order: 2
# --- Registration -----------------------------------------------------------
registration:
method: kabsch_four_holes # only this method is implemented; documented & enforced
# The four GT hole centres come from CAD; the four scan hole centres come
# from the detection module. Pairing is by greedy nearest-neighbour after
# a coarse PCA-based pre-alignment of the centroid.
pre_align: pca_centroid
refuse_if_residual_above_mm: 5.0 # quality flag if RMS pairing residual exceeds this
# --- 4-hole detection in point cloud ----------------------------------------
detection:
# Local panel-plane projection.
panel_normal_seed: from_cad # from_cad | pca | given
panel_normal_pca_kth: 1 # use k-th smallest PCA eigenvector as panel normal
# 2D occupancy grid.
grid_pixel_mm: 0.3
panel_min_area_ratio: 0.4 # largest connected component must be ≥ this fraction of bbox
hole_min_area_mm2: 10.0
hole_max_area_mm2: 1500.0
closing_iters: 2 # 原来没有,加形态学闭运算填补边界断裂
fill_bg_below_mm2: 5.0 # 原来没有,填充小碎片
# Circle fitting on hole boundary.
circle_fit:
method: algebraic_then_lsq # algebraic_then_lsq | hyper | taubin
inlier_residual_mm: 0.5
# Selection.
select_top_k_by_radius_match: 4
rectangle_aspect_tol: 0.20
# --- Panel ROI extraction ---------------------------------------------------
roi:
hole_dilate_mm: 3.0 # exclude points within (hole_radius + dilate)
central_hole_dilate_mm: 5.0
edge_buffer_mm: 5.0 # shrink ROI rectangle inward by this
chamfer_normal_dot_min: 0.85 # exclude points whose normal deviates more than acos(0.85) from panel normal
outlier_z_score: 3.0
# --- Plane fit --------------------------------------------------------------
plane_fit:
method: ransac_svd
ransac_iterations: 200
ransac_inlier_thresh_mm: auto # auto = 3*sigma_mm
min_inlier_ratio: 0.6
enforce_nx_positive: true
# --- Metrics ----------------------------------------------------------------
metrics:
# If your right axis is +y, leave this 1. If right is -y, set to -1.
right_axis_sign: 1
# Angles smaller than this are clamped to 0 (purely cosmetic; raw value is
# always in the report).
angle_clamp_deg: 0.0
# --- Output / artifacts -----------------------------------------------------
artifacts:
save_intermediate: true
ply_format: binary # binary | ascii
image_dpi: 150
heatmap_colormap: viridis

View File

@@ -0,0 +1,13 @@
# Parameter sweep over point cloud density.
matrix:
sampling.spacing_mm:
- 0.25
- 0.5
- 1.0
- 2.0
- 5.0
fixed:
sampling.method: poisson_disk
noise.sigma_mm: 0.5
transform.rotation_deg: 3.0
transform.translation_mm: 5.0

View File

@@ -0,0 +1,34 @@
# Full cartesian product. WARNING: 4 * 5 * 8 * 4 * 4 = 2560 runs.
# Use only when you have time and disk.
matrix:
sampling.method:
- uniform_area
- poisson_disk
- adaptive
- grid_spacing
sampling.spacing_mm:
- 0.25
- 0.5
- 1.0
- 2.0
- 5.0
noise.sigma_mm:
- 0.0
- 0.25
- 0.5
- 1.0
- 2.0
- 4.0
- 10.0
- 20.0
transform.rotation_deg:
- 1.0
- 3.0
- 5.0
- 10.0
transform.translation_mm:
- 0.5
- 1.0
- 5.0
- 10.0
fixed: {}

View File

@@ -0,0 +1,47 @@
# Sweep matrix for the lu1-AF4 coupler panel STP. Total 9 runs.
stp_path: D:/myDocuments/PKU/high_speed_train_proj/lu1-M000004835653_AF4_ASMP072708187_N_AF4.stp
matrix:
noise.sigma_mm: [0.0, 0.5, 2.0]
transform.rotation_deg: [1.0, 3.0, 10.0]
fixed:
sampling.method: poisson_disk
sampling.spacing_mm: null
sampling.num_points: 500000
sampling.seed: 42
scan_simulator.enabled: true
scan_simulator.view_origin: [10000.0, 0.0, 0.0]
scan_simulator.hpr_radius_mm: 200000.0
noise.seed: 43
transform.translation_mm: 5.0
transform.seed: 44
cad.locating_hole_radius_mm: [14.0, 18.0]
cad.central_hole_radius_min_mm: 80.0
detection.grid_pixel_mm: 2.0
detection.fill_bg_below_mm2: 100.0
detection.hole_min_area_mm2: 600.0
detection.hole_max_area_mm2: 5000.0
detection.locating_hole_radius_mm: [14.0, 22.0]
detection.panel_min_area_ratio: 0.15
detection.rectangle_aspect_tol: 0.40
detection.circle_fit.method: algebraic_then_lsq
detection.circle_fit.inlier_residual_mm: 1.5
roi.hole_dilate_mm: 5.0
roi.central_hole_dilate_mm: 10.0
roi.edge_buffer_mm: 8.0
roi.chamfer_normal_dot_min: 0.80
roi.outlier_z_score: 3.0
plane_fit.ransac_iterations: 300
plane_fit.ransac_inlier_thresh_mm: auto
plane_fit.min_inlier_ratio: 0.5
plane_fit.enforce_nx_positive: true
metrics.right_axis_sign: 1
denoise.steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 1.0
- type: statistical
nb_neighbors: 20
std_ratio: 2.5

View File

@@ -0,0 +1,74 @@
# Deflection-recovery sweep: vary the INJECTED panel-deflection angle and
# verify the algorithm reads it back. Single-axis at a time so the
# response of theta_right and theta_ref can be analysed independently.
stp_path: D:/myDocuments/PKU/high_speed_train_proj/lu1-M000004835653_AF4_ASMP072708187_N_AF4.stp
matrix:
panel_deflection.theta_right_deg: [0.0, 0.1, 0.3, 0.5, 1.0, 2.0]
fixed:
panel_deflection.enabled: true
panel_deflection.theta_ref_deg: 0.0
sampling.method: poisson_disk
sampling.spacing_mm: null
sampling.num_points: 500000
sampling.seed: 42
scan_simulator.enabled: true
scan_simulator.view_origin: [10000.0, 0.0, 0.0]
scan_simulator.hpr_radius_mm: 200000.0
noise.enabled: true
noise.sigma_mm: 0.05
noise.mode: isotropic
noise.seed: 43
transform.enabled: true
transform.rotation_deg: 0.5
transform.translation_mm: 2.0
transform.rotation_axis: random
transform.translation_dir: random
transform.seed: 44
cad.locating_hole_radius_mm: [14.0, 18.0]
cad.central_hole_radius_min_mm: 80.0
cad.linear_deflection_mm: 0.5
cad.angular_deflection_rad: 0.1
detection.panel_normal_seed: pca
detection.grid_pixel_mm: 2.0
detection.fill_bg_below_mm2: 100.0
detection.hole_min_area_mm2: 600.0
detection.hole_max_area_mm2: 5000.0
detection.locating_hole_radius_mm: [14.0, 22.0]
detection.panel_min_area_ratio: 0.15
detection.rectangle_aspect_tol: 0.40
detection.circle_fit.method: algebraic_then_lsq
detection.circle_fit.inlier_residual_mm: 1.5
roi.hole_dilate_mm: 5.0
roi.central_hole_dilate_mm: 10.0
roi.edge_buffer_mm: 8.0
roi.chamfer_normal_dot_min: 0.80
roi.outlier_z_score: 3.0
plane_fit.ransac_iterations: 300
plane_fit.ransac_inlier_thresh_mm: auto
plane_fit.min_inlier_ratio: 0.5
plane_fit.enforce_nx_positive: true
metrics.right_axis_sign: 1
metrics.angle_clamp_deg: 0.0
registration.method: kabsch_four_holes
registration.refuse_if_residual_above_mm: 5.0
denoise.steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 0.5
- type: statistical
nb_neighbors: 20
std_ratio: 2.5

View File

@@ -0,0 +1,73 @@
# Point-cloud density sweep: fix deflection + noise, vary num_points to
# show how many points the algorithm needs.
stp_path: D:/myDocuments/PKU/high_speed_train_proj/lu1-M000004835653_AF4_ASMP072708187_N_AF4.stp
matrix:
sampling.num_points: [200000, 350000, 500000, 750000, 1000000]
fixed:
panel_deflection.enabled: true
panel_deflection.theta_right_deg: 0.5
panel_deflection.theta_ref_deg: 0.3
sampling.method: poisson_disk
sampling.spacing_mm: null
sampling.seed: 42
scan_simulator.enabled: true
scan_simulator.view_origin: [10000.0, 0.0, 0.0]
scan_simulator.hpr_radius_mm: 200000.0
noise.enabled: true
noise.sigma_mm: 0.05
noise.mode: isotropic
noise.seed: 43
transform.enabled: true
transform.rotation_deg: 0.5
transform.translation_mm: 2.0
transform.rotation_axis: random
transform.translation_dir: random
transform.seed: 44
cad.locating_hole_radius_mm: [14.0, 18.0]
cad.central_hole_radius_min_mm: 80.0
cad.linear_deflection_mm: 0.5
cad.angular_deflection_rad: 0.1
detection.panel_normal_seed: pca
detection.grid_pixel_mm: 2.0
detection.fill_bg_below_mm2: 100.0
detection.hole_min_area_mm2: 600.0
detection.hole_max_area_mm2: 5000.0
detection.locating_hole_radius_mm: [14.0, 28.0] # wider window for low-density tests
detection.panel_min_area_ratio: 0.15
detection.rectangle_aspect_tol: 0.40
detection.circle_fit.method: algebraic_then_lsq
detection.circle_fit.inlier_residual_mm: 1.5
roi.hole_dilate_mm: 5.0
roi.central_hole_dilate_mm: 10.0
roi.edge_buffer_mm: 8.0
roi.chamfer_normal_dot_min: 0.80
roi.outlier_z_score: 3.0
plane_fit.ransac_iterations: 300
plane_fit.ransac_inlier_thresh_mm: auto
plane_fit.min_inlier_ratio: 0.5
plane_fit.enforce_nx_positive: true
metrics.right_axis_sign: 1
metrics.angle_clamp_deg: 0.0
registration.method: kabsch_four_holes
registration.refuse_if_residual_above_mm: 5.0
denoise.steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 0.5
- type: statistical
nb_neighbors: 20
std_ratio: 2.5

View File

@@ -0,0 +1,73 @@
# Noise sweep: fix the panel deflection at (theta_right=0.5°, theta_ref=0.3°)
# and vary Gaussian noise sigma to characterise robustness.
stp_path: D:/myDocuments/PKU/high_speed_train_proj/lu1-M000004835653_AF4_ASMP072708187_N_AF4.stp
matrix:
noise.sigma_mm: [0.0, 0.025, 0.05, 0.1, 0.2, 0.5]
fixed:
panel_deflection.enabled: true
panel_deflection.theta_right_deg: 0.5
panel_deflection.theta_ref_deg: 0.3
sampling.method: poisson_disk
sampling.spacing_mm: null
sampling.num_points: 500000
sampling.seed: 42
scan_simulator.enabled: true
scan_simulator.view_origin: [10000.0, 0.0, 0.0]
scan_simulator.hpr_radius_mm: 200000.0
noise.enabled: true
noise.mode: isotropic
noise.seed: 43
transform.enabled: true
transform.rotation_deg: 0.5
transform.translation_mm: 2.0
transform.rotation_axis: random
transform.translation_dir: random
transform.seed: 44
cad.locating_hole_radius_mm: [14.0, 18.0]
cad.central_hole_radius_min_mm: 80.0
cad.linear_deflection_mm: 0.5
cad.angular_deflection_rad: 0.1
detection.panel_normal_seed: pca
detection.grid_pixel_mm: 2.0
detection.fill_bg_below_mm2: 100.0
detection.hole_min_area_mm2: 600.0
detection.hole_max_area_mm2: 5000.0
detection.locating_hole_radius_mm: [14.0, 22.0]
detection.panel_min_area_ratio: 0.15
detection.rectangle_aspect_tol: 0.40
detection.circle_fit.method: algebraic_then_lsq
detection.circle_fit.inlier_residual_mm: 1.5
roi.hole_dilate_mm: 5.0
roi.central_hole_dilate_mm: 10.0
roi.edge_buffer_mm: 8.0
roi.chamfer_normal_dot_min: 0.80
roi.outlier_z_score: 3.0
plane_fit.ransac_iterations: 300
plane_fit.ransac_inlier_thresh_mm: auto
plane_fit.min_inlier_ratio: 0.5
plane_fit.enforce_nx_positive: true
metrics.right_axis_sign: 1
metrics.angle_clamp_deg: 0.0
registration.method: kabsch_four_holes
registration.refuse_if_residual_above_mm: 5.0
denoise.steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 0.5
- type: statistical
nb_neighbors: 20
std_ratio: 2.5

View File

@@ -0,0 +1,78 @@
# Sampling-strategy sweep: 4 methods × same other settings, so the saved
# intermediates per run/<method>/02_sampled.ply, 03_noisy.ply, ... can be
# compared apples-to-apples.
stp_path: D:/myDocuments/PKU/high_speed_train_proj/lu1-M000004835653_AF4_ASMP072708187_N_AF4.stp
matrix:
sampling.method:
- uniform_area
- poisson_disk
- adaptive
- grid_spacing
fixed:
panel_deflection.enabled: true
panel_deflection.theta_right_deg: 0.5
panel_deflection.theta_ref_deg: 0.3
sampling.spacing_mm: null
sampling.num_points: 500000
sampling.seed: 42
scan_simulator.enabled: true
scan_simulator.view_origin: [10000.0, 0.0, 0.0]
scan_simulator.hpr_radius_mm: 200000.0
noise.enabled: true
noise.sigma_mm: 0.05
noise.mode: isotropic
noise.seed: 43
transform.enabled: true
transform.rotation_deg: 0.5
transform.translation_mm: 2.0
transform.rotation_axis: random
transform.translation_dir: random
transform.seed: 44
cad.locating_hole_radius_mm: [14.0, 18.0]
cad.central_hole_radius_min_mm: 80.0
cad.linear_deflection_mm: 0.5
cad.angular_deflection_rad: 0.1
detection.panel_normal_seed: pca
detection.grid_pixel_mm: 2.0
detection.fill_bg_below_mm2: 100.0
detection.hole_min_area_mm2: 600.0
detection.hole_max_area_mm2: 5000.0
detection.locating_hole_radius_mm: [14.0, 22.0]
detection.panel_min_area_ratio: 0.15
detection.rectangle_aspect_tol: 0.40
detection.circle_fit.method: algebraic_then_lsq
detection.circle_fit.inlier_residual_mm: 1.5
roi.hole_dilate_mm: 5.0
roi.central_hole_dilate_mm: 10.0
roi.edge_buffer_mm: 8.0
roi.chamfer_normal_dot_min: 0.80
roi.outlier_z_score: 3.0
plane_fit.ransac_iterations: 300
plane_fit.ransac_inlier_thresh_mm: auto
plane_fit.min_inlier_ratio: 0.5
plane_fit.enforce_nx_positive: true
metrics.right_axis_sign: 1
metrics.angle_clamp_deg: 0.0
registration.method: kabsch_four_holes
registration.refuse_if_residual_above_mm: 5.0
denoise.steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 0.5
- type: statistical
nb_neighbors: 20
std_ratio: 2.5

View File

@@ -0,0 +1,16 @@
# Parameter sweep over Gaussian noise sigma.
matrix:
noise.sigma_mm:
- 0.0
- 0.25
- 0.5
- 1.0
- 2.0
- 4.0
- 10.0
- 20.0
fixed:
sampling.method: poisson_disk
sampling.spacing_mm: 1.0
transform.rotation_deg: 3.0
transform.translation_mm: 5.0

View File

@@ -0,0 +1,12 @@
# Parameter sweep over sampling methods (other knobs fixed at default).
matrix:
sampling.method:
- uniform_area
- poisson_disk
- adaptive
- grid_spacing
fixed:
sampling.spacing_mm: 1.0
noise.sigma_mm: 0.5
transform.rotation_deg: 3.0
transform.translation_mm: 5.0

View File

@@ -0,0 +1,16 @@
# Parameter sweep over GT rigid transform magnitude.
matrix:
transform.rotation_deg:
- 1.0
- 3.0
- 5.0
- 10.0
transform.translation_mm:
- 0.5
- 1.0
- 5.0
- 10.0
fixed:
sampling.method: poisson_disk
sampling.spacing_mm: 1.0
noise.sigma_mm: 0.5

View File

@@ -0,0 +1,17 @@
# Profile: high-density scan (≈100w points, sub-mm spacing).
sampling:
spacing_mm: 0.25
num_points: 1000000
denoise:
steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 0.25
- type: statistical
nb_neighbors: 50
std_ratio: 2.0
detection:
grid_pixel_mm: 0.25
plane_fit:
ransac_iterations: 500

View File

@@ -0,0 +1,18 @@
# Profile: low-density scan (≈1w points, ≈2 mm spacing).
sampling:
spacing_mm: 2.0
num_points: 10000
denoise:
steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 1.0
- type: statistical
nb_neighbors: 15
std_ratio: 2.5
detection:
grid_pixel_mm: 1.0
hole_min_area_mm2: 20.0
plane_fit:
ransac_iterations: 100

View File

@@ -0,0 +1,106 @@
# Profile tuned for the lu1-M000004835653_AF4_ASMP072708187_N_AF4.stp panel.
#
# Topology summary (from cad/iter_circular_edges):
# - locating holes: r = 16 mm × 4 corners at (y=±100, z=±180)
# - central hole: r = 100 mm at (y≈1, z=0)
# - panel size: ~200 × 360 mm in y-z, ~76 mm thick along x
#
# Use:
# coupler-measure --stp <path> --out-dir <dir> --profile lu1_af4
cad:
linear_deflection_mm: 0.5
angular_deflection_rad: 0.1
# CAD-side: strict band that selects only the r=16 mm corner holes.
locating_hole_radius_mm: [14.0, 18.0]
central_hole_radius_min_mm: 80.0
rectangle_aspect_tol: 0.30
sampling:
method: poisson_disk
spacing_mm: null
num_points: 500000
seed: 42
# Critical: simulate a single-view "+x looking at -x" scan. Without this,
# back-face points project into the hole regions and detection fails.
scan_simulator:
enabled: true
view_origin: [10000.0, 0.0, 0.0]
hpr_radius_mm: 200000.0
# --- Panel deflection injection -------------------------------------------
# This is the *signal* we want the algorithm to recover. By default it is
# off — sweeps override these.
panel_deflection:
enabled: true
theta_right_deg: 0.5 # rotation around z so n_y > 0
theta_ref_deg: 0.3 # rotation around -y so n_z > 0
# --- Realistic LiDAR / structured-light noise -----------------------------
noise:
enabled: true
sigma_mm: 0.05 # ≈ 50 µm; matches typical industrial scanners
mode: isotropic
seed: 43
# --- Scanner-pose jitter --------------------------------------------------
# Modest values: 4-hole Kabsch should remove this completely.
transform:
enabled: true
rotation_deg: 0.5
translation_mm: 2.0
rotation_axis: random
translation_dir: random
seed: 44
denoise:
steps:
- type: passthrough
bbox_padding_mm: 50.0
- type: voxel
voxel_mm: 0.5 # finer voxel for low-noise data
- type: statistical
nb_neighbors: 20
std_ratio: 2.5
detection:
panel_normal_seed: pca # critical: use cloud's own PCA, not CAD seed
grid_pixel_mm: 2.0
closing_iters: 0
fill_bg_below_mm2: 100.0
panel_min_area_ratio: 0.15
hole_min_area_mm2: 600.0
hole_max_area_mm2: 5000.0
locating_hole_radius_mm: [14.0, 22.0]
circle_fit:
method: algebraic_then_lsq
inlier_residual_mm: 1.5
rectangle_aspect_tol: 0.40
roi:
hole_dilate_mm: 5.0
central_hole_dilate_mm: 10.0
edge_buffer_mm: 8.0
chamfer_normal_dot_min: 0.80
outlier_z_score: 3.0
plane_fit:
ransac_iterations: 300
ransac_inlier_thresh_mm: auto
min_inlier_ratio: 0.5
enforce_nx_positive: true
metrics:
right_axis_sign: 1
angle_clamp_deg: 0.0
artifacts:
save_intermediate: true
ply_format: binary
image_dpi: 150
heatmap_colormap: viridis
registration:
method: kabsch_four_holes
refuse_if_residual_above_mm: 5.0