boring_parser/classification.rs
1/// 岩石群コード(全バージョン共通)
2///
3/// V1/V2: `Single` or `Interbedded` のみ(`Mixed` は構造上表現不可)
4/// V3/V4: `Single`, `Interbedded`, `Mixed` の全3値
5///
6/// PDF仕様: V3.00 表2-13 / V4.00 表2-11
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum RockGroupCode {
9 /// 単一種の岩石(V3+: コード1)
10 Single,
11 /// 互層(V3+: コード2 / V1-V2: classification2が非空)
12 Interbedded,
13 /// 混在岩(V3+: コード3 / V1-V2: 表現不可)
14 Mixed,
15}
16
17impl RockGroupCode {
18 /// XML値("1", "2", "3")からenumに変換
19 pub fn from_code(code: &str) -> Option<Self> {
20 match code {
21 "1" => Some(Self::Single),
22 "2" => Some(Self::Interbedded),
23 "3" => Some(Self::Mixed),
24 _ => None,
25 }
26 }
27
28 /// 互層かどうか
29 pub fn is_interbedded(&self) -> bool {
30 *self == Self::Interbedded
31 }
32}
33
34/// 構成岩種の情報
35///
36/// V1.10〜V2.10 と V3.00+ でデータの性質が異なるためenumで分岐。
37/// V1/V2は各構成岩種に個別の名前を持ち、V3+は9桁コードで識別する。
38#[derive(Debug, Clone)]
39pub enum Constituent {
40 /// V1.10〜V2.10: 各構成岩種に個別の名前がある
41 Named {
42 /// 地質名称 / 土質岩種区分名(例: "シルト質砂")
43 name: String,
44 /// V1: 地質コード / V2: 土質岩種記号(例: "SM")
45 symbol: Option<String>,
46 },
47 /// V3.00+: 構成岩種は9桁コードで識別(個別の名前なし)
48 Coded {
49 /// 堆積岩・火成岩の岩相コード
50 lithofacies: Option<String>,
51 /// 岩石コード
52 rock: Option<String>,
53 /// 変成岩の岩相コード
54 metamorphic_rock_lithofacies: Option<String>,
55 /// 変成岩の岩石コード
56 metamorphic_rock: Option<String>,
57 },
58}
59
60/// 岩石群情報(1つの岩石群 = コード + 構成岩種リスト)
61#[derive(Debug, Clone)]
62pub struct RockGroupInfo {
63 pub code: RockGroupCode,
64 pub constituents: Vec<Constituent>,
65}
66
67/// 地質分類の統一インターフェース
68///
69/// 各バージョンの地質分類構造体に実装し、バージョンを意識せず
70/// 互層判定・構成岩種の取得を行えるようにする。
71///
72/// # Example
73/// ```ignore
74/// use boring_parser::classification::ClassificationInfo;
75///
76/// let groups = classification.rock_groups();
77/// // 互層判定
78/// if groups[0].code == RockGroupCode::Interbedded {
79/// println!("互層: 構成岩種数 = {}", groups[0].constituents.len());
80/// }
81/// ```
82pub trait ClassificationInfo {
83 /// 岩石群のリストを返す。
84 ///
85 /// - V1/V2: 常に1要素(classification1/2から推定)
86 /// - V3/V4: `rock_groups` の数だけ返す
87 ///
88 /// 互層判定: `groups[i].code == RockGroupCode::Interbedded`
89 /// 構成岩種数: `groups[i].constituents.len()`
90 fn rock_groups(&self) -> Vec<RockGroupInfo>;
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_rock_group_code_from_code() {
99 assert_eq!(RockGroupCode::from_code("1"), Some(RockGroupCode::Single));
100 assert_eq!(
101 RockGroupCode::from_code("2"),
102 Some(RockGroupCode::Interbedded)
103 );
104 assert_eq!(RockGroupCode::from_code("3"), Some(RockGroupCode::Mixed));
105 assert_eq!(RockGroupCode::from_code("4"), None);
106 assert_eq!(RockGroupCode::from_code(""), None);
107 }
108
109 #[test]
110 fn test_rock_group_code_is_interbedded() {
111 assert!(!RockGroupCode::Single.is_interbedded());
112 assert!(RockGroupCode::Interbedded.is_interbedded());
113 assert!(!RockGroupCode::Mixed.is_interbedded());
114 }
115}