Area of bottom polygons using obj.to_mesh post modifier but without applying it
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
First of all, I'm quite new to python so please bear with me if I'm asking dumb questions. I've seen similar questions answered but still can't get where I want.
Say we have an active object in the scene, which is a polyline, which is extruded in z direction and altered with solidify modifier to give it some thickness (like a wall for example). I'm trying to get the summary area of all the bottom faces of the object as visible in the scene without actually applying the modifier. From what I've read it should be possible via obj.to_mesh, but while I can get the area of all faces with sum(f.calc_area()
, I'm missing something (possibly obvious) when it comes to getting just the sum of bottom ones.
Here is my attempt:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
bpy.ops.object.mode_set(mode = 'EDIT')
if z ==0:
face.select==True
bpy.ops.object.mode_set(mode = 'OBJECT')
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
What I get is value "0" printed out 16 times (for each face in the object I guess as it has 16 faces).
I realise it's probably something trivial I'm missing but maybe someone could please explain it to me?
scripting measurement
New contributor
add a comment |Â
up vote
1
down vote
favorite
First of all, I'm quite new to python so please bear with me if I'm asking dumb questions. I've seen similar questions answered but still can't get where I want.
Say we have an active object in the scene, which is a polyline, which is extruded in z direction and altered with solidify modifier to give it some thickness (like a wall for example). I'm trying to get the summary area of all the bottom faces of the object as visible in the scene without actually applying the modifier. From what I've read it should be possible via obj.to_mesh, but while I can get the area of all faces with sum(f.calc_area()
, I'm missing something (possibly obvious) when it comes to getting just the sum of bottom ones.
Here is my attempt:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
bpy.ops.object.mode_set(mode = 'EDIT')
if z ==0:
face.select==True
bpy.ops.object.mode_set(mode = 'OBJECT')
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
What I get is value "0" printed out 16 times (for each face in the object I guess as it has 16 faces).
I realise it's probably something trivial I'm missing but maybe someone could please explain it to me?
scripting measurement
New contributor
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
First of all, I'm quite new to python so please bear with me if I'm asking dumb questions. I've seen similar questions answered but still can't get where I want.
Say we have an active object in the scene, which is a polyline, which is extruded in z direction and altered with solidify modifier to give it some thickness (like a wall for example). I'm trying to get the summary area of all the bottom faces of the object as visible in the scene without actually applying the modifier. From what I've read it should be possible via obj.to_mesh, but while I can get the area of all faces with sum(f.calc_area()
, I'm missing something (possibly obvious) when it comes to getting just the sum of bottom ones.
Here is my attempt:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
bpy.ops.object.mode_set(mode = 'EDIT')
if z ==0:
face.select==True
bpy.ops.object.mode_set(mode = 'OBJECT')
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
What I get is value "0" printed out 16 times (for each face in the object I guess as it has 16 faces).
I realise it's probably something trivial I'm missing but maybe someone could please explain it to me?
scripting measurement
New contributor
First of all, I'm quite new to python so please bear with me if I'm asking dumb questions. I've seen similar questions answered but still can't get where I want.
Say we have an active object in the scene, which is a polyline, which is extruded in z direction and altered with solidify modifier to give it some thickness (like a wall for example). I'm trying to get the summary area of all the bottom faces of the object as visible in the scene without actually applying the modifier. From what I've read it should be possible via obj.to_mesh, but while I can get the area of all faces with sum(f.calc_area()
, I'm missing something (possibly obvious) when it comes to getting just the sum of bottom ones.
Here is my attempt:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
bpy.ops.object.mode_set(mode = 'EDIT')
if z ==0:
face.select==True
bpy.ops.object.mode_set(mode = 'OBJECT')
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
What I get is value "0" printed out 16 times (for each face in the object I guess as it has 16 faces).
I realise it's probably something trivial I'm missing but maybe someone could please explain it to me?
scripting measurement
scripting measurement
New contributor
New contributor
New contributor
asked 3 hours ago
MatH
83
83
New contributor
New contributor
add a comment |Â
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
1
down vote
accepted
I guess, you are getting zero because the face.select
is not assigned value True, but is being checked for condition True (face.select == True
). Also if you are interested only in bottom faces, i.e faces with all vertices having z coordinate value zero, then checking for median z coordinate may not work in all cases. There could be faces with median z at zero but vertices lying on either side of x-y plane.
I can think of the following alternative (I am open to critique and corrections as I am also comparatively new to blender :)
import bpy
import bmesh
bm = bmesh.new()
#bm = bmesh.from_edit_mesh(bpy.context.active_object.data) (without modifier)
bm.from_object(bpy.context.active_object, bpy.context.scene)
#Floats are not always absolute zero, so comparing with a tolerance
total_area = sum(f.calc_area() for f in bm.faces if len([v for v in f.verts if v.co[2] < 0.0001 and v.co[2] > -0.0001]) == len(f.verts))
print('total area:', total_area)
bm.free()
Upvoted. Suggestion:if all(abs(v.co.z) < 0.0001 for v in f.verts)
â batFINGER
1 hour ago
add a comment |Â
up vote
1
down vote
Use the face normal as test for bottom face.
Note: Between starting this answer, getting sidetracked, and posting another similar answer has been posted using bmesh from object.
CHecking that a local coordinate z is at some level is limiting.
If the mesh is as mentioned simply a wall can get the bottom faces by testing if the face normal points down (or close enough (within 4 degrees).
import bpy
import bmesh
from mathutils import Vector
from math import radians
context = bpy.context
scene = context.scene
ob = context.object
bm = bmesh.new()
bm.from_object(ob, scene)
down = Vector((0, 0, -1))
area = sum(f.calc_area() for f in bm.faces
if f.normal.angle(down) < radians(4))
print(area)
bm.free()
add a comment |Â
up vote
0
down vote
I assume this behaviour is caused by an inconsistent selection state when you only select the face but not the respective vertices and edges. As a result, something like print([f.select for f in bm.faces])
returns a list of False
values.
Using the function BMFace.select_set
instead of setting BMFace.select
will âÂÂupdate the selection state of assosiated geometryâÂÂ. BMFace.select
then will also return True
for these faces.
# snip
if z == 0:
face.select_set(True)
# snip
Apart from that, I guess you should unindent the area calculation so it's outside of the for face in bm.faces
loop. And switching between object and edit mode is not necessary here:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
if z == 0:
face.select_set(True)
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
I guess, you are getting zero because the face.select
is not assigned value True, but is being checked for condition True (face.select == True
). Also if you are interested only in bottom faces, i.e faces with all vertices having z coordinate value zero, then checking for median z coordinate may not work in all cases. There could be faces with median z at zero but vertices lying on either side of x-y plane.
I can think of the following alternative (I am open to critique and corrections as I am also comparatively new to blender :)
import bpy
import bmesh
bm = bmesh.new()
#bm = bmesh.from_edit_mesh(bpy.context.active_object.data) (without modifier)
bm.from_object(bpy.context.active_object, bpy.context.scene)
#Floats are not always absolute zero, so comparing with a tolerance
total_area = sum(f.calc_area() for f in bm.faces if len([v for v in f.verts if v.co[2] < 0.0001 and v.co[2] > -0.0001]) == len(f.verts))
print('total area:', total_area)
bm.free()
Upvoted. Suggestion:if all(abs(v.co.z) < 0.0001 for v in f.verts)
â batFINGER
1 hour ago
add a comment |Â
up vote
1
down vote
accepted
I guess, you are getting zero because the face.select
is not assigned value True, but is being checked for condition True (face.select == True
). Also if you are interested only in bottom faces, i.e faces with all vertices having z coordinate value zero, then checking for median z coordinate may not work in all cases. There could be faces with median z at zero but vertices lying on either side of x-y plane.
I can think of the following alternative (I am open to critique and corrections as I am also comparatively new to blender :)
import bpy
import bmesh
bm = bmesh.new()
#bm = bmesh.from_edit_mesh(bpy.context.active_object.data) (without modifier)
bm.from_object(bpy.context.active_object, bpy.context.scene)
#Floats are not always absolute zero, so comparing with a tolerance
total_area = sum(f.calc_area() for f in bm.faces if len([v for v in f.verts if v.co[2] < 0.0001 and v.co[2] > -0.0001]) == len(f.verts))
print('total area:', total_area)
bm.free()
Upvoted. Suggestion:if all(abs(v.co.z) < 0.0001 for v in f.verts)
â batFINGER
1 hour ago
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
I guess, you are getting zero because the face.select
is not assigned value True, but is being checked for condition True (face.select == True
). Also if you are interested only in bottom faces, i.e faces with all vertices having z coordinate value zero, then checking for median z coordinate may not work in all cases. There could be faces with median z at zero but vertices lying on either side of x-y plane.
I can think of the following alternative (I am open to critique and corrections as I am also comparatively new to blender :)
import bpy
import bmesh
bm = bmesh.new()
#bm = bmesh.from_edit_mesh(bpy.context.active_object.data) (without modifier)
bm.from_object(bpy.context.active_object, bpy.context.scene)
#Floats are not always absolute zero, so comparing with a tolerance
total_area = sum(f.calc_area() for f in bm.faces if len([v for v in f.verts if v.co[2] < 0.0001 and v.co[2] > -0.0001]) == len(f.verts))
print('total area:', total_area)
bm.free()
I guess, you are getting zero because the face.select
is not assigned value True, but is being checked for condition True (face.select == True
). Also if you are interested only in bottom faces, i.e faces with all vertices having z coordinate value zero, then checking for median z coordinate may not work in all cases. There could be faces with median z at zero but vertices lying on either side of x-y plane.
I can think of the following alternative (I am open to critique and corrections as I am also comparatively new to blender :)
import bpy
import bmesh
bm = bmesh.new()
#bm = bmesh.from_edit_mesh(bpy.context.active_object.data) (without modifier)
bm.from_object(bpy.context.active_object, bpy.context.scene)
#Floats are not always absolute zero, so comparing with a tolerance
total_area = sum(f.calc_area() for f in bm.faces if len([v for v in f.verts if v.co[2] < 0.0001 and v.co[2] > -0.0001]) == len(f.verts))
print('total area:', total_area)
bm.free()
answered 2 hours ago
Blender Dadaist
3117
3117
Upvoted. Suggestion:if all(abs(v.co.z) < 0.0001 for v in f.verts)
â batFINGER
1 hour ago
add a comment |Â
Upvoted. Suggestion:if all(abs(v.co.z) < 0.0001 for v in f.verts)
â batFINGER
1 hour ago
Upvoted. Suggestion:
if all(abs(v.co.z) < 0.0001 for v in f.verts)
â batFINGER
1 hour ago
Upvoted. Suggestion:
if all(abs(v.co.z) < 0.0001 for v in f.verts)
â batFINGER
1 hour ago
add a comment |Â
up vote
1
down vote
Use the face normal as test for bottom face.
Note: Between starting this answer, getting sidetracked, and posting another similar answer has been posted using bmesh from object.
CHecking that a local coordinate z is at some level is limiting.
If the mesh is as mentioned simply a wall can get the bottom faces by testing if the face normal points down (or close enough (within 4 degrees).
import bpy
import bmesh
from mathutils import Vector
from math import radians
context = bpy.context
scene = context.scene
ob = context.object
bm = bmesh.new()
bm.from_object(ob, scene)
down = Vector((0, 0, -1))
area = sum(f.calc_area() for f in bm.faces
if f.normal.angle(down) < radians(4))
print(area)
bm.free()
add a comment |Â
up vote
1
down vote
Use the face normal as test for bottom face.
Note: Between starting this answer, getting sidetracked, and posting another similar answer has been posted using bmesh from object.
CHecking that a local coordinate z is at some level is limiting.
If the mesh is as mentioned simply a wall can get the bottom faces by testing if the face normal points down (or close enough (within 4 degrees).
import bpy
import bmesh
from mathutils import Vector
from math import radians
context = bpy.context
scene = context.scene
ob = context.object
bm = bmesh.new()
bm.from_object(ob, scene)
down = Vector((0, 0, -1))
area = sum(f.calc_area() for f in bm.faces
if f.normal.angle(down) < radians(4))
print(area)
bm.free()
add a comment |Â
up vote
1
down vote
up vote
1
down vote
Use the face normal as test for bottom face.
Note: Between starting this answer, getting sidetracked, and posting another similar answer has been posted using bmesh from object.
CHecking that a local coordinate z is at some level is limiting.
If the mesh is as mentioned simply a wall can get the bottom faces by testing if the face normal points down (or close enough (within 4 degrees).
import bpy
import bmesh
from mathutils import Vector
from math import radians
context = bpy.context
scene = context.scene
ob = context.object
bm = bmesh.new()
bm.from_object(ob, scene)
down = Vector((0, 0, -1))
area = sum(f.calc_area() for f in bm.faces
if f.normal.angle(down) < radians(4))
print(area)
bm.free()
Use the face normal as test for bottom face.
Note: Between starting this answer, getting sidetracked, and posting another similar answer has been posted using bmesh from object.
CHecking that a local coordinate z is at some level is limiting.
If the mesh is as mentioned simply a wall can get the bottom faces by testing if the face normal points down (or close enough (within 4 degrees).
import bpy
import bmesh
from mathutils import Vector
from math import radians
context = bpy.context
scene = context.scene
ob = context.object
bm = bmesh.new()
bm.from_object(ob, scene)
down = Vector((0, 0, -1))
area = sum(f.calc_area() for f in bm.faces
if f.normal.angle(down) < radians(4))
print(area)
bm.free()
answered 1 hour ago
batFINGER
20k32060
20k32060
add a comment |Â
add a comment |Â
up vote
0
down vote
I assume this behaviour is caused by an inconsistent selection state when you only select the face but not the respective vertices and edges. As a result, something like print([f.select for f in bm.faces])
returns a list of False
values.
Using the function BMFace.select_set
instead of setting BMFace.select
will âÂÂupdate the selection state of assosiated geometryâÂÂ. BMFace.select
then will also return True
for these faces.
# snip
if z == 0:
face.select_set(True)
# snip
Apart from that, I guess you should unindent the area calculation so it's outside of the for face in bm.faces
loop. And switching between object and edit mode is not necessary here:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
if z == 0:
face.select_set(True)
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
add a comment |Â
up vote
0
down vote
I assume this behaviour is caused by an inconsistent selection state when you only select the face but not the respective vertices and edges. As a result, something like print([f.select for f in bm.faces])
returns a list of False
values.
Using the function BMFace.select_set
instead of setting BMFace.select
will âÂÂupdate the selection state of assosiated geometryâÂÂ. BMFace.select
then will also return True
for these faces.
# snip
if z == 0:
face.select_set(True)
# snip
Apart from that, I guess you should unindent the area calculation so it's outside of the for face in bm.faces
loop. And switching between object and edit mode is not necessary here:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
if z == 0:
face.select_set(True)
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
add a comment |Â
up vote
0
down vote
up vote
0
down vote
I assume this behaviour is caused by an inconsistent selection state when you only select the face but not the respective vertices and edges. As a result, something like print([f.select for f in bm.faces])
returns a list of False
values.
Using the function BMFace.select_set
instead of setting BMFace.select
will âÂÂupdate the selection state of assosiated geometryâÂÂ. BMFace.select
then will also return True
for these faces.
# snip
if z == 0:
face.select_set(True)
# snip
Apart from that, I guess you should unindent the area calculation so it's outside of the for face in bm.faces
loop. And switching between object and edit mode is not necessary here:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
if z == 0:
face.select_set(True)
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
I assume this behaviour is caused by an inconsistent selection state when you only select the face but not the respective vertices and edges. As a result, something like print([f.select for f in bm.faces])
returns a list of False
values.
Using the function BMFace.select_set
instead of setting BMFace.select
will âÂÂupdate the selection state of assosiated geometryâÂÂ. BMFace.select
then will also return True
for these faces.
# snip
if z == 0:
face.select_set(True)
# snip
Apart from that, I guess you should unindent the area calculation so it's outside of the for face in bm.faces
loop. And switching between object and edit mode is not necessary here:
import bpy
import bmesh
context = bpy.context
scene = context.scene
obj = bpy.context.active_object
# --- get a mesh from the object ---
apply_modifiers = True
settings = 'PREVIEW'
mesh = obj.to_mesh(scene, apply_modifiers, settings)
bm = bmesh.new()
bm.from_mesh(mesh)
for face in bm.faces:
face_location = face.calc_center_median()
z = face_location[2]
if z == 0:
face.select_set(True)
area = sum(f.calc_area() for f in bm.faces if f.select)
print(area)
bm.free()
bpy.data.meshes.remove(mesh)
answered 2 hours ago
binweg
1,9311412
1,9311412
add a comment |Â
add a comment |Â
MatH is a new contributor. Be nice, and check out our Code of Conduct.
MatH is a new contributor. Be nice, and check out our Code of Conduct.
MatH is a new contributor. Be nice, and check out our Code of Conduct.
MatH is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fblender.stackexchange.com%2fquestions%2f119446%2farea-of-bottom-polygons-using-obj-to-mesh-post-modifier-but-without-applying-it%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password