# Using python and bmesh to scale/resize a face in place

I'm playing around with bmesh and have run into something I can't figure out how to do and can't find any related documentation on.

I have extruded a face directly outward (after subdividing a larger object to create it) and now want to scale it inward after the extrusion. When I try to use bmesh transform and scale operators (code below), it ends up moving the face location, apparently in relation to the global space. It seems like the answer is related to feeding the proper matrix into whatever function I'm calling, but I haven't quite wrapped my head around how it all works yet.

Here is what the result looks like just after the extruding operation:

And here is what I'm trying to achieve:

Basically, what I want is to use the equivalent of:

bpy.ops.transform.resize()


...inside of bmesh, to scale the face on the X and Z axis in place/relative to the face center.

I've tried performing the operation using the scale operator with different "space" arguments:

face = bm.faces[0]
bmesh.ops.scale(
bm,
vec=(.5, 1, .5),
space=matrix,
verts=face.verts
)


I've also tried using the transform operator with manually constructed matrices

face = bm.faces[0]
matrix = mathutils.Matrix([ ... ])
bmesh.ops.transform(
bm,
matrix=matrix,
verts=face.verts


I can't figure out how to get the boundaries of the scale transformation space to be confined to the face area.

Thanks for any insight or help!

Scale the distance from face centre to vert.

Propose in this case could simply use the face centre as stationary point, and reposition each vertex coordinate by a scale factor. For a face face with a centre c = face.calc_center_median() having a vertex v the vector v.co - c represents the straight line from vert to c. Can then move the vertex to a new location by a factor along this line v.co = c + scale_factor * (v.co - c)

Example script, run in edit mode with the face you want to scale active.

import bpy
import bmesh

context = bpy.context
ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
scale_factor = 0.5

face = bm.select_history.active
if isinstance(face, bmesh.types.BMFace):
c = face.calc_center_median()
for v in face.verts:
v.co = c + scale_factor * (v.co - c)

bmesh.update_edit_mesh(me)


Have assumed the face is co-planar

Using Matrices.

Another way to achieve this is using matrices, v.co = c + scale_factor * (v.co - c) Indicates the operation needs both a transformation and scale. For the transformation can change the space locally such that the point c becomes the origin. (Wont be shifted by any scale).

face = bm.select_history.active
if isinstance(face, bmesh.types.BMFace):
c = face.calc_center_median()
T = Matrix.Translation(-c)
S = Matrix.Scale(scale_factor, 4)
bmesh.ops.transform(bm, matrix=S, verts=face.verts, space=T)

• Thanks for this - I was just thinking about implementing a similar solution myself and your code will save me a few minutes and hopefully help others in the future. I was hoping for a matrix-based solution vs. operating on each vertex individually, because it's a lot cleaner - this is much easier to understand though! Do you know if it's possible to do it with transformation matrices? – ineedhelp Oct 24 '18 at 4:30
• Very cool, thanks for the matrix update - just seeing it now. I've been struggling to wrap my mind around exactly how to use matrices and your explanation and script helped a lot. I don't think I've ever encountered matrices before scripting Blender operations. I was not a very ambitious mathematician in school :P One further question, if you can spare another moment: Would you consider it safe to view the named "space" parameter as synonymous (in this context) with "transformation origin"? If so, is it the same for every function (in Blender) where the "space" argument exists? – ineedhelp Dec 18 '18 at 5:54