Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 42 additions & 6 deletions Libs/Optimize/Domain/Surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,15 @@ PointType Surface::geodesic_walk(PointType p, int idx, VectorType vector) const
if (idx >= 0 && ending_face >= 0) {
if (idx >= particle_triangles_.size()) {
particle_triangles_.resize(idx + 1, -1);
particle_face_query_pts_.resize(idx + 1);
particle_face_closest_pts_.resize(idx + 1);
}

particle_triangles_[idx] = ending_face;
// new_point_pt is on ending_face, so seed the per-particle face cache so the next
// get_triangle_for_point(new_point_pt, idx, ...) hits without a cell_locator query.
particle_face_query_pts_[idx] = new_point_pt;
particle_face_closest_pts_[idx] = new_point_pt;
geo_lq_cached_ = false;

calculate_normal_at_point(new_point_pt, idx);
Expand Down Expand Up @@ -356,18 +362,40 @@ PointType Surface::get_point_on_mesh() const {
int Surface::get_triangle_for_point(const double pt[3], int idx, double closest_point[3]) const {
// given a guess, just check whether it is still valid.
if (idx >= 0) {
// ensure that the cache has enough elements. this will never be resized to more than the number of particles,
// ensure that the caches have enough elements. these will never be resized to more than the number of particles.
if (idx >= particle_triangles_.size()) {
particle_triangles_.resize(idx + 1, -1);
particle_face_query_pts_.resize(idx + 1);
particle_face_closest_pts_.resize(idx + 1);
}

const int guess = particle_triangles_[idx];

if (guess != -1 && is_in_triangle(pt, guess)) {
closest_point[0] = pt[0];
closest_point[1] = pt[1];
closest_point[2] = pt[2];
return guess;
if (guess != -1) {
// Same query point as the previous lookup for this particle: reuse the cached face and
// closest_point. This is the only fast path that works when pt is not on this mesh — e.g.
// particles snapped to a separate surface_ being queried against a remeshed geodesics_mesh_.
const auto& q = particle_face_query_pts_[idx];
if (q[0] == pt[0] && q[1] == pt[1] && q[2] == pt[2]) {
const auto& c = particle_face_closest_pts_[idx];
closest_point[0] = c[0];
closest_point[1] = c[1];
closest_point[2] = c[2];
return guess;
}
// pt moved but is still on the cached face (only succeeds when pt lies on this mesh).
if (is_in_triangle(pt, guess)) {
closest_point[0] = pt[0];
closest_point[1] = pt[1];
closest_point[2] = pt[2];
particle_face_query_pts_[idx][0] = pt[0];
particle_face_query_pts_[idx][1] = pt[1];
particle_face_query_pts_[idx][2] = pt[2];
particle_face_closest_pts_[idx][0] = pt[0];
particle_face_closest_pts_[idx][1] = pt[1];
particle_face_closest_pts_[idx][2] = pt[2];
return guess;
}
}
}

Expand All @@ -381,6 +409,12 @@ int Surface::get_triangle_for_point(const double pt[3], int idx, double closest_
if (idx >= 0) {
// update cache, no need to check size as it was already checked above
particle_triangles_[idx] = cell_id;
particle_face_query_pts_[idx][0] = pt[0];
particle_face_query_pts_[idx][1] = pt[1];
particle_face_query_pts_[idx][2] = pt[2];
particle_face_closest_pts_[idx][0] = closest_point[0];
particle_face_closest_pts_[idx][1] = closest_point[1];
particle_face_closest_pts_[idx][2] = closest_point[2];
}

assert(cell_id >= 0);
Expand Down Expand Up @@ -780,6 +814,8 @@ void Surface::invalidate_particle(int idx) {
assert(idx >= 0); // should always be passed a valid particle
if (idx >= particle_triangles_.size()) {
particle_triangles_.resize(idx + 1, -1);
particle_face_query_pts_.resize(idx + 1);
particle_face_closest_pts_.resize(idx + 1);
}
particle_triangles_[idx] = -1;
geo_lq_cached_ = false;
Expand Down
6 changes: 6 additions & 0 deletions Libs/Optimize/Domain/Surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ class Surface {
// Caches of triangle, normal and position
// Has to be mutable because all of the accessor APIs are const
mutable std::vector<int> particle_triangles_;
// Per-particle position used to look up particle_triangles_[idx] and the corresponding
// closest point on that face. Used so a query whose pt is not exactly on this mesh
// (e.g. particles snapped to a different surface) still gets a cache hit when the same
// pt is queried again, instead of re-running cell_locator_->FindClosestPoint.
mutable std::vector<PointType> particle_face_query_pts_;
mutable std::vector<PointType> particle_face_closest_pts_;
mutable std::vector<NormalType> particle_normals_;
mutable std::vector<PointType> particle_positions_;
mutable std::vector<double> particle_neighboorhood_;
Expand Down
Loading