2
$\begingroup$

I am generating a mesh from a collection of points read from a json file. That collection of points will define the vertices, and from them I will derive the faces of the final mesh

Code is working fine until I try to scale down just one of the faces. I have used the accepted answer of this question as a reference: Using python and bmesh to scale/resize a face in place

The problem is I don't know what is the criteria used in that answer to select the face to be scaled down, since the line face = bm.select_history.active looks very generic. Instead what I tried is to access the first face in the sequence of faces in the mesh with face = bm.faces[0], but then I get the following error:

Traceback (most recent call last):
  File "\Text", line 88, in <module>
IndexError: BMElemSeq[index]: outdated internal index table, run ensure_lookup_table() first
Error: Python script failed, check the message in the system console


This is the script I wrote:

import bpy
import json
import bmesh
import os
    
# make collection
new_collection = bpy.data.collections.new('new_collection')

# Link object with collection
bpy.context.scene.collection.children.link(new_collection)

# Reading from a file a collection of points
with open(r'path\\vertices.json','r') as f: 
      j=json.load(f) 

vertices = j["vertices"]
faces = ... # here generating the faces from the vertices
edges = []
    
# Creating Mesh
new_mesh = bpy.data.meshes.new(str(country_name)+'_mesh')
new_mesh.from_pydata(vertices, edges, faces)

# Recalculating Normals for each face
bm = bmesh.new()
bm.from_mesh(new_mesh)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
bm.to_mesh(new_mesh)
bm.free()

# Applying changes to the Mesh
new_mesh.update()
      
# Making object from mesh
new_object = bpy.data.objects.new(str(country_name)+'_object', new_mesh)

# add object to scene collection
new_collection.objects.link(new_object)

# Scaling one face
bm = bmesh.new()
bm.from_mesh(new_mesh)

scale_factor = 0.5
face = bm.faces[0]
if isinstance(face, bmesh.types.BMFace):
    c = face.calc_center_median()
    for v in face.verts:
        v.co = c + scale_factor * (v.co - c)

bm.to_mesh(new_mesh)
bm.free()

# Applying changes to the Mesh
new_mesh.update()

I also tried to select and resize the first face in the mesh like this:

bpy.ops.mesh.select_nth(nth=0)
bpy.ops.transform.resize(value=(0.5, 0.5, 1))

But this approach triggers:

Traceback (most recent call last):
  File "\Text", line 91, in <module>
  File "C:\Program Files\Blender Foundation\Blender 2.93\2.93\scripts\modules\bpy\ops.py", line 132, in __call__
    ret = _op_call(self.idname_py(), None, kw)
RuntimeError: Operator bpy.ops.mesh.select_nth.poll() failed, context is incorrect

How can I select a single face as active to then scale it down?

$\endgroup$

1 Answer 1

1
$\begingroup$

replace

# Scaling one face
bm = bmesh.new()
bm.from_mesh(new_mesh)

with

bm = bmesh.from_edit_mesh(new_mesh)
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
bm.faces.ensure_lookup_table()

to rid yourself of the first error. You only need the 3rd ensure_lookup_table for your specific problem. I've just put the other two in for completeness. That should allow your scale operations to work.

If your mesh isn't in edit mode, you'll need

bpy.ops.object.editmode_toggle()

before that fragment, although that assumes that you're working on the current active object.

$\endgroup$
2
  • $\begingroup$ Thanks Marty, I will try this approach and let you know $\endgroup$ Oct 19, 2021 at 6:00
  • $\begingroup$ Thanks! works perfectly $\endgroup$ Oct 19, 2021 at 16:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .