Notifications
Clear all

[Closed] 3D Transform API. Existential doubt

I’m creating a C# API for 3D transformations (Vector3D, Matrix3D, Quaternion, …) with double precision to use with 3dsMax (mostly for scriptControllers).
I have an existencial doubt…

What do you think is better to do with functions (methods) like ‘normalize’: would you update the instance to its new normalized value or would you create a new instance?


   // Case 1: change 'this'
        public void Normalize1()
        {
            double length = Math.Sqrt(_x * _x + _y * _y + _z * _z);
            this /= length;
        }

   // Case 2: return new instance
        public Vector3D Normalize2()
        {
            double length = Math.Sqrt(_x * _x + _y * _y + _z * _z);
            return new Vector3D(_x / length, _y / length, _z / length);
        }

The same doubt may be applied to adding another Vector3D to This, multiplying This by a Matrix3D or negating This for example.
Any advice will be welcome.

10 Replies

This will be for example the behaviour in both cases when creating a random Vector3D:


   // Case 1:
        public static Vector3D Random1()
        {
            Random random = new Random((int)DateTime.Now.Ticks);
            double valueX = random.NextDouble(-1, 1);
            double valueY = random.NextDouble(-1, 1);
            double valueZ = random.NextDouble(-1, 1);
            Vector3D v = new Vector3D(valueX, valueY, valueZ);
            v.Normalize1();
            return v;
        }
   // Case 2:
        public static Vector3D Random2()
        {
            Random random = new Random((int)DateTime.Now.Ticks);
            double valueX = random.NextDouble(-1, 1);
            double valueY = random.NextDouble(-1, 1);
            double valueZ = random.NextDouble(-1, 1);
            return (new Vector3D(valueX, valueY, valueZ)).Normalize2();
        }

 j83

You could have static method of your vector class that returns a copy and an instance method that just returns void.

Yes, thanks, I always do that. But it really doesn’t solve my “existencial doubt” for what’s better (if there’s really a better solution for these cases).
And, in fact, you can’t use the static solution in my “random” examples, as they are static methods too and you can’t call to ‘this’.

 j83

It all comes down to style really.

You can call other static methods just fine, you just normally preface it by the namespace name.

Returning this from a normalize function is nice primarily when chaining several things, though at times, you may want a normalized version and non-normalized version of a vector for when checking magnitude.

My thoughts are:

  • Returning this (thus, corrupting it), seems to me a little dramatic. But it’s fast and straightforward. Perhaps clearer.
  • Returning a new instance just obliges to create a new one. But, for structs as in this case, it’s just: Vector3D p2 = p.normalize() (as it’s a value, not a reference).
    In fact, you can ‘chain’ it in operations: p3 = p.normalize() * transformMatrix. You can’t do that if p.normalize() returns void.

It’s a hard to answer question as it depends on what you will use it for, but in general cases, if you are normalizing a vector, you would most probably not need the old value, so I think it would be better to just update it and not create a new one, moreover if it will be for controllers, were there can be literally millions of operations.

You could also have a second parameter in the method like “copy=true/false”, but I don’t know how it would affect the performance.

I would try in a real case, an expensive one, how they both performs.

If you need to keep the old value, you can always make a copy of it.

if we are talking about good practice you have to implement both methods. as well as for Rotate, Transform, etc. vector
To create an instance always takes a time and memory usage. But both are very small.
Also you always have to provide a constructor MyObject acopy = new MyObject(target);

Thanks, Jorge.
Yes, that would be the best: “it depends on what you will use it for”. But, as you know well, users will do with your code the least you could imagine.
For example, 3dsMax both maxscript and SDK, return a new instance for the ‘normalize’ function. And we are used to that behavior.

Denis, when you say “you have to implement both methods”, as both have the same signature (no parameters), you mean to have two methods with different names, for example ‘normalize()’ and ‘selfNormalize()’ ? And, additionaly, the static one ‘normalize(Vector3D v)’? Perhaps this will get few intuitive for users… Never mind, don’t think anyone but me will use it!

About constructors, don’t worry, I have at least six of them (from 3 values X/Y/Z, from 3dsMax IPoint, from double[3], from another Vector3D, from Point4D…). Most of them are too as explicit conversion operators (for casting) and as ‘set()’ method (for example: ‘public void Set(IPoint3 p)’). Would you keep all this or is it redundant?

 lo1

As a user both options in the OP seem fine to me, I’ve seen APIs use both.
The only thing that would be a big no-no is normalizing in place AND returning ‘this’.

I’ve seen some APIs use .Normalize() to normalize in place and .Normalized() to return a normalized copy.

Page 1 / 2