From 2b8f655020adeab5d5d679fec19bf4f73a8ab16a Mon Sep 17 00:00:00 2001
From: Vojtech Bubnik <bubnikv@gmail.com>
Date: Thu, 21 May 2020 11:04:53 +0200
Subject: [PATCH] WIP AABBIndirect: Documentation, polishing.

---
 src/libslic3r/AABBTreeIndirect.hpp    | 210 +++++++++++++++++---------
 tests/libslic3r/test_aabbindirect.cpp |   6 +-
 2 files changed, 139 insertions(+), 77 deletions(-)

diff --git a/src/libslic3r/AABBTreeIndirect.hpp b/src/libslic3r/AABBTreeIndirect.hpp
index a541345ae..134b15b71 100644
--- a/src/libslic3r/AABBTreeIndirect.hpp
+++ b/src/libslic3r/AABBTreeIndirect.hpp
@@ -1,4 +1,7 @@
 // AABB tree built upon external data set, referencing the external data by integer indices.
+// The AABB tree balancing and traversal (ray casting, closest triangle of an indexed triangle mesh)
+// were adapted from libigl AABB.{cpp,hpp} Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// while the implicit balanced tree representation and memory optimizations are Vojtech's.
 
 #ifndef slic3r_AABBTreeIndirect_hpp_
 #define slic3r_AABBTreeIndirect_hpp_
@@ -11,22 +14,37 @@
 
 extern "C"
 {
+// Ray-Triangle Intersection Test Routines by Tomas Moller, May 2000
 #include <igl/raytri.c>
 }
+// Definition of the ray intersection hit structure.
 #include <igl/Hit.h>
