Plotting a line / vector in the form ai+bj+ck code seems almost right

 0     down vote          [favorite](http://stackoverflow.com/questions/14624474/plotting-a-vector-via-a-script-in-blender-python#)     <b>1</b>
                     I want to plot a vector in the form xi+yj+zk at a position (a,b,c). This is a repost from a very quite blender forum.

This code is pretty near but it misses the origin by a little bit, (maybe about 0.1?). Can anyone see where I am going wrong.

The code assumes that I am correct that the three rotation parameters work like this.
In rotation(p,q,r)

p is an angle in the zy plane measured from z toward y,
q is an angle in the zx plane measured from z toward x.

r seems to have no effect at all.

import bpy;
#plot the vector 4i-2j-3k from the origin as a thin cylinder
import math;
from math import *;
x=4
y=-2
z=-3
length=sqrt(z*z+y*y+x*x)
cog=length/2;
bpy.ops.mesh.primitive_cylinder_add(vertices=16, radius=0.01, depth=length, 

end_fill_type='NGON', view_align=False, enter_editmode=False, location=(x/2,y/2,z/2), 

rotation=(atan(y/x),atan(x/z),0));


So far as I can tell, the way to create a line in Blender is to use a long thin cube or cylinder. The API for Blender/Python gives a cube / cylinder as this syntax

bpy.ops.mesh.primitive_cube_add(view_align=False, enter_editmode=False, location=(0,0,0),
 rotation=(0, 0, 0)) 

 bpy.ops.mesh.primitive_cylinder_add(vertices=64, radius=0.01, depth=4, 

end_fill_type='NGON', view_align=False, enter_editmode=False, location=(0, 0 , 4/2), rotation=(0, 0, 0)) 

I know the position is at the cog and can handle the transform to do that but can’t work out how to transform my components into a rotation. I cannot see from the api what the definition of the rotation parameter is.

I have tried splitting long code lines with returns for clarity
A pointer to a resource would be fine if it has some code in it.

I’m not sure about debugging your Euler angles but I have an alternative approach. I’m not sure if this is the most efficient way to do this but it will work. Note, this will only let you generate cylinders that go from (0,0,0) out to the target point.

What makes this a little tricky is managing the fact that the cylinder origin moves around and you have to compute the Euler angles based that move.


import bpy;


#plot the vector 4i-2j-3k from the origin as a thin cylinder
import math;
from math import *;
from mathutils import Vector, Matrix


# This is the point that you want to draw your line to.
targetPt = Vector( (4, -2, -3) )


# When adding the cylinder it is moved then rotated.  So we have
# to change our target location to be relative to where the cylinder
# will be placed.  The cylindr will be placed at 1/2 between
# (0,0,0) and the targetPt.  So the target relative to the 
# new location is 1/2 the distance it used to be.
localTargetPt = targetPt * .5


# This is where the tip of the cylindar starts out when it is placed.
basePt = Vector( (0, 0, localTargetPt.length) )


# We want to rotate the 'basePt' (0, 0, length) to point to the 
# localTargetPt


# So, get the angle between the base point and the localTarget
angle = basePt.angle(localTargetPt)


# And compute the axis that will rotate us to that direction
rotationAxis = basePt.cross(localTargetPt)


# Turn this into an Euler using an axis-angle rotation
euler = Matrix.Rotation(angle, 4, rotationAxis).to_euler()


# And generate the cylindar
bpy.ops.mesh.primitive_cylinder_add(vertices=16, radius=0.01, depth=targetPt.length, end_fill_type='NGON', view_align=False, 
enter_editmode=False, location=(localTargetPt.x, localTargetPt.y , localTargetPt.z), rotation=euler)

Thank you, this is very helpful.

Though now it occurs to me that it might be even easier or quicker to computer a change-of-basis matrix for the object directly. So if this does not work for some reason I have another idea that is more direct and does not rely on the rotation or finding the angle between the vectors.

Do you mean make the rotation parameters work in a body centred coordinate as opposed to World Centred? If so, how do you do that.

I am just about to try doing a combination of cylinder_add at (0,0,0) and then translate to do the thing I want via Direction Cosines.

In the 3D math that is done to translate and rotate objects in Blender, rotations always happen around the origin (0,0,0). If you want to rotate the object around its center, then you have to move the object so that its center is at (0,0,0), then rotate it, then put it back.

What is your end goal here? Are you trying to draw a mesh from an arbitrary point to another point?

instead of adding a cylinder add a mesh line or a curve instead
so it will always be at exact location for head and tail of your vetor !

happy blendering

My end goal is to be able to plot lines (long cyclinders is good becuase I can use colour easily) in vector form where I can alos give the position vector of where I want the vector plotted.

e.g. Plot l1=ai+bj+ck + t(mi+nj+pk) and another line l2 in the same form and then explore the lines from different directions using a 3D viewer.

it can be done using curve and curve bevel !
and ends will always be at precise location!

happy blendering

If you could expand on this answer or point me to an example of someone constructing a vector using a “mesh line” that would be very helpful.

if you have verts making a line you can convert to curve
then add a bevel curve circle and adjust scale size and you also get a cylinder on which you can add some color!

and the 2 ends will always be precicely where they should be no movement cause of rotation!

i don’t have an example of this right now but i’ll check if i can find one

edit :

found this convert to curve

bpy.ops.object.convert(target=‘CURVE’, keep_original=False)

bpy.ops.curve.subdivide(number_cuts=4)
for operation in range(4):
bpy.ops.curve.smooth()

happy blendering

here is an extract from code snippet on wiki pages

add a curve with curve bevel



----------------------------------------------------------
# File curve_types.py
#----------------------------------------------------------
import bpy
from math import sin, pi
# Poly and nurbs
def makePolySpline(cu):
    spline = cu.splines.new('POLY')
    cu.dimensions = '3D'
    addPoints(spline, 8)
def makeNurbsSpline(cu):
    spline = cu.splines.new('NURBS')
    cu.dimensions = '3D'
    addPoints(spline, 4)
    spline.order_u = 3
    return spline
def addPoints(spline, nPoints):
    spline.points.add(nPoints-1)
    delta = 1/(nPoints-1)
    for n in range(nPoints):
        spline.points[n].co = (0, n*delta, sin(n*pi*delta), 1)
# Bezier
def makeBezierSpline(cu):
    spline = cu.splines.new('BEZIER')
    cu.dimensions = '3D'
    order = 3
    addBezierPoints(spline, order+1)
    spline.order_u = order
def addBezierPoints(spline, nPoints):
    spline.bezier_points.add(nPoints-1)
    bzs = spline.bezier_points
    delta = 1/(nPoints-1)
    for n in range(nPoints):
        bzs[n].co = (0, n*delta, sin(n*pi*delta))
        print(bzs[n].co)
    for n in range(1, nPoints):
        bzs[n].handle_left = bzs[n-1].co
    for n in range(nPoints-1):
        bzs[n].handle_right = bzs[n+1].co
    return spline
# Create curve and object and link to scene
def makeCurve(name, origin, dx):
    cu = bpy.data.curves.new('%sCurve' % name, 'CURVE')
    ob = bpy.data.objects.new('%sObject' % name, cu)
    (x,y,z) = origin
    ob.location = (x+dx,y,z)
    ob.show_name = True
    bpy.context.scene.objects.link(ob)
    return cu
def run(origin):
    polyCurve = makeCurve("Poly", origin, 0)
    makePolySpline(polyCurve)    
    nurbsCurve = makeCurve("NurbsEnd", origin, 1)
    spline = makeNurbsSpline(nurbsCurve)
    spline.use_endpoint_u = True
    nurbsCurve = makeCurve("NurbsNoend", origin, 2)
    spline = makeNurbsSpline(nurbsCurve)
    spline.use_endpoint_u = False
    bezierCurve = makeCurve("Bezier", origin, 3)
    makeBezierSpline(bezierCurve)
    return
if __name__ == "__main__":
    run((0,0,0))



hope it helps

Thanks I will pursue in nxt 24 hours and report back.