# Can ncollide work with units of measure?

The `uom` crate essentially raises physical units to the Rust type level. That is, it prevents you from confusing, say, mass with length.

Can `ncollide` be sensibly made to work with `uom` types? I’m guessing that this would involve implementing `nalgebra::RealField` for the `uom` types. In which case I see two immediate problems

• Orphan rules (unless done within `uom` or `nalgebra`)
• It would be veeeery repetitive, unless there is some meta-programming support for implementing `RealField`.

Hmm, it seems that I must have made a mistake when I tried this earlier. It appears to be working now. I’ll have to do some more extensive testing when I have the time, but it’s looking good at the moment!

It turns out it’s a bit more subtle: It works up to a point.

Here is an example which demonstrates that making `nc::math::{Vector, Point}` and subtracting the latter, works just as well with `uom::Length` as it does with `f32`.

However, `Vector::norm()` does not work with `uom::Length` (no problem with `f32`).

# Sample code

``````use uom::si::f32::Length;
use uom::si::length::meter;
use ncollide3d as nc;
use nc::math::{Vector, Point};

fn  m(x: f32) -> Length { Length::new::<meter> (x) }

type PL = nc::math::Point<Length>;
type Pf = nc::math::Point<f32>;

fn main() {

let p1f: Point<f32>    = Pf::new(  1.2,    1.3,    1.4);
let p2f                = Pf::new(  2.1,    3.1,    4.1);

let p1u: Point<Length> = PL::new(m(1.2), m(1.3), m(1.4));
let p2u                = PL::new(m(2.1), m(3.1), m(4.1));

let vf: Vector<f32>    = p2f - p1f;
let vu: Vector<Length> = p2u - p1u;

println!("{:?}", p2u - p1u);
println!("{:?}", p2f - p1f);

println!("{:?}", vf);
println!("{:?}", vu);

#[cfg(feature = "show-compiler-error")]
println!("{:?}", vu.norm());
println!("{:?}", vf.norm());
}
``````

# Error message digest

The most relevant part of the compiler error is probably

``````doesn't satisfy `<_ as ncollide3d::nalgebra::SimdComplexField>::SimdRealField = _`
doesn't satisfy `_: ncollide3d::nalgebra::SimdComplexField`
``````

# Question

Can I do anything to get around this problem, in order to be able to use `.norm()` on `nc::math::Vector<uom::si::f32::Length>`?

# Full error message

For completeness, the (very noisy) full compiler error message is

