6
$\begingroup$

I want to delete all faces (of "Mesh") with a distance > 0.5 to the nearest point of an other object ("Sphere"). Unfortunately it deletes the whole object.

Thanks for helping!

Scene

import bpy
import bmesh
from math import sqrt

# Get the active mesh

obj_sphere = bpy.data.objects['Sphere']
obj = bpy.context.edit_object
me = obj.data

# Get a BMesh representation
bm = bmesh.from_edit_mesh(me)

for face in bm.faces:

    # select face and Sphere
    bpy.ops.mesh.select_all(action='TOGGLE')
    face.select = True
    obj_sphere.select = True

    # get distance for selected objects
    l = []
    for item in bpy.context.selected_objects:
        l.append(item.location)

    distance = sqrt( (l[0][0] - l[1][0])**2 + (l[0][1] - l[1][1])**2 + (l[0][2] - l[1][2])**2)

    # check distance > 0.5 and delete
    if distance > 0.5:
        bpy.ops.mesh.delete(type='FACE')

bmesh.update_edit_mesh(me, True)
$\endgroup$
1

2 Answers 2

3
$\begingroup$

Came up with similar to @TLousky, test code below only selects faces without the range value.

To use closest point on mesh you need to put the reference point into the calling object's object space, if not you will get undesired results when away from the origin.

Also note: use vectors to calculate distance.

import bpy
import bmesh

L = 0.5 # distance limit
sphere = bpy.data.objects.get("Sphere")
mesh_obj = bpy.context.edit_object
me = mesh_obj.data
smwi = sphere.matrix_world.inverted()

bm = bmesh.from_edit_mesh(me)

for face in bm.faces:
    v1 = mesh_obj.matrix_world * face.calc_center_median() # global face median
    localPos = smwi * v1  # face cent in sphere local space

    (hit, loc, norm, face_index) = sphere.closest_point_on_mesh(localPos)
    # Edited for new hit success return val.  
    v2 = sphere.matrix_world * loc
    face.select = ((v2 - v1).length > L)

test result

enter image description here

To make it more accurate consider using the normal returned to determine which point of a face to use. If the angle between the face normal and the normal to the closest point is ~ 90 use the closest edge, ~ 180 degrees it's on the inside.

$\endgroup$
1
  • $\begingroup$ @Basti edited slightly to take inverting the sphere's world matrix out of the loop. $\endgroup$
    – batFINGER
    Commented Nov 3, 2015 at 17:27
2
$\begingroup$

This code does the trick, and uses some nice built in functions to make things simpler:

import bpy, bmesh

s = bpy.data.objects['Sphere']
o = bpy.context.object

bpy.ops.object.mode_set(  mode   = 'EDIT'     )
bpy.ops.mesh.select_all(  action = 'DESELECT' )
bpy.ops.mesh.select_mode( type   = 'FACE'     )

bm = bmesh.from_edit_mesh( o.data )

for f in bm.faces:
    # Calculate the global location of the current face's median point
    gCenterMedian = o.matrix_world * f.calc_center_median()

    # Find the closest point on the Sphere to the current face's median
    loc = s.closest_point_on_mesh( gCenterMedian )[0]

    # Find the distance by calculating the length of the vector between the two points
    distance = ( loc - gCenterMedian).length

    if distance < 0.5: f.select = True

bm.select_flush( True )

# Delete all selected faces
bpy.ops.mesh.delete( type = 'FACE' )

bpy.ops.object.mode_set( mode = 'OBJECT' )

As the gif shows, reverse the sign to delete far away faces enter image description here

$\endgroup$
1
  • $\begingroup$ For some reason got this : TypeError: Element-wise multiplication: not supported between 'Matrix' and 'Vector' types On this line of code : gCenterMedian = Plane.matrix_world * face.calc_center_median() $\endgroup$ Commented Nov 18, 2021 at 14:57

You must log in to answer this question.

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