5
$\begingroup$

I was trying to write a script to generate an object from primitives but came across a problem I couldn't solve. The code generates a cylinder and finds the face as well as putting it into edit mode. However when I try and select it in edit mode the whole object is still selected.
How do I script the selection of just that face?
When I do it by hand the selection of the face which I can do generates nothing in the info window.

import bpy

bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=2)
ob = bpy.data.objects['Cylinder']
ob.name = 'NewCylinder'
mesh = ob.data

bpy.ops.object.mode_set(mode = 'EDIT')
n = 0
for face in mesh.polygons:
    face.select = False
    if len(face.vertices) > 4:
        print(' end face {}'.format(n))
        n += 1
        if n == 2:
            face.select = True
bpy.ops.transform.resize(value=(0.33, 0.33, 0.33))
$\endgroup$
5
$\begingroup$

It might seem counter-intuitive, but you need to be in Object mode to change the selection when using .mesh. I changed a few more things, like you can use the 'DESELECT' action in mesh.select_all else edges are still selected when you try to un-select faces

import bpy

bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=2, enter_editmode=True)
ob = bpy.context.object  # gets a reference to the newly created object 
ob.name = 'NewCylinder'
mesh = ob.data

bpy.ops.mesh.select_all(action='DESELECT')

bpy.ops.object.mode_set(mode = 'OBJECT')
n = 0
for face in mesh.polygons:
    if len(face.vertices) > 4:
        n += 1
        if n == 2:
            face.select = True

bpy.ops.object.mode_set(mode = 'EDIT')
bpy.ops.transform.resize(value=(0.33, 0.33, 0.33))

enter image description here

$\endgroup$
  • $\begingroup$ Noteworthy: bpy.context.object should be used after calling a mesh primitive operator to refer to the newly created object (like zeffii did). You might pick the wrong object otherwise if the name already existed. $\endgroup$ – CodeManX Aug 9 '15 at 19:03
  • $\begingroup$ @CoDEmanX i'll add that as a comment into the code too $\endgroup$ – zeffii Aug 9 '15 at 19:28
  • $\begingroup$ (Sorry for the comment but @zeffi I am delighted with the solution and stackexchange. I racked my head about this for 1 day) $\endgroup$ – hum3 Aug 9 '15 at 23:13
  • $\begingroup$ @hum3, as you can see by the other answer there's a variety of approaches to this. My preference is the bmesh method shown by CoDEmanX, but I wanted to provide an answer that shared more with your original question - to keep the point of reference. $\endgroup$ – zeffii Aug 10 '15 at 5:06
  • $\begingroup$ @zeffi I know that I ought to learn the bmesh route but I am just starting and this matched using the info window like a macro recorder. $\endgroup$ – hum3 Aug 11 '15 at 7:04
4
$\begingroup$

You could also do this with Bmesh module, which does not require mode switches:

import bpy
import bmesh
from mathutils import Matrix

scene = bpy.context.scene

bm = bmesh.new()
bmesh.ops.create_cone(bm, cap_ends=True, segments=32, diameter1=1, diameter2=1, depth=2)

caps = [f for f in bm.faces if len(f.verts) > 4]
bottom_cap = min(caps, key=lambda f: f.verts[0].co.z)

mat = Matrix.Identity(4)
mat[0][0] = 1/3
mat[1][1] = 1/3
mat[2][2] = 1
bmesh.ops.transform(bm, matrix=mat, verts=bottom_cap.verts)

me = bpy.data.meshes.new("Cylinder")
bm.to_mesh(me)
me.update()

ob = bpy.data.objects.new("NewCylinder", me)
ob.location = scene.cursor_location
scene.objects.link(ob)
scene.update()

BTW: The same result (with bottom face scaled down by 1/3) can also be achieved with a single call to create_cone():

# diameter1 controls the size of the bottom cap
bmesh.ops.create_cone(bm, cap_ends=True, segments=32, diameter1=1/3, diameter2=1, depth=2)
$\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.