@@ -25,7 +25,7 @@ use processing_render::{
2525use processing_render::{GEN_GAUSSIAN, GEN_SIGNED, GEN_UNIFORM};
2626use processing_render::{
2727 MAP_ABS, MAP_AFFINE, MAP_CLAMP, MAP_EQ, MAP_FLOOR, MAP_GEQ, MAP_GREATER, MAP_LEQ, MAP_LESS,
28- MAP_NEGATE, MAP_NEQ, MAP_SQRT, MAP_SQUARE,
28+ MAP_LIMIT, MAP_NEGATE, MAP_NEQ, MAP_NORMALIZE , MAP_SQRT, MAP_SQUARE,
2929};
3030use processing_render::{
3131 REDUCE_LENGTH, REDUCE_MAX, REDUCE_MEAN, REDUCE_MIN, REDUCE_SUM, REDUCE_SUMSQ,
@@ -46,6 +46,8 @@ fn parse_map_op(s: &str) -> PyResult<u32> {
4646 _ if s.eq_ignore_ascii_case(c::LEQ) => Ok(MAP_LEQ),
4747 _ if s.eq_ignore_ascii_case(c::EQ) => Ok(MAP_EQ),
4848 _ if s.eq_ignore_ascii_case(c::NEQ) => Ok(MAP_NEQ),
49+ _ if s.eq_ignore_ascii_case(c::NORMALIZE) => Ok(MAP_NORMALIZE),
50+ _ if s.eq_ignore_ascii_case(c::LIMIT) => Ok(MAP_LIMIT),
4951 _ => Err(PyValueError::new_err(format!("map: unknown op {s:?}"))),
5052 }
5153}
@@ -239,6 +241,11 @@ fn map_params(kwargs: Option<&Bound<'_, PyDict>>, op: u32) -> PyResult<(f32, f32
239241 kw_f32(kwargs, "offset", 0.0)?,
240242 ),
241243 MAP_CLAMP => (kw_f32(kwargs, "lo", 0.0)?, kw_f32(kwargs, "hi", 1.0)?),
244+ MAP_NORMALIZE => (kw_f32(kwargs, "length", 1.0)?, 0.0),
245+ MAP_LIMIT => (
246+ kw_f32(kwargs, "min_length", 0.0)?,
247+ kw_f32(kwargs, "max_length", f32::MAX)?,
248+ ),
242249 MAP_GREATER | MAP_LESS | MAP_GEQ | MAP_LEQ | MAP_EQ | MAP_NEQ => (
243250 kw_f32(kwargs, "threshold", 0.0)?,
244251 kw_f32(kwargs, "epsilon", 1.0e-6)?,
@@ -251,6 +258,8 @@ fn map_param_keys(op: u32) -> &'static [&'static str] {
251258 match op {
252259 MAP_AFFINE => &["scale", "offset"],
253260 MAP_CLAMP => &["lo", "hi"],
261+ MAP_NORMALIZE => &["length"],
262+ MAP_LIMIT => &["min_length", "max_length"],
254263 MAP_GREATER | MAP_LESS | MAP_GEQ | MAP_LEQ | MAP_EQ | MAP_NEQ => &["threshold", "epsilon"],
255264 _ => &[],
256265 }
@@ -567,9 +576,9 @@ impl Particles {
567576 reject_unknown_kwargs(kwargs, &["a", "b", "out", "op", "b_scale", "b_offset"])?;
568577 let (a, comp) = self.operand(kwargs, "a")?;
569578 let (b, b_comp) = self.operand(kwargs, "b")?;
570- if b_comp != comp {
579+ if b_comp != comp && b_comp != 1 {
571580 return Err(PyValueError::new_err(format!(
572- "apply(combine): `a` has {comp} components but `b` has {b_comp} (must match) "
581+ "apply(combine): the first operand has {comp} components, so the second needs {comp} or 1, not {b_comp} "
573582 )));
574583 }
575584 let out = self.dest(kwargs, a)?;
0 commit comments