Can I calculate the surface of a part of a mesh, confined by a square boundary? I have one single mesh object that consists of many little, randomly placed but non-overlapping circles, like so (top view):



The object was created by looping the bmesh.ops.create_cone(... ) -operator.
I need to calculate the surface of the (parts of) circles that are within the square boundaries drawn in the image, which is in this case a square of radius 2 centered around the origin.
I found this command in related questions

area = sum(f.calc_area() for f in bm.faces if ...), 

which works well if I leave out the if statement, but I don't know how I can include a statement to cut away all pieces of circles that are outside of the bounding box.

Edit: @batFINGER I made a minimal working example of two non-overlapping circles of radius 2. For the sake of clarity I did not include the part of the code that puts them in random places, but I just defined the centers manually in ccValids. Each circle has 64 segments, so since both circles belong to the same mesh data, Blender considers this single mesh object, consisting of two circles, to have 128 faces that are all shaped like pieces of pie.

ccValids = [(-1,2,0), (2,-2,0)] 

bm = bmesh.new()
for c in ccValids:
    m = Matrix()
    bmesh.ops.create_cone( 
        bm, 
        diameter1 = cRad, 
        diameter2 = 0, 
        depth     = 0, 
        segments  = 64,
        matrix    = m.Translation( c )
    )

l_d = bpy.data.meshes.new('LeafsM')
bm.to_mesh( l_d )
l_o = bpy.data.objects.new('LeafsO', l_d )
bpy.context.scene.objects.link( l_o )


Now let's say I want to know what part of the total surface of these two circles lies inside the square of radius 2, that is shown in the camera view below:



Clearly the parts of interest are not segment-shaped, so it won't be useful to base the calculation on the counting on segments.
Is there a way to perhaps "split" segments (thus the 128 faces) in an inside and an outside part first, and then count the surfaces of the parts that are inside?
Boolean Intersection modifier.

Given you are chopping aligned cylinders with an aligned box, the boolean modifier would be a much better way to go IMO.

Add a cube to the scene as the bounding box, scale in z to make sure it is taller than cylinders in z. Add a boolean intersection modifier to cylinders using cube as bounds.  A  copy of the cylinders mesh with the modifiers applied is calculated using  Object.to_mesh(...) This mesh can be loaded into a bmesh, to do face area calculations.

To only calculate the areas of the circular tops, would need to look at face normals being parallel to z axis or similar.


Result of running script. The result mesh on left in place, result in edit mode on right. The top face area is 2.5704, which is 64.26% of the square area (4).

Test script

import bpy
import bmesh
from mathutils import Vector
TOL = 0.0001 # anle test
up = Vector((0, 0, 1))

context = bpy.context
scene = context.scene
obj = context.object
# add a new default cube
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0))
cube = context.object
cube.scale.z = 4
# add a boolean modifer to the obj
bmod = obj.modifiers.new(name="bbox", type='BOOLEAN')
bmod.operation = 'INTERSECT'
bmod.object = cube

scene.update()
# create a copy
copy_mesh = obj.to_mesh(scene, True, settings='PREVIEW')
bm = bmesh.new()
bm.from_mesh(copy_mesh)
area = sum(f.calc_area() for f in bm.faces 
        if f.normal.angle(up) &lt; TOL)
print("Top face area:", area)
bm.free()
# clean up... 
obj.modifiers.remove(bmod)

#scene.objects.unlink(cube)
# uncomment below to see mesh.
cube.data = copy_mesh
cube.scale.z = 1



Test run on cones. Bottom faces normals matched with -Z axis.  The sum of the areas of bottom edges of the mesh is 3.04279, 70.70% of a 2 x 2 square.