Sign in to follow this  
markww

drawing an arrow

Recommended Posts

Hi, I have two points in 3d space: point1 (x,y,z) point2 (x,y,z) I want to draw an arrow from point1, to point2. At point2, I'd like to draw a small pyramid head cap to indicate direction. I CANNOT find a formula for generating some based points for a head given the two end points of the arrow. Does anyone have such a formula? I need something like: headBasePt0 = (x,y,z); headBasePt1 = (x,y,z); headBasePt2 = (x,y,z); headBasePt3 = (x,y,z); I don't need any help with drawing it, just finding some points to use. Then I can connect the dots and have a nice wireframe arrow. Thanks

Share this post


Link to post
Share on other sites
I think it is a matter of a)determining the direction the line will face in relation to point1, b)having a preexisting arrow head model, c)rotating that arrow head model to point the same direction as the line, d)translating the arrow head model to point2

I don't work with 3D drawing and I'm not sure exactly what API calls it would take to perform the above steps, though, sorry. Hope it helps.

Share this post


Link to post
Share on other sites
for an arrow from A -> B

get the vector pointing from B -> A
normalize it
scale it by the lenght of your arrow head

rotate it 30degrees (or whatever looks good) clockwise
add it to B's position (thats' one point) call it point C

rotate it 30degrees (or whatever looks good) counter-clockwise
add it to B's position (thats' the other point) call it point D

then you:
draw a line from A -> B
draw a line from B -> C
draw a line from B -> D

now you have an arrow that looks like this:

C
A -- > B
D

-me

Share this post


Link to post
Share on other sites
Hi,

I made a drawing of what I mean:

http://i87.photobucket.com/albums/k153/bnf_intro/arrow_example.jpg

@Palidine:

Won't that draw an arrow only in 2D space?

Thanks

Share this post


Link to post
Share on other sites
Also I have this snippet:

point0 can be any point not along the line through point1 and point2
perpendicular0 = (Point1-Point2) × (Point0-Point2)
perpendicular1 = perpendicular0*(radius of cone)/|perpendicular0|
perpendicular2 = perpendicular0 × (Point1-Point2) / |Point1-Point2|
pontx = point2+(point1-point2)*(length of cone)/|Point1-Point2| + sin(x)*perpendicular1+cos(x)*perpendicular2


but I'm not sure what to do what a component of perpendicular0 is zero - then I'll get a divide by zero.

Share this post


Link to post
Share on other sites
Quote:
Original post by markww
Also I have this snippet:

point0 can be any point not along the line through point1 and point2
perpendicular0 = (Point1-Point2) × (Point0-Point2)
perpendicular1 = perpendicular0*(radius of cone)/|perpendicular0|
perpendicular2 = perpendicular0 × (Point1-Point2) / |Point1-Point2|
pontx = point2+(point1-point2)*(length of cone)/|Point1-Point2| + sin(x)*perpendicular1+cos(x)*perpendicular2


but I'm not sure what to do what a component of perpendicular0 is zero - then I'll get a divide by zero.


'a component of perpendicular0 is zero' is equivalent to 'point0 is on the line through point1 and point2'. That's why you pick a point not on that line. :)

Share this post


Link to post
Share on other sites
Quote:
Original post by markww
ok dumb question, but is there some guaranteed way of picking a point not coliear to point 1 and 2?
What you're really looking for here is a vector that is not collinear with the arrow direction vector (choosing a point not on the line is just a roundabout way of generating this vector).

One sure way to pick such a vector is to select the cardinal basis vector corresponding to the element of the direction vector with the least magnitude. Using this method you can generate a basis that is guaranteed to be valid, but the results may not be ideal, depending on the circumstances.

Another option is to use a fixed vector (say, the world up vector) in all cases other than when the direction vector is parallel or nearly parallel to this vector. This can give more consistent results in some cases.

Perhaps you could tell us a little more about the context. Will the arrow be in motion? Are there any constraints on its orientation?

Share this post


Link to post
Share on other sites
Hi jyk,

I'd like to be able to use this with any two arbitrary points - just a general arrow class.

What do you mean by:

"but the results may not be ideal, depending on the circumstances."

does that mean that the base points of the arrow head generated will be 'right' but come out looking.. funky?

Thanks

Share this post


Link to post
Share on other sites
Quote:
Original post by markww
Hi jyk,

