PDA

View Full Version : drawing an arrow: A line + a cone (problems with the cone, rotation!)



newsb
01-02-2013, 06:25 AM
What seems to be the problem with this rotation here (python-code) ?

I'm drawing an arrow from (x1,y1,z2) to (x2,y2,z2). Please see this and I hope you can explain what is going on...


def coordSysArrow(x1, y1, z1, x2, y2, z2):
glPushMatrix()
glPushAttrib( GL_POLYGON_BIT ) # includes GL_CULL_FACE
glDisable(GL_CULL_FACE) # draw from all sides

# Size of cone in arrow:
coneFractionAxially = 0.2
coneFractionRadially = 0.1

# Calculate cone parameters:
v = numpy.array((x2-x1, y2-y1, z2-z1))
norm_of_v = numpy.sqrt( numpy.dot(v,v) )
coneHgt = coneFractionAxially * norm_of_v
coneRadius = coneFractionRadially * norm_of_v
vConeLocation = (1.0-coneFractionAxially) * v

# Construct transformation matrix
mat44 = numpy.eye(4)
normalized_v = v/norm_of_v

mat44[0,0] = normalized_v[0]
mat44[1,1] = normalized_v[1]
mat44[2,2] = normalized_v[2]

# -----------------------
# Draw line + cone
# -----------------------
# Draw single line:
glBegin(GL_LINES)
glVertex3f(x1, y1, z1) # from
glVertex3f(x2, y2, z2) # to
glEnd() # GL_LINES

# Move and rotate in position:
glTranslate( *vConeLocation )
if 0: # turn on/off here
#glLoadIdentity()
glMultMatrixf( mat44 ) # <===== PROBLEM HERE?!?! WHAT?

# Make a cone!
cone_obj = gluNewQuadric();
# gluCylinder(gluNewQuadr, Radius_base, Radius_top,
# height, slices, stacks)
gluCylinder(cone_obj, 0, coneRadius,\
coneHgt, 8, 1);

glPopAttrib() # GL_CULL_FACE
glPopMatrix()
As you can see I've made an option to disable using the mat44-matrix. When I disable it, the cone gets drawn but the rotation is wrong. When I enable it, the cone is NOT drawn... Am I multiplying with a wrong rotation matrix and does that explain why nothing gets drawn?

There are no errors/warnings or anything... I don't understand this...

newsb
01-02-2013, 11:41 PM
There are no errors/warnings or anything... I don't understand this...

Ok, to help myself and some of you, I've tried to make a complete program in C which you can compile and run:


// gcc arrowTest.c -lglut -lGLU && ./a.out//-------------------------
#include <GL/glut.h>
#include <math.h>
#include <stdio.h>

void coordSysArrow(float x1, float y1_, float z1, float x2, float y2, float z2)
{
glPushMatrix();
glPushAttrib( GL_POLYGON_BIT ); // includes GL_CULL_FACE
glDisable(GL_CULL_FACE); // draw from all sides

float v[3];
// Calculate arrow parameters:
v[0] = x2-x1;
v[1] = y2-y1_;
v[2] = z2-z1;

// Draw single line:
glBegin(GL_LINES);
glVertex3f(x1, y1_, z1); // from
glVertex3f(x2, y2, z2); // to
glEnd(); // GL_LINES

// Easy enough - now let's make the cone in the arrow!
if (1 == 1) // Make a cone! Change test to "0 == 1" to disable this part...
{
float norm_of_v = sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] );

// Size of cone in arrow:
float coneFractionAxially = 0.2;
float coneFractionRadially = 0.1;

float coneHgt = coneFractionAxially * norm_of_v;
float coneRadius = coneFractionRadially * norm_of_v;

float normalized_v[3];
normalized_v[0] = v[0] / norm_of_v;
normalized_v[1] = v[1] / norm_of_v;
normalized_v[2] = v[2] / norm_of_v;

// Construct transformation matrix
float mat44[16] =
{1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1};

mat44[0] = normalized_v[0]; // [0,0]
mat44[5] = normalized_v[1]; // [1,1]
mat44[10] = normalized_v[2]; // [2,2]
mat44[15] = 1.0;

if (0==1)
{
int i;
for (i=0; i<16; i++)
{
printf ("[%i]: %f\n", i, mat44[i]);
}
exit(EXIT_FAILURE);
}

float vConeLocation[3];
vConeLocation[0] = (1.0-coneFractionAxially) * v[0];
vConeLocation[1] = (1.0-coneFractionAxially) * v[1];
vConeLocation[2] = (1.0-coneFractionAxially) * v[2];

// Move and rotate in position:
glTranslatef( vConeLocation[0], vConeLocation[1], vConeLocation[2] );
if (0 == 1) // <===== PROBLEM HERE?!?! WHAT?
{
//glLoadIdentity()
glMultMatrixf( mat44 );
}
GLUquadric* cone_obj = gluNewQuadric();
gluCylinder(cone_obj, 0, coneHgt, coneRadius, 8, 1);
}
glPopAttrib(); // GL_CULL_FACE
glPopMatrix();
}

float x1 = 0.0; float y1_ = 0.0; float z1 = 0.0;
float x2 = 1.0; float y2 = 1.0; float z2 = 0.0;

void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -5);

glColor4ub(255,128,128,255); // red, green, blue, alpha

int drawArrow = 1; // turn on/off here
if (drawArrow == 1)
coordSysArrow(x1, y1_, z1, x2, y2, z2);
else {
glBegin(GL_LINES);
glVertex3f(x1, y1_, z1); // from
glVertex3f(x2, y2, z2); // to
glEnd(); // GL_LINES
}
glFlush();
glutSwapBuffers();
}

