MADEAPPS / newton-dynamics

Newton Dynamics is an integrated solution for real time simulation of physics environments.
http://www.newtondynamics.com
Other
942 stars 182 forks source link

Simplify User Facing API #300

Closed olitheolix closed 1 year ago

olitheolix commented 1 year ago

Hi,

I wonder if we could add a few convenience methods/functions to make the Newton API more intuitive for end users.

For instance, the simplest way I could find to compute the distance between a body and a given target position is

  ndVector target(1.f, 2.f, 3.f, 0.f);                      # Need to specify a 4D vector to encode a 3D position.
  ndVector delta = body->GetMatrix().m_posit - target;      # Arcane knowledge.
  ndFloat  dist  = delta.DotProduct(delta).GetScalar();     # DotProduct returns a vector?!

I think most users know why Newton needs to represent data this way but from an end user perspective we only care about 3D location vectors and scalar distance metrics. I therefore wonder if we could add convenience methods to simplify the above to:

  ndFloat dist = ndLength(body->GetPosition() - ndVector(1, 2, 3)); 

The additions here are ndBody::GetPosition and ndLength to return a body's position and the L2 norm of a vector, respectively. Also, note that ndVector here accepts 3 scalars to make it look and feel like a 3D position vector (w is implicitly set to zero).

Similarly, the simplest way to set the position of a body that I could find goes like this:

  ndBody*  body;
  ndVector pos(1., 2., 3., 4.);

  ndMatrix matrix(ndGetIdentityMatrix());
  matrix.m_posit = pos;
  body->SetMatrix(matrix);

Here, too I wonder if we could have something more straightforward like this:

  ndBody*  body;
  ndVector pos(1, 2, 3);        // No need to specify W.

  body->SetPostion(pos);        // Accepts ndVector and ignores W component.
  body->SetPosition(1, 2, 3);   // Optional: also accept 3 scalars without creating an explicit vector.

Unless Newton already has comparable functionality that I have missed, I think this would streamline the Newton API.

I think it would be possible to implement this without changing any of the existing functionality. What do you think? Is this doable and if so, should we? I am happy to start on a PR to provide these features and the associated tests, if you want.

JulioJerez commented 1 year ago

a few thing. as you might noticed by now, most of the support classes in the engine are kind of minimal functionality. a typical example is the ndVector or ndMatrix. It is possible to make the case that of providing ton of more functionality or even more classes, stuff like ndVec3 or nsMatrix3x3 and so on.

The problem I see with that, is that is just add more complexity but not new information. This complexity can easy the learning curve when first start, but is just takes a few examples for the user to realize that more functions that do the same thing do not really make for better library.

I do not really follow that design pattern strictly myself, as you can find places where there are more than one function that do the same for example, the ndMatrix class has function TransformVector and also has RotateVector where rotation a vector can be accomplished by Tranforming a vector where the w component was set to zero. but in these cases, the Rotate version does save 25% of the operation, which in a tight loop makes a difference that a compiler cannot remove.

The secund point, is that the user of the engine is expected to have some minimal knowledge of basics linear algebra and basic Newtonian mechanic. The setting the w component to zero trick, is a very basics operation in numerical analysis. stuff like applying a force at a point, is the same as applying a force couple, which is a basics principle in mechanic or rigid bodies classes. https://en.wikipedia.org/wiki/Couple_(mechanics) so, there is not needed to have an interface for all the permutations.

finally, In general, when people use a third-party library, they write their own wrappers over the basic functionality, these classes are usually wrapper of inline functions that allows for few things. -minimize change when new updates, interface changes, or bug fixes -for trying different libraries, that offer the same functionality. -provide that clint application whit the client interfaces.

olitheolix commented 1 year ago

I think we have different expectations for libraries. All good. Thank you anyway.