11import numpy as np
2+ from compas .geometry import Point
23from compas .plugins import plugin
34
45from compas_libigl import _intersections
56
67
7- def _conversion_libigl_to_compas (hits_per_ray ):
8+ def _conversion_libigl_to_compas (hits_per_ray , M ):
89 """Convert libigl barycentric coordinates to COMPAS barycentric coordinates.
910
1011 Parameters
1112 ----------
1213 hits_per_ray : list[tuple[int, float, float, float]]
1314 Tuples of (face_index, u, v, distance) from libigl ray intersection
15+ M : tuple[list[list[float]], list[list[int]]]
16+ A mesh represented by a tuple of (vertices, faces)
17+ where vertices are 3D points and faces are triangles
1418
1519 Returns
1620 -------
17- list[tuple[int, float, float, float]]
18- Tuples of (face_index, w , u, v) in COMPAS barycentric coordinate ordering
21+ list[tuple[list[float], int, float, float, float]]
22+ Tuples of (point, face_index , u, v, w ) in COMPAS barycentric coordinate ordering
1923
2024 Note
2125 ----
2226 libigl uses: P = (1-u-v)*v0 + u*v1 + v*v2
23- This function returns [w, u, v] = [1-u-v, u, v] to match COMPAS ordering
27+ COMPAS uses: P = u*v0 + v*v1 + w*v2 where u + v + w = 1
28+ This function converts libigl coordinates to match COMPAS barycentric coordinate ordering
2429 """
30+ vertices = M [0 ]
31+ faces = M [1 ]
2532
2633 hits_compas = []
2734 for h in hits_per_ray :
28- idx , u , v , _ = h
29- w = 1.0 - u - v
30- hits_compas .append ([idx , w , v , u ])
35+ idx , u_libigl , v_libigl , _ = h
36+ w = 1.0 - u_libigl - v_libigl # libigl's (1-u-v) coefficient
37+ u = u_libigl # libigl's u coefficient
38+ v = v_libigl # libigl's v coefficient
39+
40+ face = faces [idx ]
41+ p1 , p2 , p3 = vertices [face [0 ]], vertices [face [1 ]], vertices [face [2 ]]
42+ point = barycenter_to_point (u , v , w , p1 , p2 , p3 )
43+
44+ # To match COMPAS barycentric coordinates exactly:
45+ # COMPAS expects coordinates in order [p1_weight, p2_weight, p3_weight]
46+ # Our formula is P = w*p1 + u*p2 + v*p3, so COMPAS order should be [w, u, v]
47+ hits_compas .append ([point , idx , u , v , w ])
3148 return hits_compas
3249
3350
3451def barycenter_to_point (u , v , w , p1 , p2 , p3 ):
35- """Convert COMPAS barycentric coordinates to a point.
52+ """Convert barycentric coordinates to a point using the working interpolation formula .
3653
3754 Parameters
3855 ----------
3956 u : float
40- The u coordinate
57+ The u coordinate (weight for p2)
4158 v : float
42- The v coordinate
59+ The v coordinate (weight for p3)
4360 w : float
44- The w coordinate
61+ The w coordinate (weight for p1)
4562 p1 : tuple[float, float, float]
46- The first point
63+ The first vertex
4764 p2 : tuple[float, float, float]
48- The second point
65+ The second vertex
4966 p3 : tuple[float, float, float]
50- The third point
51-
67+ The third vertex
5268
5369 Returns
5470 -------
55- list[float]
56- The point at the intersection of the ray and the mesh
71+ Point
72+ The interpolated point
5773
5874 Note
5975 ----
60- libigl uses : P = (1-u-v)*v0 + u*v1 + v*v2
61- This function returns [w, u, v] = [1-u-v, u, v] to match COMPAS ordering
76+ Uses barycentric interpolation : P = w*p1 + u*p2 + v*p3
77+ where w + u + v = 1
6278 """
63- w = 1 - u - v # barycentric coordinates
64-
65- phit = [ u * p1 [ 0 ] + v * p2 [ 0 ] + w * p3 [ 0 ], u * p1 [1 ] + v * p2 [ 1 ] + w * p3 [ 1 ], u * p1 [ 2 ] + v * p2 [2 ] + w * p3 [2 ]]
79+ phit = [ w * p1 [ 0 ] + u * p2 [ 0 ] + v * p3 [ 0 ],
80+ w * p1 [ 1 ] + u * p2 [ 1 ] + v * p3 [ 1 ],
81+ w * p1 [2 ] + u * p2 [2 ] + v * p3 [2 ]]
6682
67- return phit
83+ return Point ( * phit )
6884
6985
7086@plugin (category = "intersections" )
@@ -81,21 +97,23 @@ def intersection_ray_mesh(ray, M):
8197
8298 Returns
8399 -------
84- list[tuple[int, float, float, float]]
100+ list[tuple[list[float], int, float, float, float]]
85101 The array contains a tuple per intersection of the ray with the mesh.
86102 Each tuple contains:
87103
88- 0. the index of the intersected face
89- 1. the u coordinate of the intersection in the barycentric coordinates of the face
90- 2. the v coordinate of the intersection in the barycentric coordinates of the face
91- 3. the distance between the ray origin and the hit
104+ 0. the point of intersection
105+ 1. the index of the intersected face
106+ 2. the u coordinate of the intersection in COMPAS barycentric coordinates
107+ 3. the v coordinate of the intersection in COMPAS barycentric coordinates
108+ 4. the w coordinate of the intersection in COMPAS barycentric coordinates
109+
92110
93111 Note
94112 ----
95- The barycentric coordinates (u, v) follow the libigl convention where:
96- - For a triangle with vertices (v0, v1, v2 ) at face indices F[face_id]
97- - The intersection point P = (1-u-v)*v0 + u*v1 + v*v2
98- - This differs from COMPAS barycentric_coordinates which uses a different vertex ordering
113+ The returned barycentric coordinates follow COMPAS convention where:
114+ - For a triangle with vertices (p1, p2, p3 ) at face indices F[face_id]
115+ - The intersection point P = u*p1 + v*p2 + w*p3 where u + v + w = 1
116+ - These coordinates match those returned by compas.geometry.barycentric_coordinates
99117 """
100118 point , vector = ray
101119 vertices , faces = M
@@ -107,7 +125,7 @@ def intersection_ray_mesh(ray, M):
107125 hits_per_ray = _intersections .intersection_ray_mesh (P , D , V , F )
108126
109127 # Convert libigl barycentric coordinates to COMPAS convention
110- hits_compas = _conversion_libigl_to_compas (hits_per_ray )
128+ hits_compas = _conversion_libigl_to_compas (hits_per_ray , M )
111129
112130 return hits_compas
113131
@@ -125,14 +143,16 @@ def intersection_rays_mesh(rays, M):
125143
126144 Returns
127145 -------
128- list[list[tuple[int, float, float, float]]]
146+ list[list[tuple[list[float], int, float, float, float]]]
129147 List of intersection results, one per ray.
130148 Each intersection result contains tuples with:
131149
132- 0. the index of the intersected face
133- 1. the u coordinate of the intersection in the barycentric coordinates of the face
134- 2. the v coordinate of the intersection in the barycentric coordinates of the face
135- 3. the distance between the ray origin and the hit
150+ 0. the point of intersection
151+ 1. the index of the intersected face
152+ 2. the u coordinate of the intersection in COMPAS barycentric coordinates
153+ 3. the v coordinate of the intersection in COMPAS barycentric coordinates
154+ 4. the w coordinate of the intersection in COMPAS barycentric coordinates
155+
136156 """
137157 points , vectors = zip (* rays )
138158 vertices , faces = M
@@ -146,6 +166,6 @@ def intersection_rays_mesh(rays, M):
146166 # Convert libigl barycentric coordinates to COMPAS convention
147167 hits_per_ray_compas = []
148168 for hit in hits_per_ray :
149- hits_per_ray_compas .append (_conversion_libigl_to_compas (hit ))
169+ hits_per_ray_compas .append (_conversion_libigl_to_compas (hit , M ))
150170
151171 return hits_per_ray_compas
0 commit comments