

Hey, I figured it out! :)
If you have a vector direction, or spatial point position, or a traced(...)
normal, this code will find the angles that it makes with the <0,0,0> origin.
In other words, it finds the actual rotation angles for a given <x,y,z> vector,
to use for whatever purpose like rotating an object to align to that vector.
Or for placing into a #debug statement.
There are already tools in POVRay that align objects FOR you like
Point_At_Trans and Reorient_Trans but they don't give you the actual rotation
angles that are used. That's why I wrote this.
I went back to basic trigonometry to figure it out... then had to do some
readingup on the asin function (arcsin.) There are only a few 'special
rules' in the code, to take care of certain asin behavior.
And... no matrix math ;)
For grins, I've included the visual trig diagrams the triangles. They helped
me to work out the code.
You might notice that the code produces rotations for only TWO axes, around x
and y; but that's enough for determining the proper orientation of an object.
The third rotation axis is 'synthesized' by the other two, in a manner of
speaking... and it has its own weird but understandable logic: Imagine that you
(as an 'object') are standing vertically, with your arms in front of you,
holding onto a vertical pole. As you tilt backwards, you will always still face
the pole, no matter how far you spin around it in y. Same logic here. (Of
course, you could prespin the object in y to face some other direction,
*before* applying the found rotations.) I might work up some code to counteract
this so that an object always faces a set direction when it's rotated; but
that's icing on the cake for now.
In the code, there are two meaningful objects a BLACK rod, which is simply the
physical embodiment of the vector; and a WHITE rod as a 'real' object, made
later and rotated with the code's results. But you'll see only a *single* rod,
with speckles that's both rods occupying the same space, to prove that the
code works. I used POVray's coincidentsurface phenomenon as proof! ;) If you
mess with the code in some bad way, you'll probably see BOTH rods.
If you see a way to make the code simpler or more elegant, speak up. I
eventually want to turn it into a macro(?)
[You may have guessed that I plan to use this in my ongoing 'position finder'
work, to solve a problem *there*.]

// October 34 2018
#version 3.7; // or 3.71 or 3.8
global_settings {assumed_gamma 1.0}
#default{finish{ambient .1 diffuse .9}}
#declare VECTOR = <.9,.8,.6>; // or whatever values
//
camera {
perspective
location <.5, 1.5, 2.5>
look_at <0, .3, 0>
right x*image_width/image_height
angle 35
}
light_source {
0*x
color rgb .8
translate <200, 400, 200>
}
light_source {
0*x
color rgb .5
translate <200, 100, 200>
}
background{rgb .1}
// origin indicators
union{
cylinder{<.15,0,0>,<.15,0,0> .010} // X
cylinder{<0,.15,0>,<0,.15,0> .010} // Y
cylinder{<0,0,.15>,<0,0,.15> .010 } // Z
no_shadow
pigment{rgb <1,.6,0>}
}
plane{y,0
no_shadow
pigment{
cells color_map{[0 rgb .1][1 rgb .6]} translate 3
}
}
// THE CODE 
// Important 'fudge factors' due to POVRay's inner workings, to prevent
// fatal "uncategorized error" (because of vnormalize below?)
#if(VECTOR.x = 0)
#declare VECTOR = <0.0001,VECTOR.y,VECTOR.z>;
#else
#end
#if(VECTOR.y = 0)
#declare VECTOR = <VECTOR.x,0.0001,VECTOR.z>;
#else
#end
#if(VECTOR.z = 0)
#declare VECTOR = <VECTOR.x,VECTOR.y,0.0001>;
#else
#end
#declare VECTOR = vnormalize(VECTOR);
// The visual standin for the VECTOR
cylinder{0, VECTOR .015 no_shadow}
// The trig construction lines...
// RED
union{
cylinder{VECTOR,<VECTOR.x,0,VECTOR.z> .007}
cylinder{0,<VECTOR.x,0,VECTOR.z> .007}
pigment{rgbt <1,0,0,.5>}
no_shadow
}
// GREEN
union{
cylinder{0,<VECTOR.x,0,0> .007}
cylinder{<VECTOR.x,0,0>, <VECTOR.x,0,VECTOR.z> .007}
pigment{rgbt <0,.2,0,.5>}
no_shadow
}
#declare X_Y_PLANE_ANGLE = 90  degrees(asin(VECTOR.y/1));
// to get the degree of rotation, referenced to an imaginary
// 'rotated' X/Y plane think of it as the final 'elevation'.
// It's the arcsin of y/R in that plane
// R (the hypoteneuse length) is 1.0 the VECTOR length
#declare NEW_HYPOT = sqrt(pow(VECTOR.x,2) + pow(VECTOR.z,2));
// The PROJECTION of the 'VECTOR' length onto the horizontal X/Z plane
// its length *there* compared to its real length of 1.0. This is for use
// in the X_Z_PLANE_ANGLE equation below, as the 'R' for its trig function.
// sqrt(x^2 + y^2 = R^2) to find the length of this 'new'
// hypoteneuse with the Z value substituted for Y.
// NOTE: At this point, the NEW_HYPOT value is always positive which may or
// may not be a good thing(?). But it causes no problem.
// This #if is the KEY to getting things right...
#if(VECTOR.x < 0)
#declare X_Z_PLANE_ANGLE = degrees(asin(VECTOR.z/NEW_HYPOT));
// to get the degree of rotation, AS SEEN ON the horizontal X/Z plane
// it will actually be the rotation around the yaxis, to be applied AFTER
// the previous xaxis 'elevation'. Arcsin of y/R, as seen looking DOWN
// on X/Z plane. NEW_HYPOT is NOT 1.0 in this plane.
#else
#declare X_Z_PLANE_ANGLE = degrees(asin(VECTOR.z/NEW_HYPOT)); // ditto
#end
// The special rules...
#if(VECTOR.x < 0)
#declare X_Z_PLANE_ANGLE = X_Z_PLANE_ANGLE  90;
#else
#end
#if(VECTOR.x >= 0)
#declare X_Z_PLANE_ANGLE = X_Z_PLANE_ANGLE + 90;
#else
#end
#declare FINAL_ROT =
<X_Y_PLANE_ANGLE,X_Z_PLANE_ANGLE,0>; // the final rotations!
//  END OF CODE 
// NEW rod, using the found rotation values
union{
cylinder{0,1.0*y .015}
text{ttf "cyrvetic.ttf" "POVRay" 1, 0
pigment{
gradient z
color_map{
[.5 rgb .6*x]
[.5 rgb .2*z]
}
scale 1.1
translate .05*z
}
scale .5*<.2,.2,.04>
translate <.2,1,.02>
}
// rotate ... *y // optional, to add any desired prespin to the object
#if(VECTOR.y < 0) rotate 180*y #else #end // optional, and only if
// VECTOR.y goes negative to keep the visual orientation of the
// object consistent with positive VECTOR.y appearance.
rotate FINAL_ROT
pigment{rgb 2}
no_shadow
}
Post a reply to this message

