Couple of small bugs (LVecBase3f and NodePathCollection)

Just wanted to report 2 tiny bugs.

  1. According to the API it should be possible to raise LVecBase3f objects to a float power, but when I try:
v = LVecBase3f(1., 2., 3.)
v **= 1.5

I get:

TypeError: Arguments must match:
__ipow__(const LVecBase3f self, float exponent)


v = LVecBase3f(1., 2., 3.)
w = pow(v, 1.5)


TypeError: Arguments must match:
__pow__(LVecBase3f self, float exponent)

Maybe I’m doing it wrong or I just don’t know what a float is.

  1. It would seem that NodePathCollection doesn’t support pickling using cPickle, as it yields the following error:
cPickle.PicklingError: Fourth element of tuple returned by <built-in method __reduce_ex__ of panda3d.core.NodePathCollection object at 0x0000000004777418> must be an iterator, not panda3d.core.NodePathCollection

(using the pure-Python pickle module works fine)
A simple workaround I’m currently using is to replace the NodePathCollection with a list upon pickling.


print map(lambda x:x**1.5, LVecBase3f(1., 2., 3.))

since python :slight_smile:

Thank you for trying to help, but this simply raises the components of the vector to the given power, which is not what I would expect LVecBase3f.pow to do. What I expect, is that it would raise the length of the vector to that power.
This would be helpful, since now I have to:

  1. get the length from the vector;
  2. raise that length to the given power;
  3. normalize the vector;
  4. multiply the normalized vector by that new length.

Yeah in the API it’s not listed as an operator but as a special Python method, here.
See the Python docs here.

Thanks a lot! I’ve fixed these bugs now.

I would suggest using the bug tracker in the future for more efficient handling of bugs.

Thank you very much :slight_smile: !

Will do, sorry about that.

Concerning the vector issue, it seems that serega-kkz was right then: it’s the components that get raised to the given power, not the length of the vector? That’s a bit disappointing, since a vector seems to be treated like an ordinary container object (like a list of numbers) in this case. It’s easy (although less efficient of course) to just use a one-liner instead then:

v = (1., 2., 3.)
w = LVecBase3f(*map(lambda x: x**1.5, v))

As I explained in the post above, raising the length of a vector to a power seems less trivial.
But if there are objections to changing the way it works currently (e.g. for reasons of backwards compatibility), then it’s OK. It just seemed like a nice opportunity to make it a bit more "power"ful :wink: .

Hmm, you mean that vec ** 3 should have the same effect as vec.normalized() * (vec.length() ** 3)? Is there any precedence for implementing it like this?

Alright, after some searching it seems that it is indeed generally done component-wise. Since I usually imagine a vector to be a magnitude coupled with a direction, it seemed more intuitive to me to apply it to the length instead, but I can see why it is the way it is.
What I also noticed, is that the components are often raised to the power of components of another vector; perhaps LVecBase3f.pow could additionally accept another LVecBase3f as well? This would certainly remove any doubt about it being applied component-wise.

But your code pleasantly surprised me: there really is a normalize[b]d/b method! It’s not in the API docs, so all this time I thought there was only the in-place normalize() method.
There wouldn’t happen to be an undocumented set_length() or similar method as well, would there :smiley: ?
At any rate, vec.normalized() * (vec.length() ** 3) already looks quite good, thanks!

Sure, it would theoretically be possible to overload pow to also accept vectors.

normalized() is new in the as-yet-unreleased 1.9.3.