Skip to main content

cumulus3d_align/
lib.rs

1//! GPS→ENU, Sim3 정렬, 공유 3D 점 정렬, 점군 후처리.
2//!
3//! - [`geodesy`]: WGS84 LLA ↔ ECEF ↔ ENU.
4//! - [`umeyama`](mod@umeyama): Umeyama Sim3, LO-RANSAC 견고 추정, 반복 재가중(견고 Umeyama).
5//! - [`model_aligner`]: 등록 영상 투영 중심 ↔ GPS ENU 정렬(강건 Sim3 추정).
6//! - [`shared`]: 두 재구성 간 공유 3D 점 대응과 그 정렬.
7//! - [`kdtree`], [`cloud`]: 점군 변환·근접 마스킹·추출·스냅샷 합성.
8//! - [`reanchor`]: 새 정밀 모델 기준으로 이전 구역 좌표계를 다시 잇는 연쇄 Sim3.
9//!
10//! # 사용 예
11//!
12//! ```
13//! use cumulus3d_align::{compose_snapshot, umeyama, EnuFrame, SnapshotOptions};
14//! use cumulus3d_core::io::PointCloud;
15//! use cumulus3d_core::{Quat, Sim3, Vec3};
16//!
17//! // GPS(WGS84) ↔ ENU: 원점 기준 동쪽·북쪽·위 미터 좌표.
18//! let enu = EnuFrame::new(37.5, 127.0, 10.0);
19//! let p = enu.lla_to_enu(37.5001, 127.0001, 10.0);
20//! let (lat, lon, _alt) = enu.enu_to_lla(&p);
21//! assert!((lat - 37.5001).abs() < 1e-9 && (lon - 127.0001).abs() < 1e-9);
22//!
23//! // 대응점 집합 사이의 Sim3(src → dst) 추정.
24//! let truth = Sim3::new(2.0, Quat::from_axis_angle(&Vec3::z(), 0.3), Vec3::new(1.0, 2.0, 3.0));
25//! let src: Vec<Vec3> = (0..10).map(|i| Vec3::new(i as f64, (i * i) as f64 * 0.1, (i as f64).sin())).collect();
26//! let dst: Vec<Vec3> = src.iter().map(|x| truth.transform_point(x)).collect();
27//! let est = umeyama(&src, &dst, true).unwrap();
28//! assert!((est.scale - 2.0).abs() < 1e-9);
29//!
30//! // 스냅샷: 정밀 점과 1.5 m 안에 있는 초벌 점을 지우고 합친 뒤 1/stride 추출.
31//! let fine = PointCloud { positions: vec![[0.0, 0.0, 0.0]], ..Default::default() };
32//! let coarse = PointCloud { positions: vec![[0.5, 0.0, 0.0], [10.0, 0.0, 0.0]], ..Default::default() };
33//! let snap = compose_snapshot(&[&fine], &[&coarse], &SnapshotOptions { mask_radius: 1.5, stride: 1 });
34//! assert_eq!(snap.len(), 2);
35//! ```
36//!
37//! ```no_run
38//! use cumulus3d_align::{align_to_gps_file, ModelAlignerOptions};
39//! let mut rec = cumulus3d_core::interop::read_model("model/0").unwrap();
40//! let a = align_to_gps_file(&mut rec, "gps_ref.txt", &ModelAlignerOptions::default()).unwrap();
41//! println!("인라이어 {}/{}, 중앙 오차 {:.2} m", a.num_inliers, a.common.len(), a.median_error);
42//! ```
43#![warn(missing_docs)]
44
45pub mod cloud;
46pub mod error;
47pub mod geodesy;
48pub mod kdtree;
49pub mod model_aligner;
50pub mod reanchor;
51pub mod shared;
52pub mod umeyama;
53
54pub use cloud::{compose_snapshot, decimate, merge_clouds, remove_near, transform_cloud, SnapshotOptions};
55pub use error::{AlignError, Result};
56pub use geodesy::{ecef_to_lla, lla_to_ecef, EnuFrame, WGS84_A, WGS84_B, WGS84_E2, WGS84_F};
57pub use kdtree::KdTree;
58pub use model_aligner::{
59    align_to_gps, align_to_gps_file, estimate_gps_alignment, gps_to_enu, EnuOrigin, GpsAlignment, ModelAlignerOptions,
60};
61pub use reanchor::AnchorChain;
62pub use shared::{align_reconstructions, position_index_from_name, shared_point_correspondences, SharedPointOptions};
63pub use umeyama::{
64    estimate_sim3_ransac, robust_umeyama, umeyama, RankCheck, RobustUmeyamaOptions, RobustUmeyamaResult, Sim3Estimator,
65};