``````error[E0599]: no method named `norm` found for struct `ncollide3d::nalgebra::Matrix<uom::si::Quantity<(dyn uom::si::Dimension<N = uom::typenum::Z0, T = uom::typenum::Z0, Kind = (dyn uom::Kind + 'static), L = uom::typenum::PInt<uom::typenum::UInt<uom::typenum::UTerm, uom::typenum::B1>>, M = uom::typenum::Z0, J = uom::typenum::Z0, Th = uom::typenum::Z0, I = uom::typenum::Z0> + 'static), (dyn uom::si::Units<f32, mass = uom::si::mass::kilogram, luminous_intensity = uom::si::luminous_intensity::candela, thermodynamic_temperature = uom::si::thermodynamic_temperature::kelvin, electric_current = uom::si::electric_current::ampere, length = uom::si::length::meter, amount_of_substance = uom::si::amount_of_substance::mole, time = uom::si::time::second> + 'static), f32>, ncollide3d::nalgebra::U3, ncollide3d::nalgebra::U1, ncollide3d::nalgebra::ArrayStorage<uom::si::Quantity<(dyn uom::si::Dimension<N = uom::typenum::Z0, T = uom::typenum::Z0, Kind = (dyn uom::Kind + 'static), L = uom::typenum::PInt<uom::typenum::UInt<uom::typenum::UTerm, uom::typenum::B1>>, M = uom::typenum::Z0, J = uom::typenum::Z0, Th = uom::typenum::Z0, I = uom::typenum::Z0> + 'static), (dyn uom::si::Units<f32, mass = uom::si::mass::kilogram, luminous_intensity = uom::si::luminous_intensity::candela, thermodynamic_temperature = uom::si::thermodynamic_temperature::kelvin, electric_current = uom::si::electric_current::ampere, length = uom::si::length::meter, amount_of_substance = uom::si::amount_of_substance::mole, time = uom::si::time::second> + 'static), f32>, ncollide3d::nalgebra::U3, ncollide3d::nalgebra::U1>>` in the current scope
--> examples/playground.rs:29:25
|
29  |       println!("{:?}", vu.norm());
|                           ^^^^ method not found in `ncollide3d::nalgebra::Matrix<uom::si::Quantity<(dyn uom::si::Dimension<N = uom::typenum::Z0, T = uom::typenum::Z0, Kind = (dyn uom::Kind + 'static), L = uom::typenum::PInt<uom::typenum::UInt<uom::typenum::UTerm, uom::typenum::B1>>, M = uom::typenum::Z0, J = uom::typenum::Z0, Th = uom::typenum::Z0, I = uom::typenum::Z0> + 'static), (dyn uom::si::Units<f32, mass = uom::si::mass::kilogram, luminous_intensity = uom::si::luminous_intensity::candela, thermodynamic_temperature = uom::si::thermodynamic_temperature::kelvin, electric_current = uom::si::electric_current::ampere, length = uom::si::length::meter, amount_of_substance = uom::si::amount_of_substance::mole, time = uom::si::time::second> + 'static), f32>, ncollide3d::nalgebra::U3, ncollide3d::nalgebra::U1, ncollide3d::nalgebra::ArrayStorage<uom::si::Quantity<(dyn uom::si::Dimension<N = uom::typenum::Z0, T = uom::typenum::Z0, Kind = (dyn uom::Kind + 'static), L = uom::typenum::PInt<uom::typenum::UInt<uom::typenum::UTerm, uom::typenum::B1>>, M = uom::typenum::Z0, J = uom::typenum::Z0, Th = uom::typenum::Z0, I = uom::typenum::Z0> + 'static), (dyn uom::si::Units<f32, mass = uom::si::mass::kilogram, luminous_intensity = uom::si::luminous_intensity::candela, thermodynamic_temperature = uom::si::thermodynamic_temperature::kelvin, electric_current = uom::si::electric_current::ampere, length = uom::si::length::meter, amount_of_substance = uom::si::amount_of_substance::mole, time = uom::si::time::second> + 'static), f32>, ncollide3d::nalgebra::U3, ncollide3d::nalgebra::U1>>`
|
::: /tmp/testing/.cargo/registry/src/github.com-1ecc6299db9ec823/uom-0.30.0/src/si/mod.rs:10:1
|
10  | / system! {
11  | |     /// [International System of Quantities](http://jcgm.bipm.org/vim/en/1.6.html) (ISQ).
12  | |     ///
13  | |     /// # Generic Parameters
...   |
102 | |     }
103 | | }
| | -
| | |
| |_doesn't satisfy `<_ as ncollide3d::nalgebra::SimdComplexField>::SimdRealField = _`
|   doesn't satisfy `_: ncollide3d::nalgebra::SimdComplexField`
|
= note: the method `norm` exists but the following trait bounds were not satisfied:
`uom::si::Quantity<dyn uom::si::Dimension<N = uom::typenum::Z0, T = uom::typenum::Z0, Kind = (dyn uom::Kind + 'static), L = uom::typenum::PInt<uom::typenum::UInt<uom::typenum::UTerm, uom::typenum::B1>>, M = uom::typenum::Z0, J = uom::typenum::Z0, Th = uom::typenum::Z0, I = uom::typenum::Z0>, dyn uom::si::Units<f32, mass = uom::si::mass::kilogram, luminous_intensity = uom::si::luminous_intensity::candela, thermodynamic_temperature = uom::si::thermodynamic_temperature::kelvin, electric_current = uom::si::electric_current::ampere, length = uom::si::length::meter, amount_of_substance = uom::si::amount_of_substance::mole, time = uom::si::time::second>, f32>: ncollide3d::nalgebra::SimdComplexField`
`<uom::si::Quantity<dyn uom::si::Dimension<N = uom::typenum::Z0, T = uom::typenum::Z0, Kind = (dyn uom::Kind + 'static), L = uom::typenum::PInt<uom::typenum::UInt<uom::typenum::UTerm, uom::typenum::B1>>, M = uom::typenum::Z0, J = uom::typenum::Z0, Th = uom::typenum::Z0, I = uom::typenum::Z0>, dyn uom::si::Units<f32, mass = uom::si::mass::kilogram, luminous_intensity = uom::si::luminous_intensity::candela, thermodynamic_temperature = uom::si::thermodynamic_temperature::kelvin, electric_current = uom::si::electric_current::ampere, length = uom::si::length::meter, amount_of_substance = uom::si::amount_of_substance::mole, time = uom::si::time::second>, f32> as ncollide3d::nalgebra::SimdComplexField>::SimdRealField = _`

``````