rotate bmesh around bounding box center, not global

how do I rotate the mesh around its center using the bmesh.rotate

import bpy
import bmesh
import mathutils

tech_list = ["TechA"]
for tech in tech_list:
# these lines create the bmesh with the techA as text
bpy.data.curves.new(type="FONT", name='label').body = tech
label = bpy.data.objects.new("label", bpy.data.curves['label'])
meshed_up = bmesh.new()
meshed_up.from_mesh(label.to_mesh())

# this transform_matrix places the mesh in the correct position
# But still mirrored :(
transform_matrix = mathutils.Matrix.Rotation(1.5708, 4, 'Z').to_4x4()
transform_matrix = mathutils.Matrix.Rotation(3.1415, 4, 'X').to_4x4() @ transform_matrix
# transform_matrix = mathutils.Matrix.Rotation(selet center of mesh, not X-axis)
meshed_up.transform(transform_matrix)

# and then we create a mesh for object and link and clean
label_mesh = bpy.data.meshes.new("label")
meshed_up.to_mesh(label_mesh)
meshed_up.free()
bpy.data.curves.remove(bpy.data.curves['label'])
label_object = bpy.data.objects.new(tech, label_mesh)
bpy.context.collection.objects.link(label_object)

# EOF


As you can see, so far all is well but the label is still mirrored, it should now be rotated in place 3.14 radians around its own x-axis, but I don't know how

1 Answer

I would do this using the bmesh rotation operator, rather than computing the transformation matrices, as it seems like easier code to read. Basically you need the bounding box center, which can be calculated thusly:

from mathutils import Vector
# code up to creating label as an object
center = sum((Vector(b) for b in label.bound_box), Vector())
center /= 8


and instead of the transformations use bmesh.ops.rotate:

from mathutils import Matrix
from math import radians
# code up to where you calculate transforms.
# replace everything up to the call to transform with this:
rotation_Z = Matrix.Rotation(radians(90), 4, 'Z')
bmesh.ops.rotate(meshed_up, cent=center, matrix=rotation_Z, verts=meshed_up.verts)

rotation_X = Matrix.Rotation(radians(180), 4, 'X')
bmesh.ops.rotate(meshed_up, cent=center, matrix=rotation_X, verts=meshed_up.verts)


or, putting it all together:

import bpy
import bmesh
from mathutils import Matrix, Vector
from math import radians

tech_list = ["TechA"]
for tech in tech_list:
# these lines create the bmesh with the techA as text
bpy.data.curves.new(type="FONT", name='label').body = tech
label = bpy.data.objects.new("label", bpy.data.curves['label'])
center = sum((Vector(b) for b in label.bound_box), Vector())
center /= 8
meshed_up = bmesh.new()
meshed_up.from_mesh(label.to_mesh())

rotation_Z = Matrix.Rotation(radians(90), 4, 'Z')
bmesh.ops.rotate(meshed_up, cent=center, matrix=rotation_Z, verts=meshed_up.verts)
rotation_X = Matrix.Rotation(radians(180), 4, 'X')
bmesh.ops.rotate(meshed_up, cent=center, matrix=rotation_X, verts=meshed_up.verts)

# and then we create a mesh for object and link and clean
label_mesh = bpy.data.meshes.new("label")
meshed_up.to_mesh(label_mesh)
meshed_up.free()
bpy.data.curves.remove(bpy.data.curves['label'])
label_object = bpy.data.objects.new(tech, label_mesh)
bpy.context.collection.objects.link(label_object)


By the way, I left the rotation on X in, but it's what's causing your mirroring. If you remove the two lines with rotation_X in them, you won't have the mirror.

Had you wanted to continue to use the transform matrix, you would need to calculate a new center of rotation. This just seems clearer to read and easier to follow.

Look at this answer to see how to convert the code to use any arbitrary axis for rotation.