-
Notifications
You must be signed in to change notification settings - Fork 27
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
Feature/qhull #99
Feature/qhull #99
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## develop #99 +/- ##
===========================================
- Coverage 63.02% 63.01% -0.01%
===========================================
Files 792 792
Lines 45351 45358 +7
===========================================
+ Hits 28583 28584 +1
- Misses 16768 16774 +6 ☔ View full report in Codecov by Sentry. |
I've swapped @simondsmart for @danovaro as reviewer given his experience with computational geometry. |
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.
See below comments.
I'm wondering if the list_triangles() function should be there at all as it is a special case. Open to discuss.
Atlas already has a bespoke Qhull triangulation API in any case.
src/eckit/maths/Qhull.h
Outdated
|
||
std::vector<size_t> list_vertices() const; | ||
std::vector<std::vector<size_t>> list_facets() const; | ||
std::vector<Triangle> list_triangles() const; |
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.
list_triangles() only works in particular case I suppose. This should be documented.
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.
Yes, but triangulation is rather the common usage in most cases of both convex hull and delaunay triangulations, that's why I've included it. The Triangle element is a "flat" as can be. I didn't go as far as to specify a Polygon element though, I think it's overkill (and there is intersection with the ::geo/::geometry parts too), but it would be correct though.
In random lists of points (in most geometry cases for our applications, but not necessarily the case for polytope (where many of the axes are aligned or of the same size), the result is a triangulation. The common examples using Qhull (that I found) are with "Qt" which enforces this, so, I think it is natural to have it as base functionality
src/eckit/maths/ConvexHullN.h
Outdated
|
||
std::vector<size_t> list_vertices() const override { return qhull_.list_vertices(); } | ||
std::vector<std::vector<size_t>> list_facets() const override { return qhull_.list_facets(); } | ||
std::vector<Triangle> list_triangles() const override { return qhull_.list_triangles(); } |
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.
list_triangles() only works in particular case. This should be documented.
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.
(as above)
src/eckit/maths/ConvexHull.h
Outdated
|
||
virtual std::vector<size_t> list_vertices() const = 0; | ||
virtual std::vector<std::vector<size_t>> list_facets() const = 0; | ||
virtual std::vector<Triangle> list_triangles() const = 0; |
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.
list_triangles() only works in particular case I suppose. This should be documented.
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.
(as above)
I'm not sure of the triangulation, but it is rather the common than the special case (hence why I included it). It was in fact the more "testable" situation as in that simpler geometry checks are needed to check correctness. |
What I refer to is that currently I would suggest an additional API for
The third vector is for the case that you'd want some byte alignment where a new facet starts in vector 1, and the nb_facets cannot be inferred from the difference in offsets in vector 2. An additional API could wrap these 2/3 vectors in a |
Following the recommendation, I decided to follow for the 2-vector solution while removing the list_triangles in favour of a overloaded list_facets(size_t n). For simplicity and to make the return type compatible in the two list_facets methods, the argument n filters the factes for those of the expected size. This is keeping in mind the considered case (of Polytope?). I agree that for mesh generation one could make the API even more specific, but in that case I would instead pass a single vector, addressable as n*i + j as a block connectivity (as we've used before). @danovaro @jameshawkes @tlmquintino @wdeconinck what do you think? |
… optimal building of block connectivities
I've just updated the interface to allow low-level, optimal access to connectivity using a 1-vector solution. So now I see this as a good interface for pure geometrical operations. New methods are:
Test are modified accordingly. |
Thanks for addressing my recommendations. for( auto& [nb_vertices, nb_facets] : qhull.facets_n() ) {
auto facets_with_nb_vertices = qhull.facets(nb_vertices);
ASSERT( facets_with_nb_vertices.size() == nb_vertices * nb_facets );
} So that for each type of facets you get a separate list? |
An additional comment to @jameshawkes , I understood from @tlmquintino that you are currently using CGAL in C++ somewhere, but I can only see python code for polytope. Could you show the use case for this, as this is basically supposed to be used for polytope. |
I've covered in the tests specifically the square pyramid case, so that one gets 4 triangles and 1 quadrilateral. I've extended the test to show this functionality at play, showing the usage of both the more generic list_facets() method, and the more specific pair of methods facets_n() and facets(size_t). |
Amazing @pmaciel! Thanks for extending the square pyramid test! This is good to merge a.f.a.i.c. |
We don't currently use CGAL, but as we are building a port of polytope to C++ (currently in Python) we need a convex hull interface we can use. QHull is what we use in Python, via scipy.spatial. You can see how we currently use it in Python here: The interface for passing args in and receiving a result is pretty standard. The main challenge is the error handling. You can see in that code we are switching based on the error description to detect some failure edge cases which are important to us (detecting if the input points are "flat" or if the input shape is lower dimension than the space it occupies). This interface through scipy isn't great. I discussed a bit with @pmaciel about the need to handle this error-handling a bit better in our C++ wrapper, if possible. |
…ConvexHull to be abstract from dependency
The exception handling is now exceptional! 😅 I think no-one else is probably interested in reviewing this but I'd give some time to the end of the week. |
This PR adds a ConvexHull base class and an implementation ConvexHullN which is templated to the number of dimensions of calculating a convex hull on. This exists in the eckit::maths library as discussed, and it is disabled by default (enable with cmake -DENABLE_CONVEX_HULL=ON ...)
The convex hull calculation itself is implemented by Qhull, hidden behind the interfacing classes, but exposing enough interface to catch exceptions including those internal to Qhull, so that the returned message(s) is meaningful to client code. Tests (and minimal examples) are in test_convex_hull.cc.