diff --git a/README.md b/README.md index c9c8045..ed6708b 100644 --- a/README.md +++ b/README.md @@ -83,10 +83,10 @@ For more examples, see the [tutorials](https://heremaps.github.io/pptk/tutorial. ## Build pptk-revived contains C++ extensions (Qt viewer, k-d tree, normal estimator) -that must be compiled before packaging. The build process is: - -1. Compile C++ extensions with CMake -2. Package the compiled artifacts into a wheel +that are compiled with CMake. You don't run CMake yourself — the `setuptools` +build backend invokes it automatically while building the wheel (see the +`CMakeBuild` command in [`setup.py`](setup.py)), so a single `uv build` +produces a ready-to-install wheel. ### System requirements @@ -101,54 +101,67 @@ that must be compiled before packaging. The build process is: On Ubuntu/Debian: ```bash -sudo apt install build-essential cmake patchelf libtbb-dev libeigen3-dev qtbase5-dev libqt5opengl5-dev +sudo apt install build-essential cmake patchelf \ + libtbb-dev libeigen3-dev qtbase5-dev libqt5opengl5-dev libgl1-mesa-dev ``` -### Build with uv (recommended) +### Build a wheel ```bash -# 1. Compile C++ extensions -mkdir _cmake_build && cd _cmake_build -cmake .. -DCMAKE_BUILD_TYPE=Release -cmake --build . -- -j$(nproc) -cd .. +uv build # compiles the C++ + packages -> dist/ +uv pip install dist/pptk_revived-*.whl +``` -# 2. Package into a wheel (uv detects the pre-compiled .so files and skips cmake) -uv build +> **Run build/install commands from the repository root**, never from inside +> `_cmake_build/`. The CMake build copies a `setup.py` into `_cmake_build/`, so +> running `uv build` or `pip install .` from there builds a broken, stale +> package (you'll see CMake fail with *"source directory … does not appear to +> contain CMakeLists.txt"*). -# 3. Install the wheel -uv pip install dist/pptk_revived-*.whl +This is exactly what the release CI runs (`.github/workflows/build-wheels.yml`). +Plain pip works the same way, since it uses the same backend: + +```bash +pip install . # build C++ and install +python -m build # or only build the wheel + sdist into dist/ ``` -### Build with pip / venv +> **Forcing a recompile.** To avoid needless work, the build **skips CMake when +> the compiled artifacts already exist** in the source tree. After editing any +> C++ source, set `PPTK_FORCE_CMAKE=1` to clear the cached artifacts and rebuild +> from scratch: +> +> ```bash +> PPTK_FORCE_CMAKE=1 uv build +> ``` + +### Development install (editable) ```bash -# 1. Create a venv -python3 -m venv venv && source venv/bin/activate -pip install numpy - -# 2. Compile C++ extensions -mkdir _cmake_build && cd _cmake_build -cmake .. -DCMAKE_BUILD_TYPE=Release -DPython3_EXECUTABLE=$(which python) -cmake --build . -- -j$(nproc) -cd .. - -# 3. Package and install -python setup.py bdist_wheel -pip install dist/pptk_revived-*.whl --force-reinstall +uv sync # set up the dev env + editable install +# after changing C++ sources, force a recompile: +PPTK_FORCE_CMAKE=1 uv pip install -e . ``` -### Windows +While iterating on C++ you can recompile a single target and refresh the +in-tree artifact the editable install loads, instead of rebuilding everything +(after an initial build has configured `_cmake_build/`): -```bat -mkdir _cmake_build && cd _cmake_build -cmake -G "NMake Makefiles" .. -nmake -cd .. -python setup.py bdist_wheel -pip install dist\pptk_revived-*.whl +```bash +cmake --build _cmake_build --target viewer -- -j$(nproc) +cp _cmake_build/pptk/viewer/viewer pptk/viewer/viewer ``` +Available targets: `viewer`, `kdtree`, `vfuncs`, `estimate_normals` (for the +library modules, copy the resulting `.so` into the matching `pptk//` +directory). + +### Windows + +The same `uv build` command applies. Make sure Qt5, TBB, and Eigen are +discoverable by CMake (e.g. via `CMAKE_PREFIX_PATH`); CMake selects the Visual +Studio generator by default. + ## Acknowledgements Originally developed by [HERE Europe B.V.](https://github.com/heremaps) (Copyright 2011–2018). diff --git a/docs/source/conf.py b/docs/source/conf.py index 1a66cb0..d33b9e1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -67,9 +67,9 @@ def setup(app): # built documents. # # The short X.Y version. -version = u'0.1' +version = u'0.3' # The full version, including alpha/beta/rc tags. -release = u'0.1.1' +release = u'0.3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pptk/__init__.py b/pptk/__init__.py index f8bcc74..e8edacf 100644 --- a/pptk/__init__.py +++ b/pptk/__init__.py @@ -9,7 +9,7 @@ from .colors import label_to_colors from .ply import load_ply -__version__ = '0.1.1' +__version__ = '0.3.0' connect = viewer.connect diff --git a/pptk/viewer/point_cloud.h b/pptk/viewer/point_cloud.h index 6e5f3a9..e5aa57d 100644 --- a/pptk/viewer/point_cloud.h +++ b/pptk/viewer/point_cloud.h @@ -201,7 +201,12 @@ class PointCloud : protected OpenGLFuncs { // render methods void draw(const QtCamera& camera, const SelectionBox* box = NULL) { - queryLOD(_octree_ids, camera, 0.25f); + // Coarse (interactive) LOD. Lower fudge_factor collapses octree nodes into + // large world-space centroid splats sooner; the fine pass uses 1.0f. A + // value too far below 1.0f makes points balloon during interaction and then + // visibly snap smaller once the fine pass runs. 0.5f keeps interaction fast + // while halving that size jump. + queryLOD(_octree_ids, camera, 0.5f); if (_octree_ids.empty()) return; draw(&_octree_ids[0], (unsigned int)_octree_ids.size(), camera, box); } diff --git a/pptk/viewer/viewer.h b/pptk/viewer/viewer.h index 6e4de90..f58ae52 100644 --- a/pptk/viewer/viewer.h +++ b/pptk/viewer/viewer.h @@ -256,13 +256,18 @@ class Viewer : public QWindow, protected OpenGLFuncs { _camera.zoom(ev->angleDelta().y() / 120.0f); _camera.save(); renderPoints(); - renderPointsFine(500); + // Debounce the fine render so continuous scrolling stays on the fast coarse + // pass, but correct quickly once scrolling stops (was 500ms, which left the + // large coarse splats on screen long enough to look like a glitch). + renderPointsFine(100); } virtual void exposeEvent(QExposeEvent* ev) { Q_UNUSED(ev); renderPoints(); - renderPointsFine(1000); + // Coalesce expose storms (show/uncover/move) without holding the oversized + // coarse splats for a full second after the window settles (was 1000ms). + renderPointsFine(200); } virtual void resizeEvent(QResizeEvent* ev) { diff --git a/pyproject.toml b/pyproject.toml index d736b5e..9aba14d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pptk-revived" -version = "0.2.0" +version = "0.3.0" requires-python = ">=3.9" dependencies = ["numpy<2", "pillow", "scikit-learn"] description = "A Python package for facilitating point cloud processing." diff --git a/setup.py b/setup.py index 7d426ba..c496e79 100644 --- a/setup.py +++ b/setup.py @@ -168,7 +168,7 @@ def list_libs(): setup( name='pptk-revived', - version='0.1.1', + version='0.3.0', description='A Python package for facilitating point cloud processing.', author='Nikolaas Steenbergen', classifiers=[