Writing documentation¶
The site is MkDocs with the Material theme, built from docs/ by mkdocs.yml. Everything on it
is either written in docs/ or generated from the code on every build; nothing generated is
committed.
Building the site¶
pip install -r docs/requirements.txt
mkdocs serve # http://127.0.0.1:8000, rebuilt on every change
mkdocs build --strict # as CI does: a broken link or anchor fails the build
CI (.github/workflows/docs.yml) builds the site with --strict on every pull request and
deploys it from main, with the Doxygen C++ reference under /api/.
What is generated¶
docs/tools/gen_reference.py reads every components/<name>/wmtk/components/<name>/<name>_spec.json
and docs/components.yml, and writes, at build time:
reference/<name>.md: every option of the component, with its type, default and doc. The options inkey_options(components.yml) come first;DEBUG_,EXPERIMENTAL_andTESTING_options are folded away. Each option has an anchor: link to one as../reference/tetwild.md#eps_rel.reference/<name>_defaults.json: the options that have a default, with it.schemas/<name>.jsonandschemas/wmtk_app.json: JSON Schemas for editors (see JSON Schemas).- The reference's navigation: a new component appears on its own.
So the spec is the documentation of an option: improve an option's description by editing its
doc in the spec, and help(wildmeshing.<name>), wmtk_app --options <name> and the reference
change with it. gen_reference.py --check (run in CI) fails when a rule has no doc, when a spec
has no entry in components.yml, or when an entry names an option its spec does not have.
Examples¶
Every example on the site is a file under docs/examples/, included into pages, built and run
by the tests. A page never contains example code of its own that is not in one of these files.
| Directory | What | How it is tested |
|---|---|---|
docs/examples/json/<name>.json |
a wmtk_app input file |
copied into a directory with the meshes it names, run with wmtk_app -j |
docs/examples/python/<name>.py |
a script | run with python <name>.py in a directory of its own |
docs/examples/cpp/<name>.cpp |
a program | built as wmtk_doc_example_<name>, linking every component, and run |
All three are registered in ctest when CMake runs with -DWMTK_BUILD_DOC_EXAMPLES=ON (and
BUILD_TESTING), in Release builds only: doc_example_cpp_<name> for each program, and
doc_examples_python_json for the scripts and JSON files together
(tests/python/test_docs_examples.py).
Conventions, so that the files run the same from the repository root, in the tests and on a reader's machine:
-
Input meshes come from
data/models(the data repository, cloned by CMake when tests are enabled). Python and C++ read the directory from the environment variableWMTK_DATA, defaulting todata/models, so they run from the repository root as they are:const char* env = std::getenv("WMTK_DATA"); const std::filesystem::path data = env ? env : "data/models";A JSON file names its meshes by file name alone (
"input": "bunny.obj"):wmtk_appresolves input paths against the JSON file's directory (and writes outputs to the working directory), and the test copies the meshes there and runs in it. - Outputs go to the working directory, under names that say what they are (bunny_remeshed.msh). - Small and fast: an example takes seconds, a minute at most in Release. Pick a small mesh and options that keep the run short; a tutorial explains what to change for quality. - Sections: mark the part a page shows with snippet markers, and include it by name:octocat = wm.read_mesh(str(DATA / "Octocat.obj")) outputs, report = wm.qslim( {"input": "octocat", "target_rel": 0.1, "eps_rel": 0.002, "num_threads": 4}, {"octocat": octocat}, ) simplified = outputs["mesh"] print(len(octocat["V"]), "->", len(simplified["V"]), "vertices")A section name may not start with a digit (
[start:2d]fails the build;[start:two_d]works). Inside a fenced block on the page, with the language set (```python). Paths are relative to the repository root. Including a whole file (--8<-- "docs/examples/json/qslim.json") is right for JSON. - An example with a test of its own starts with# docs-example: tested by <test file>, andtest_docs_examples.pyskips it (the tracking tutorial's pipeline is one:tests/python/test_tracking_correspondences.py).
Run them while writing:
cmake -B build -DWMTK_BUILD_DOC_EXAMPLES=ON ...
cmake --build build --target wmtk_doc_example_qslim wmtk_app wildmeshing
ctest --test-dir build -R 'doc_example' --output-on-failure
Renderings¶
Pages show meshes in an interactive viewer, <wmtk-viewer> (docs/viewer, three.js, loaded on
every page): the input on the left, the output on the right, one camera; tet meshes with a cut
plane; cells colored by quality or by region. A page shows a gallery example by its id:
The examples are listed in docs/gallery/examples.yaml. Each runs a tutorial's JSON example
(json: qslim), a component on meshes of data/models (component, inputs, options), or a
pipeline, a function of docs/gallery/scenes.py that runs a workflow's script and returns the
meshes to show. docs/tools/build_gallery.py runs them through the Python bindings and writes
their assets to docs/gallery/assets/<id>/ (not committed: CI builds them, cached by the code
they depend on); --posters also takes a still of each, used before the viewer starts and in the
README. The gallery page is generated from the same list. To preview locally:
build_gallery.py --check (in CI) fails when a page names an example the list does not have.
The viewer's source is docs/viewer/src/wmtk-viewer.js; after changing it, rebuild the bundle
(npm install && npm run build in docs/viewer) and commit docs/assets/viewer/wmtk-viewer.min.js.
Keep the input on the left and the output on the right in every figure.
A tutorial page¶
One page per component, docs/tutorials/<name>.md, in this order:
- What it does, in a paragraph, and when to use it (and when another component fits better).
-
A first run, in three tabs over the same run, with the same options:
=== "Command line" ```json { "application": "qslim", "input": "Octocat.obj", "output": "octocat_qslim.obj", "target_rel": 0.1, "eps_rel": 0.002, "num_threads": 4 } ``` ```bash wmtk_app -j qslim.json ``` === "Python" ```python octocat = wm.read_mesh(str(DATA / "Octocat.obj")) outputs, report = wm.qslim( {"input": "octocat", "target_rel": 0.1, "eps_rel": 0.002, "num_threads": 4}, {"octocat": octocat}, ) simplified = outputs["mesh"] print(len(octocat["V"]), "->", len(simplified["V"]), "vertices") ``` === "C++" ```cpp wmtk::MeshMap meshes{{"octocat", wmtk::io::read_mesh(data / "Octocat.obj")}}; auto [outputs, report] = wmtk::components::qslim::qslim( {{"input", "octocat"}, {"target_rel", 0.1}, {"eps_rel", 0.002}, {"num_threads", 4}}, meshes); const wmtk::MeshData& simplified = outputs.at("mesh"); std::cout << meshes.at("octocat").V.rows() << " -> " << simplified.V.rows() << " vertices\n"; wmtk::io::write_mesh("octocat_qslim.msh", simplified); ```The tabs are linked across the site (
content.tabs.link): a reader who picks Python sees Python everywhere. 3. Key settings: the options in the component'skey_options, each with what it changes and when to change it, a link to its reference entry, and the numbers a reader needs (what the default does on the example, what a coarser or finer value gives). Measure them: run the example and say what came out. 4. Outputs: the files written, the fields on the mesh, what the report holds. 5. Recipes and pitfalls: what goes wrong in practice and what to do. 6. See also: the reference page, related tutorials, the paper.
Write in plain declarative sentences, present tense, without marketing. Numbers come from runs, not from memory: if a page says "about 1,000 faces", an example produced it.