From 9ffdd894619a8c20408f153b01e4f2e8bd01f5cd Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Fri, 29 Nov 2024 09:21:47 +0100 Subject: [PATCH 01/10] fix unknown escape sequence warning --- docs/make_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/make_docs.py b/docs/make_docs.py index bb8ebfbacb0..7f691afd81c 100644 --- a/docs/make_docs.py +++ b/docs/make_docs.py @@ -88,7 +88,7 @@ def _get_documented_module_names(): with open("documented_modules.txt", "r") as f: for line in f: print(line, end="") - m = re.match("^(open3d\..*)\s*$", line) + m = re.match(r"^(open3d\..*)\s*$", line) if m: module_names.append(m.group(1)) print("Documented modules:") From ebb495a7541bbdab1c2c6c92431eb1f70aff248d Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Fri, 29 Nov 2024 09:22:21 +0100 Subject: [PATCH 02/10] add docstrings for NearestNeighborSearch --- .../core/nns/nearest_neighbor_search.cpp | 272 +++++++++++++++--- 1 file changed, 236 insertions(+), 36 deletions(-) diff --git a/cpp/pybind/core/nns/nearest_neighbor_search.cpp b/cpp/pybind/core/nns/nearest_neighbor_search.cpp index ad8de540b93..6ed494767c0 100644 --- a/cpp/pybind/core/nns/nearest_neighbor_search.cpp +++ b/cpp/pybind/core/nns/nearest_neighbor_search.cpp @@ -21,10 +21,35 @@ namespace nns { void pybind_core_nns_declarations(py::module &m_nns) { py::class_> nns(m_nns, "NearestNeighborSearch", - "NearestNeighborSearch class for nearest neighbor search. " - "Construct a NearestNeighborSearch object with input " - "dataset_points of shape {n_dataset, d}."); + R"(NearestNeighborSearch class for nearest neighbor search. + +This class holds multiple index types to accelerate various nearest neighbor +search operations for a dataset of points with shape {n,d} with `n` as the number +of points and `d` as the dimension of the points. The class supports knn search, +fixed-radius search, multi-radius search, and hybrid search. + +Example: + The following example demonstrates how to perform knn search using the class:: + + import open3d as o3d + import numpy as np + + dataset = np.random.rand(10,3) + query_points = np.random.rand(5,3) + + nns = o3d.core.nns.NearestNeighborSearch(dataset) + + # initialize the knn_index before we can use knn_search + nns.knn_index() + + # perform knn search to get the 3 closest points with respect to the + # Euclidean distance. The returned distance is given as the squared + # distances + indices, squared_distances = nns.knn_search(query_points, knn=3) + + )"); } + void pybind_core_nns_definitions(py::module &m_nns) { auto nns = static_cast>>( @@ -35,7 +60,14 @@ void pybind_core_nns_definitions(py::module &m_nns) { // Index functions. nns.def("knn_index", &NearestNeighborSearch::KnnIndex, - "Set index for knn search."); + R"(Initialize the index for knn search. + +This function needs to be called once before performing search operations. + +Returns: + True on success. + )"); + nns.def( "fixed_radius_index", [](NearestNeighborSearch &self, utility::optional radius) { @@ -45,9 +77,28 @@ void pybind_core_nns_definitions(py::module &m_nns) { return self.FixedRadiusIndex(radius.value()); } }, - py::arg("radius") = py::none()); + py::arg("radius") = py::none(), + R"(Initialize the index for fixed-radius search. + +This function needs to be called once before performing search operations. + +Args: + radius (float, optional): Radius value for fixed-radius search. Required + for GPU fixed radius index. + +Returns: + True on success. + )"); + nns.def("multi_radius_index", &NearestNeighborSearch::MultiRadiusIndex, - "Set index for multi-radius search."); + R"(Initialize the index for multi-radius search. + +This function needs to be called once before performing search operations. + +Returns: + True on success. + )"); + nns.def( "hybrid_index", [](NearestNeighborSearch &self, utility::optional radius) { @@ -57,11 +108,57 @@ void pybind_core_nns_definitions(py::module &m_nns) { return self.HybridIndex(radius.value()); } }, - py::arg("radius") = py::none()); + py::arg("radius") = py::none(), + R"(Initialize the index for hybrid search. + +This function needs to be called once before performing search operations. + +Args: + radius (float, optional): Radius value for hybrid search. Required + for GPU hybrid index. + +Returns: + True on success. + )"); // Search functions. nns.def("knn_search", &NearestNeighborSearch::KnnSearch, "query_points"_a, - "knn"_a, "Perform knn search."); + "knn"_a, + R"(Perform knn search. + +Note: + To use knn_search initialize the index using knn_index before calling this function. + +Args: + query_points (open3d.core.Tensor): Query points with shape {n, d}. + knn (int): Number of neighbors to search per query point. + +Example: + The following searches the 3 nearest neighbors for random dataset and query points:: + + import open3d as o3d + import numpy as np + + dataset = np.random.rand(10,3) + query_points = np.random.rand(5,3) + + nns = o3d.core.nns.NearestNeighborSearch(dataset) + + # initialize the knn_index before we can use knn_search + nns.knn_index() + + # perform knn search to get the 3 closest points with respect to the + # Euclidean distance. The returned distance is given as the squared + # distances + indices, squared_distances = nns.knn_search(query_points, knn=3) + +Returns: + Tuple of Tensors (indices, squared_distances). + - indices: Tensor of shape {n, knn}. + - squared_distances: Tensor of shape {n, knn}. The distances are squared L2 distances. + + )"); + nns.def( "fixed_radius_search", [](NearestNeighborSearch &self, Tensor query_points, double radius, @@ -74,38 +171,141 @@ void pybind_core_nns_definitions(py::module &m_nns) { } }, py::arg("query_points"), py::arg("radius"), - py::arg("sort") = py::none()); + py::arg("sort") = py::none(), + R"(Perform fixed-radius search. + +Note: + To use fixed_radius_search initialize the index using fixed_radius_index before calling this function. + +Args: + query_points (open3d.core.Tensor): Query points with shape {n, d}. + radius (float): Radius value for fixed-radius search. Note that this + parameter can differ from the radius used to initialize the index + for convenience, which may cause the index to be rebuilt for GPU + devices. + sort (bool, optional): Sort the results by distance. Default is True. + +Returns: + Tuple of Tensors (indices, splits, distances). + - indices: The indices of the neighbors. + - distances: The squared L2 distances. + - splits: The splits of the indices and distances defining the start + and exclusive end of each query point's neighbors. The shape is {num_queries+1} + +Example: + The following searches the neighbors within a radius of 1.0 a set of data and query points:: + + # define data and query points + points = np.array([ + [0.1,0.1,0.1], + [0.9,0.9,0.9], + [0.5,0.5,0.5], + [1.7,1.7,1.7], + [1.8,1.8,1.8], + [0.3,2.4,1.4]], dtype=np.float32) + + queries = np.array([ + [1.0,1.0,1.0], + [0.5,2.0,2.0], + [0.5,2.1,2.1], + [100,100,100], + ], dtype=np.float32) + + nns = o3d.core.nns.NearestNeighborSearch(points) + nns.fixed_radius_index(radius=1.0) + + neighbors_index, neighbors_distance, neighbors_splits = nns.fixed_radius_search(queries, radius=1.0, sort=True) + # returns neighbors_index = [1, 2, 5, 5] + # neighbors_distance = [0.03 0.75 0.56000006 0.62] + # neighbors_splits = [0, 2, 3, 4, 4] + + for i, (start_i, end_i) in enumerate(zip(neighbors_splits, neighbors_splits[1:])): + start_i = start_i.item() + end_i = end_i.item() + print(f"query_point {i} has the neighbors {neighbors_index[start_i:end_i].numpy()} " + f"with squared distances {neighbors_distance[start_i:end_i].numpy()}") + )"); + nns.def("multi_radius_search", &NearestNeighborSearch::MultiRadiusSearch, "query_points"_a, "radii"_a, - "Perform multi-radius search. Each query point has an independent " - "radius."); + R"(Perform multi-radius search. Each query point has an independent radius. + +Note: + To use multi_radius_search initialize the index using multi_radius_index before calling this function. + +Args: + query_points (open3d.core.Tensor): Query points with shape {n, d}. + radii (open3d.core.Tensor): Radii of query points. Each query point has one radius. + +Returns: + Tuple of Tensors (indices, splits, distances). + - indices: The indices of the neighbors. + - distances: The squared L2 distances. + - splits: The splits of the indices and distances defining the start + and exclusive end of each query point's neighbors. The shape is {num_queries+1} + +Example: + The following searches the neighbors with an individual radius for each query point:: + + # define data, query points and radii + points = np.array([ + [0.1,0.1,0.1], + [0.9,0.9,0.9], + [0.5,0.5,0.5], + [1.7,1.7,1.7], + [1.8,1.8,1.8], + [0.3,2.4,1.4]], dtype=np.float32) + + queries = np.array([ + [1.0,1.0,1.0], + [0.5,2.0,2.0], + [0.5,2.1,2.1], + [100,100,100], + ], dtype=np.float32) + + radii = np.array([0.5, 1.0, 1.5, 2], dtype=np.float32) + + nns = o3d.core.nns.NearestNeighborSearch(points) + + nns.multi_radius_index() + + neighbors_index, neighbors_distance, neighbors_splits = nns.multi_radius_search(queries, radii) + # returns neighbors_index = [1 5 5 3 4] + # neighbors_distance = [0.03 0.56 0.62 1.76 1.87] + # neighbors_splits = [0 1 2 5 5] + + + for i, (start_i, end_i) in enumerate(zip(neighbors_splits, neighbors_splits[1:])): + start_i = start_i.item() + end_i = end_i.item() + print(f"query_point {i} has the neighbors {neighbors_index[start_i:end_i].numpy()} " + f"with squared distances {neighbors_distance[start_i:end_i].numpy()}") + )"); + nns.def("hybrid_search", &NearestNeighborSearch::HybridSearch, "query_points"_a, "radius"_a, "max_knn"_a, - "Perform hybrid search."); - - // Docstrings. - static const std::unordered_map - map_nearest_neighbor_search_method_docs = { - {"query_points", "The query tensor of shape {n_query, d}."}, - {"radii", - "Tensor of shape {n_query,} containing multiple radii, " - "one for each query point."}, - {"radius", "Radius value for radius search."}, - {"max_knn", - "Maximum number of neighbors to search per query point."}, - {"knn", "Number of neighbors to search per query point."}}; - docstring::ClassMethodDocInject(m_nns, "NearestNeighborSearch", - "knn_search", - map_nearest_neighbor_search_method_docs); - docstring::ClassMethodDocInject(m_nns, "NearestNeighborSearch", - "multi_radius_search", - map_nearest_neighbor_search_method_docs); - docstring::ClassMethodDocInject(m_nns, "NearestNeighborSearch", - "fixed_radius_search", - map_nearest_neighbor_search_method_docs); - docstring::ClassMethodDocInject(m_nns, "NearestNeighborSearch", - "hybrid_search", - map_nearest_neighbor_search_method_docs); + R"(Perform hybrid search. + +Hybrid search behaves similarly to fixed-radius search, but with a maximum number of neighbors to search per query point. + +Note: + To use hybrid_search initialize the index using hybrid_index before calling this function. + +Args: + query_points (open3d.core.Tensor): Query points with shape {n, d}. + radius (float): Radius value for hybrid search. + max_knn (int): Maximum number of neighbor to search per query. + +Returns: + Tuple of Tensors (indices, distances, counts) + - indices: The indices of the neighbors with shape {n, max_knn}. + If there are less than max_knn neighbors within the radius then the + last entries are padded with -1. + - distances: The squared L2 distances with shape {n, max_knn}. + If there are less than max_knn neighbors within the radius then the + last entries are padded with 0. + - counts: Counts of neighbour for each query points with shape {n}. + )"); } } // namespace nns From 9c4eef46c6494dddf6779b8726d1cf9f70c171d7 Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Fri, 29 Nov 2024 09:22:50 +0100 Subject: [PATCH 03/10] docstring improvements for tensor PointCloud and TriangleMesh --- cpp/pybind/t/geometry/pointcloud.cpp | 34 ++++++++++------ cpp/pybind/t/geometry/trianglemesh.cpp | 54 ++++++++++++++++---------- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/cpp/pybind/t/geometry/pointcloud.cpp b/cpp/pybind/t/geometry/pointcloud.cpp index 10a5735389c..0aecc64aa44 100644 --- a/cpp/pybind/t/geometry/pointcloud.cpp +++ b/cpp/pybind/t/geometry/pointcloud.cpp @@ -769,17 +769,29 @@ the partition id for each point. )"); - pointcloud.def( - "compute_metrics", &PointCloud::ComputeMetrics, "pcd2"_a, - "metrics"_a, "params"_a, - R"(Compute various metrics between two point clouds. Currently, Chamfer distance, Hausdorff distance and F-Score [[Knapitsch2017]] are supported. The Chamfer distance is the sum of the mean distance to the nearest neighbor from the points of the first point cloud to the second point cloud. The F-Score at a fixed threshold radius is the harmonic mean of the Precision and Recall. Recall is the percentage of surface points from the first point cloud that have the second point cloud points within the threshold radius, while Precision is the percentage of points from the second point cloud that have the first point cloud points within the threhold radius. - - .. math: - \text{Chamfer Distance: } d_{CD}(X,Y) = \frac{1}{|X|}\sum_{i \in X} || x_i - n(x_i, Y) || + \frac{1}{|Y|}\sum_{i \in Y} || y_i - n(y_i, X) ||\\ - \text{Hausdorff distance: } d_H(X,Y) = \max \left{ \max_{i \in X} || x_i - n(x_i, Y) ||, \max_{i \in Y} || y_i - n(y_i, X) || \right}\\ - \text{Precision: } P(X,Y|d) = \frac{100}{|X|} \sum_{i \in X} || x_i - n(x_i, Y) || < d \\ - \text{Recall: } R(X,Y|d) = \frac{100}{|Y|} \sum_{i \in Y} || y_i - n(y_i, X) || < d \\ - \text{F-Score: } F(X,Y|d) = \frac{2 P(X,Y|d) R(X,Y|d)}{P(X,Y|d) + R(X,Y|d)} \\ + pointcloud.def("compute_metrics", &PointCloud::ComputeMetrics, "pcd2"_a, + "metrics"_a, "params"_a, + R"(Compute various metrics between two point clouds. + +Currently, Chamfer distance, Hausdorff distance and F-Score `[Knapitsch2017] <../tutorial/reference.html#Knapitsch2017>`_ are supported. +The Chamfer distance is the sum of the mean distance to the nearest neighbor +from the points of the first point cloud to the second point cloud. The F-Score +at a fixed threshold radius is the harmonic mean of the Precision and Recall. +Recall is the percentage of surface points from the first point cloud that have +the second point cloud points within the threshold radius, while Precision is +the percentage of points from the second point cloud that have the first point +cloud points within the threhold radius. + +.. math:: + :nowrap: + + \begin{align} + \text{Chamfer Distance: } d_{CD}(X,Y) &= \frac{1}{|X|}\sum_{i \in X} || x_i - n(x_i, Y) || + \frac{1}{|Y|}\sum_{i \in Y} || y_i - n(y_i, X) ||\\ + \text{Hausdorff distance: } d_H(X,Y) &= \max \left\{ \max_{i \in X} || x_i - n(x_i, Y) ||, \max_{i \in Y} || y_i - n(y_i, X) || \right\}\\ + \text{Precision: } P(X,Y|d) &= \frac{100}{|X|} \sum_{i \in X} || x_i - n(x_i, Y) || < d \\ + \text{Recall: } R(X,Y|d) &= \frac{100}{|Y|} \sum_{i \in Y} || y_i - n(y_i, X) || < d \\ + \text{F-Score: } F(X,Y|d) &= \frac{2 P(X,Y|d) R(X,Y|d)}{P(X,Y|d) + R(X,Y|d)} \\ + \end{align} Args: pcd2 (t.geometry.PointCloud): Other point cloud to compare with. diff --git a/cpp/pybind/t/geometry/trianglemesh.cpp b/cpp/pybind/t/geometry/trianglemesh.cpp index b6a27b0a102..3f56bb52d8b 100644 --- a/cpp/pybind/t/geometry/trianglemesh.cpp +++ b/cpp/pybind/t/geometry/trianglemesh.cpp @@ -261,13 +261,14 @@ shared storage on the CPU (GPU resident images for textures is not yet supported Dictionary of names to triangle meshes. Example: + Converting the FlightHelmetModel to a dictionary of triangle meshes:: - flight_helmet = o3d.data.FlightHelmetModel() - model = o3d.io.read_triangle_model(flight_helmet.path) - mesh_dict = o3d.t.geometry.TriangleMesh.from_triangle_mesh_model(model) - o3d.visualization.draw(list({"name": name, "geometry": tmesh} for - (name, tmesh) in mesh_dict.items())) - )"); + flight_helmet = o3d.data.FlightHelmetModel() + model = o3d.io.read_triangle_model(flight_helmet.path) + mesh_dict = o3d.t.geometry.TriangleMesh.from_triangle_mesh_model(model) + o3d.visualization.draw(list({"name": name, "geometry": tmesh} for + (name, tmesh) in mesh_dict.items())) +)"); // conversion triangle_mesh.def("to_legacy", &TriangleMesh::ToLegacy, "Convert to a legacy Open3D TriangleMesh."); @@ -773,8 +774,7 @@ This function always uses the CPU device. Input meshes must be manifold for this method to work. The algorithm is based on: -Zhou et al, "Iso-charts: Stretch-driven Mesh Parameterization using Spectral - Analysis", Eurographics Symposium on Geometry Processing (2004) +Zhou et al, "Iso-charts: Stretch-driven Mesh Parameterization using Spectral Analysis", Eurographics Symposium on Geometry Processing (2004) Sander et al. "Signal-Specialized Parametrization" Europgraphics 2002 This function always uses the CPU device. @@ -1112,23 +1112,37 @@ Example:: )"); - triangle_mesh.def( - "compute_metrics", &TriangleMesh::ComputeMetrics, "mesh2"_a, - "metrics"_a, "params"_a, - R"(Compute various metrics between two triangle meshes. This uses ray casting for distance computations between a sampled point cloud and a triangle mesh. Currently, Chamfer distance, Hausdorff distance and F-Score [\\[Knapitsch2017\\]](../tutorial/reference.html#Knapitsch2017) are supported. The Chamfer distance is the sum of the mean distance to the nearest neighbor from the sampled surface points of the first mesh to the second mesh and vice versa. The F-Score at the fixed threshold radius is the harmonic mean of the Precision and Recall. Recall is the percentage of surface points from the first mesh that have the second mesh within the threshold radius, while Precision is the percentage of sampled points from the second mesh that have the first mesh surface within the threhold radius. - - .. math:: - \text{Chamfer Distance: } d_{CD}(X,Y) = \frac{1}{|X|}\sum_{i \in X} || x_i - n(x_i, Y) || + \frac{1}{|Y|}\sum_{i \in Y} || y_i - n(y_i, X) ||\\ - \text{Hausdorff distance: } d_H(X,Y) = \max \left{ \max_{i \in X} || x_i - n(x_i, Y) ||, \max_{i \in Y} || y_i - n(y_i, X) || \right}\\ - \text{Precision: } P(X,Y|d) = \frac{100}{|X|} \sum_{i \in X} || x_i - n(x_i, Y) || < d \\ - \text{Recall: } R(X,Y|d) = \frac{100}{|Y|} \sum_{i \in Y} || y_i - n(y_i, X) || < d \\ - \text{F-Score: } F(X,Y|d) = \frac{2 P(X,Y|d) R(X,Y|d)}{P(X,Y|d) + R(X,Y|d)} \\ + triangle_mesh.def("compute_metrics", &TriangleMesh::ComputeMetrics, + "mesh2"_a, "metrics"_a, "params"_a, + R"(Compute various metrics between two triangle meshes. + +This uses ray casting for distance computations between a sampled point cloud +and a triangle mesh. Currently, Chamfer distance, Hausdorff distance and +F-Score `[Knapitsch2017] <../tutorial/reference.html#Knapitsch2017>`_ are supported. +The Chamfer distance is the sum of the mean distance to the nearest neighbor from +the sampled surface points of the first mesh to the second mesh and vice versa. +The F-Score at the fixed threshold radius is the harmonic mean of the Precision +and Recall. Recall is the percentage of surface points from the first mesh that +have the second mesh within the threshold radius, while Precision is the +percentage of sampled points from the second mesh that have the first mesh +surface within the threhold radius. + +.. math:: + :nowrap: + + \begin{align} + \text{Chamfer Distance: } d_{CD}(X,Y) &= \frac{1}{|X|}\sum_{i \in X} || x_i - n(x_i, Y) || + \frac{1}{|Y|}\sum_{i \in Y} || y_i - n(y_i, X) ||\\ + \text{Hausdorff distance: } d_H(X,Y) &= \max \left\{ \max_{i \in X} || x_i - n(x_i, Y) ||, \max_{i \in Y} || y_i - n(y_i, X) || \right\}\\ + \text{Precision: } P(X,Y|d) &= \frac{100}{|X|} \sum_{i \in X} || x_i - n(x_i, Y) || < d \\ + \text{Recall: } R(X,Y|d) &= \frac{100}{|Y|} \sum_{i \in Y} || y_i - n(y_i, X) || < d \\ + \text{F-Score: } F(X,Y|d) &= \frac{2 P(X,Y|d) R(X,Y|d)}{P(X,Y|d) + R(X,Y|d)} \\ + \end{align} As a side effect, the triangle areas are saved in the "areas" attribute. Args: mesh2 (t.geometry.TriangleMesh): Other triangle mesh to compare with. - metrics (Sequence[t.geometry.Metric]): List of Metric s to compute. Multiple metrics can be computed at once for efficiency. + metrics (Sequence[t.geometry.Metric]): List of Metrics to compute. Multiple metrics can be computed at once for efficiency. params (t.geometry.MetricParameters): This holds parameters required by different metrics. Returns: From 4edae8432359667a0012df5e9182ec69fd7d3d29 Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Fri, 29 Nov 2024 11:49:08 +0100 Subject: [PATCH 04/10] template python docstring --- docs/template_python_docstring.txt | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 docs/template_python_docstring.txt diff --git a/docs/template_python_docstring.txt b/docs/template_python_docstring.txt new file mode 100644 index 00000000000..e8420ee5063 --- /dev/null +++ b/docs/template_python_docstring.txt @@ -0,0 +1,85 @@ +Single line short description: Example docstring for Open3D. + +Use the ``Args``, ``Returns``, ``Example``, ``Note`` sections to describe classes +or functions as needed. +Giving a code example showing how to use a class or function in the ``Example`` +section is highly recommended. + +To explain what a method does you can use code and math. +This is a literal block to show code:: + + import open3d as o3d + +This is an inline equation :math:`e^{i\pi} + 1 = 0` and this is a display equation +(don't forget the blank line before the ``..math::`` directive): + +.. math:: + e^{i\pi} + 1 = 0. + + +The default alignment for multiple equations is right-align, which is often not +desired. +To align multiple equations manually use the ``align`` environment with ``:nowrap:`` +**Don't forget to add a blank line after ``:nowrap:`` to make this work!** + +.. math:: + :nowrap: + + \begin{align} + x &= r \sin(\theta) \cos(\phi) \\ + y &= r \sin(\theta) \sin(\phi) \\ + z &= r \cos(\theta). + \end{align} + + +Note: + You can use inline markup to format your documentation. + - *italics* for emphasis + - **boldface** for strong emphasis + - ``code`` for inline code + + A list must be separated with blank lines to work. + + - This is a list + - Second item + + - A nested list must be .. + - separated with blank lines too + - **Use only two spaces to indent or it will be treated as a block quote.** + + - Third item + + This is a link `The space before the pointy left bracket is important! `_ + This does not work, `you forgot the space`_ + + +Args: + param1 (o3d.core.Tensor): Specify the shape with curly braces, {N,3}, and + the dtype, Float32, as necessary for Tensor parameters + param2 (str): Another parameter + +Returns: + Returned values can be tuples, lists or dictionaries sometimes. + Describing every item can be done with lists + + - o3d.core.Tensor: vertices with shape {N,3} and type Float32. + - int: the number of vertices. This is N. + + or definition lists, which is recommended if the returned value is a dictionary + + vertices (o3d.core.Tensor) [term must be a single line] + Description, first paragraph. + A tensor with the vertices of shape {N,3} and type Float32. + + Description, second paragraph. + The tensor has the same shape as param1. + + count (int) + Description. + The number of vertices. This is N. + + +Example: + This is a code example showing how to install Open3D:: + + pip install open3d \ No newline at end of file From 8752b04f98a043931f534d0dac312d9045feb507 Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Fri, 29 Nov 2024 15:17:19 +0100 Subject: [PATCH 05/10] improved template --- docs/template_python_docstring.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/template_python_docstring.txt b/docs/template_python_docstring.txt index e8420ee5063..8ed96f37ba4 100644 --- a/docs/template_python_docstring.txt +++ b/docs/template_python_docstring.txt @@ -6,9 +6,9 @@ Giving a code example showing how to use a class or function in the ``Example`` section is highly recommended. To explain what a method does you can use code and math. -This is a literal block to show code:: +This is a literal block started with ``::`` followed by a blank line to show code:: - import open3d as o3d + pip install open3d This is an inline equation :math:`e^{i\pi} + 1 = 0` and this is a display equation (don't forget the blank line before the ``..math::`` directive): @@ -20,7 +20,7 @@ This is an inline equation :math:`e^{i\pi} + 1 = 0` and this is a display equati The default alignment for multiple equations is right-align, which is often not desired. To align multiple equations manually use the ``align`` environment with ``:nowrap:`` -**Don't forget to add a blank line after ``:nowrap:`` to make this work!** +**(don't forget to add a blank line after :nowrap: to make this work!)** .. math:: :nowrap: @@ -34,9 +34,10 @@ To align multiple equations manually use the ``align`` environment with ``:nowra Note: You can use inline markup to format your documentation. - - *italics* for emphasis - - **boldface** for strong emphasis - - ``code`` for inline code + + - *italics* for emphasis + - **boldface** for strong emphasis + - ``code`` for inline code A list must be separated with blank lines to work. @@ -80,6 +81,6 @@ Returns: Example: - This is a code example showing how to install Open3D:: + This is a code example showing how Open3D is imported:: - pip install open3d \ No newline at end of file + import open3d as o3d \ No newline at end of file From ce48b35d8da58f52133491e4aeec906e0ee7973c Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Mon, 9 Dec 2024 08:53:46 +0100 Subject: [PATCH 06/10] change to round brackets --- docs/template_python_docstring.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/template_python_docstring.txt b/docs/template_python_docstring.txt index 8ed96f37ba4..778477a9142 100644 --- a/docs/template_python_docstring.txt +++ b/docs/template_python_docstring.txt @@ -55,22 +55,23 @@ Note: Args: - param1 (o3d.core.Tensor): Specify the shape with curly braces, {N,3}, and + param1 (o3d.core.Tensor): Specify the shape with round brackets, (N,3), and the dtype, Float32, as necessary for Tensor parameters + param2 (str): Another parameter Returns: Returned values can be tuples, lists or dictionaries sometimes. Describing every item can be done with lists - - o3d.core.Tensor: vertices with shape {N,3} and type Float32. + - o3d.core.Tensor: vertices with shape (N,3) and type Float32. - int: the number of vertices. This is N. or definition lists, which is recommended if the returned value is a dictionary vertices (o3d.core.Tensor) [term must be a single line] Description, first paragraph. - A tensor with the vertices of shape {N,3} and type Float32. + A tensor with the vertices of shape (N,3) and type Float32. Description, second paragraph. The tensor has the same shape as param1. From 7e6442408b6aaba368cb09d224ffffbb6232684c Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Mon, 9 Dec 2024 09:05:58 +0100 Subject: [PATCH 07/10] update conribution recipes with example py docstring --- .../contribute/template_python_docstring.webp | Bin 0 -> 80578 bytes docs/contribute/contribution_recipes.rst | 39 +++++++----------- .../example_python_docstring.rst} | 0 3 files changed, 15 insertions(+), 24 deletions(-) create mode 100644 docs/_static/contribute/template_python_docstring.webp rename docs/{template_python_docstring.txt => contribute/example_python_docstring.rst} (100%) diff --git a/docs/_static/contribute/template_python_docstring.webp b/docs/_static/contribute/template_python_docstring.webp new file mode 100644 index 0000000000000000000000000000000000000000..746d50e84c7b7bfb7c846be198e8c216c872a8bd GIT binary patch literal 80578 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. Make sure to write the high-level docstrings for the classes and functions. Also use ``"param_name"_a`` to denote function parameters. Use standard RST based docstring syntax (`Google style `__) as explained `here `_ and `there `_. -* Use the ``docstring::ClassMethodDocInject()`` or ``docstring::FunctionDocInject()`` to insert parameter docs. -* Example binding and docstrings for the ``Calculator`` class: - -.. code:: cpp - - py::class_ calculator( - m, "Calculator", - "Calculator class performs numerical computations."); - calculator.def("add", &Calculator::Add, - "Performs ``a`` plus ``b``, i.e. :math:`c=a+b` Unlike " - ":math:`open3d.Calculator.sub`, " - ":math:`open3d.Calculator.add` is " - "commutative.", - "a"_a, "b"_a); - calculator.def("sub", &Calculator::Add, "Subtracts ``b`` from ``a``," - " i.e. :math:`c=a-b`", - "a"_a, - "b"_a); - docstring::ClassMethodDocInject(m, "Calculator", "add", - {{"a", "LHS operand for summation."}, - {"b", "RHS operand for summation."}}); - docstring::ClassMethodDocInject(m, "Calculator", "sub", - {{"a", "LHS operand for subtraction."}, - {"b", "RHS operand for subtraction."}}); +* Writing docstrings that render as expected can be tricky. The following example docstring points out some of the pitfalls to watch out for: + +.. tabs:: + + .. tab:: Docstring example + + .. literalinclude:: ./example_python_docstring.rst + :language: rest + + .. tab:: Rendered result + + .. image:: ../../_static/contribute/template_python_docstring.webp + :width: 800 + :alt: Rendered docstring + Case 3: When documenting pure Python code (no bindings) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/template_python_docstring.txt b/docs/contribute/example_python_docstring.rst similarity index 100% rename from docs/template_python_docstring.txt rename to docs/contribute/example_python_docstring.rst From 8eb79ab2e12a816cb1df7ad7f9f79468c3ebdd35 Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Mon, 9 Dec 2024 09:06:43 +0100 Subject: [PATCH 08/10] add sphinx-tabs and sphinx-copybutton --- docs/conf.py | 2 ++ docs/requirements.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 867fcae1423..eac752217c7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -67,6 +67,8 @@ def get_git_short_hash(): "sphinx.ext.autosummary", "sphinx.ext.napoleon", "sphinx.ext.todo", + "sphinx_tabs.tabs", + "sphinx_copybutton", "nbsphinx", "m2r2", ] diff --git a/docs/requirements.txt b/docs/requirements.txt index 144653773f8..d52283a5db3 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,6 +5,8 @@ m2r2==0.3.3.post2 matplotlib==3.7.3 nbsphinx==0.9.3 sphinx==7.1.2 +sphinx-tabs==3.4.7 +sphinx-copybutton==0.5.2 nbconvert==6.5.4 lxml==5.2.1 lxml_html_clean==0.4.0 From 6eddd31599b4eefdd50d009293a0fe8f0059d5b4 Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Mon, 9 Dec 2024 09:07:16 +0100 Subject: [PATCH 09/10] add missing blank line in docstring for tb summary --- python/open3d/visualization/tensorboard_plugin/summary.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/open3d/visualization/tensorboard_plugin/summary.py b/python/open3d/visualization/tensorboard_plugin/summary.py index 4a02e8e4cdc..8e35948b5be 100644 --- a/python/open3d/visualization/tensorboard_plugin/summary.py +++ b/python/open3d/visualization/tensorboard_plugin/summary.py @@ -575,6 +575,7 @@ def add_3d(name, data (dict): A dictionary of tensors representing 3D data. Tensorflow, PyTorch, Numpy and Open3D tensors are supported. The following keys are supported: + - ``vertex_positions``: shape `(B, N, 3)` where B is the number of point clouds and must be same for each key. N is the number of 3D points. Will be cast to ``float32``. From f94b58a5586f89af473655572c139d20e1b92d6e Mon Sep 17 00:00:00 2001 From: Benjamin Ummenhofer Date: Mon, 9 Dec 2024 10:01:10 +0100 Subject: [PATCH 10/10] rename image for rendered docstring --- ...docstring.webp => example_python_docstring.webp} | Bin docs/contribute/contribution_recipes.rst | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/_static/contribute/{template_python_docstring.webp => example_python_docstring.webp} (100%) diff --git a/docs/_static/contribute/template_python_docstring.webp b/docs/_static/contribute/example_python_docstring.webp similarity index 100% rename from docs/_static/contribute/template_python_docstring.webp rename to docs/_static/contribute/example_python_docstring.webp diff --git a/docs/contribute/contribution_recipes.rst b/docs/contribute/contribution_recipes.rst index bdb06100388..454aff99e25 100644 --- a/docs/contribute/contribution_recipes.rst +++ b/docs/contribute/contribution_recipes.rst @@ -234,7 +234,7 @@ Case 2: When documenting Python bindings .. tab:: Rendered result - .. image:: ../../_static/contribute/template_python_docstring.webp + .. image:: ../../_static/contribute/example_python_docstring.webp :width: 800 :alt: Rendered docstring