Skip to content

Commit 818bd57

Browse files
Documentation on developing this library (#68)
* Developing documentation * doc for adding new icp instance * update links * Move writing icp docs --------- Co-authored-by: Yey007 <55263178+Yey007@users.noreply.github.com> Co-authored-by: jesswang7 <jesswang172@gmail.com>
1 parent 0788790 commit 818bd57

6 files changed

Lines changed: 134 additions & 81 deletions

File tree

AUTHOR.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
This library was made by Ethan Uppal and Utku Melemetci.
1+
This library was made by Ethan Uppal, Jess Wang, and Utku Melemetci.

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,14 @@ This repository hosts CEV's implementation of Iterative Closest Points (ICP) as
1717
Please see [LICENSE](LICENSE). Note that all code is licensed under the MIT license, with the exception of some additions to `doxygen-style.css`. Files with copyright headers denoting specific copyright holders belong to said holders. Files under `book/asset` are from [doxygen_theme_flat_design](https://github.com/kcwongjoe/doxygen_theme_flat_design) under its MIT license (again with the exception of some additions to `doxygen-style.css`). Files without copyright headers are under the MIT license, Copyright (c) 2024-2025 Cornell Electric Vehicles.
1818

1919
## Install
20-
2120
You can view installation instructions at [INSTALL.md](INSTALL.md).
2221

2322
## Usage and Documentation
24-
2523
We host the usage information and documentation at [cornellev.github.io/icp/](https://cornellev.github.io/icp/).
2624
Please see there for information on how to download and how to use or extend the library.
2725

2826
You can build the documentation yourself locally with `make docs`.
2927
The main page will be located at `docs/index.html` relative to the project root.
3028

3129
## Versions
32-
3330
Version information can be found in the [releases](https://github.com/cornellev/icp/releases) page.

book/developing.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Developing
2+
3+
This document explains how to effectively develop `icp`. It covers development environment setup, the general repository structure, how to add new ICP methods, and how to add benchmarks and tests.
4+
5+
## Development environment
6+
7+
### Dependencies
8+
`libicp` itself can be built and installed with only Eigen as a dependency---this is by design. However, to effectively develop the project, you'll need a few extra things.
9+
10+
1. [libcmdapp2](https://github.com/cornellev/libcmdapp2), a command-line parsing library (built by Ethan) which we use for the 2D visualization.
11+
2. [sdl-wrapper](https://github.com/cornellev/sdl-wrapper), a C++ wrapper for SDL to make things easier for the visualization.
12+
3. [simple-test](https://github.com/cornellev/simple-test), a header-only testing library.
13+
4. [PCL](https://pointclouds.org/) 1.12.1 (ideally), a point cloud processing library. We actually only use this to parse 3D point clouds for testing.
14+
15+
Each of the links above should have installation instructions. If you have everything installed correctly, you should be able to [build](#building) the project and not have any errors.
16+
17+
### Tooling setup
18+
I'll mainly cover VSCode here as it's relatively popular, but other IDEs shouldn't be too difficult.
19+
20+
You'll need the [clangd](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd) and [clang-format](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format) extensions. You may also need to install `clang-format` itself. Please install at least version 19 as some of the rules depend on recent versions.
21+
22+
The build system, by default, will generate the `compile_commands.json` file that `cland` relies on. However, it will be in `build/`. To configure VSCode to pick up on this file, you can add the following to your `.vscode/settings.json`
23+
24+
```json
25+
{
26+
"clangd.arguments": [
27+
"-compile-commands-dir=build"
28+
],
29+
}
30+
```
31+
32+
## Repository structure
33+
```
34+
.
35+
├── bench - code for benchmarking
36+
├── book - documentation and files for the website
37+
├── common - common code across benches, tests, library, and vis
38+
├── ex_data
39+
│ ├── ply - .ply example data (3D)
40+
│ └── scan{n} - .csv example data (2D)
41+
├── include - library header files
42+
├── lib - library source files
43+
├── script - various utility scripts
44+
├── tests - unit test code
45+
└── vis - 2D visualization app
46+
```
47+
48+
A few things to note:
49+
1. `tests` also contains `test_ply.cpp`. This isn't really a test, but a program you can run to look at the output from aligning two `.ply` scans. We might want to mvoe this in the future.
50+
2. A lot of the library code is templated. So you may need to look in `include` for some of the core functionality.
51+
3. You'll probably be doing most of your work in `include` and `lib`. These are the core folders.
52+
53+
## Building
54+
`CMakeLists.txt` is the main build file. However, for convenience, there is a `Makefile` that shortens the `cmake` commands. Just typing `make` will build everything: the library, visualization, benchmarks, and tests.
55+
56+
There are some extra options you should be aware of. Setting `OPT=[Release | Debug]` (i.e. `make OPT=Release`) changes the optimization level. `USE_SANTIZERS=ON` will enable the address and undefined behavior sanitizers, which can be useful when debugging UB. `CI=ON` will run a CI build, which compiles with warnings as errors and enables the sanitizers.
57+
58+
Make sure to check the `Makefile` for other utilities you might find useful. You may be interested in `make tidy` and `make view`.
59+
60+
## Testing
61+
You can run `make test` to run the 2D tests and `make test_3d` to run the 3D tests. Ideally, in the future, we combine these into one executable, but we haven't done this yet.
62+
63+
### Adding Tests
64+
To add tests, you can follow the examples already in `test.cpp` and `test3d.cpp`. If you want to create a new test file, it's probably best that you refactor and bring all the tests under one executable.
65+
66+
## Benchmarking
67+
You can use `make bench` to run the benchmarks. They'll run 2D ICP on the example data. There are currently no 3D ICP benchmarks.
68+
69+
## Continuous Integration
70+
The CI system is defined in `.github/workflows/ci.yaml`. It's pretty standard: it just runs the tests on MacOS and Linux.

book/writing_icp.md

Lines changed: 61 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,90 @@
1-
<!--
2-
Copyright (C) 2025 Ethan Uppal.
3-
SPDX-License-Identifier: MIT
4-
--->
5-
\page write_icp_instance Writing an ICP Instance
1+
# Contributing: Adding a New ICP Instance
62

7-
\tableofcontents
3+
This section explains how to implement and document a new **ICP instance**.
84

9-
To write an ICP instance, create a C++ source file with at least the following:
5+
---
106

11-
1. A `final` class that inherits from `public icp::ICP`
12-
2. A static initialization variable (described below)
7+
## 1. Overview
138

14-
It is highly recommended you also provide documentation for your ICP instance in the format described here.
9+
An ICP instance is a specific implementation of the Iterative Closest Point algorithm. Each instance should be:
1510

16-
\section core_func_sec Core Functionality
11+
- A `final` C++ class that inherits from `icp::ICP`
12+
- Properly registered so users can instantiate it
1713

18-
The class must define the following behavior:
14+
---
1915

20-
- A constructor that calls the `icp::ICP` constructor
21-
- An overridden destructor (which may do nothing)
22-
- `void iterate() override`
16+
## 2. File and Class Requirements
2317

24-
In `iterate`, the point clouds are given by the instance variables `a` and `b`.
25-
There is also the `match` instance variable, allocated to have size `a.size()`, which cannot be assumed to contain any definite values.
26-
At the end of `iterate`, the `transform` instance variable should have been updated (although the update may be zero).
18+
Create a new `method_xd.cpp` file in `lib/icp/impl/`, and implement your instance class.
2719

28-
Optionally, the class can override:
20+
### Required
2921

30-
- `void setup() override`
22+
- Class must be `final` and inherit from `public icp::ICP`
23+
- Must implement `void iterate() override`
24+
- Must provide a constructor that calls the `icp::ICP` constructor
25+
- A destructor (can be empty)
3126

32-
`setup` is invoked upon the user call to `ICP::begin` after the internals of ICP have been readied.
27+
Example:
3328

34-
\section static_init_sec Static Initialization
29+
```cpp
30+
class MyICP final : public icp::ICP {
31+
public:
32+
MyICP();
33+
MyICP(const Config& config);
34+
~MyICP();
3535

36-
TODO: update -- we do this in icp.cpp now and the documentation builder will
37-
automatically search there.
36+
void setup() override; // Optional
37+
void iterate() override;
38+
};
39+
````
3840
39-
The static initialization is required so that users can instantiate your ICP instance.
40-
Define
41+
---
4142
42-
```cpp
43-
static bool static_initialization = []() {
44-
assert(ICP::register_method("name_of_instance", []() -> std::unique_ptr<ICP> {
45-
return std::make_unique<NameOfClass>();
46-
}));
47-
return true;
48-
}();
49-
```
43+
## 3. ICP Lifecycle
5044
51-
where `"name_of_instance"` is the name of your ICP implementation and `NameOfClass` is the name of the class.
45+
### Provided Instance Variables
5246
53-
\section icp_dpc_sec Documentation
47+
| Variable | Type | Description |
48+
| ----------- | ------------------ | ---------------------------------- |
49+
| `a` | `PointCloud` | Source point cloud |
50+
| `b` | `PointCloud` | Target point cloud |
51+
| `match` | `std::vector<int>` | Matches from `a` to `b` |
52+
| `transform` | `RBTransform` | Current accumulated transformation |
5453
55-
The script icp_doc_builder.py will automatically generate documentation for your ICP instances as markdown files and place them in a desired directory. The invocation format is:
54+
### Method Responsibilities
5655
57-
```shell
58-
python3 icp_doc_builder.py dir/where/your/icps/are/ dir/where/markdown/should/go/ where/main/file/is.md
59-
```
56+
| Method | When it is Called | What to Do |
57+
| ----------- | --------------------------- | ---------------------------------------------- |
58+
| `setup()` | Once before first iteration | Initialize resources (e.g. KD-tree) |
59+
| `iterate()` | Once per iteration | Compute correspondences and update `transform` |
6060
61-
Notably, `where/main/file/is.md` should contain two lines of the form
61+
---
6262
63-
```md
64-
<!-- ICP_DOCS_BUILDER EDIT MARKER START -->
65-
...
66-
<!-- ICP_DOCS_BUILDER EDIT MARKER END -->
67-
```
63+
## 4. Registration
6864
69-
the contents between which markers will be automatically updated by the
70-
documentation builder.
71-
72-
If the file name is `foo_bar.cpp`, then the Doxygen page reference (from which you can refer to from other pages) will be be `foo_bar_icp Foo_bar`. Information about the file should be encoded in special block comments of the following format.
65+
To allow users to select your ICP instance by name, add it to the static methods map in `ICP2` or `ICP3` in `icp.cpp`
7366
7467
```cpp
75-
/*
76-
#command values...
77-
*/
68+
#include "icp/impl/my_icp.h"
69+
70+
namespace icp {
71+
template<>
72+
std::unordered_map<std::string, ICPX::MethodConstructor> ICPX::methods{
73+
{"my_icp", CONSTRUCT_CONFIG(MyICP)}, // ← Register your method here
74+
};
75+
}
7876
```
7977
80-
Supported commands are described below.
81-
82-
- The name of the instance should be given by `/* #name Name of Instance */`.
83-
- An overview of the algorithm should be provided by `/* #desc Overview of algorithm. */`. This description will be rendered as Doxygen source, so you can use markdown and Doxygen commands such as `\ref`.
84-
- If your instance uses icp::ICP::Config parameters, document them as `/* #conf "name_of_param" This is a sentence. This is another sentence describing the parameter. */`. This description will be rendered as Doxygen source.
85-
- Every major step your instance takes should be documented by
86-
87-
```cpp
88-
/*
89-
#step My Step: brief description
90-
91-
Detailed explanation.
78+
---
9279
93-
Sources:
94-
https://www.example.com
95-
https://www.example.com
96-
https://www.example.com
97-
https://www.example.com
98-
*/
99-
```
80+
## 5. Examples
10081
101-
The `: brief description` section is optional, as are the detailed explanation and sources sections.
102-
These descriptions will be rendered as Doxygen source.
82+
See the following reference implementations:
10383
104-
See the source code of vanilla.cpp or trimmed.cpp as examples.
84+
| File | Type |
85+
| -------------------------------------------------------- | ---------|
86+
| [`vanilla.cpp`](/lib/icp/impl/vanilla.cpp) | 2d |
87+
| [`trimmed.cpp`](/lib/icp/impl/trimmed.cpp) | 2d |
88+
| [`feature_aware.cpp`](/lib/icp/impl/feature_aware.cpp) | 2d |
89+
| [`vanilla_3d.cpp`](/lib/icp/impl/vanilla_3d.cpp) | 3d |
90+
| [`trimmed_3d.cpp`](/lib/icp/impl/trimmed_3d.cpp) | 3d. |

include/icp/impl/trimmed_3d.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
namespace icp {
1414

15-
class Trimmed3d : public ICP3 {
15+
class Trimmed3d final : public ICP3 {
1616
public:
1717
Trimmed3d(const Config& config);
1818
Trimmed3d();

include/icp/impl/vanilla_3d.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
namespace icp {
1414

15-
class Vanilla3d : public ICP3 {
15+
class Vanilla3d final : public ICP3 {
1616
public:
1717
Vanilla3d(const Config& config);
1818
Vanilla3d();

0 commit comments

Comments
 (0)