Skip to content

Commit 378d807

Browse files
committed
Add Processing math functions (closes #135, closes #140)
1 parent 856202c commit 378d807

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

  • crates/processing_pyo3/src

crates/processing_pyo3/src/lib.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,85 @@ mod mewnala {
756756
PyColor::xyz(x, y, z, a)
757757
}
758758

759+
760+
// ── Processing math functions (issues #135, #140) ────────────────────────
761+
762+
// Trig
763+
#[pyfunction] fn sin(x: f32) -> f32 { x.sin() }
764+
#[pyfunction] fn cos(x: f32) -> f32 { x.cos() }
765+
#[pyfunction] fn tan(x: f32) -> f32 { x.tan() }
766+
#[pyfunction] fn asin(x: f32) -> f32 { x.asin() }
767+
#[pyfunction] fn acos(x: f32) -> f32 { x.acos() }
768+
#[pyfunction] fn atan(x: f32) -> f32 { x.atan() }
769+
#[pyfunction] fn atan2(y: f32, x: f32) -> f32 { y.atan2(x) }
770+
771+
// Math
772+
#[pyfunction] fn sqrt(x: f32) -> f32 { x.sqrt() }
773+
#[pyfunction] fn sq(x: f32) -> f32 { x * x }
774+
#[pyfunction] fn pow(x: f32, e: f32) -> f32 { x.powf(e) }
775+
#[pyfunction] fn exp(x: f32) -> f32 { x.exp() }
776+
#[pyfunction] fn log(x: f32) -> f32 { x.ln() }
777+
778+
// Rounding
779+
#[pyfunction] fn floor(x: f32) -> f32 { x.floor() }
780+
#[pyfunction] fn ceil(x: f32) -> f32 { x.ceil() }
781+
#[pyfunction] fn round(x: f32) -> f32 { x.round() }
782+
783+
// Abs / sign
784+
#[pyfunction]
785+
fn abs(x: &Bound<'_, PyAny>) -> PyResult<f32> {
786+
if let Ok(v) = x.extract::<f32>() { return Ok(v.abs()); }
787+
if let Ok(v) = x.extract::<i64>() { return Ok((v.abs()) as f32); }
788+
Err(pyo3::exceptions::PyTypeError::new_err("abs() requires a number"))
789+
}
790+
791+
// Min / max (handle int and float)
792+
#[pyfunction]
793+
fn min(a: &Bound<'_, PyAny>, b: &Bound<'_, PyAny>) -> PyResult<f32> {
794+
let a: f32 = a.extract::<f32>().or_else(|_| a.extract::<i64>().map(|v| v as f32))?;
795+
let b: f32 = b.extract::<f32>().or_else(|_| b.extract::<i64>().map(|v| v as f32))?;
796+
Ok(a.min(b))
797+
}
798+
#[pyfunction]
799+
fn max(a: &Bound<'_, PyAny>, b: &Bound<'_, PyAny>) -> PyResult<f32> {
800+
let a: f32 = a.extract::<f32>().or_else(|_| a.extract::<i64>().map(|v| v as f32))?;
801+
let b: f32 = b.extract::<f32>().or_else(|_| b.extract::<i64>().map(|v| v as f32))?;
802+
Ok(a.max(b))
803+
}
804+
805+
// Constrain / clamp
806+
#[pyfunction] fn constrain(x: f32, lo: f32, hi: f32) -> f32 { x.clamp(lo, hi) }
807+
808+
// Map range
809+
#[pyfunction]
810+
fn map(value: f32, start1: f32, stop1: f32, start2: f32, stop2: f32) -> f32 {
811+
start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1))
812+
}
813+
814+
// Lerp
815+
#[pyfunction] fn lerp(start: f32, stop: f32, t: f32) -> f32 { start + (stop - start) * t }
816+
817+
// Norm
818+
#[pyfunction] fn norm(value: f32, start: f32, stop: f32) -> f32 { (value - start) / (stop - start) }
819+
820+
// Distance
821+
#[pyfunction]
822+
#[pyo3(signature = (x1, y1, x2, y2, z1=0.0, z2=0.0))]
823+
fn dist(x1: f32, y1: f32, x2: f32, y2: f32, z1: f32, z2: f32) -> f32 {
824+
let dx = x2 - x1; let dy = y2 - y1; let dz = z2 - z1;
825+
(dx*dx + dy*dy + dz*dz).sqrt()
826+
}
827+
828+
// Mag
829+
#[pyfunction]
830+
#[pyo3(signature = (x, y, z=0.0))]
831+
fn mag(x: f32, y: f32, z: f32) -> f32 { (x*x + y*y + z*z).sqrt() }
832+
833+
// Degrees / radians
834+
#[pyfunction] fn degrees(r: f32) -> f32 { r.to_degrees() }
835+
#[pyfunction] fn radians(d: f32) -> f32 { d.to_radians() }
836+
837+
// ─────────────────────────────────────────────────────────────────────────
759838
#[cfg(feature = "webcam")]
760839
#[pymodule_export]
761840
use super::webcam::Webcam;

0 commit comments

Comments
 (0)