+// Find intersection parameters of a ray with axis aligned bounding box.
 #include <igl/ray_box_intersect.h>
 
 namespace Slic3r {
 namespace AABBTreeIndirect {
 
-// AABB tree for raycasting and closest triangle search.
+// Static balanced AABB tree for raycasting and closest triangle search.
+// The balanced tree is built over a single large std::vector of nodes, where the children of nodes
+// are addressed implicitely using a power of two indexing rule.
+// Memory for a full balanced tree is allocated, but not all nodes at the last level are used.
+// This may seem like a waste of memory, but one saves memory for the node links and there is zero
+// overhead of a memory allocator management (usually the memory allocator adds at least one pointer 
+// before the memory returned). However, allocating memory in a single vector is very fast even
+// in multi-threaded environment and it is cache friendly.
+//
+// A balanced tree is built upon a vector of bounding boxes and their centroids, storing the reference
+// to the source entity (a 3D triangle, a 2D segment etc, a 3D or 2D point etc).
+// The source bounding boxes may have an epsilon applied to fight numeric rounding errors when 
+// traversing the AABB tree.
 template<int ANumDimensions, typename ACoordType>
 class Tree
 {
 public:
     static constexpr int    NumDimensions = ANumDimensions;
 	using					CoordType     = ACoordType;
-    using 					Vec3crd 	  = Eigen::Matrix<CoordType, NumDimensions, 1, Eigen::DontAlign>;
+    using 					VectorType 	  = Eigen::Matrix<CoordType, NumDimensions, 1, Eigen::DontAlign>;
     using  					BoundingBox   = Eigen::AlignedBox<CoordType, NumDimensions>;
     // Following could be static constexpr size_t, but that would not link in C++11
     enum : size_t {
@@ -36,10 +54,13 @@ public:
         inner = size_t(-2)
     };
 
+    // Single node of the implicit balanced AABB tree. There are no links to the children nodes,
+    // as these links are calculated implicitely using a power of two rule.
     struct Node {
     	// Index of the external source entity, for which this AABB tree was built, npos for internal nodes.
         size_t 			idx = npos;
-    	// Bounding box around this entity, possibly with epsilons applied.
+    	// Bounding box around this entity, possibly with epsilons applied to fight numeric rounding errors
+    	// when traversing the AABB tree.
         BoundingBox 	bbox;
 
         bool 	is_valid() const { return this->idx != npos; }
@@ -57,11 +78,13 @@ public:
 
 	// SourceNode shall implement
 	// size_t SourceNode::idx() const
-	// 		- index to the outside triangle.
-	// const Vec3crd& SourceNode::centroid() const
-	// 		- centroid of this node, for splitting the triangles into left / right bounding box.
+	// 		- Index to the outside entity (triangle, edge, point etc).
+	// const VectorType& SourceNode::centroid() const
+	// 		- Centroid of this node. The centroid is used for balancing the tree.
 	// const BoundingBox& SourceNode::bbox() const
-	// 		- bounding box of this node, likely expanded with epsilon to account for numeric rounding during tree traversal.
+	// 		- Bounding box of this node, likely expanded with epsilon to account for numeric rounding during tree traversal.
+	//        Union of bounding boxes at a single level of the AABB tree is used for deciding the longest axis aligned dimension
+	//        to split around.
 	template<typename SourceNode>
 	void build(std::vector<SourceNode> &&input)
 	{
@@ -69,8 +92,7 @@ public:
 			clear();
 		else {
 			// Allocate enough memory for a full binary tree.
-            //FIXME fianlize the tree size formula.
-            m_nodes.assign(next_highest_power_of_2(input.size() * 2 + 1), Node());
+            m_nodes.assign(next_highest_power_of_2(input.size()) * 2 - 1, Node());
             build_recursive(input, 0, 0, input.size() - 1);
 		}
         input.clear();
@@ -80,6 +102,12 @@ public:
 	const Node& 				node(size_t idx) const { return m_nodes[idx]; }
 	bool 						empty() const { return m_nodes.empty(); }
 
+	// Addressing the child nodes using the power of two rule.
+    static size_t				left_child_idx(size_t idx) { return idx * 2 + 1; }
+    static size_t				right_child_idx(size_t idx) { return left_child_idx(idx) + 1; }
+	const Node&					left_child(size_t idx) const { return m_nodes[left_child_idx(idx)]; }
+	const Node&					right_child(size_t idx) const { return m_nodes[right_child_idx(idx)]; }
+
 	template<typename SourceNode>
     void build(const std::vector<SourceNode> &input)
 	{
@@ -111,7 +139,7 @@ private:
 		// Partition the input to left / right pieces of the same length to produce a balanced tree.
 		size_t center = (left + right) / 2;
 		partition_input(input, size_t(dimension), left, right, center);
-		// Insert a node into the tree.
+		// Insert an inner node into the tree. Inner node does not reference any input entity (triangle, line segment etc).
 		m_nodes[node].idx  = inner;
 		m_nodes[node].bbox = bbox;
         build_recursive(input, node * 2 + 1, left, center);
@@ -178,53 +206,10 @@ private:
 		}
 	}
 
+	// The balanced tree storage.
 	std::vector<Node> m_nodes;
 };
 
-template<typename VertexType, typename IndexedFaceType>
-inline Tree<3, typename VertexType::Scalar>
-	build_aabb_tree(const std::vector<VertexType> &vertices, const std::vector<IndexedFaceType> &faces)
-{
-    using 				 TreeType 		= Tree<3, typename VertexType::Scalar>;
-    using				 CoordType      = typename TreeType::CoordType;
-    using 				 Vec3crd 	    = typename TreeType::Vec3crd;
-    using 				 BoundingBox 	= typename TreeType::BoundingBox;
-    static constexpr CoordType eps      = CoordType(1e-4);
-
-	struct InputType {
-        size_t 				idx()       const { return m_idx; }
-        const BoundingBox& 	bbox()      const { return m_bbox; }
-        const Vec3crd& 		centroid()  const { return m_centroid; }
-
-		size_t 		m_idx;
-		BoundingBox m_bbox;
-        Vec3crd 	m_centroid;
-	};
-
-	std::vector<InputType> input;
-	input.reserve(faces.size());
-    Vec3crd veps(eps, eps, eps);
-	for (size_t i = 0; i < faces.size(); ++ i) {
-        const IndexedFaceType &face = faces[i];
-		const VertexType &v1 = vertices[face(0)];
-		const VertexType &v2 = vertices[face(1)];
-		const VertexType &v3 = vertices[face(2)];
-		InputType n;
-        n.m_idx      = i;
-        n.m_centroid = (1./3.) * (v1 + v2 + v3);
-        n.m_bbox = BoundingBox(v1, v1);
-        n.m_bbox.extend(v2);
-        n.m_bbox.extend(v3);
-        n.m_bbox.min() -= veps;
-        n.m_bbox.max() += veps;
-        input.emplace_back(n);
-	}
-
-	TreeType out;
-	out.build(std::move(input));
-	return out;
-}
-
 namespace detail {
 	template<typename AVertexType, typename AIndexedFaceType, typename ATreeType, typename AVectorType>
 	struct RayIntersector {
@@ -253,14 +238,9 @@ namespace detail {
         Scalar                  min_t,
         igl::Hit 			   &hit)
 	{
-		const auto &nodes = ray_intersector.tree.nodes();
-		if (node_idx >= nodes.size())
-            return false;
-
-        const auto &node = nodes[node_idx];
-		if (! node.is_valid())
-            return false;
-
+        const auto &node = ray_intersector.tree.node(node_idx);
+        assert(node.is_valid());
+		
 		{
 	    	Scalar t_start, t_end;
             if (! igl::ray_box_intersect(ray_intersector.origin, ray_intersector.dir, node.bbox.template cast<Scalar>(), Scalar(0), min_t, t_start, t_end))
@@ -268,7 +248,7 @@ namespace detail {
 		}
 
 	  	if (node.is_leaf()) {
-            using Vector = Eigen::Matrix<Scalar, 3, 1>;
+            using Vector = Eigen::Matrix<double, 3, 1>;
             Vector origin_d	= ray_intersector.origin.template cast<double>();
             Vector dir_d 	= ray_intersector.dir   .template cast<double>();
             auto   face     = ray_intersector.faces[node.idx];
@@ -306,12 +286,10 @@ namespace detail {
     template<typename RayIntersectorType>
 	static inline void intersect_ray_recursive_all_hits(RayIntersectorType &ray_intersector, size_t node_idx)
 	{
-        using Vector = typename RayIntersectorType::VectorType;
-        using Scalar = typename Vector::Scalar;
+        using Scalar = typename RayIntersectorType::VectorType::Scalar;
 
 		const auto &node = ray_intersector.tree.node(node_idx);
-		if (! node.is_valid())
-			return;
+		assert(node.is_valid());
 
 	  	{
 	    	Scalar t_start, t_end;
@@ -321,7 +299,7 @@ namespace detail {
 	    }
 
 	  	if (node.is_leaf()) {
-            using Vector = Eigen::Matrix<Scalar, 3, 1>;
+            using Vector = Eigen::Matrix<double, 3, 1>;
             Vector origin_d = ray_intersector.origin.template cast<double>();
             Vector dir_d    = ray_intersector.dir   .template cast<double>();
             auto   face     = ray_intersector.faces[node.idx];
@@ -342,6 +320,7 @@ namespace detail {
 	  	intersect_ray_recursive_all_hits(ray_intersector, right);
 	}
 
+	// Nothing to do with COVID-19 social distancing.
 	template<typename AVertexType, typename AIndexedFaceType, typename ATreeType, typename AVectorType>
 	struct IndexedTriangleSetDistancer {
 		using VertexType 		= AVertexType;
@@ -407,7 +386,7 @@ namespace detail {
 	};
 
 	template<typename IndexedTriangleSetDistancerType, typename Scalar>
-    static inline Scalar squared_distance_recursive(
+    static inline Scalar squared_distance_to_indexed_triangle_set_recursive(
         IndexedTriangleSetDistancerType	&distancer,
 		size_t 							 node_idx,
 		Scalar 							 low_sqr_d,
@@ -420,6 +399,7 @@ namespace detail {
   		if (low_sqr_d > up_sqr_d)
 			return low_sqr_d;
 	  
+	  	// Save the best achieved hit.
         auto set_min = [&i, &c, &up_sqr_d](const Scalar sqr_d_candidate, const size_t i_candidate, const Vector &c_candidate) {
 			if (sqr_d_candidate < up_sqr_d) {
 				i     	 = i_candidate;
@@ -455,7 +435,7 @@ namespace detail {
 			{
                 size_t	i_left;
                 Vector 	c_left = c;
-                Scalar	sqr_d_left = squared_distance_recursive(distancer, left_node_idx, low_sqr_d, up_sqr_d, i_left, c_left);
+                Scalar	sqr_d_left = squared_distance_to_indexed_triangle_set_recursive(distancer, left_node_idx, low_sqr_d, up_sqr_d, i_left, c_left);
 				set_min(sqr_d_left, i_left, c_left);
 				looked_left = true;
 			};
@@ -463,7 +443,7 @@ namespace detail {
 			{
                 size_t	i_right;
                 Vector	c_right = c;
-                Scalar	sqr_d_right = squared_distance_recursive(distancer, right_node_idx, low_sqr_d, up_sqr_d, i_right, c_right);
+                Scalar	sqr_d_right = squared_distance_to_indexed_triangle_set_recursive(distancer, right_node_idx, low_sqr_d, up_sqr_d, i_right, c_right);
 				set_min(sqr_d_right, i_right, c_right);
 				looked_right = true;
 			};
@@ -494,13 +474,73 @@ namespace detail {
 
 } // namespace detail
 
+// Build a balanced AABB Tree over an indexed triangles set, balancing the tree
+// on centroids of the triangles.
+// Epsilon is applied to the bounding boxes of the AABB Tree to cope with numeric inaccuracies
+// during tree traversal.
+template<typename VertexType, typename IndexedFaceType>
+inline Tree<3, typename VertexType::Scalar> build_aabb_tree_over_indexed_triangle_set(
+	// Indexed triangle set - 3D vertices.
+	const std::vector<VertexType> 		&vertices, 
+	// Indexed triangle set - triangular faces, references to vertices.
+	const std::vector<IndexedFaceType> 	&faces)
+{
+    using 				 TreeType 		= Tree<3, typename VertexType::Scalar>;
+    using				 CoordType      = typename TreeType::CoordType;
+    using 				 VectorType	    = typename TreeType::VectorType;
+    using 				 BoundingBox 	= typename TreeType::BoundingBox;
+    static constexpr CoordType eps      = CoordType(1e-4);
+
+	struct InputType {
+        size_t 				idx()       const { return m_idx; }
+        const BoundingBox& 	bbox()      const { return m_bbox; }
+        const VectorType& 	centroid()  const { return m_centroid; }
+
+		size_t 		m_idx;
+		BoundingBox m_bbox;
+        VectorType 	m_centroid;
+	};
+
+	std::vector<InputType> input;
+	input.reserve(faces.size());
+    VectorType veps(eps, eps, eps);
+	for (size_t i = 0; i < faces.size(); ++ i) {
+        const IndexedFaceType &face = faces[i];
+		const VertexType &v1 = vertices[face(0)];
+		const VertexType &v2 = vertices[face(1)];
+		const VertexType &v3 = vertices[face(2)];
+		InputType n;
+        n.m_idx      = i;
+        n.m_centroid = (1./3.) * (v1 + v2 + v3);
+        n.m_bbox = BoundingBox(v1, v1);
+        n.m_bbox.extend(v2);
+        n.m_bbox.extend(v3);
+        n.m_bbox.min() -= veps;
+        n.m_bbox.max() += veps;
+        input.emplace_back(n);
+	}
+
+	TreeType out;
+	out.build(std::move(input));
+	return out;
+}
+
+// Find a first intersection of a ray with indexed triangle set.
+// Intersection test is calculated with the accuracy of VectorType::Scalar
+// even if the triangle mesh and the AABB Tree are built with floats.
 template<typename VertexType, typename IndexedFaceType, typename TreeType, typename VectorType>
 inline bool intersect_ray_first_hit(
+	// Indexed triangle set - 3D vertices.
 	const std::vector<VertexType> 		&vertices,
+	// Indexed triangle set - triangular faces, references to vertices.
 	const std::vector<IndexedFaceType> 	&faces,
+	// AABBTreeIndirect::Tree over vertices & faces, bounding boxes built with the accuracy of vertices.
 	const TreeType 						&tree,
+	// Origin of the ray.
 	const VectorType					&origin,
+	// Direction of the ray.
 	const VectorType 					&dir,
+	// First intersection of the ray with the indexed triangle set.
 	igl::Hit 							&hit)
 {
     using Scalar = typename VectorType::Scalar;
@@ -512,13 +552,24 @@ inline bool intersect_ray_first_hit(
         ray_intersector, size_t(0), std::numeric_limits<Scalar>::infinity(), hit);
 }
 
+// Find all intersections of a ray with indexed triangle set.
+// Intersection test is calculated with the accuracy of VectorType::Scalar
+// even if the triangle mesh and the AABB Tree are built with floats.
+// The output hits are sorted by the ray parameter.
+// If the ray intersects a shared edge of two triangles, hits for both triangles are returned.
 template<typename VertexType, typename IndexedFaceType, typename TreeType, typename VectorType>
 inline bool intersect_ray_all_hits(
+	// Indexed triangle set - 3D vertices.
 	const std::vector<VertexType> 		&vertices,
+	// Indexed triangle set - triangular faces, references to vertices.
 	const std::vector<IndexedFaceType> 	&faces,
+	// AABBTreeIndirect::Tree over vertices & faces, bounding boxes built with the accuracy of vertices.
 	const TreeType 						&tree,
+	// Origin of the ray.
 	const VectorType					&origin,
+	// Direction of the ray.
 	const VectorType 					&dir,
+	// All intersections of the ray with the indexed triangle set, sorted by parameter t.
 	std::vector<igl::Hit> 				&hits)
 {
     auto ray_intersector = detail::RayIntersectorHits<VertexType, IndexedFaceType, TreeType, VectorType> {
@@ -534,20 +585,31 @@ inline bool intersect_ray_all_hits(
 	return ! hits.empty();
 }
 
-// Closest point to triangle test will be performed with the accuracy of VectorType::Scalar.
+// Finding a closest triangle, its closest point and squared distance to the closest point
+// on a 3D indexed triangle set using a pre-built AABBTreeIndirect::Tree.
+// Closest point to triangle test will be performed with the accuracy of VectorType::Scalar
+// even if the triangle mesh and the AABB Tree are built with floats.
+// Returns squared distance to the closest point or -1 if the input is empty.
 template<typename VertexType, typename IndexedFaceType, typename TreeType, typename VectorType>
-inline typename VectorType::Scalar squared_distance(
+inline typename VectorType::Scalar squared_distance_to_indexed_triangle_set(
+	// Indexed triangle set - 3D vertices.
 	const std::vector<VertexType> 		&vertices,
+	// Indexed triangle set - triangular faces, references to vertices.
 	const std::vector<IndexedFaceType> 	&faces,
+	// AABBTreeIndirect::Tree over vertices & faces, bounding boxes built with the accuracy of vertices.
 	const TreeType 						&tree,
+	// Point to which the closest point on the indexed triangle set is searched for.
 	const VectorType					&point,
+	// Index of the closest triangle in faces.
 	size_t 								&hit_idx_out,
+	// Position of the closest point on the indexed triangle set.
 	Eigen::PlainObjectBase<VectorType>	&hit_point_out)
 {
     using Scalar = typename VectorType::Scalar;
     auto distancer = detail::IndexedTriangleSetDistancer<VertexType, IndexedFaceType, TreeType, VectorType>
         { vertices, faces, tree, point };
-    return detail::squared_distance_recursive(distancer, size_t(0), Scalar(0), std::numeric_limits<Scalar>::infinity(), hit_idx_out, hit_point_out);
+    return tree.empty() ? Scalar(-1) : 
+    	detail::squared_distance_to_indexed_triangle_set_recursive(distancer, size_t(0), Scalar(0), std::numeric_limits<Scalar>::infinity(), hit_idx_out, hit_point_out);
 }
 
 } // namespace AABBTreeIndirect
diff --git a/tests/libslic3r/test_aabbindirect.cpp b/tests/libslic3r/test_aabbindirect.cpp
index 017df9307..c0792a943 100644
--- a/tests/libslic3r/test_aabbindirect.cpp
+++ b/tests/libslic3r/test_aabbindirect.cpp
@@ -11,7 +11,7 @@ TEST_CASE("Building a tree over a box, ray caster and closest query", "[AABBIndi
     TriangleMesh tmesh = make_cube(1., 1., 1.);
     tmesh.repair();
 
-    auto tree = AABBTreeIndirect::build_aabb_tree(tmesh.its.vertices, tmesh.its.indices);
+    auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(tmesh.its.vertices, tmesh.its.indices);
     REQUIRE(! tree.empty());
 
     igl::Hit hit;
@@ -39,7 +39,7 @@ TEST_CASE("Building a tree over a box, ray caster and closest query", "[AABBIndi
 
     size_t hit_idx;
     Vec3d  closest_point;
-    double squared_distance = AABBTreeIndirect::squared_distance(
+    double squared_distance = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(
 		tmesh.its.vertices, tmesh.its.indices,
 		tree,
         Vec3d(0.3, 0.5, -5.),
@@ -49,7 +49,7 @@ TEST_CASE("Building a tree over a box, ray caster and closest query", "[AABBIndi
     REQUIRE(closest_point.y() == Approx(0.5));
     REQUIRE(closest_point.z() == Approx(0.));
 
-    squared_distance = AABBTreeIndirect::squared_distance(
+    squared_distance = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(
 		tmesh.its.vertices, tmesh.its.indices,
 		tree,
         Vec3d(0.3, 0.5, 5.),