In 2D this task is pretty simple but how can I determine in 3D on which of the two triangles of a given quad-polygon a given point is located?
I face this problem because of the following bigger task:
I have two meshs, which have the same topology but are differently deformed in space. Now I have hundreds of points on one mesh and I want to determine their corresponding location on the other mesh. With
p, n, f = object.closest_point_on_mesh(point)
I can get the polygon f of the point on my first object and use this to determine the vertices on the other object to calculate the corresponding position. This could be easily done with
mathutils.geometry.barycentric_transform
However, therefore, I need to know which three vertices I have to use. For 2D, the corresponding command would be
mathutils.geometry.intersect_point_tri_2d
but how can I determine the triangle on which the point is in 3D?
Use .tessfaces (quads+tris) and triangulate if it’s a quad. I’m not sure if blender changed (or will change) default behavior, but it should be as easy as:
import bpy
me = bpy.context.object.data
verts = me.vertices
me.calc_tessface()
tf = me.tessfaces[0] # pick any tessface
v = tf.vertices
if len(v) == 3:
tris = (verts[v[0]], verts[v[1]], verts[v[2]]),
else:
tris = (verts[v[0]], verts[v[1]], verts[v[2]]), (verts[v[2]], verts[v[3]], verts[v[0]])
for tri in tris:
# this may either run once or twice, twice if input tessface is a quad
print(tri[0].co, tri[1].co, tri[2].co)
Note that other vertex orders are possible, what you see in viewport may differ from blender’s definition of a triangulated quad (in editmode, it should work like above, but in object mode it is up to opengl driver and may differ again with VBO enabled). A triangulation modifier provides more control, you can also triangulate from script using the beauty-option (more available in 2.70)
thanks for the tips, codemanx. I think, I found the solution for my problem. This is not very efficient, but at least I have solved it for my purposes. I first project the point into a 2d-triangle, check whether the point is in this triangle and then I transform it to its real locatoin
import bpy
import mathutils.geometry as mug
def map3dPointTo3d(o1, o2, point):
''' maps a 3d-point on a given object on another object. Both objects must have the
same topology '''
# get point, normal and face of closest point to particle
p, n, f = o1.closest_point_on_mesh(point)
# get the vertices of the first triangle of the polygon from both objects
A1 = o1.data.vertices[o1.data.polygons[f].vertices[0]].co
B1 = o1.data.vertices[o1.data.polygons[f].vertices[1]].co
C1 = o1.data.vertices[o1.data.polygons[f].vertices[2]].co
# project the point on a 2d-surface and check, whether we are in the right triangle
t1 = mathutils.Vector();
t2 = mathutils.Vector((1.0, 0.0, 0.0))
t3 = mathutils.Vector((0.0, 1.0, 0.0))
p_test = mug.barycentric_transform(p,A1,B1,C1,t1, t2, t3)
# if the point is on the 2d-triangle, proceed with the real barycentric_transform
if mug.intersect_point_tri_2d(p_test.to_2d(), t1.xy, t2.xy, t3.xy) == 1:
A2 = o2.data.vertices[o2.data.polygons[f].vertices[0]].co
B2 = o2.data.vertices[o2.data.polygons[f].vertices[1]].co
C2 = o2.data.vertices[o2.data.polygons[f].vertices[2]].co
# convert 3d-coordinates of the point
p_new = mug.barycentric_transform(p,A1,B1,C1,A2,B2,C2)
else:
# use the other triangle
A1 = o1.data.vertices[o1.data.polygons[f].vertices[0]].co
B1 = o1.data.vertices[o1.data.polygons[f].vertices[2]].co
C1 = o1.data.vertices[o1.data.polygons[f].vertices[3]].co
A2 = o2.data.vertices[o2.data.polygons[f].vertices[0]].co
B2 = o2.data.vertices[o2.data.polygons[f].vertices[2]].co
C2 = o2.data.vertices[o2.data.polygons[f].vertices[3]].co
# convert 3d-coordinates of the point
p_new = mug.barycentric_transform(p,A1,B1,C1,A2,B2,C2)
### TODO ###
### triangle check could be made more efficient ###
return p_new