I'd like to be able to use this with any two arbitrary points - just a general arrow class.

What do you mean by:

"but the results may not be ideal, depending on the circumstances."

does that mean that the base points of the arrow head generated will be 'right' but come out looking.. funky?
It will always look 'right'. The problem with the element-of-least-magnitude approach is that if the arrow is in motion, the arrowhead may 'snap' between two orientations suddenly (this happens when the cardinal basis vector selected to generate the initial cross product changes).

If you use a fixed vector instead, the orientation of the arrowhead should change smoothly, more or less, as the arrow moves. The only problem as that you then have to handle the case where the arrow direction vector is parallel or nearly parallel to this fixed vector separately.

Another option would be to create an initial (complete) orientation for your arrow, and then update it incrementally as you go. Again though, what method will work best depends on what exactly the arrow will be doing (remaining stationary, translating but not rotating, flying through the air, etc.).

Share this post


Link to post
Share on other sites
Quote:
Original post by markww
In my case it will be stationary - which method should I use then?
If it's going to be stationary, I'd use the element-of-least-magnitude method. That way there will be no special cases and the basis will always be valid.

Share this post


Link to post
Share on other sites


One sure way to pick such a vector is to select the cardinal basis vector corresponding to the element of the direction vector with the least magnitude. Using this method you can generate a basis that is guaranteed to be valid, but the results may not be ideal, depending on the circumstances.

Hi jyk,

How do I do that? I have the two points:

point1 (10, 5, 8)
point2 (20, 3, 8)

so the vector between them is:

(10, -2, 0) ?

but what does "select the cardinal basis vector corresponding to the element of the direction vector with the least magnitude" mean? Here the least element is element [1] (the y component). What do I do with it?

Thanks

Share this post


Link to post
Share on other sites
Quote:
Original post by markww
How do I do that? I have the two points:

point1 (10, 5, 8)
point2 (20, 3, 8)

so the vector between them is:

(10, -2, 0) ?

but what does "select the cardinal basis vector corresponding to the element of the direction vector with the least magnitude" mean? Here the least element is element [1] (the y component). What do I do with it?

Thanks
Actually the element with the least magnitude would be [2] (z) in this case.

Once you've identified this element, you cross the vector with the cardinal basis vector that has the same index. The cardinal basis vectors are (1,0,0), (0,1,0), and (0,0,1). So if the index of the element of least magnitude is [0], you would cross the vector with (1,0,0). If the index is [1], you'd cross with (0,1,0). And so on.

Here's an example of how you might construct the basis:


// A couple of support functions:

template < typename T >
size_t index_of_min(T a, T b, T c) {
return a < b ? (c < a ? 2 : 0) : (b < c ? 1 : 2);
}

template < typename T >
size_t index_of_min_abs(T a, T b, T c) {
return index_of_min(std::fabs(a),std::fabs(b),std::fabs(c));
}

// Construct a basis given two points, p1 and p2 (this code
// hasn't been compiled or tested):
vector3 z = p2 - p1;
z.normalize();
size_t i = index_of_min_abs(z[0],z[1],z[2]);
vector3 v(0,0,0);
v[i] = 1.f;
vector3 y = cross(z,v);
y.normalize();
vector3 x = cross(y,z);

Share this post


Link to post
Share on other sites
Sorry jyk, one last question if you have time.

I get up to:

vector3 y = cross(z,v);
y.normalize();


But what is vector 'x'? Is that the final vector I use for my point0 in that original formula I posted?

Thanks

Share this post


Link to post
Share on other sites
Quote:
Original post by markww
But what is vector 'x'? Is that the final vector I use for my point0 in that original formula I posted?
No, at this point we've completely bypassed all that 'point 0' business. The x, y, and z vectors we've computed are the actual solution to the problem, i.e. an orthonormal basis that you can use to build the arrowhead vertices.

Here's some more (uncompiled and untested) example code:


// We've computed the x, y, and z vectors. Assume p2 is
// the endpoint of the arrow direction vector, that 'length'
// is the length of the arrowhead, and that 'extent' is
// how far you want the arrowhead to 'flare out' at the base.

// We can then compute the four base vertices as follows:

vector3 p = p2 - z * length;

vector3 v[4];
v[0] = p - x * extent;
v[1] = p - y * extent;
v[2] = p + x * extent;
v[3] = p + y * extent;

// And you're done.


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this