Restraining input meshes to have a euler characteristic of 2, will also block meshes that this algorithm can easily solve. Most simple example: two non intersecting cubes (EC = 4). E.g.
Dunno what is the result after applying the code above cause I havent tested it.
At these cases, although the mesh consists of 2 non-intersecting parts, each part has Euler result = 2, the correct algorithm based on the fact “counting ALL intersections of a ray at any direction and judging the point is INSIDE the body if they are an ODD number” will ALWAYS work cause for any point in INSIDE either body you will have n = 1 as a result. Thus, you’re correctly pointing out that the mesh should be processed first to defining its parts.
Apparently, there is a nice API function that tells you if a point is inside a mesh or not. Frankly, I didnt pay much attention to it by now. It’s use is rather simple and it may be like this:
sce = Scene.GetCurrent()
ob = Object.GetSelected()[0]
me = ob.getData(mesh=1)
mat = ob.mat
mat_inv = Mathutils.Matrix(mat).invert()
point = Mathutils.Vector(0,-2,2)
if me.pointInside(point*mat_inv):
blah-blah-blah
.................................
As per my testings, it works also in case your mesh consists of several parts.
I need this also!
I still haven’t found a reliable way to do this.
I have one method, but it doesn’t always work.
Was that 2.49 version reliable?
If so, why isn’t it in the current release?
This thread helped me too. Thx to all for sharing. Here are my updated version (2.74). And a second approach by using closest_point_on_mesh method, but sometimes it seems to be unprecise.
def point_inside(point,obj):
axes = [ Vector((1,0,0)), Vector((0,1,0)), Vector((0,0,1)) ]
outside = False
mat = obj.matrix_world.copy()
mat.invert()
for axis in axes:
orig = mat*point
count = 0
while True:
location,normal,index = obj.ray_cast(orig,orig+axis*1.84467e+19)
if index == -1: break
count += 1
orig = location + axis*0.00001
if count%2 == 0:
outside = True
break
return not outside
def inside_to_closest_point(p, obj):
inv = obj.matrix_world.copy()
inv.invert()
point, normal, face = obj.closest_point_on_mesh(inv*p, 1.84467e+19)
return (point-inv*p).dot(normal) >= 0.0