Skip to main content

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}