-
Notifications
You must be signed in to change notification settings - Fork 8
Align libigl barycentric coordinates to compas. #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||||
| import compas.geometry | ||||||
| import compas.datastructures | ||||||
| from compas_libigl.intersections import intersection_ray_mesh | ||||||
| from compas_libigl.intersections import barycenter_to_point | ||||||
| from compas_viewer import Viewer | ||||||
| from compas.colors import Color | ||||||
| from compas.geometry import Line | ||||||
| import compas | ||||||
|
|
||||||
|
|
||||||
| p0 = compas.geometry.Point(2, 0, 0) | ||||||
| p1 = compas.geometry.Point(3 + 2, 0 - 2, 13) | ||||||
| p2 = compas.geometry.Point(0 - 2, 0 - 2, 10) | ||||||
| p3 = compas.geometry.Point(0 - 2, 2 + 2, 10) | ||||||
|
|
||||||
| mesh = compas.datastructures.Mesh.from_points([[p1.x, p1.y, p1.z], [p2.x, p2.y, p2.z], [p3.x, p3.y, p3.z]]) | ||||||
|
|
||||||
| ray = (p0, compas.geometry.Vector(0, 0, 1)) | ||||||
| hits_per_ray = intersection_ray_mesh(ray, mesh.to_vertices_and_faces()) | ||||||
|
|
||||||
| point, idx, u, v, w = hits_per_ray[0][0], hits_per_ray[0][1], hits_per_ray[0][2], hits_per_ray[0][3], hits_per_ray[0][4] | ||||||
|
|
||||||
| intersections = [] | ||||||
| for hit in hits_per_ray: | ||||||
| point, idx, w, u, v = hit | ||||||
|
||||||
| point, idx, w, u, v = hit | |
| point, idx, u, v, w = hit |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,9 +1,88 @@ | ||||||||||
| import numpy as np | ||||||||||
| from compas.geometry import Point | ||||||||||
| from compas.plugins import plugin | ||||||||||
|
|
||||||||||
| from compas_libigl import _intersections | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def _conversion_libigl_to_compas(hits_per_ray, M): | ||||||||||
| """Convert libigl barycentric coordinates to COMPAS barycentric coordinates. | ||||||||||
|
|
||||||||||
| Parameters | ||||||||||
| ---------- | ||||||||||
| hits_per_ray : list[tuple[int, float, float, float]] | ||||||||||
| Tuples of (face_index, u, v, distance) from libigl ray intersection | ||||||||||
| M : tuple[list[list[float]], list[list[int]]] | ||||||||||
| A mesh represented by a tuple of (vertices, faces) | ||||||||||
| where vertices are 3D points and faces are triangles | ||||||||||
|
|
||||||||||
| Returns | ||||||||||
| ------- | ||||||||||
| list[tuple[list[float], int, float, float, float]] | ||||||||||
| Tuples of (point, face_index, u, v, w) in COMPAS barycentric coordinate ordering | ||||||||||
|
|
||||||||||
| Note | ||||||||||
| ---- | ||||||||||
| libigl uses: P = (1-u-v)*v0 + u*v1 + v*v2 | ||||||||||
| COMPAS uses: P = u*v0 + v*v1 + w*v2 where u + v + w = 1 | ||||||||||
| This function converts libigl coordinates to match COMPAS barycentric coordinate ordering | ||||||||||
| """ | ||||||||||
| vertices = M[0] | ||||||||||
| faces = M[1] | ||||||||||
|
|
||||||||||
| hits_compas = [] | ||||||||||
| for h in hits_per_ray: | ||||||||||
| idx, u_libigl, v_libigl, _ = h | ||||||||||
| w = 1.0 - u_libigl - v_libigl # libigl's (1-u-v) coefficient | ||||||||||
| u = u_libigl # libigl's u coefficient | ||||||||||
|
||||||||||
| u = u_libigl # libigl's u coefficient | |
| u = u_libigl # libigl's u coefficient |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace on this line. This should be removed for code cleanliness.
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The barycentric coordinate ordering is incorrect. The conversion computes the correct coordinate values (w=1-u_libigl-v_libigl for p1, u=u_libigl for p2, v=v_libigl for p3), and the formula P = w*p1 + u*p2 + v*p3 is correct. However, the returned tuple [point, idx, u, v, w] returns coordinates in order (u, v, w) which corresponds to weights for (p2, p3, p1).
According to the documentation claiming compatibility with compas.geometry.barycentric_coordinates, the order should be (p1_weight, p2_weight, p3_weight), which is (w, u, v). The return statement should be hits_compas.append([point, idx, w, u, v]) to match COMPAS convention.
| hits_compas.append([point, idx, u, v, w]) | |
| hits_compas.append([point, idx, w, u, v]) |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new barycentric coordinate conversion logic lacks test coverage. Given that this PR fixes a coordinate system bug, it's critical to add tests that verify:
- The barycentric coordinates returned match those from
compas.geometry.barycentric_coordinatesfor the same point and triangle - The point reconstruction using the returned barycentric coordinates produces the correct intersection point
- The coordinate ordering is correct (weights should be in order p1, p2, p3 to match COMPAS convention)
These tests would prevent regression of the bug this PR aims to fix.
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The barycenter_to_point function is being imported in example files (line 4 and line 10 of the example files), but it's not clear if this function is intended to be part of the public API. If it is public, it should be documented as such (e.g., via __all__). If it's meant to be private/internal, it should be prefixed with an underscore (e.g., _barycenter_to_point) and the example imports should be reconsidered.
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable names in the parameter documentation are inconsistent. The parameters are named u, v, w but the documentation describes them with different semantics. According to the formula P = w*p1 + u*p2 + v*p3, the parameter names should better reflect the vertex they weight (e.g., u_p2, v_p3, w_p1) or the documentation should clarify that despite the generic names, u weights p2, v weights p3, and w weights p1.
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation formula is inconsistent with the actual implementation. Line 115 states P = u*p1 + v*p2 + w*p3, but based on the coordinate order being returned [point, idx, u, v, w] where (u, v, w) are supposed to be weights for (p2, p3, p1) based on the conversion formula P = w*p1 + u*p2 + v*p3.
If the return order is corrected to [point, idx, w, u, v] to match COMPAS convention (weights in order p1, p2, p3), then this documentation formula should be updated to P = w*p1 + u*p2 + v*p3 where the first coordinate is w, second is u, and third is v.
| - The intersection point P = u*p1 + v*p2 + w*p3 where u + v + w = 1 | |
| - These coordinates match those returned by compas.geometry.barycentric_coordinates | |
| - The intersection point P = w*p1 + u*p2 + v*p3 where w + u + v = 1 | |
| - The returned tuple is (point, face_index, w, u, v), matching COMPAS barycentric coordinate ordering. |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a breaking API change. The original API returned (face_index, u, v, distance), but now returns [point, face_index, u, v, w]. While this change appears intentional to fix the bug, existing code that depends on this API will break. Consider:
- Documenting this as a breaking change more prominently in the CHANGELOG
- Updating all existing tests and examples to use the new API
- Considering a deprecation period or version bump to signal the breaking change to users
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'barycenter_to_point' is not used.