PDA

View Full Version : FYI: C code for drawing a line & 3D arrow head



wall-e
08-22-2013, 05:49 AM
Hi all,
This is my first post. I must say this forum is very un-friendly to new users. Users seem to have Private Messages disabled by default, and my Control Panel says "access denied" when I try to re-enable them for my account.
And of course no links or images allowed, which prevents spam, but makes it difficult to post an image showing the problem/solution!
Then when I wrote this post, I clicked "preview" and got an error message about "too many links", then all my text was deleted. Well done Admins.


For reference purposes, here is some C code for drawing a line and 3D arrow head.
The result: www.postimg.org/image/sz13ngmq7/

This is a continuation of this thread:
"drawing an arrow: A line + a cone (problems with the cone, rotation!)"
Link: www.opengl.org/discussion_boards/showthread.php/180682-drawing-an-arrow-A-line-a-cone-%28problems-with-the-cone-rotation!%29
which gives only correct Python code for drawing an arrow, but the thread is now closed.


Here is the complete C code:


// 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)
{

// Co-ordinates of the line are
// start: xyz_1
// end: xyz_2

glPushMatrix();
glPushAttrib( GL_POLYGON_BIT ); // includes GL_CULL_FACE
glDisable(GL_CULL_FACE); // draw from all sides

// Calculate vector along direction of line
float v[3];
v[0] = x2-x1;
v[1] = y2-y1;
v[2] = z2-z1;

// Line thickness
glLineWidth(2);

// Draw single line:
glBegin(GL_LINES);

//glVertex3f(x1, y1, z1); // Starting point for line (arrow head end)
glVertex3f( x1+0.05*v[0], y1+0.05*v[1], z1+0.05*v[2] ); // Make the line a bit shorter,
glVertex3f(x2, y2, z2); // so the arrowhead is not blunted by the line thickness
glEnd(); // GL_LINES

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.025; // radius at thickest part
float coneFractionRadially = 0.12; // length of arrow

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;

// Set location of arrowhead to be at the startpoint of the line
float vConeLocation[3];
//vConeLocation[0] = (1.0-coneFractionAxially) * v[0]; // <---- ORIGINAL CODE
//vConeLocation[1] = (1.0-coneFractionAxially) * v[1];
//vConeLocation[2] = (1.0-coneFractionAxially) * v[2];
vConeLocation[0] = x1;
vConeLocation[1] = y1;
vConeLocation[2] = z1;

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

// The direction of the arrowhead is the line vector
float dVec[3];
dVec[0] = v[0]; // 0.5;
dVec[1] = v[1]; // 0.5;
dVec[2] = v[2]; // 0.5;

// Normalize dVec to get Unit Vector norm_startVec
float norm_startVec[3];
Unit( dVec, norm_startVec );

// Normalize zaxis to get Unit Vector norm_endVec
float zaxis[3] = { 0.0, 0.0, 1.0 };
float norm_endVec[3];
Unit( zaxis, norm_endVec );

if ( isnan(norm_endVec[0]) || isnan(norm_endVec[1]) || isnan(norm_endVec[2]) )
{
norm_endVec[0] = 0.0;
norm_endVec[1] = 0.0;
norm_endVec[2] = 0.0;
}

// If vectors are identical, set transformation matrix to identity
if ( ((norm_startVec[0] - norm_endVec[0]) > 1e-14) && ((norm_startVec[1] - norm_endVec[1]) > 1e-14) && ((norm_startVec[2] - norm_endVec[2]) > 1e-14) )
{
mat44[0] = 1.0;
mat44[5] = 1.0;
mat44[10] = 1.0;
mat44[15] = 1.0;
}
// otherwise create the matrix
else
{

// Vector cross-product, result = axb
float axb[3];
Cross(norm_startVec, norm_endVec, axb);

// Normalize axb to get Unit Vector norm_axb
float norm_axb[3];
Unit( axb, norm_axb );

if ( isnan(norm_axb[0]) || isnan(norm_axb[1]) || isnan(norm_axb[2]) )
{
norm_axb[0] = 0.0;
norm_axb[1] = 0.0;
norm_axb[2] = 0.0;
}

// Build the rotation matrix
float ac = acos( Dot(norm_startVec, norm_endVec) );

float s = sin( ac );
float c = cos( ac );
float t = 1 - c;

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

// Fill top-left 3x3
mat44[0] = t*x*x + c;
mat44[1] = t*x*y - s*z;
mat44[2] = t*x*z + s*y;

mat44[4] = t*x*y + s*z;
mat44[5] = t*y*y + c;
mat44[6] = t*y*z - s*x;

mat44[8] = t*x*z - s*y;
mat44[9] = t*y*z + s*x;
mat44[10] = t*z*z + c;

mat44[15] = 1.0;
}

// Translate and rotate arrowhead to correct position
glTranslatef( vConeLocation[0], vConeLocation[1], vConeLocation[2] );
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;
}