Well you didnt specify that you need to preserve some kind of virtual history on your data. Thats pretty much the hardest part. Let me explain this but first some comments to build up some foundation. The problem can not be satisfactorily solved, it can be solved with some caveats, but not without problems.
then isn't it just a question of syntax?
No this is not about syntax because this is not the function you want to use. Matrices will not account for rotation around, ever, hence you must use theMFnTransform::rotateBy
The above mel code works 100% of the time
Is not really true it works 100% of the time, the property s temporarily unstable. It can work in favorable conditions, however its easy to show that there are condition's where even this fails to work out. Also sidestepping the question did it do what you expected it to do, but yes i guess it did since you say so.
Rotate -r -os is equivalent with matrixChild * matrixParent. Yes that does not go beyond 360 slice tough. The real thing is however that rotations beyond 0-360 do not really exist, so the fundamental problem is that you want something thats not really motivated in a physical sense. But yeah we can change the code to use more info than this tough.
BLEND orientations together
Yes i know, no matter you can still use a constraints to do this. Sure constraints do not add stuff at first sight. However they do have this offset feature which adds your data on top. Ergo the orient constraint node CAN ADD 2 rotations together.
object space euler rotations from a connected node in a hierarchy.
You dont need anything other than the values since you know how they are chained
Adding 2 Quaternions
Not quite!
Well see thing is all other methods except euler angles are constrained by one slice of the world, matrices, quaternions, axis angles all have the property that they can not give you results over one 0-360 slice. Thats why the math in these systems work out. One of the parts self lie in euler angles that you could somehow have over rotation history in the data*. You can use quaternions in maya too if you wish. In theory you could use extra data in these systems could be organized so encode revolutions, but it woukldnt encode it in teh same ways as Euler do, still its still having the observation problem see below.
What is the real problem then?
Observation of the object. Rotation beyond one slice is a history property, no values outside the one slice of 360 do exist you can define whatever slice you want but all data outside that slice is the same data so 180, 540, 900, 1260, 1620, 1980... Are ALL THE SAME ANGLE!
Lets motivate this with a thought experiment: Lets say you have a ball and i ask you what its rotation is, for simplicity lets assume its only ever going to rotate around one axis. Well you dont know, certainly you can not say how many times the ball has rolled since it was first made! Now suddenly you realize that the measurement is a thought construct, measurements do not really exist. They are just something that ties real world observations to math. But you can define a baseline here and now so you say its rotation is 0 so now you go happily observing the ball and suddenly it has a rotation, and it can go over 360 too since your vigilantly following the ball around. Now i come and interrupt you, and suddenly you have lost the track of that the rotation of the ball is! Well almost, you can still say what angle it is in one slice of 360 but you have NO IDEA how many revolutions it took since you last observed this.
What does this have to do with maya? Maya has this same observation interruption problem. Why on earth would maya have this problem? See maya dg evaluation assumes that the entire frames data is in this frame. Now if you rotate a ball on one axis and allow it to slip (so that you cant just calculate the rotation for distance), you will get the correct answer if you evaluate all frames in succession. But because the calculation depends on the value it was set form previous frame it stops working when you jump in the timeline. This si why its balantly easy in a game engine, but hard in maya (game engines dont need to jump back and forth in time, and evaluate thing concurrently). But you have more favorable conditions offcourse.
You could go all ape on maya and evaluate all proceeding frames of maya for each frame. But thats just stupid, bake the data when you need it. Incidentally the orient constraint does JUST THIS. Use it.
So can we add the values then please?
Sure. The easiest way is to just use the orient constraint this sidesteps your entire porblem and lets you say somebody else did all the mental acrobatics you need, Mel follows as this:
$joint = joint -p 0 0 0
;
joint -p 0 0 -4;
joint -e -zso -oj xyz -sao yup $joint;
rotate -r -os 0 195 0 $joint;
setAttr ($joint+".jointOrientY") 285;
$target = spaceLocator -p 0 0 0
;
// this works because the makers of maya KNOW theres a disparity so they fix it
orientConstraint -weight 1 $joint $target[0];
Now this is almost the same solution as what you use, it does however have a offset value form what you expected, as it transparently ignores the joint orient in as if it was a constant value. The solution is otherwise exactly the same (yes it even accounts for outside 360 slice rotations for joint manipulations, but NOT animation of joimt orient), it just has a permanent computational offset for your solution. I don't really see why this would matter one bit, since it will be consistently offset by same amount the whole animation. Just different initial values. Unless you animate the joint orient, but you should avoid that ist very easy to do.
If you must you can just repurpose the connection orders, did it once and ended up billing 2 times as much as the client would have needed to pay, since they sure as hell didn't need the right offset.** And yess it can add any 3 differnt values. Ahh found it, here you go (after all ive billed this work allready and dont plan to rebill it ever again) assuming names are in clean scene:
connectAttr -f joint1.jointOrient locator1_orientConstraint1.target[0].targetRotate;
disconnectAttr joint1.jointOrient locator1_orientConstraint1.target[0].targetJointOrient;
Please note you should key the joint for it to rotate over the default slice. Back to the question:
then isn't it just a question of syntax?
Well not quite, in order to use the built in rotational rotate -r -os functionality you need to use MFnTransform, to do this you need a Trasform node to refeer to inside your node that has to be the node itself, so theres a bit of wor as id have to implement the whole shebang for you. And I don't really have the time to re implement functionality you already have. This is for fun not work, an dthis is the place where i draw the line.
*you see Euler didn't claim you can describe a sequence rotations with this system, but any one rotation can be described as
** client was happy, go figure. Usually the same client complained that the cost was too high for everybody else than me tough. Well doh if you ask for extra things that you dont explicitly need it tend to jack up the price. Weird. (and i did sugget the cheper way mainly because i have other thing to do as well, and usually getting the things done the right way is better than paying extra for extra you dont need in terms of client return rate)
PS: actually the angles you call euler angles aren't proper eulers angles at all. In fact all the mayas angle systems are Tait–Bryan angles but thats just plain nitpicking
PPS: the best possible solutions the solution you dont have to do. Oh yes im afraid this does not seem all that billable, but yes many right solutions have that property. Which si why many software vendors suck so much. The monetary incentive of business logic is sometimes so stupid. Anyway i just read beoutifull code and seems like im not the only one of this sentiment. The more you know the less code ypu end up writing for same effect.