8
$\begingroup$

I want to position a cylinder such that the center of one end is at (x0, y0, z0) and the center of the other end is at (x1, y1, z1) using the Python API.

The intention is that there will be two spheres centered at those coordinates and the cylinder will act as a spoke or connector between them.

I guess I will create the cylinder then translate, scale, rotate it. I am struggling mainly with the rotate part.

$\endgroup$
  • $\begingroup$ Could you provide a sketch with cylinder and spheres? $\endgroup$ – CodeManX Dec 31 '13 at 0:40
2
$\begingroup$

You could use a curve to join them together.

import bpy

# add sphere1
bpy.ops.surface.primitive_nurbs_surface_sphere_add(radius=.5, location=(-1, -1, 0))

# add sphere2
bpy.ops.surface.primitive_nurbs_surface_sphere_add(radius=.5, location=(1, 1, 0))

# add a curve to link them together
bpy.ops.curve.primitive_bezier_curve_add()
obj = bpy.context.object
obj.data.dimensions = '3D'
obj.data.fill_mode = 'FULL'
obj.data.bevel_depth = 0.1
obj.data.bevel_resolution = 4
# set first point to centre of sphere1
obj.data.splines[0].bezier_points[0].co = (-1,-1,0)
obj.data.splines[0].bezier_points[0].handle_left_type = 'VECTOR'
# set second point to centre of sphere2
obj.data.splines[0].bezier_points[1].co = (1,1,0)
obj.data.splines[0].bezier_points[1].handle_left_type = 'VECTOR'
| improve this answer | |
$\endgroup$
15
$\begingroup$

i wrote my own script, as there is no way to do it with blender API direcly:

def cylinder_between(x1, y1, z1, x2, y2, z2, r):

  dx = x2 - x1
  dy = y2 - y1
  dz = z2 - z1    
  dist = math.sqrt(dx**2 + dy**2 + dz**2)

  bpy.ops.mesh.primitive_cylinder_add(
      radius = r, 
      depth = dist,
      location = (dx/2 + x1, dy/2 + y1, dz/2 + z1)   
  ) 

  phi = math.atan2(dy, dx) 
  theta = math.acos(dz/dist) 

  bpy.context.object.rotation_euler[1] = theta 
  bpy.context.object.rotation_euler[2] = phi 

enjoy :-)

| improve this answer | |
$\endgroup$
3
$\begingroup$

UI

A really fast way to do this is to make an Mesh object which is based on an edge-net (just edges), then in Object mode press Alt+C to convert to Curve, then use a bevel object or increase the bevel_depth + bevel_resolution

python

here's how to generate one Curve object, to hold all segments. It works on the idea that you have a Mesh object called 'EdgesObject', which just contains a collection of edges. Then you run the script and it will generate a new Curve object called 'TubesCurve'

enter image description here

import bpy

curves = bpy.data.curves
objects = bpy.data.objects
scene = bpy.context.scene

obj_name = "EdgesObject"
obj = objects[obj_name]

def make_tubes(obj, bevel_depth=0.1, resolution=3):

    mesh = obj.data
    curve_name = 'TubesCurve'

    # if exists, pick up else generate a new one
    cu = curves.get(curve_name, curves.new(name=curve_name, type='CURVE'))
    cu.dimensions = '3D'
    cu.fill_mode = 'FULL'
    cu.bevel_depth = bevel_depth
    cu.bevel_resolution = resolution
    cu_obj = objects.get(curve_name, objects.new(curve_name, cu))

    # break down existing splines entirely.
    if cu.splines:
        cu.splines.clear()

    # and rebuild
    verts = mesh.vertices
    for e in mesh.edges:
        idx_v1, idx_v2 = e.vertices
        v0, v1 = verts[idx_v1].co, verts[idx_v2].co
        full_flat = [v0[0], v0[1], v0[2], 0.0, v1[0], v1[1], v1[2], 0.0]

        # each spline has a default first coordinate but we need two.
        segment = cu.splines.new('POLY')
        segment.points.add(1)
        segment.points.foreach_set('co', full_flat)

    if not curve_name in scene.objects:
        scene.objects.link(cu_obj)  


make_tubes(obj)

The script will reuse an existing instance of the 'TubesCurve' object if the script is run repeatedly.

cons

If you need the cylinders to be capped, then it is necessary to use a bevel object, else that option (may 2015) is not available).

| improve this answer | |
$\endgroup$
0
$\begingroup$

Considering Cylinder API document: bpy.ops.mesh.primitive_cylinder_add(vertices=32, radius=1.0, depth=2.0, end_fill_type='NGON', view_align=False, enter_editmode=False, location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), layers=(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)) apparently there is no way to construct what you want directly using cylinder parameters because there is only one point as the centre point (location) not endpoints.

solution 1) You will need to find rotations for rotation parameter of cylinder. If you have them you just simply set the location of cylinder as centre of your endpoints; set rotation values; the depth will be the distance between the endpoints.

solution 2) However, you may simply draw a line between the endpoints and apply blending. It will be a cylinder.

bpy.ops.curve.primitive_bezier_circle_add()    #for blending
obj = bpy.context.object
bpy.ops.curve.primitive_bezier_curve_add()     # a curve, your endpoints for example
bpy.context.object.data.bevel_object = bpy.data.objects[obj.name] #a cylinder
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.