void reshape(int w, int h)
{
glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective( 60, (double)w / (double)h, 0.01, 100 );
}

int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);

glutInitWindowSize(800,600);
glutCreateWindow("Arrowing");

glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return EXIT_SUCCESS;
}


I don't understand why the cone doesn't get displayed correctly... I would REALLY appreciate some feedback, thank you... And now you should be able to copy/paste the code and run it (test on linux with gcc - I think windows would work out of the box too). You can then disable/enable the cone stuff (which I don't understand why is not working)...

I hope to hear from someone soon. Thanks.

Carmine
01-03-2013, 09:53 AM
I've run your code and had slightly better results than you.
The cone does show up when I do glMultMatrixf (mat44).
But it is not oriented or positioned properly.
Make sure you're not calling glLoadIdentity before MultMatrix.
That will definitely mess things up.

I noticed that you have the ability to print out the contents of mat44.
It's a good idea. When you do that do you get what you expected?
Do you know what the contents of a rotation transformation matrix should look like?
This can be Googled. Trig functions are involved.
Do you know what axis you should be rotating the cone around to put it in the proper orientation?

Did you know that you can use the glRotate command to accomplish what you
are trying to do without ever messing around with matrices?

newsb
01-03-2013, 01:03 PM
I've run your code and had slightly better results than you.
The cone does show up when I do glMultMatrixf (mat44).
But it is not oriented or positioned properly.Oh, sorry... After many hours and after having read and thought about what you wrote, I realized that my way of getting the mat44-matrix is completely nonsense... I had it mixed up with something else in my head... Sorry...

Make sure you're not calling glLoadIdentity before MultMatrix.
That will definitely mess things up.Ok, thank you - you're right - I understand...
I noticed that you have the ability to print out the contents of mat44.
It's a good idea. When you do that do you get what you expected?
Do you know what the contents of a rotation transformation matrix should look like?
This can be Googled. Trig functions are involved.
Do you know what axis you should be rotating the cone around to put it in the proper orientation?
I think I can do it without using trig functions, but by using cross products... I've done something similar another time before, let me look into my old code and get back within 1-2 days...

Did you know that you can use the glRotate command to accomplish what you
are trying to do without ever messing around with matrices?
As I wrote - I found out that I cannot construct mat44 like I do it now. I typically/usually get an invalid rotation matrix by using the method I've shown here. That explains why python didn't show anything. However, it doesn't explain why the C-code shows something... hmmmmmm. Strange C-code.... I don't understand why it shows anything at all because that transformation/rotation matrix I've made is simply nonsense with invalid directions - for instance, here is something from my python program:

(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0)
(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0)
(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)

NONSENSE - invalid directions! :D

I'm very happy that you took the time to write a few things - just these small things made me think a lot and spend hours remembering how I one solved a similar problem... I'll go to bed now and go to work tomorrow, but within 1-2 days I'll get back and write how I think this can be solved in an elegant way...

Thank you very much - I appreciate your help - I think I'm on the right track again now, after having been stuck for some days with this now ! :D

I'll get back with a solution - for the record - now people are helping me, so I want to give something back too, that others can/might use...

Carmine
01-03-2013, 02:27 PM
Yes. You could do this with some vector cross products, normalization, etc.

gvtheogioC
01-04-2013, 08:39 AM
Chuc mung nam moi
Chuc vui ve va hanh phuc
Tiep tuc xay dung dien dan cua chung toi nhe
Best regards.

newsb
01-05-2013, 09:44 AM
Chuc mung nam moi
Chuc vui ve va hanh phuc
Tiep tuc xay dung dien dan cua chung toi nhe
Best regards.Please write in english...

newsb
01-05-2013, 09:50 AM
Yes. You could do this with some vector cross products, normalization, etc.

Thanks a lot for your help, Carmine. Just for the record, here's my python solution so other people can use if they like. If anyone modifies my original C-program to work with this, please post the code. It should be a VERY small task for anyone to rewrite this python-code into the equivalent C-code.



def constructRotMatrixFromDirection(dVec):
norm_startVec = dVec / norm(dVec)
zaxis = [0, 0, 1]
norm_endVec = zaxis / norm(zaxis)
if numpy.isnan(norm_endVec).any():
norm_endVec = numpy.zeros( numpy.shape(norm_endVec) )
ipdb.set_trace()

# Check if trying to match identital vectors:
if not ( any(norm_startVec - norm_endVec) > 1e-14 ):
return numpy.eye(4)

axb = cross(norm_startVec, norm_endVec) # cross-product of a and b
norm_axb = axb / norm(axb)
if numpy.isnan(norm_axb).any():
norm_axb = numpy.zeros( numpy.shape(norm_axb) )
ipdb.set_trace()

ac = math.acos(numpy.dot(norm_startVec, norm_endVec))
# build the rotation matrix
s = math.sin( ac )
c = math.cos( ac )
t = 1 - c

x = norm_axb[0]
y = norm_axb[1]
z = norm_axb[2]

mat33 = [ \
[t*x*x + c, t*x*y - s*z, t*x*z + s*y], \
[t*x*y + s*z, t*y*y + c, t*y*z - s*x], \
[t*x*z - s*y, t*y*z + s*x, t*z*z + c], \
]
return expand33to44(mat33)

Anyway, thanks all - use the transformation matrix as described above, and it'll work. I'll continue with my other problems now - problem is solved now :-)

If you have any questions to the above, feel free to ask...