1
$\begingroup$

I try to get the are_inside function working from: https://blender.stackexchange.com/a/80781/21443

No matter what I try, I just get new errors. My scene is as follows:

enter image description here

I don't want to rely on edit mode for selections for the script.

The closest I got is:

import bpy
from mathutils import *
from mathutils.bvhtree import BVHTree
import bmesh


def are_inside(points, bm):
    """
    input: 
        points
        - a list of vectors (can also be tuples/lists)
        bm
        - a manifold bmesh with verts and (edge/faces) for which the 
          normals are calculated already. (add bm.normal_update() otherwise)
    returns:
        a list
        - a mask lists with True if the point is inside the bmesh, False otherwise
    """

    rpoints = []
    addp = rpoints.append
    bvh = BVHTree.FromBMesh(bm, epsilon=0.0001)

    # return points on polygons
    for point in points:
        fco, normal, _, _ = bvh.find_nearest(point)
        p2 = fco - Vector(point)
        v = p2.dot(normal)
        addp(not v < 0.0)  # addp(v >= 0.0) ?

    return rpoints



def test():
    print("test")

    mesh_points = bpy.data.objects['Grid'].to_mesh()
    bm_points = bmesh.new()
    bm_points.from_mesh(mesh_points)
    points = bm_points.verts


    mesh = bpy.data.objects['Suzanne'].to_mesh()
    bm = bmesh.new()
    bm.from_mesh(mesh)

    inside = are_inside(points, bm)

test()

How can I get this working?

$\endgroup$

2 Answers 2

4
$\begingroup$

Set the points to a collection of coords.

Needed to change to the points from a collection of bmesh.types.BMVert to a collection of 3d coordinates.

points = [v.co.copy() for v in bm_points.verts]

May still need some tests, here is the result

enter image description here

added some code such that if the grid is in edit mode, select the result.

import bpy
from mathutils import *
from mathutils.bvhtree import BVHTree
import bmesh


def are_inside(points, bm):
    """
    input: 
        points
        - a list of vectors (can also be tuples/lists)
        bm
        - a manifold bmesh with verts and (edge/faces) for which the 
          normals are calculated already. (add bm.normal_update() otherwise)
    returns:
        a list
        - a mask lists with True if the point is inside the bmesh, False otherwise
    """

    rpoints = []
    addp = rpoints.append
    bvh = BVHTree.FromBMesh(bm, epsilon=0.0001)

    # return points on polygons
    for point in points:
        fco, normal, _, _ = bvh.find_nearest(point)
        p2 = fco - Vector(point)
        v = p2.dot(normal)
        addp(not v < 0.0)  # addp(v >= 0.0) ?

    return rpoints



def test(grid, ob):
    print("test")
    mesh_points = grid.to_mesh()
    bm_points = bmesh.new()
    bm_points.from_mesh(mesh_points)
    points = [v.co.copy() for v in bm_points.verts]


    mesh = ob.data
    bm = bmesh.new()

    bm.from_mesh(ob.to_mesh())

    inside = are_inside(points, bm)
    if grid.mode == 'EDIT':
        # view the result
        bm = bmesh.from_edit_mesh(grid.data)

        for v, select in zip(bm.verts, inside):
            v.select = select
        bmesh.update_edit_mesh(grid.data)

scene = bpy.context.scene
test(scene.objects["Grid"], scene.objects["Suzanne"])

Consider using bmesh_from_object() or applying the global transform to the bmesh. If using an edit mode bmesh and not wanting to commit changes bmesh.from_edit_mesh(me).copy() provides an unbound copy.

If only the transform needed then transforming a mesh copy with

me.transform(ob.matrix_world)

or using the operator, will provide global coordinates.

bmesh.ops.transform(bm,
        matrix=ob.matrix_world,
        verts=bm.verts)

Alternatively could put one in the object space of the other to make their coordinates equivalent.

The mesh provided from ob.to_mesh() is "not what it used to be"

How do I get a mesh data-block with modifiers and shape keys applied in Blender 2.8?

May be worth noting too that Suzanne has 3 separate parts.

$\endgroup$
1
  • $\begingroup$ Thanks, eventually I used animation nodes, which was more easy for me. $\endgroup$
    – clankill3r
    Commented Dec 8, 2019 at 13:33
0
$\begingroup$

I ended up using animation nodes, here is my solution.

enter image description here

from mathutils import Vector
import time

FLB = 0
FLT = 1
BLB = 2
BLT = 3
FRB = 4
FRT = 5
BRB = 6
BRT = 7


start = time.time()



def map(val, in_low, in_high, out_low, out_high):
    return out_low + (out_high - out_low) * ((val - in_low) / (in_high - in_low))


def lerp(vector_a, vector_b, t):
    return (1 - t) * vector_a + t * vector_b


VectorList = []


for z in range(X_Steps):

    t_z = float(z) / (X_Steps-1)

    lt = lerp(Corners[FLT], Corners[BLT], t_z)
    lb = lerp(Corners[FLB], Corners[BLB], t_z)
    rt = lerp(Corners[FRT], Corners[BRT], t_z)
    rb = lerp(Corners[FRB], Corners[BRB], t_z)

    for y in range(Y_Steps):

        t_y = float(y) / (Y_Steps-1)

        v1 = lerp(lt, lb, t_y)
        v2 = lerp(rt, rb, t_y)

        for x in range(X_Steps):

            t_x = float(x) / (X_Steps-1)

            v = lerp(v1, v2, t_x)
            VectorList.append(v)

print(time.time() - start)

enter image description here

enter image description here

$\endgroup$

You must log in to answer this question.

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