Skip to main content

oxihuman_export/
curve_modifier_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Curve modifier deformation export for mesh-along-curve operations.
6
7#[allow(dead_code)]
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum CurveModAxis {
10    X,
11    Y,
12    Z,
13}
14
15#[allow(dead_code)]
16#[derive(Debug, Clone)]
17pub struct CurveModEntry {
18    pub control_points: Vec<[f32; 3]>,
19    pub axis: CurveModAxis,
20    pub stretch: bool,
21    pub bounds_clamp: bool,
22}
23
24#[allow(dead_code)]
25#[derive(Debug, Clone)]
26pub struct CurveModifierExport {
27    pub modifiers: Vec<CurveModEntry>,
28}
29
30#[allow(dead_code)]
31pub fn new_curve_modifier_export() -> CurveModifierExport {
32    CurveModifierExport {
33        modifiers: Vec::new(),
34    }
35}
36
37#[allow(dead_code)]
38pub fn add_curve_mod(exp: &mut CurveModifierExport, points: Vec<[f32; 3]>, axis: CurveModAxis) {
39    exp.modifiers.push(CurveModEntry {
40        control_points: points,
41        axis,
42        stretch: false,
43        bounds_clamp: true,
44    });
45}
46
47#[allow(dead_code)]
48pub fn mod_count(exp: &CurveModifierExport) -> usize {
49    exp.modifiers.len()
50}
51
52#[allow(dead_code)]
53pub fn curve_mod_length(entry: &CurveModEntry) -> f32 {
54    let mut len = 0.0_f32;
55    for pair in entry.control_points.windows(2) {
56        let d = [
57            pair[1][0] - pair[0][0],
58            pair[1][1] - pair[0][1],
59            pair[1][2] - pair[0][2],
60        ];
61        len += (d[0] * d[0] + d[1] * d[1] + d[2] * d[2]).sqrt();
62    }
63    len
64}
65
66#[allow(dead_code)]
67pub fn axis_name(axis: CurveModAxis) -> &'static str {
68    match axis {
69        CurveModAxis::X => "X",
70        CurveModAxis::Y => "Y",
71        CurveModAxis::Z => "Z",
72    }
73}
74
75#[allow(dead_code)]
76pub fn validate_curve_mod(entry: &CurveModEntry) -> bool {
77    entry.control_points.len() >= 2
78}
79
80#[allow(dead_code)]
81pub fn curve_modifier_to_json(exp: &CurveModifierExport) -> String {
82    format!("{{\"modifier_count\":{}}}", exp.modifiers.len())
83}
84
85#[allow(dead_code)]
86pub fn total_curve_length(exp: &CurveModifierExport) -> f32 {
87    exp.modifiers.iter().map(curve_mod_length).sum()
88}
89
90#[allow(dead_code)]
91pub fn clear_curve_mods(exp: &mut CurveModifierExport) {
92    exp.modifiers.clear();
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    fn sample_points() -> Vec<[f32; 3]> {
100        vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0]]
101    }
102
103    #[test]
104    fn test_new_empty() {
105        let exp = new_curve_modifier_export();
106        assert_eq!(mod_count(&exp), 0);
107    }
108
109    #[test]
110    fn test_add_mod() {
111        let mut exp = new_curve_modifier_export();
112        add_curve_mod(&mut exp, sample_points(), CurveModAxis::Y);
113        assert_eq!(mod_count(&exp), 1);
114    }
115
116    #[test]
117    fn test_curve_length() {
118        let entry = CurveModEntry {
119            control_points: sample_points(),
120            axis: CurveModAxis::Y,
121            stretch: false,
122            bounds_clamp: true,
123        };
124        assert!((curve_mod_length(&entry) - 2.0).abs() < 1e-5);
125    }
126
127    #[test]
128    fn test_axis_name_y() {
129        assert_eq!(axis_name(CurveModAxis::Y), "Y");
130    }
131
132    #[test]
133    fn test_validate_valid() {
134        let entry = CurveModEntry {
135            control_points: sample_points(),
136            axis: CurveModAxis::X,
137            stretch: false,
138            bounds_clamp: true,
139        };
140        assert!(validate_curve_mod(&entry));
141    }
142
143    #[test]
144    fn test_validate_single_point() {
145        let entry = CurveModEntry {
146            control_points: vec![[0.0; 3]],
147            axis: CurveModAxis::X,
148            stretch: false,
149            bounds_clamp: true,
150        };
151        assert!(!validate_curve_mod(&entry));
152    }
153
154    #[test]
155    fn test_json_output() {
156        let exp = new_curve_modifier_export();
157        let j = curve_modifier_to_json(&exp);
158        assert!(j.contains("modifier_count"));
159    }
160
161    #[test]
162    fn test_total_length() {
163        let mut exp = new_curve_modifier_export();
164        add_curve_mod(&mut exp, sample_points(), CurveModAxis::Z);
165        assert!(total_curve_length(&exp) > 0.0);
166    }
167
168    #[test]
169    fn test_clear_mods() {
170        let mut exp = new_curve_modifier_export();
171        add_curve_mod(&mut exp, sample_points(), CurveModAxis::X);
172        clear_curve_mods(&mut exp);
173        assert_eq!(mod_count(&exp), 0);
174    }
175
176    #[test]
177    fn test_axis_x_name() {
178        assert_eq!(axis_name(CurveModAxis::X), "X");
179    }
180}