units icon indicating copy to clipboard operation
units copied to clipboard

Math vector with first-class unit support

Open OverMalo opened this issue 6 years ago • 8 comments

Hi,

We are using your library for a serious game project and we are wondering if you has think to add vectors with first-class unit support.

It will be interesanting to do operations like this:

Example: auto G = 6,674E−11_N·(1_m)^2/(1_kg)^2 auto m1 = 45_kg auto r1 = untis::math::vector(3_m, 5_m, 8_m); auto r2 = untis::math::vector(6_m, 7_m, 9_m); auto force = -G * m1 * 5_mg / math::pow(units::abs(r2-r1)), 2); static_assert(std::is_same_t<newton_t, typeof(force)>, "force is not newtons");

Example: auto v1 = untis::math::vector(3,2,1); static_assert(std::is_same_t<untis::math::vector<no_unit_t>, typeof(v1)>, "v1 is not adimensional"); auto v2 = v1 * 25_meter_per_second; static_assert(std::is_same_t<untis::math::vector<meter_per_second_t>, typeof(v2)>, "v2 is not velocity");

Congratulations for your library.

Regards,

OverMalo avatar Oct 31 '17 10:10 OverMalo

A few people have asked over the years, and I feel like it's a little out of scope for the library, but that said I'll consider it for the next release because it does seem to be beyond the capacity of most users to implement. I'm thinking homogeneous 3-value vectors, which support +,-,dot, and cross-product, as well as scalar multiplication/division?

nholthaus avatar Oct 31 '17 15:10 nholthaus

+1 for a low-level linear algebra library for real-time simulation! I'd really like to fork GLM and fix it so that it worked with numeric types like those in units (and my own library, CNL. But that's a big task.

johnmcfarlane avatar Oct 31 '17 19:10 johnmcfarlane

Maybe it would be possible to for example adapt a linear algebra library like Eigen, which allows the use of custom scalar types, see also here? Not sure whether such a construct could work as units are rather a set of types rather than a single scalar type?

JaapAap avatar Mar 17 '18 14:03 JaapAap

I have actually tried to work with Eigen using unit types as scalars, and the main problem is that the unit type safety gets in the way of basic operations. For example, if I have a vector of meters, I can't get the norm of that vector because that requires a multiplication between elements that yields square meters, and then a square root that takes meters and yields square rooted meters (is that even a thing?).

Mind you, the type compounding system in the units library is pretty brilliant, it's just that most math code out there assumes that operations on scalars yield results of the same type as the argument(s).

A simple but somewhat ugly fix could be a macro that conditionally disables type compounding on arithmetic operations (e.g. 2 m * 3 m = 6 m instead of 2 m * 3 m = 6 m²) in order to make unit types compatible with other math code such as Eigen matrices. I think that would be simpler than implementing your own linear algebra library or going around fixing all the other math libraries so that they support units.

@nholthaus, I could work on that (I really want to have vectors of units in my code). Just tell me where in the code there is such unit squaring and rooting, and I'll get on that. I would also use this macro to disable dimensionless results of division (so that 6 m / 3 m = 2 m instead of 6 m / 2 m = 3) just to make sure.

chosson avatar Jul 13 '18 21:07 chosson

The problem is that libraries are being built with concrete types, rather than being constrained with concepts. If a concept such as Number were used instead for a math library, then this library's units might just work with it.

I think it's been mentioned before, about having a macro to disable strong typing. This breaks things like overloading.

JohelEGP avatar Jul 14 '18 00:07 JohelEGP

Right. The solution is not to return results with the wrong dimensions. But while concepts may help, they are not necessary. What is needed is simply a well designed generic vector type that returns results of the correct type. I haven't checked, but I'd expect this to work with unit types:

template<typename Ta, typename Tb>
constexpr auto operator*(vec<Ta, 3> const& a, vec<Tb, 3> const& b) {
    return vec{a.x*b.x, a.y*b.y, a.z*b.z};
}

This approach should work as well for any arithmetic operation. Here's the full example using CNL types. (And there's no reason not to write a slightly more verbose version that is C++11 compatible.)

I still think GLM would be a good starting-point for a game-friendly generic vector library. But GLM is GLSL-idiomatic: GLSL arithmetic always returns the output of the same types as the inputs. I estimate that forking GLM and making it C++-idiomatic would involve a solid week of highly tedious edits to make it work like the above code. But the result would be an incredibly versatile, low-level, high-performance vector math library.

Irrespective of how you achieve this goal, the result would not be units-specific so I'd encourage you to make it an independent project. I'd be more than happy to ensure it was compatible with CNL.

johnmcfarlane avatar Jul 14 '18 04:07 johnmcfarlane

I store velocity and position in Eigen vectors. Is it expected that the up coming 3 release will allow the scalar type used by eigen as a template parameter to have unit support? It would be great to have unit support for vectors (and matrices) for third party libraries with the pedigree of eigen. Thanks Andy

a-jp avatar Nov 07 '20 07:11 a-jp

Not yet.

JohelEGP avatar Nov 07 '20 16:11 JohelEGP