diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 45d2179fb6c1..106a9bbd9245 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -18,3 +18,5 @@ To get an auto-generated PR description you can put "copilot:summary" or "copilo PR Build Summary: {{ pr-build-summary }} + + diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml new file mode 100644 index 000000000000..c3080ab886f8 --- /dev/null +++ b/.github/workflows/documentation.yaml @@ -0,0 +1,35 @@ +name: Documentation + +on: + pull_request: + push: + branches: + - "main" + +permissions: + contents: read + +jobs: + spellcheck: + name: Spellcheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: streetsidesoftware/cspell-action@v2 + with: + config: "docs/cspell.json" + files: "docs/**/*.md" + linkinator: + name: linkinator + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: jprochazk/linkinator-action@main + with: + paths: "docs/**/*.md" + linksToSkip: "https://crates.io/crates/rerun" + retry: true + retryErrors: true + retryErrorsCount: 5 + retryErrorsJitter: 2000 + diff --git a/.github/workflows/manual_adhoc_web.yml b/.github/workflows/manual_adhoc_web.yml index 30296bb0f34a..9e0b713bc8ab 100644 --- a/.github/workflows/manual_adhoc_web.yml +++ b/.github/workflows/manual_adhoc_web.yml @@ -45,6 +45,7 @@ jobs: MARK_TAGGED_VERSION: false ADHOC_NAME: ${{ github.event.inputs.ADHOC_NAME }} RRD_ARTIFACT_NAME: linux-rrd-fast + UPLOAD_COMMIT: false secrets: inherit build-web-demo-adhoc: @@ -65,4 +66,5 @@ jobs: MARK_PRERELEASE_FOR_MAINLINE: false MARK_TAGGED_VERSION: false ADHOC_NAME: ${{ github.event.inputs.ADHOC_NAME }} + UPLOAD_COMMIT: false secrets: inherit diff --git a/.github/workflows/manual_build_release.yml b/.github/workflows/manual_build_release.yml index 171cc75ea079..4fa458534114 100644 --- a/.github/workflows/manual_build_release.yml +++ b/.github/workflows/manual_build_release.yml @@ -113,6 +113,26 @@ jobs: RRD_ARTIFACT_NAME: linux-rrd RELEASE_VERSION: ${{ github.event.inputs.RELEASE_VERSION }} secrets: inherit + + build-web-demo: + name: 'Build Web Demo' + needs: [build-linux, build-web] + uses: ./.github/workflows/reusable_build_web_demo.yml + with: + CONCURRENCY: manual-dispatch-${{ github.run_id}} + WHEEL_ARTIFACT_NAME: linux-wheel + secrets: inherit + + upload-web-demo: + name: 'Upload Web' + needs: [build-web-demo] + uses: ./.github/workflows/reusable_upload_web_demo.yml + with: + CONCURRENCY: manual-dispatch-${{ github.run_id}} + MARK_PRERELEASE_FOR_MAINLINE: false + MARK_TAGGED_VERSION: true + RELEASE_VERSION: ${{ github.event.inputs.RELEASE_VERSION }} + secrets: inherit generate-wheel-index: name: 'Generate Pip Index' diff --git a/.github/workflows/manual_dispatch.yml b/.github/workflows/manual_dispatch.yml index 8c490883506b..af5fa67c1ef1 100644 --- a/.github/workflows/manual_dispatch.yml +++ b/.github/workflows/manual_dispatch.yml @@ -36,16 +36,10 @@ on: default: 'linux' BUILD_WEB: - description: 'Run reusable_build_web' - type: boolean - required: false - default: true - - BUILD_WEB_DEMO: - description: 'Run reusable_build_web' - type: boolean + description: 'Run reusable_build_web/reusable_build_web_demo (Full build: app,demo)' + type: string required: false - default: true + default: 'app,demo' RELEASE_VERSION: description: 'Release Version Number (Must match Cargo.toml)' @@ -218,7 +212,7 @@ jobs: build-web: name: 'Build Web' - if: ${{ github.event.inputs.BUILD_WEB == 'true'}} + if: ${{ contains(github.event.inputs.BUILD_WEB, 'app') }} uses: ./.github/workflows/reusable_build_web.yml with: CONCURRENCY: manual-dispatch-${{ github.run_id}} @@ -228,7 +222,7 @@ jobs: upload-web: name: 'Upload Web' needs: [min-test-wheel, build-web] - if: ${{ (github.event.inputs.BUILD_WEB == 'true') && (github.event.inputs.UPLOAD_GCLOUD == 'true') }} + if: ${{ contains(github.event.inputs.BUILD_WEB, 'app') && (github.event.inputs.UPLOAD_GCLOUD == 'true') }} uses: ./.github/workflows/reusable_upload_web.yml with: CONCURRENCY: manual-dispatch-${{ github.run_id}} @@ -240,7 +234,7 @@ jobs: build-web-demo: name: 'Build Web Demo' needs: [min-test-wheel, build-web] - if: ${{ github.event.inputs.BUILD_WEB_DEMO == 'true'}} + if: ${{ contains(github.event.inputs.BUILD_WEB, 'demo') }} uses: ./.github/workflows/reusable_build_web_demo.yml with: CONCURRENCY: manual-dispatch-${{ github.run_id}} @@ -250,7 +244,7 @@ jobs: upload-web-demo: name: 'Upload Web Demo' needs: [build-web-demo] - if: ${{ (github.event.inputs.BUILD_WEB_DEMO == 'true') && (github.event.inputs.UPLOAD_GCLOUD == 'true') }} + if: ${{ contains(github.event.inputs.BUILD_WEB, 'demo') && (github.event.inputs.UPLOAD_GCLOUD == 'true') }} uses: ./.github/workflows/reusable_upload_web_demo.yml with: CONCURRENCY: manual-dispatch-${{ github.run_id}} diff --git a/.github/workflows/manual_release.yml b/.github/workflows/manual_release.yml index 7d34ebe2ade5..c5d6926cf09e 100644 --- a/.github/workflows/manual_release.yml +++ b/.github/workflows/manual_release.yml @@ -91,4 +91,8 @@ jobs: generateReleaseNotes: true allowUpdates: true draft: true + + - name: Release Web Demo + run: | + gsutil -m cp -r "gs://rerun-demo/commit/${{ env.SHORT_SHA }}/*" "gs://rerun-demo/version/latest/" diff --git a/.github/workflows/on_pull_request.yml b/.github/workflows/on_pull_request.yml index afddc5531171..a8b2ff16b04b 100644 --- a/.github/workflows/on_pull_request.yml +++ b/.github/workflows/on_pull_request.yml @@ -81,3 +81,11 @@ jobs: CONCURRENCY: pr-${{ github.event.pull_request.number }} PR_NUMBER: ${{ github.event.pull_request.number }} secrets: inherit + + link-docs: + name: 'Link Docs' + uses: ./.github/workflows/reusable_pr_link_docs.yml + with: + CONCURRENCY: pr-${{ github.event.pull_request.number }} + PR_NUMBER: ${{ github.event.pull_request.number }} + secrets: inherit diff --git a/.github/workflows/on_push_main.yml b/.github/workflows/on_push_main.yml index ceb0ad653287..e69f410b5c91 100644 --- a/.github/workflows/on_push_main.yml +++ b/.github/workflows/on_push_main.yml @@ -60,7 +60,7 @@ jobs: secrets: inherit upload-web-demo: - name: 'Upload Web' + name: 'Upload Web Demo' needs: [build-web-demo] uses: ./.github/workflows/reusable_upload_web_demo.yml with: diff --git a/.github/workflows/reusable_build_and_test_wheels.yml b/.github/workflows/reusable_build_and_test_wheels.yml index cf856df4f47b..fea97a4ec62d 100644 --- a/.github/workflows/reusable_build_and_test_wheels.yml +++ b/.github/workflows/reusable_build_and_test_wheels.yml @@ -170,10 +170,10 @@ jobs: run: ./scripts/setup_web.sh # The first steps of setup_web.sh, for Windows: - - name: Install wasm32 and wasm-bindgen-cli for building the web-viewer Wasm on windows + - name: Install wasm32 cargo target for building the web-viewer Wasm on windows if: inputs.platform == 'windows' shell: bash - run: rustup target add wasm32-unknown-unknown && cargo install wasm-bindgen-cli --version 0.2.86 + run: rustup target add wasm32-unknown-unknown # The last step of setup_web.sh, for Windows. # Since 'winget' is not available within the GitHub runner, we download the package directly: @@ -243,7 +243,7 @@ jobs: # TODO(jleibs): understand why deps can't be installed in the same step as the wheel shell: bash run: | - pip install deprecated numpy>=1.23 pyarrow==10.0.1 pytest==7.1.2 + pip install deprecated numpy>=1.23 pillow>=9.5.0 pyarrow==10.0.1 pytest==7.1.2 - name: Install built wheel if: needs.set-config.outputs.RUN_TESTS == 'true' @@ -278,9 +278,9 @@ jobs: id: dataset uses: actions/cache@v3 with: - path: examples/python/colmap/dataset/ + path: examples/python/structure_from_motion/dataset/ # TODO(jleibs): Derive this key from the invocation below - key: colmap-dataset-colmap-fiat-v0 + key: structure-from-motion-dataset-structure-from-motion-fiat-v1 - name: Generate Embedded RRD file if: needs.set-config.outputs.RUN_TESTS == 'true' @@ -288,8 +288,8 @@ jobs: # If you change the line below you should almost definitely change the `key:` line above by giving it a new, unique name run: | mkdir rrd - pip install -r examples/python/colmap/requirements.txt - python3 examples/python/colmap/main.py --dataset colmap_fiat --resize 800x600 --save rrd/colmap_fiat.rrd + pip install -r examples/python/structure_from_motion/requirements.txt + python3 examples/python/structure_from_motion/main.py --dataset colmap_fiat --resize 800x600 --save rrd/colmap_fiat.rrd # All platforms are currently creating the same rrd file, upload one of them - name: Save RRD artifact diff --git a/.github/workflows/reusable_pr_link_docs.yml b/.github/workflows/reusable_pr_link_docs.yml new file mode 100644 index 000000000000..04c9da2d09ed --- /dev/null +++ b/.github/workflows/reusable_pr_link_docs.yml @@ -0,0 +1,49 @@ +name: Reusable PR Link Docs + +on: + workflow_call: + inputs: + CONCURRENCY: + required: true + type: string + PR_NUMBER: + required: true + type: string + +concurrency: + group: ${{ inputs.CONCURRENCY }}-pr-summary + cancel-in-progress: true + +jobs: + pr-link-docs: + name: Link to docs preview in PR + + permissions: + contents: "read" + id-token: "write" + pull-requests: "write" + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + + - name: Install deps + run: pip install PyGithub # NOLINT + + - name: Link to docs + run: | + python scripts/pr_link_docs.py \ + --github-token ${{ secrets.GITHUB_TOKEN }} \ + --github-repository ${GITHUB_REPOSITORY} \ + --pr-number ${{ inputs.PR_NUMBER }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ inputs.PR_NUMBER }} + diff --git a/.github/workflows/reusable_upload_web.yml b/.github/workflows/reusable_upload_web.yml index 41bcd4896d11..86122112f617 100644 --- a/.github/workflows/reusable_upload_web.yml +++ b/.github/workflows/reusable_upload_web.yml @@ -32,6 +32,10 @@ on: required: false type: string default: '' + UPLOAD_COMMIT: + required: false + type: boolean + default: true concurrency: group: ${{ inputs.CONCURRENCY }}-upload-web @@ -80,6 +84,7 @@ jobs: echo "SHORT_SHA=$(echo $USED_SHA | cut -c1-7)" >> $GITHUB_ENV - name: "Upload web-viewer (commit)" + if: ${{ inputs.UPLOAD_COMMIT }} uses: google-github-actions/upload-cloud-storage@v1 with: path: "web_viewer" @@ -87,6 +92,7 @@ jobs: parent: false - name: "Upload RRD (commit)" + if: ${{ inputs.UPLOAD_COMMIT }} uses: google-github-actions/upload-cloud-storage@v1 with: path: "rrd" diff --git a/.github/workflows/reusable_upload_web_demo.yml b/.github/workflows/reusable_upload_web_demo.yml index 37975702317e..57b5eec72b56 100644 --- a/.github/workflows/reusable_upload_web_demo.yml +++ b/.github/workflows/reusable_upload_web_demo.yml @@ -28,6 +28,10 @@ on: required: false type: string default: '' + UPLOAD_COMMIT: + required: false + type: boolean + default: true concurrency: group: ${{ inputs.CONCURRENCY }}-upload-web-demo @@ -69,6 +73,7 @@ jobs: echo "SHORT_SHA=$(echo $USED_SHA | cut -c1-7)" >> $GITHUB_ENV - name: "Upload web demo (commit)" + if: ${{ inputs.UPLOAD_COMMIT }} uses: google-github-actions/upload-cloud-storage@v1 with: path: "web_demo" @@ -90,14 +95,6 @@ jobs: path: "web_demo" destination: "rerun-demo/version/${{inputs.RELEASE_VERSION}}" parent: false - - - name: "Upload web demo (latest)" - if: inputs.MARK_TAGGED_VERSION - uses: google-github-actions/upload-cloud-storage@v1 - with: - path: "web_demo" - destination: "rerun-demo/version/latest" - parent: false - name: "Upload web demo (adhoc)" if: ${{ inputs.ADHOC_NAME != '' }} diff --git a/.mypy.ini b/.mypy.ini index 3975c2924ca1..2a8a952bee28 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -1,6 +1,6 @@ [mypy] files = rerun_py/rerun_sdk/rerun, rerun_py/tests, examples/python -exclude = examples/python/objectron/proto|examples/python/ros +exclude = examples/python/objectron/proto|examples/python/ros_node namespace_packages = True show_error_codes = True strict = True diff --git a/BUILD.md b/BUILD.md index 93b712dd1b20..01243da94528 100644 --- a/BUILD.md +++ b/BUILD.md @@ -11,17 +11,23 @@ This is a guide to how to build Rerun. * [`RELEASES.md`](RELEASES.md) -## Getting started with the repository. -* Install the Rust toolchain: -* `git clone git@github.com:rerun-io/rerun.git && cd rerun` -* Run `./scripts/setup_dev.sh`. -* Make sure `cargo --version` prints `1.69.0` once you are done +## Getting started with the repository -All Rust examples are separate executable projections. Meaning to run them you specify the package, e.g. `cargo run -p dna`. +First, install the Rust toolchain using the installer from . -You can type `cargo rerun` to compile and run the `rerun` binary with most features enabled, thanks to a shortcut in `.cargo/config.toml`. +Then, clone the repository: +```sh +git clone git@github.com:rerun-io/rerun.git +cd rerun +``` + +Finally, run the following script to install the dependencies and CLI tools needed for Rerun's build environment: + +```sh +./scripts/setup_dev.sh +``` -### Apple-silicon Macs +Make sure `cargo --version` prints `1.69.0` once you are done. If you are using an Apple-silicon Mac (M1, M2), make sure `rustc -vV` outputs `host: aarch64-apple-darwin`. If not, this should fix it: @@ -29,54 +35,91 @@ If you are using an Apple-silicon Mac (M1, M2), make sure `rustc -vV` outputs `h rustup set default-host aarch64-apple-darwin && rustup install 1.69.0 ``` -## Building the docs +## Building and running the viewer -High-level documentation for rerun can be found at [http://rerun.io/docs](http://rerun.io/docs). It is built from the separate repository [rerun-docs](https://github.com/rerun-io/rerun-docs). +Use this command for building and running the viewer: -Python API docs can be found at and are built via `mkdocs` and hosted on GitHub. For details on the python doc-system, see [Writing Docs](https://github.com/rerun-io/rerun/blob/main/rerun_py/docs/writing_docs.md). +```sh +cargo rerun +``` -Rust documentation is hosted on . You can build them locally with: `cargo doc --all-features --no-deps --open` +This custom cargo command is enabled by an alias located in `.cargo/config.toml`. + + +## Running the Rust examples + +All Rust examples are set up as separate executables, so they can be run by specifying the corresponding package, for example: + +```sh +cargo run -p dna +``` + + +## Building and installing the Rerun Python SDK + +Rerun is available as a package on PyPi and can be installed with `pip install rerun-sdk`. + +Additionally, prebuilt dev wheels from head of main are available at . -## Build and install the Rerun Python SDK -Rerun is available as a package on PyPi and can be installed with `pip install rerun-sdk` +If you want to build from source, use the following instructions. -Additionally, prebuilt dev wheels from head of main are available at . +### Mac/Linux -However, if you want to build from source you can follow the instructions below. +First, a local virtual environment must be created and the necessary dependencies installed (this needs to be done only once): -### Set up virtualenv +```sh +just py-dev-env +``` -Mac/Linux: +Then, the SDK can be compiled and installed in the virtual environment using the following command: + +```sh +just py-build +``` + +This needs to be repeated each time the Rust source code is updated, for example after updating your clone using `git pull`. + +Finally, the virtual environment must be activated to run Python examples: ```sh -python3 -m venv venv # Rerun supports Python version >= 3.7 source venv/bin/activate -python -m pip install --upgrade pip # We need pip version >=21.3 +python examples/python/car/main.py ``` -Windows (powershell): +### Windows (PowerShell) + +The `justfile` currently doesn't support Windows, so each step must be run manually. + +First, create and activate a local virtual environment and install the required dependencies using the following commands: ```ps1 python -m venv venv .\venv\Scripts\Activate.ps1 python -m pip install --upgrade pip +python -m pip install -r scripts/requirements-dev.txt ``` -From here on out, we assume you have this virtualenv activated. +Then build and install the Rerun SDK with: -### Build and install - -You need to setup your build environment once with -```sh -./scripts/setup.sh +```ps1 +maturin develop \ + --manifest-path rerun_py/Cargo.toml \ + --extras="tests" ``` -Then install the Rerun SDK with: -``` -pip install ./rerun_py +You can then run the example using the following command: + +```ps1 +python examples/python/car/main.py ``` -> Note: If you are unable to upgrade pip to version `>=21.3`, you need to pass `--use-feature=in-tree-build` to the `pip install` command. +## Building the docs + +High-level documentation for rerun can be found at [http://rerun.io/docs](http://rerun.io/docs). It is built from the separate repository [rerun-docs](https://github.com/rerun-io/rerun-docs). + +Python API docs can be found at and are built via `mkdocs` and hosted on GitHub. For details on the python doc-system, see [Writing Docs](https://github.com/rerun-io/rerun/blob/main/rerun_py/docs/writing_docs.md). + +Rust documentation is hosted on . You can build them locally with: `cargo doc --all-features --no-deps --open` ## Building for the Web @@ -95,7 +138,7 @@ cargo run -p re_build_web_viewer -- --release ### Building with WebGPU support -By default all web builds are using WebGL for rendering. +By default, all web builds are using WebGL for rendering. However, Rerun can also build with experimental WebGPU support! Note that currently we can't build wasm files that support both WebGPU and WebGL. @@ -114,7 +157,7 @@ cargo run -p re_build_web_viewer -- --release --webgpu As of today, we link everything statically in both debug and release builds, which makes custom linkers and split debuginfo the two most impactful tools we have at our disposal in order to improve compile times. -These tools can configured through your `Cargo` configuration, available at `$HOME/.cargo/config.toml`. +These tools can be configured through your `Cargo` configuration, available at `$HOME/.cargo/config.toml`. ### macOS diff --git a/CHANGELOG.md b/CHANGELOG.md index f7e7f7c5d627..200d629e37d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## [Unreleased](https://github.com/rerun-io/rerun/compare/latest...HEAD) -## [0.6.0](https://github.com/rerun-io/rerun/compare/v0.5.0...v0.6.0) - 3D in 2D ands SDK batching + +## [0.6.0](https://github.com/rerun-io/rerun/compare/v0.5.1...v0.6.0) - 3D in 2D and SDK batching - 2023-05-26 ### Overview & Highlights @@ -16,7 +17,6 @@ ### In Detail - #### 🐍 Python SDK - ⚠️ BREAKING: You must now call `rr.init` if you want logging to work. - ⚠️ BREAKING: `set_enabled` has been removed. @@ -86,6 +86,7 @@ - Optimize GLTF/GLB texture loading in debug builds [#2096](https://github.com/rerun-io/rerun/pull/2096) - Premultiply the alpha on the GPU [#2190](https://github.com/rerun-io/rerun/pull/2190) - Switch compression algorithm from zstd to lz4 [#2112](https://github.com/rerun-io/rerun/pull/2112) +- Support RRD streams with and without compression. Turn off for SDK comms [#2219](https://github.com/rerun-io/rerun/pull/2219) #### 🧑‍🏫 Examples - Join threads at end of multi-threading example [#1934](https://github.com/rerun-io/rerun/pull/1934) @@ -99,7 +100,6 @@ - Fix glb mesh data set downloads [#2100](https://github.com/rerun-io/rerun/pull/2100) - Add more examples to https://app.rerun.io/ [#2062](https://github.com/rerun-io/rerun/pull/2062) - #### 🖼 UI Improvements - Update egui to latest and wgpu to 0.16 [#1958](https://github.com/rerun-io/rerun/pull/1958) - Add keyboard shortcut for "Follow", and stop following on "Restart" [#1986](https://github.com/rerun-io/rerun/pull/1986) (thanks [@h3mosphere](https://github.com/h3mosphere)!) @@ -110,7 +110,6 @@ - Nicer (& fixed up) help texts for space views [#2070](https://github.com/rerun-io/rerun/pull/2070) - Allow dragging time cursor in plots [#2115](https://github.com/rerun-io/rerun/pull/2115) - #### 🕸️ Web - Set the GC limit to 2.5GB on web [#1944](https://github.com/rerun-io/rerun/pull/1944) - Better crash reports on Web, plus WebGPU support detection [#1975](https://github.com/rerun-io/rerun/pull/1975) @@ -140,8 +139,6 @@ - Update minimum supported Rust version to `1.69.0` [#1935](https://github.com/rerun-io/rerun/pull/1935) - Allow users to select the bind address (ip) to use with `--bind` [#2159](https://github.com/rerun-io/rerun/pull/2159) - - #### 🧑‍💻 Dev-experience - Suggest users open an issue on crash, and other fixes [#1993](https://github.com/rerun-io/rerun/pull/1993) - Lint error names in `map_err` [#1948](https://github.com/rerun-io/rerun/pull/1948) @@ -216,7 +213,8 @@ This Release fixes a few small bugs on top of the v0.5.0 release. * Don't use console.error [#1984](https://github.com/rerun-io/rerun/pull/1984) * Fix failure to save files when split table contains no data [#2007](https://github.com/rerun-io/rerun/pull/2007) -## [0.5.0](https://github.com/rerun-io/rerun/compare/v0.4.0...v0.5.0) - Jupyter MVP, GPU-based picking & colormapping, new datastore! + +## [0.5.0](https://github.com/rerun-io/rerun/compare/v0.4.0...v0.5.0) - Jupyter MVP, GPU-based picking & colormapping, new datastore! - 2023-04-20 ### Overview & Highlights @@ -354,8 +352,6 @@ This new release adds MVP support for embedding Rerun in Jupyter notebooks, and - Datastore revamp 7: garbage collection [#1801](https://github.com/rerun-io/rerun/pull/1801) - Incremental metadata registry stats [#1833](https://github.com/rerun-io/rerun/pull/1833) -#### ✨ Other Enhancement - #### 🗣 Merged RFCs - RFC: datastore state of the union & end-to-end batching [#1610](https://github.com/rerun-io/rerun/pull/1610) @@ -387,10 +383,10 @@ This new release adds MVP support for embedding Rerun in Jupyter notebooks, and - `just rs-run-all` [b14087b40bd805c95f030a4c7d3fb7a0482e13f4](https://github.com/rerun-io/rerun/commit/b14087b40bd805c95f030a4c7d3fb7a0482e13f4) - `just py-run-all-{native|web|rrd}` [#1927](https://github.com/rerun-io/rerun/pull/1927) -## [0.4.0](https://github.com/rerun-io/rerun/compare/v0.3.1...v0.4.0) - Outlines, web viewer and performance improvements -https://user-images.githubusercontent.com/1220815/228241887-03b311e2-80e9-4541-9281-6d334a15ab04.mp4 +## [0.4.0](https://github.com/rerun-io/rerun/compare/v0.3.1...v0.4.0) - Outlines, web viewer and performance improvements - 2023-03-28 +https://user-images.githubusercontent.com/1220815/228241887-03b311e2-80e9-4541-9281-6d334a15ab04.mp4 ### Overview & Highlights * Add support for mesh vertex colors [#1671](https://github.com/rerun-io/rerun/pull/1671) @@ -562,12 +558,12 @@ We now host an experimental and unpolished web-viewer at - Lint fixes [9901e7c6735356b1970ddabc926bc5378d82e057](https://github.com/rerun-io/rerun/commit/9901e7c6735356b1970ddabc926bc5378d82e057) -## [0.3.1](https://github.com/rerun-io/rerun/compare/v0.3.0...v0.3.1) - Remove potentially sensitive analytics +## [0.3.1](https://github.com/rerun-io/rerun/compare/v0.3.0...v0.3.1) - Remove potentially sensitive analytics - 2023-03-13 Remove potentially sensitive analytics, including path to rerun source code on panics, and rerun branch name when building from source [#1563](https://github.com/rerun-io/rerun/pull/1563) -## [0.3.0](https://github.com/rerun-io/rerun/compare/v0.2.0...v0.3.0) +## [0.3.0](https://github.com/rerun-io/rerun/compare/v0.2.0...v0.3.0) - 2023-03-07 ### Overview & Highlights After a successful launch a couple of weeks ago, we're back with our second release! @@ -726,5 +722,5 @@ Meanwhile, we did a bunch of improvements to our manual. If you had trouble runn [Full Changelog](https://github.com/rerun-io/rerun/compare/v0.2.0...v0.3.0) -## 0.2.0 +## 0.2.0 - 2023-02-14 First public release! diff --git a/Cargo.lock b/Cargo.lock index 5233077f37db..5e52a72dda66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1667,6 +1667,17 @@ dependencies = [ "web-sys", ] +[[package]] +name = "extend_viewer_ui" +version = "0.6.0" +dependencies = [ + "mimalloc", + "re_crash_handler", + "re_sdk_comms", + "re_viewer", + "tokio", +] + [[package]] name = "fastrand" version = "1.9.0" @@ -3179,6 +3190,7 @@ dependencies = [ "glam", "prost", "prost-build", + "protoc-prebuilt", "rerun", ] @@ -3631,6 +3643,16 @@ dependencies = [ "prost", ] +[[package]] +name = "protoc-prebuilt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37aee930fb53074ec083bf049aa6133bb1a93cce8fc39f83e07f36a0937304dd" +dependencies = [ + "ureq", + "zip", +] + [[package]] name = "puffin" version = "0.15.0" @@ -3823,7 +3845,7 @@ dependencies = [ [[package]] name = "re_analytics" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "crossbeam", @@ -3844,7 +3866,7 @@ dependencies = [ [[package]] name = "re_arrow_store" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "anyhow", @@ -3871,7 +3893,7 @@ dependencies = [ [[package]] name = "re_build_build_info" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "cargo_metadata", @@ -3881,18 +3903,33 @@ dependencies = [ [[package]] name = "re_build_info" -version = "0.6.0" +version = "0.7.0" [[package]] name = "re_build_web_viewer" -version = "0.6.0" +version = "0.7.0" dependencies = [ + "anyhow", "cargo_metadata", + "re_error", + "wasm-bindgen-cli-support", +] + +[[package]] +name = "re_crash_handler" +version = "0.7.0" +dependencies = [ + "backtrace", + "itertools", + "libc", + "parking_lot 0.12.1", + "re_analytics", + "re_build_info", ] [[package]] name = "re_data_store" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "criterion", @@ -3915,7 +3952,7 @@ dependencies = [ [[package]] name = "re_data_ui" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "bytemuck", @@ -3940,7 +3977,7 @@ dependencies = [ [[package]] name = "re_error" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "re_log", @@ -3948,7 +3985,7 @@ dependencies = [ [[package]] name = "re_format" -version = "0.6.0" +version = "0.7.0" dependencies = [ "arrow2", "arrow2_convert", @@ -3958,7 +3995,7 @@ dependencies = [ [[package]] name = "re_int_histogram" -version = "0.6.0" +version = "0.7.0" dependencies = [ "criterion", "insta", @@ -3969,7 +4006,7 @@ dependencies = [ [[package]] name = "re_log" -version = "0.6.0" +version = "0.7.0" dependencies = [ "env_logger", "js-sys", @@ -3982,7 +4019,7 @@ dependencies = [ [[package]] name = "re_log_encoding" -version = "0.6.0" +version = "0.7.0" dependencies = [ "criterion", "ehttp", @@ -4006,7 +4043,7 @@ dependencies = [ [[package]] name = "re_log_types" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "array-init", @@ -4022,7 +4059,6 @@ dependencies = [ "image", "itertools", "lazy_static", - "macaw", "ndarray", "nohash-hasher", "num-derive", @@ -4047,7 +4083,7 @@ dependencies = [ [[package]] name = "re_memory" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "backtrace", @@ -4067,7 +4103,7 @@ dependencies = [ [[package]] name = "re_query" -version = "0.6.0" +version = "0.7.0" dependencies = [ "arrow2", "criterion", @@ -4086,7 +4122,7 @@ dependencies = [ [[package]] name = "re_renderer" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "anyhow", @@ -4132,13 +4168,14 @@ dependencies = [ "web-time", "wgpu", "wgpu-core", + "wgpu-hal", "winit", "zip", ] [[package]] name = "re_sdk" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "arrow2_convert", @@ -4161,10 +4198,9 @@ dependencies = [ [[package]] name = "re_sdk_comms" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", - "anyhow", "crossbeam", "document-features", "rand", @@ -4172,12 +4208,13 @@ dependencies = [ "re_log_encoding", "re_log_types", "re_smart_channel", + "thiserror", "tokio", ] [[package]] name = "re_smart_channel" -version = "0.6.0" +version = "0.7.0" dependencies = [ "crossbeam", "web-time", @@ -4185,7 +4222,7 @@ dependencies = [ [[package]] name = "re_string_interner" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "nohash-hasher", @@ -4196,7 +4233,7 @@ dependencies = [ [[package]] name = "re_tensor_ops" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "ndarray", @@ -4206,7 +4243,7 @@ dependencies = [ [[package]] name = "re_tuid" -version = "0.6.0" +version = "0.7.0" dependencies = [ "arrow2", "arrow2_convert", @@ -4220,7 +4257,7 @@ dependencies = [ [[package]] name = "re_ui" -version = "0.6.0" +version = "0.7.0" dependencies = [ "eframe", "egui", @@ -4238,7 +4275,7 @@ dependencies = [ [[package]] name = "re_viewer" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "anyhow", @@ -4298,7 +4335,7 @@ dependencies = [ [[package]] name = "re_viewer_context" -version = "0.6.0" +version = "0.7.0" dependencies = [ "ahash 0.8.3", "anyhow", @@ -4330,7 +4367,7 @@ dependencies = [ [[package]] name = "re_web_viewer_server" -version = "0.6.0" +version = "0.7.0" dependencies = [ "clap", "document-features", @@ -4339,6 +4376,7 @@ dependencies = [ "re_analytics", "re_build_build_info", "re_build_web_viewer", + "re_error", "re_log", "thiserror", "tokio", @@ -4347,7 +4385,7 @@ dependencies = [ [[package]] name = "re_ws_comms" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "bincode", @@ -4425,20 +4463,18 @@ checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b" [[package]] name = "rerun" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", - "backtrace", "clap", "document-features", "itertools", - "libc", - "parking_lot 0.12.1", "puffin", "rayon", "re_analytics", "re_build_build_info", "re_build_info", + "re_crash_handler", "re_data_store", "re_format", "re_log", @@ -4457,7 +4493,7 @@ dependencies = [ [[package]] name = "rerun-cli" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "document-features", @@ -4472,7 +4508,7 @@ dependencies = [ [[package]] name = "rerun_py" -version = "0.6.0" +version = "0.7.0" dependencies = [ "arrow2", "document-features", @@ -4575,7 +4611,7 @@ dependencies = [ [[package]] name = "run_wasm" -version = "0.6.0" +version = "0.7.0" dependencies = [ "cargo-run-wasm", "pico-args", @@ -5102,7 +5138,7 @@ dependencies = [ [[package]] name = "test_image_memory" -version = "0.6.0" +version = "0.7.0" dependencies = [ "mimalloc", "re_format", @@ -5631,9 +5667,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -5641,9 +5677,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", @@ -5656,9 +5692,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-cli-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8315d6503415e5d44ff64f1ba34aefd8264c561df17e0f1c8eb8c96bde79c45e" +checksum = "d21c60239a09bf9bab8dfa752be4e6c637db22296b9ded493800090448692da9" dependencies = [ "anyhow", "base64 0.9.3", @@ -5678,9 +5714,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-externref-xform" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4522bf3be16c6274c87a5a2c5d2a62efa80253b025f8e813f9682d0d6a8a8fca" +checksum = "bafbe1984f67cc12645f12ab65e6145e8ddce1ab265d0be58435f25bb0ce2608" dependencies = [ "anyhow", "walrus", @@ -5700,9 +5736,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5710,9 +5746,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", @@ -5723,9 +5759,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-multi-value-xform" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "113256596776ebb4b243512d3711e73d5475eaeff373e1ae65427c66e5aa2073" +checksum = "581419e3995571a1d2d066e360ca1c0c09da097f5a53c98e6f00d96eddaf0ffe" dependencies = [ "anyhow", "walrus", @@ -5733,15 +5769,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-bindgen-threads-xform" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89106aaf83a2b80464fc8f60a074a4575135b73a491e174f35bbeae6ff0d7ec6" +checksum = "e05d272073981137e8426cf2a6830d43d1f84f988a050b2f8b210f0e266b8983" dependencies = [ "anyhow", "walrus", @@ -5750,9 +5786,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-wasm-conventions" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e5ad27a7930400994cb40823d3d4a7ef235fac52d0c75ebd61fa40eba994a8" +checksum = "0e9c65b1ff5041ea824ca24c519948aec16fb6611c617d601623c0657dfcd47b" dependencies = [ "anyhow", "walrus", @@ -5760,9 +5796,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-wasm-interpreter" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69500063b7b20f3e9422d78c2b381dd192c7c4ebaef34d205332877cd78e0d3" +checksum = "7c5c796220738ab5d44666f37205728a74141c0039d1166bcf8110b26bafaa1e" dependencies = [ "anyhow", "log", @@ -5976,9 +6012,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41af2ea7d87bd41ad0a37146252d5f7c26490209f47f544b2ee3b3ff34c7732e" +checksum = "74851c2c8e5d97652e74c241d41b0656b31c924a45dcdecde83975717362cfa4" dependencies = [ "android_system_properties", "arrayvec", @@ -6323,9 +6359,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d8f380ae16a37b30e6a2cf67040608071384b1450c189e61bea3ff57cde922d" +checksum = "52839dc911083a8ef63efa4d039d1f58b5e409f923e44c80828f206f66e5541c" [[package]] name = "xxhash-rust" diff --git a/Cargo.toml b/Cargo.toml index 8fab520d17fa..7081c802d4a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,41 +16,44 @@ include = ["../../LICENSE-APACHE", "../../LICENSE-MIT", "**/*.rs", "Cargo.toml"] license = "MIT OR Apache-2.0" repository = "https://github.com/rerun-io/rerun" rust-version = "1.69" -version = "0.6.0" +version = "0.7.0" [workspace.dependencies] # When using alpha-release, always use exact version, e.g. `version = "=0.x.y-alpha.z" # This is because we treat alpha-releases as incompatible, but semver doesn't. # In particular: if we compile rerun 0.3.0-alpha.0 we only want it to use # re_log_types 0.3.0-alpha.0, NOT 0.3.0-alpha.4 even though it is newer and semver-compatible. -re_analytics = { path = "crates/re_analytics", version = "0.6.0", default-features = false } -re_arrow_store = { path = "crates/re_arrow_store", version = "0.6.0", default-features = false } -re_build_build_info = { path = "crates/re_build_build_info", version = "0.6.0", default-features = false } -re_build_info = { path = "crates/re_build_info", version = "0.6.0", default-features = false } -re_build_web_viewer = { path = "crates/re_build_web_viewer", version = "0.6.0", default-features = false } -re_data_store = { path = "crates/re_data_store", version = "0.6.0", default-features = false } -re_data_ui = { path = "crates/re_data_ui", version = "0.6.0", default-features = false } -re_error = { path = "crates/re_error", version = "0.6.0", default-features = false } -re_format = { path = "crates/re_format", version = "0.6.0", default-features = false } -re_int_histogram = { path = "crates/re_int_histogram", version = "0.6.0", default-features = false } -re_log = { path = "crates/re_log", version = "0.6.0", default-features = false } -re_log_encoding = { path = "crates/re_log_encoding", version = "0.6.0", default-features = false } -re_log_types = { path = "crates/re_log_types", version = "0.6.0", default-features = false } -re_memory = { path = "crates/re_memory", version = "0.6.0", default-features = false } -re_query = { path = "crates/re_query", version = "0.6.0", default-features = false } -re_renderer = { path = "crates/re_renderer", version = "0.6.0", default-features = false } -re_sdk = { path = "crates/re_sdk", version = "0.6.0", default-features = false } -re_sdk_comms = { path = "crates/re_sdk_comms", version = "0.6.0", default-features = false } -re_smart_channel = { path = "crates/re_smart_channel", version = "0.6.0", default-features = false } -re_string_interner = { path = "crates/re_string_interner", version = "0.6.0", default-features = false } -re_tensor_ops = { path = "crates/re_tensor_ops", version = "0.6.0", default-features = false } -re_tuid = { path = "crates/re_tuid", version = "0.6.0", default-features = false } -re_ui = { path = "crates/re_ui", version = "0.6.0", default-features = false } -re_viewer = { path = "crates/re_viewer", version = "0.6.0", default-features = false } -re_viewer_context = { path = "crates/re_viewer_context", version = "0.6.0", default-features = false } -re_web_viewer_server = { path = "crates/re_web_viewer_server", version = "0.6.0", default-features = false } -re_ws_comms = { path = "crates/re_ws_comms", version = "0.6.0", default-features = false } -rerun = { path = "crates/rerun", version = "0.6.0", default-features = false } +re_analytics = { path = "crates/re_analytics", version = "0.7.0", default-features = false } +re_arrow_store = { path = "crates/re_arrow_store", version = "0.7.0", default-features = false } +re_build_build_info = { path = "crates/re_build_build_info", version = "0.7.0", default-features = false } +re_build_info = { path = "crates/re_build_info", version = "0.7.0", default-features = false } +re_build_web_viewer = { path = "crates/re_build_web_viewer", version = "0.7.0", default-features = false } +re_crash_handler = { path = "crates/re_crash_handler", version = "0.7.0", default-features = false } +re_data_store = { path = "crates/re_data_store", version = "0.7.0", default-features = false } +re_data_ui = { path = "crates/re_data_ui", version = "0.7.0", default-features = false } +re_error = { path = "crates/re_error", version = "0.7.0", default-features = false } +re_format = { path = "crates/re_format", version = "0.7.0", default-features = false } +re_int_histogram = { path = "crates/re_int_histogram", version = "0.7.0", default-features = false } +re_log = { path = "crates/re_log", version = "0.7.0", default-features = false } +re_log_encoding = { path = "crates/re_log_encoding", version = "0.7.0", default-features = false } +re_log_types = { path = "crates/re_log_types", version = "0.7.0", default-features = false } +re_memory = { path = "crates/re_memory", version = "0.7.0", default-features = false } +re_query = { path = "crates/re_query", version = "0.7.0", default-features = false } +re_renderer = { path = "crates/re_renderer", version = "0.7.0", default-features = false } +re_sdk = { path = "crates/re_sdk", version = "0.7.0", default-features = false } +re_sdk_comms = { path = "crates/re_sdk_comms", version = "0.7.0", default-features = false } +re_smart_channel = { path = "crates/re_smart_channel", version = "0.7.0", default-features = false } +re_string_interner = { path = "crates/re_string_interner", version = "0.7.0", default-features = false } +re_tensor_ops = { path = "crates/re_tensor_ops", version = "0.7.0", default-features = false } +re_time_panel = { path = "crates/re_time_panel", version = "==0.6.0", default-features = false } +re_tuid = { path = "crates/re_tuid", version = "0.7.0", default-features = false } +re_ui = { path = "crates/re_ui", version = "0.7.0", default-features = false } +re_viewer = { path = "crates/re_viewer", version = "0.7.0", default-features = false } +re_viewer_context = { path = "crates/re_viewer_context", version = "0.7.0", default-features = false } +re_viewport = { path = "crates/re_viewport", version = "0.7.0", default-features = false } +re_web_viewer_server = { path = "crates/re_web_viewer_server", version = "0.7.0", default-features = false } +re_ws_comms = { path = "crates/re_ws_comms", version = "0.7.0", default-features = false } +rerun = { path = "crates/rerun", version = "0.7.0", default-features = false } ahash = "0.8" anyhow = "1.0" diff --git a/RELEASES.md b/RELEASES.md index d789f651a472..5523c08f32ff 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -76,7 +76,7 @@ This is a living document. Strive to improve it on each new release. * [ ] For the final release, manually run the workflow to publish the artifacts to pypi and create the GitHub release. * https://github.com/rerun-io/rerun/actions/workflows/manual_release.yml * Choose the release branch, and enter the release number `0.x.y` - * This will create the github release page in draft state. + * This will create the GitHub release page in draft state. * Publishing this release will create the release tag * [ ] Edit the GitHub release at https://github.com/rerun-io/rerun/releases/edit/v0.x.0 * [ ] Mark it as as the latest release diff --git a/_typos.toml b/_typos.toml index 0fdd9d9a0b88..5bc80ff01e65 100644 --- a/_typos.toml +++ b/_typos.toml @@ -16,3 +16,10 @@ teh = "teh" # part of @teh-cmc # American English: grey = "gray" + +[default] +# Work around for typos inside of 8-character hashes. These show up inside of ipynb. +# e.g. "f4e1caf9" -> `caf` should be `calf` +# Specifically limit ourselves to exactly 8 chars in a quoted strong. +# Just don't spell "defaced" wrong. +extend-ignore-re = ["\"[a-f0-9]{8}\""] diff --git a/crates/re_arrow_store/src/arrow_util.rs b/crates/re_arrow_store/src/arrow_util.rs index ef119bd51b31..44bf32b5bbd8 100644 --- a/crates/re_arrow_store/src/arrow_util.rs +++ b/crates/re_arrow_store/src/arrow_util.rs @@ -233,109 +233,64 @@ fn test_clean_for_polars_nomodify() { assert_eq!(cell.as_arrow_ref(), &*cleaned); } -#[test] -fn test_clean_for_polars_modify() { - use re_log_types::{DataCell, Pinhole, Transform}; - // transforms are a nice pathological type with both Unions and FixedSizeLists - let transforms = vec![Transform::Pinhole(Pinhole { - image_from_cam: [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]].into(), - resolution: None, - })]; +#[cfg(test)] +mod tests { + use arrow2::datatypes::{DataType, Field, UnionMode}; + use arrow2_convert::{ArrowDeserialize, ArrowField, ArrowSerialize}; + use re_log_types::{component_types::Vec3D, Component, DataCell}; - let cell: DataCell = transforms.try_into().unwrap(); - assert_eq!( - *cell.datatype(), - DataType::Union( - vec![ - Field::new("Unknown", DataType::Boolean, false), - Field::new( - "Rigid3", - DataType::Struct(vec![ - Field::new( - "rotation", - DataType::FixedSizeList( - Box::new(Field::new("item", DataType::Float32, false)), - 4 - ), - false - ), - Field::new( - "translation", - DataType::FixedSizeList( - Box::new(Field::new("item", DataType::Float32, false)), - 3 - ), - false - ) - ]), - false - ), - Field::new( - "Pinhole", - DataType::Struct(vec![ - Field::new( - "image_from_cam", - DataType::FixedSizeList( - Box::new(Field::new("item", DataType::Float32, false)), - 9 - ), - false, - ), - Field::new( - "resolution", - DataType::FixedSizeList( - Box::new(Field::new("item", DataType::Float32, false)), - 2 - ), - true, - ), - ]), - false - ) - ], - None, - UnionMode::Dense - ), - ); + use crate::ArrayExt; - let cleaned = cell.as_arrow_ref().clean_for_polars(); + #[derive(Clone, Copy, Debug, PartialEq, ArrowField, ArrowSerialize, ArrowDeserialize)] + #[arrow_field(type = "dense")] + enum TestComponentWithUnionAndFixedSizeList { + Bool(bool), + Vec3D(Vec3D), + } - assert_eq!( - *cleaned.data_type(), - DataType::Struct(vec![ - Field::new("Unknown", DataType::Boolean, false), - Field::new( - "Rigid3", - DataType::Struct(vec![ - Field::new( - "rotation", - DataType::List(Box::new(Field::new("item", DataType::Float32, false)),), - false - ), + impl Component for TestComponentWithUnionAndFixedSizeList { + fn name() -> re_log_types::ComponentName { + "test_component_with_union_and_fixed_size_list".into() + } + } + + #[test] + fn test_clean_for_polars_modify() { + // Pick a type with both Unions and FixedSizeLists + let elements = vec![TestComponentWithUnionAndFixedSizeList::Bool(false)]; + + let cell: DataCell = elements.try_into().unwrap(); + assert_eq!( + *cell.datatype(), + DataType::Union( + vec![ + Field::new("Bool", DataType::Boolean, false), Field::new( - "translation", - DataType::List(Box::new(Field::new("item", DataType::Float32, false)),), + "Vec3D", + DataType::FixedSizeList( + Box::new(Field::new("item", DataType::Float32, false)), + 3 + ), false ) - ]), - false - ), - Field::new( - "Pinhole", - DataType::Struct(vec![ - Field::new( - "image_from_cam", - DataType::List(Box::new(Field::new("item", DataType::Float32, false))), - false, - ), - Field::new( - "resolution", - DataType::List(Box::new(Field::new("item", DataType::Float32, false))), - true, - ), - ]), - false + ], + None, + UnionMode::Dense ) - ],), - ); + ); + + let cleaned = cell.as_arrow_ref().clean_for_polars(); + + assert_eq!( + *cleaned.data_type(), + DataType::Struct(vec![ + Field::new("Bool", DataType::Boolean, false), + Field::new( + "Vec3D", + DataType::List(Box::new(Field::new("item", DataType::Float32, false))), + false + ) + ],) + ); + } } diff --git a/crates/re_arrow_store/src/lib.rs b/crates/re_arrow_store/src/lib.rs index 0ac2be79a28e..5d7b90596cf5 100644 --- a/crates/re_arrow_store/src/lib.rs +++ b/crates/re_arrow_store/src/lib.rs @@ -20,6 +20,7 @@ mod store_arrow; mod store_dump; mod store_format; mod store_gc; +mod store_helpers; mod store_read; mod store_sanity; mod store_stats; @@ -52,6 +53,10 @@ pub use arrow2::io::ipc::read::{StreamReader, StreamState}; #[doc(no_inline)] pub use re_log_types::{TimeInt, TimeRange, TimeType, Timeline}; // for politeness sake +pub mod external { + pub use arrow2; +} + // --- /// Native-only profiling macro for puffin. diff --git a/crates/re_arrow_store/src/store_helpers.rs b/crates/re_arrow_store/src/store_helpers.rs new file mode 100644 index 000000000000..5a4233771e1f --- /dev/null +++ b/crates/re_arrow_store/src/store_helpers.rs @@ -0,0 +1,158 @@ +use re_log_types::{ + ComponentName, DataCell, DataRow, DeserializableComponent, EntityPath, RowId, + SerializableComponent, TimePoint, Timeline, +}; + +use crate::{DataStore, LatestAtQuery}; + +// --- Read --- + +impl DataStore { + /// Get the latest value for a given [`re_log_types::Component`]. + /// + /// This assumes that the row we get from the store only contains a single instance for this + /// component; it will log a warning otherwise. + /// + /// This should only be used for "mono-components" such as `Transform` and `Tensor`. + /// + /// This is a best-effort helper, it will merely log errors on failure. + pub fn query_latest_component( + &self, + entity_path: &EntityPath, + query: &LatestAtQuery, + ) -> Option + where + for<'b> &'b C::ArrayType: IntoIterator, + { + crate::profile_function!(); + + let (_, cells) = self.latest_at(query, entity_path, C::name(), &[C::name()])?; + let cell = cells.get(0)?.as_ref()?; + + let mut iter = cell + .try_to_native::() + .map_err(|err| { + re_log::error_once!( + "Couldn't deserialize component at {entity_path}.{}: {err}", + C::name() + ); + }) + .ok()?; + + let component = iter.next(); + + if iter.next().is_some() { + re_log::warn_once!("Unexpected batch for {} at: {}", C::name(), entity_path); + } + + component + } + + /// Get the latest value for a given [`re_log_types::Component`], assuming it is timeless. + /// + /// This assumes that the row we get from the store only contains a single instance for this + /// component; it will log a warning otherwise. + /// + /// This should only be used for "mono-components" such as `Transform` and `Tensor`. + /// + /// This is a best-effort helper, it will merely log errors on failure. + pub fn query_timeless_component( + &self, + entity_path: &EntityPath, + ) -> Option + where + for<'b> &'b C::ArrayType: IntoIterator, + { + crate::profile_function!(); + + let query = LatestAtQuery::latest(Timeline::default()); + self.query_latest_component(entity_path, &query) + } +} + +// --- Write --- + +impl DataStore { + /// Stores a single value for a given [`re_log_types::Component`]. + /// + /// This is a best-effort helper, it will merely log errors on failure. + pub fn insert_component( + &mut self, + entity_path: &EntityPath, + timepoint: &TimePoint, + component: C, + ) { + crate::profile_function!(); + + let mut row = match DataRow::try_from_cells1( + RowId::random(), + entity_path.clone(), + timepoint.clone(), + 1, + [component].as_slice(), + ) { + Ok(row) => row, + Err(err) => { + re_log::error_once!( + "Couldn't serialize component at {entity_path}.{}: {err}", + C::name() + ); + return; + } + }; + row.compute_all_size_bytes(); + + if let Err(err) = self.insert_row(&row) { + re_log::error_once!( + "Couldn't insert component at {entity_path}.{}: {err}", + C::name() + ); + } + } + + /// Stores a single empty value for a given [`re_log_types::ComponentName`]. + /// + /// This is a best-effort helper, it will merely log errors on failure. + pub fn insert_empty_component( + &mut self, + entity_path: &EntityPath, + timepoint: &TimePoint, + component: ComponentName, + ) { + crate::profile_function!(); + + if let Some(datatype) = self.lookup_datatype(&component) { + let cell = DataCell::from_arrow_empty(component, datatype.clone()); + + let mut row = match DataRow::try_from_cells1( + RowId::random(), + entity_path.clone(), + timepoint.clone(), + cell.num_instances(), + cell, + ) { + Ok(row) => row, + Err(err) => { + re_log::error_once!( + "Couldn't serialize component at {entity_path}.{}: {err}", + component + ); + return; + } + }; + row.compute_all_size_bytes(); + + if let Err(err) = self.insert_row(&row) { + re_log::error_once!( + "Couldn't insert component at {entity_path}.{}: {err}", + component + ); + } + } else { + re_log::error_once!( + "Couldn't find appropriate datatype at {entity_path}.{}", + component + ); + } + } +} diff --git a/crates/re_arrow_store/src/store_read.rs b/crates/re_arrow_store/src/store_read.rs index 02c753ce4be3..c0f24b976e30 100644 --- a/crates/re_arrow_store/src/store_read.rs +++ b/crates/re_arrow_store/src/store_read.rs @@ -35,6 +35,13 @@ impl LatestAtQuery { pub const fn new(timeline: Timeline, at: TimeInt) -> Self { Self { timeline, at } } + + pub const fn latest(timeline: Timeline) -> Self { + Self { + timeline, + at: TimeInt::MAX, + } + } } /// A query over a time range, for a given timeline. diff --git a/crates/re_build_web_viewer/Cargo.toml b/crates/re_build_web_viewer/Cargo.toml index 3aa773563ba7..ccde803a299e 100644 --- a/crates/re_build_web_viewer/Cargo.toml +++ b/crates/re_build_web_viewer/Cargo.toml @@ -17,4 +17,8 @@ all-features = true [dependencies] +re_error.workspace = true + +anyhow.workspace = true cargo_metadata = "0.15" +wasm-bindgen-cli-support = "0.2.87" diff --git a/crates/re_build_web_viewer/src/lib.rs b/crates/re_build_web_viewer/src/lib.rs index 20d8e85d2ae8..6d4db4a613e1 100644 --- a/crates/re_build_web_viewer/src/lib.rs +++ b/crates/re_build_web_viewer/src/lib.rs @@ -2,6 +2,7 @@ //! Build the Rerun web-viewer .wasm and generate the .js bindings for it. +use anyhow::Context as _; use cargo_metadata::camino::Utf8PathBuf; fn target_directory() -> Utf8PathBuf { @@ -14,7 +15,7 @@ fn target_directory() -> Utf8PathBuf { } /// Build `re_viewer` as Wasm, generate .js bindings for it, and place it all into the `./web_viewer` folder. -pub fn build(release: bool, webgpu: bool) { +pub fn build(release: bool, webgpu: bool) -> anyhow::Result<()> { eprintln!("Building web viewer wasm…"); eprintln!("We assume you've already run ./scripts/setup_web.sh"); @@ -93,7 +94,7 @@ pub fn build(release: bool, webgpu: bool) { let status = cmd .current_dir(root_dir) .status() - .expect("Failed to build Wasm"); + .context("Failed to build Wasm")?; assert!(status.success(), "Failed to build Wasm"); // -------------------------------------------------------------------------------- @@ -106,29 +107,30 @@ pub fn build(release: bool, webgpu: bool) { .join(build) .join(format!("{crate_name}.wasm")); - let mut cmd = std::process::Command::new("wasm-bindgen"); - cmd.args([ - target_wasm_path.as_str(), - "--out-dir", - build_dir.as_str(), - "--out-name", - target_name.as_str(), - "--no-modules", - "--no-typescript", - ]); - if !release { - cmd.arg("--debug"); + // wasm-bindgen --target web target_wasm_path --no-typescript --out-name target_name --out-dir build_dir + if let Err(err) = wasm_bindgen_cli_support::Bindgen::new() + .no_modules(true)? + .input_path(target_wasm_path.as_str()) + .typescript(false) + .out_name(target_name.as_str()) + .generate(build_dir.as_str()) + { + if err + .to_string() + .starts_with("cannot import from modules (`env`") + { + // Very common error: "cannot import from modules (`env`) with `--no-modules`" + anyhow::bail!( + "Failed to run wasm-bindgen: {err}. This is often because some dependency is calling `std::time::Instant::now()` or similar. You can try diagnosing this with:\n\ + wasm2wat {target_wasm_path} | rg '\"env\"'\n\ + wasm2wat {target_wasm_path} | rg 'call .now\\b' -B 20" + ); + } else { + return Err(err.context("Failed to run wasm-bindgen")); + } } - eprintln!("> {cmd:?}"); - let status = cmd - .current_dir(root_dir) - .status() - .expect("Failed to run wasm-bindgen"); - assert!(status.success(), "Failed to run wasm-bindgen"); - // -------------------------------------------------------------------------------- - // Optimize the wasm if release { eprintln!("Optimizing wasm with wasm-opt…"); @@ -143,9 +145,13 @@ pub fn build(release: bool, webgpu: bool) { let status = cmd .current_dir(root_dir) .status() - .expect("Failed to run wasm-opt"); + .context("Failed to run wasm-opt")?; assert!(status.success(), "Failed to run wasm-opt"); } + // -------------------------------------------------------------------------------- + eprintln!("Finished {wasm_path}"); + + Ok(()) } diff --git a/crates/re_build_web_viewer/src/main.rs b/crates/re_build_web_viewer/src/main.rs index 1c3d2249d26f..8f887ab89bbf 100644 --- a/crates/re_build_web_viewer/src/main.rs +++ b/crates/re_build_web_viewer/src/main.rs @@ -33,8 +33,12 @@ fn main() -> ExitCode { return ExitCode::FAILURE; }; - re_build_web_viewer::build(release, webgpu); - ExitCode::SUCCESS + if let Err(err) = re_build_web_viewer::build(release, webgpu) { + eprintln!("Failed to build web viewer: {}", re_error::format(err)); + ExitCode::FAILURE + } else { + ExitCode::SUCCESS + } } fn print_help() { diff --git a/crates/re_crash_handler/Cargo.toml b/crates/re_crash_handler/Cargo.toml new file mode 100644 index 000000000000..f3726438e081 --- /dev/null +++ b/crates/re_crash_handler/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "re_crash_handler" +authors.workspace = true +description = "Detect panics and signals, logging them and optionally sending them to analytics." +edition.workspace = true +homepage.workspace = true +include.workspace = true +license.workspace = true +publish = true +readme = "README.md" +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +all-features = true + + +[features] +default = ["analytics"] + +## Send analytics to Rerun on crashes +analytics = ["dep:re_analytics"] + +[dependencies] +re_build_info.workspace = true + +itertools.workspace = true +parking_lot.workspace = true + +# Optional dependencies: +re_analytics = { workspace = true, optional = true } + +# Native dependencies: +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +backtrace = "0.3" + +# Native unix dependencies: +[target.'cfg(not(any(target_arch = "wasm32", target_os = "windows")))'.dependencies] +libc = "0.2" diff --git a/crates/re_crash_handler/README.md b/crates/re_crash_handler/README.md new file mode 100644 index 000000000000..363c7ddfc4bd --- /dev/null +++ b/crates/re_crash_handler/README.md @@ -0,0 +1,10 @@ +# re_crash_handler + +Part of the [`rerun`](https://github.com/rerun-io/rerun) family of crates. + +[![Latest version](https://img.shields.io/crates/v/re_crash_handler.svg)](https://crates.io/crates/re_crash_handler) +[![Documentation](https://docs.rs/re_crash_handler/badge.svg)](https://docs.rs/re_crash_handler) +![MIT](https://img.shields.io/badge/license-MIT-blue.svg) +![Apache](https://img.shields.io/badge/license-Apache-blue.svg) + +Detect and handle signals, panics, and other crashes, making sure to log them and optionally send them off to analytics. diff --git a/crates/rerun/src/crash_handler.rs b/crates/re_crash_handler/src/lib.rs similarity index 98% rename from crates/rerun/src/crash_handler.rs rename to crates/re_crash_handler/src/lib.rs index 03f40e761453..293861b9d50f 100644 --- a/crates/rerun/src/crash_handler.rs +++ b/crates/re_crash_handler/src/lib.rs @@ -1,3 +1,5 @@ +//! Detect and handle signals, panics, and other crashes, making sure to log them and optionally send them off to analytics. + use re_build_info::BuildInfo; use parking_lot::Mutex; @@ -180,10 +182,7 @@ fn install_signal_handler(build_info: BuildInfo) { // Send analytics - this also sleeps a while to give the analytics time to send the event. #[cfg(feature = "analytics")] - { - let build_info = BUILD_INFO - .lock() - .unwrap_or_else(|| re_build_info::build_info!()); + if let Some(build_info) = *BUILD_INFO.lock() { send_signal_analytics(build_info, signal_name, callstack); } diff --git a/crates/re_data_store/src/log_db.rs b/crates/re_data_store/src/log_db.rs index 21ed57f7040c..2bc37f82cc68 100644 --- a/crates/re_data_store/src/log_db.rs +++ b/crates/re_data_store/src/log_db.rs @@ -43,6 +43,12 @@ impl Default for EntityDb { } impl EntityDb { + /// A sorted list of all the entity paths in this database. + pub fn entity_paths(&self) -> Vec<&EntityPath> { + use itertools::Itertools as _; + self.entity_path_from_hash.values().sorted().collect() + } + #[inline] pub fn entity_path_from_hash(&self, entity_path_hash: &EntityPathHash) -> Option<&EntityPath> { self.entity_path_from_hash.get(entity_path_hash) @@ -87,6 +93,8 @@ impl EntityDb { let cell = DataCell::from_arrow_empty(cell.component_name(), cell.datatype().clone()); + // NOTE(cmc): The fact that this inserts data to multiple entity paths using a + // single `RowId` is... interesting. Keep it in mind. let row = DataRow::from_cells1( row_id, row.entity_path.clone(), @@ -116,6 +124,9 @@ impl EntityDb { // TODO(jleibs): Faster empty-array creation let cell = DataCell::from_arrow_empty(component_path.component_name, data_type.clone()); + + // NOTE(cmc): The fact that this inserts data to multiple entity paths using a + // single `RowId` is... interesting. Keep it in mind. let row = DataRow::from_cells1( row_id, component_path.entity_path.clone(), diff --git a/crates/re_data_store/src/util.rs b/crates/re_data_store/src/util.rs new file mode 100644 index 000000000000..3d54365f4bd6 --- /dev/null +++ b/crates/re_data_store/src/util.rs @@ -0,0 +1,87 @@ +use re_arrow_store::LatestAtQuery; +use re_log_types::{ + DataRow, DeserializableComponent, EntityPath, RowId, SerializableComponent, TimePoint, Timeline, +}; + +use crate::LogDb; + +// ---------------------------------------------------------------------------- + +/// Get the latest value for a given [`re_log_types::Component`]. +/// +/// This assumes that the row we get from the store only contains a single instance for this +/// component; it will log a warning otherwise. +/// +/// This should only be used for "mono-components" such as `Transform` and `Tensor`. +pub fn query_latest_single( + data_store: &re_arrow_store::DataStore, + entity_path: &EntityPath, + query: &LatestAtQuery, +) -> Option +where + for<'b> &'b C::ArrayType: IntoIterator, +{ + crate::profile_function!(); + + // Although it would be nice to use the `re_query` helpers for this, we would need to move + // this out of re_data_store to avoid a circular dep. Since we don't need to do a join for + // single components this is easy enough. + + let (_, cells) = data_store.latest_at(query, entity_path, C::name(), &[C::name()])?; + let cell = cells.get(0)?.as_ref()?; + + let mut iter = cell.try_to_native::().ok()?; + + let component = iter.next(); + + if iter.next().is_some() { + re_log::warn_once!("Unexpected batch for {} at: {}", C::name(), entity_path); + } + + component +} + +/// Get the latest value for a given [`re_log_types::Component`] assuming it is timeless. +/// +/// This assumes that the row we get from the store only contains a single instance for this +/// component; it will log a warning otherwise. +pub fn query_timeless_single( + data_store: &re_arrow_store::DataStore, + entity_path: &EntityPath, +) -> Option +where + for<'b> &'b C::ArrayType: IntoIterator, +{ + let query = re_arrow_store::LatestAtQuery::latest(Timeline::default()); + query_latest_single(data_store, entity_path, &query) +} + +// ---------------------------------------------------------------------------- + +/// Store a single value for a given [`re_log_types::Component`]. +pub fn store_one_component( + log_db: &mut LogDb, + entity_path: &EntityPath, + timepoint: &TimePoint, + component: C, +) { + let mut row = DataRow::from_cells1( + RowId::random(), + entity_path.clone(), + timepoint.clone(), + 1, + [component].as_slice(), + ); + row.compute_all_size_bytes(); + + match log_db.entity_db.try_add_data_row(&row) { + Ok(()) => {} + Err(err) => { + re_log::warn_once!( + "Failed to store component {}.{}: {err}", + entity_path, + C::name(), + ); + } + } +} diff --git a/crates/re_data_ui/src/annotation_context.rs b/crates/re_data_ui/src/annotation_context.rs index 7bf8eed1c013..72c67eed5367 100644 --- a/crates/re_data_ui/src/annotation_context.rs +++ b/crates/re_data_ui/src/annotation_context.rs @@ -1,7 +1,7 @@ use egui::{color_picker, Vec2}; use itertools::Itertools; -use re_log_types::{context::AnnotationInfo, AnnotationContext}; +use re_log_types::{component_types::ClassId, context::AnnotationInfo, AnnotationContext}; use re_viewer_context::{auto_color, UiVerbosity, ViewerContext}; use super::DataUi; @@ -77,8 +77,11 @@ fn annotation_info( query: &re_arrow_store::LatestAtQuery, keypoint_id: &re_log_types::component_types::KeypointId, ) -> Option { - let class_id = - re_data_store::query_latest_single(&ctx.log_db.entity_db.data_store, entity_path, query)?; + let class_id = ctx + .log_db + .entity_db + .data_store + .query_latest_component::(entity_path, query)?; let annotations = crate::annotations(ctx, query, entity_path); let class = annotations .class_description(Some(class_id)) diff --git a/crates/re_data_ui/src/component.rs b/crates/re_data_ui/src/component.rs index 8931ea3c0616..23bf74687ca5 100644 --- a/crates/re_data_ui/src/component.rs +++ b/crates/re_data_ui/src/component.rs @@ -34,13 +34,7 @@ impl DataUi for EntityComponentWithInstances { ) { crate::profile_function!(self.component_name().full_name()); - let mut instance_keys = match self.component_data.iter_instance_keys() { - Ok(instance_keys) => instance_keys, - Err(err) => { - ui.label(ctx.re_ui.error_text(format!("Error: {err}"))); - return; - } - }; + let instance_keys: Vec<_> = self.component_data.iter_instance_keys().collect(); let num_instances = self.num_instances(); @@ -52,7 +46,7 @@ impl DataUi for EntityComponentWithInstances { if num_instances == 0 { ui.weak("(empty)"); } else if num_instances == 1 { - if let Some(instance_key) = instance_keys.next() { + if let Some(instance_key) = instance_keys.first() { ctx.component_ui_registry.ui( ctx, ui, @@ -60,7 +54,7 @@ impl DataUi for EntityComponentWithInstances { query, &self.entity_path, &self.component_data, - &instance_key, + instance_key, ); } else { ui.label(ctx.re_ui.error_text("Error: missing instance key")); @@ -88,15 +82,10 @@ impl DataUi for EntityComponentWithInstances { re_ui::ReUi::setup_table_body(&mut body); let row_height = re_ui::ReUi::table_line_height(); body.rows(row_height, num_instances, |index, mut row| { - if let Some(instance_key) = self - .component_data - .iter_instance_keys() - .ok() - .and_then(|mut keys| keys.nth(index)) - { + if let Some(instance_key) = instance_keys.get(index) { row.col(|ui| { let instance_path = - InstancePath::instance(self.entity_path.clone(), instance_key); + InstancePath::instance(self.entity_path.clone(), *instance_key); item_ui::instance_path_button_to( ctx, ui, @@ -113,7 +102,7 @@ impl DataUi for EntityComponentWithInstances { query, &self.entity_path, &self.component_data, - &instance_key, + instance_key, ); }); } diff --git a/crates/re_data_ui/src/component_path.rs b/crates/re_data_ui/src/component_path.rs index 8e7b5d805fc2..2bb0eefefdcb 100644 --- a/crates/re_data_ui/src/component_path.rs +++ b/crates/re_data_ui/src/component_path.rs @@ -13,26 +13,19 @@ impl DataUi for ComponentPath { ) { let store = &ctx.log_db.entity_db.data_store; - match re_query::get_component_with_instances( + if let Some((_, component_data)) = re_query::get_component_with_instances( store, query, self.entity_path(), self.component_name, ) { - Err(re_query::QueryError::PrimaryNotFound) => { - ui.label(""); - } - Err(err) => { - // Any other failure to get a component is unexpected - ui.label(ctx.re_ui.error_text(format!("Error: {err}"))); - } - Ok((_, component_data)) => { - super::component::EntityComponentWithInstances { - entity_path: self.entity_path.clone(), - component_data, - } - .data_ui(ctx, ui, verbosity, query); + super::component::EntityComponentWithInstances { + entity_path: self.entity_path.clone(), + component_data, } + .data_ui(ctx, ui, verbosity, query); + } else { + ui.label(""); } } } diff --git a/crates/re_data_ui/src/component_ui_registry.rs b/crates/re_data_ui/src/component_ui_registry.rs index f1a37eed5eda..8ec71c456e78 100644 --- a/crates/re_data_ui/src/component_ui_registry.rs +++ b/crates/re_data_ui/src/component_ui_registry.rs @@ -1,6 +1,6 @@ use re_arrow_store::LatestAtQuery; use re_log_types::{ - component_types::InstanceKey, external::arrow2, DeserializableComponent, EntityPath, SizeBytes, + component_types::InstanceKey, external::arrow2, DeserializableComponent, EntityPath, }; use re_query::ComponentWithInstances; use re_viewer_context::{ComponentUiRegistry, UiVerbosity, ViewerContext}; @@ -51,6 +51,7 @@ pub fn create_component_ui_registry() -> ComponentUiRegistry { add::(&mut registry); // add::(&mut registry); // add::(&mut registry); + add::(&mut registry); // add::(&mut registry); // add::(&mut registry); add::(&mut registry); @@ -59,7 +60,7 @@ pub fn create_component_ui_registry() -> ComponentUiRegistry { // add::(&mut registry); add::(&mut registry); add::(&mut registry); - add::(&mut registry); + add::(&mut registry); add::(&mut registry); add::(&mut registry); add::(&mut registry); @@ -78,21 +79,29 @@ fn fallback_component_ui( ) { // No special ui implementation - use a generic one: if let Some(value) = component.lookup_arrow(instance_key) { - let bytes = value.total_size_bytes(); - if bytes < 256 { - // For small items, print them - let mut repr = String::new(); - let display = arrow2::array::get_display(value.as_ref(), "null"); - display(&mut repr, 0).unwrap(); - ui.label(repr); - } else { - ui.label(format!("{bytes} bytes")); - } + ui.label(format_arrow(&*value)); } else { ui.weak("(null)"); } } +fn format_arrow(value: &dyn arrow2::array::Array) -> String { + use re_log_types::SizeBytes as _; + + let bytes = value.total_size_bytes(); + if bytes < 256 { + // Print small items: + let mut string = String::new(); + let display = arrow2::array::get_display(value, "null"); + if display(&mut string, 0).is_ok() { + return string; + } + } + + // Fallback: + format!("{bytes} bytes") +} + // ---------------------------------------------------------------------------- impl DataUi for re_log_types::component_types::TextEntry { diff --git a/crates/re_data_ui/src/data.rs b/crates/re_data_ui/src/data.rs index db0f8ca940eb..ec879d726e7d 100644 --- a/crates/re_data_ui/src/data.rs +++ b/crates/re_data_ui/src/data.rs @@ -1,10 +1,8 @@ use egui::Vec2; use re_format::format_f32; -use re_log_types::{ - component_types::ColorRGBA, - component_types::{LineStrip2D, LineStrip3D, Mat3x3, Rect2D, Vec2D, Vec3D, Vec4D}, - Pinhole, Rigid3, Transform, ViewCoordinates, +use re_log_types::component_types::{ + ColorRGBA, LineStrip2D, LineStrip3D, Mat3x3, Rect2D, Vec2D, Vec3D, Vec4D, ViewCoordinates, }; use re_viewer_context::{UiVerbosity, ViewerContext}; @@ -53,24 +51,6 @@ impl DataUi for ColorRGBA { } } -impl DataUi for Transform { - fn data_ui( - &self, - ctx: &mut ViewerContext<'_>, - ui: &mut egui::Ui, - verbosity: UiVerbosity, - query: &re_arrow_store::LatestAtQuery, - ) { - match self { - Transform::Unknown => { - ui.label("Unknown transform"); - } - Transform::Rigid3(rigid3) => rigid3.data_ui(ctx, ui, verbosity, query), - Transform::Pinhole(pinhole) => pinhole.data_ui(ctx, ui, verbosity, query), - } - } -} - impl DataUi for ViewCoordinates { fn data_ui( &self, @@ -90,90 +70,6 @@ impl DataUi for ViewCoordinates { } } -impl DataUi for Rigid3 { - #[allow(clippy::only_used_in_recursion)] - fn data_ui( - &self, - ctx: &mut ViewerContext<'_>, - ui: &mut egui::Ui, - verbosity: UiVerbosity, - query: &re_arrow_store::LatestAtQuery, - ) { - match verbosity { - UiVerbosity::Small => { - ui.label("Rigid 3D transform").on_hover_ui(|ui| { - self.data_ui(ctx, ui, UiVerbosity::All, query); - }); - } - - UiVerbosity::All | UiVerbosity::Reduced => { - let pose = self.parent_from_child(); // TODO(emilk): which one to show? - let rotation = pose.rotation(); - let translation = pose.translation(); - - ui.vertical(|ui| { - ui.label("Rigid 3D transform:"); - ui.indent("rigid3", |ui| { - egui::Grid::new("rigid3").num_columns(2).show(ui, |ui| { - ui.label("rotation"); - ui.monospace(format!("{rotation:?}")); - ui.end_row(); - - ui.label("translation"); - ui.monospace(format!("{translation:?}")); - ui.end_row(); - }); - }); - }); - } - } - } -} - -impl DataUi for Pinhole { - fn data_ui( - &self, - ctx: &mut ViewerContext<'_>, - ui: &mut egui::Ui, - verbosity: UiVerbosity, - query: &re_arrow_store::LatestAtQuery, - ) { - match verbosity { - UiVerbosity::Small => { - ui.label("Pinhole transform").on_hover_ui(|ui| { - self.data_ui(ctx, ui, UiVerbosity::All, query); - }); - } - - UiVerbosity::All | UiVerbosity::Reduced => { - let Pinhole { - image_from_cam: image_from_view, - resolution, - } = self; - - ui.vertical(|ui| { - ui.label("Pinhole transform:"); - ui.indent("pinole", |ui| { - ui.horizontal(|ui| { - ui.label("resolution:"); - if let Some(re_log_types::component_types::Vec2D([x, y])) = resolution { - ui.monospace(format!("{x}x{y}")); - } else { - ui.weak("(none)"); - } - }); - - ui.label("image from view:"); - ui.indent("image_from_view", |ui| { - image_from_view.data_ui(ctx, ui, verbosity, query); - }); - }); - }); - } - } - } -} - impl DataUi for Mat3x3 { fn data_ui( &self, diff --git a/crates/re_data_ui/src/image.rs b/crates/re_data_ui/src/image.rs index bc63b5e4f69d..e716e07ef676 100644 --- a/crates/re_data_ui/src/image.rs +++ b/crates/re_data_ui/src/image.rs @@ -57,7 +57,7 @@ fn tensor_ui( verbosity: UiVerbosity, entity_path: &re_data_store::EntityPath, annotations: &Annotations, - _encoded_tensor: &Tensor, + original_tensor: &Tensor, tensor: &DecodedTensor, ) { // See if we can convert the tensor to a GPU texture. @@ -102,18 +102,25 @@ fn tensor_ui( } ui.label(format!( - "{} x {}", + "{} x {}{}", tensor.dtype(), - format_tensor_shape_single_line(tensor.shape()) + format_tensor_shape_single_line(tensor.shape()), + if original_tensor.data.is_compressed_image() { + " (compressed)" + } else { + "" + } )) - .on_hover_ui(|ui| tensor_summary_ui(ctx.re_ui, ui, tensor, &tensor_stats)); + .on_hover_ui(|ui| { + tensor_summary_ui(ctx.re_ui, ui, original_tensor, tensor, &tensor_stats); + }); }); } UiVerbosity::All | UiVerbosity::Reduced => { ui.vertical(|ui| { ui.set_min_width(100.0); - tensor_summary_ui(ctx.re_ui, ui, tensor, &tensor_stats); + tensor_summary_ui(ctx.re_ui, ui, original_tensor, tensor, &tensor_stats); if let Some(texture) = &texture_result { let max_size = ui @@ -147,9 +154,9 @@ fn tensor_ui( // TODO(emilk): support copying and saving images on web #[cfg(not(target_arch = "wasm32"))] - if _encoded_tensor.data.is_compressed_image() || tensor.could_be_dynamic_image() + if original_tensor.data.is_compressed_image() || tensor.could_be_dynamic_image() { - copy_and_save_image_ui(ui, tensor, _encoded_tensor); + copy_and_save_image_ui(ui, tensor, original_tensor); } if let Some([_h, _w, channels]) = tensor.image_height_width_channels() { @@ -208,16 +215,17 @@ fn show_image_at_max_size( pub fn tensor_summary_ui_grid_contents( re_ui: &re_ui::ReUi, ui: &mut egui::Ui, - tensor: &Tensor, + original_tensor: &Tensor, + tensor: &DecodedTensor, tensor_stats: &TensorStats, ) { let Tensor { tensor_id: _, shape, - data, + data: _, meaning, meter, - } = tensor; + } = tensor.inner(); re_ui .grid_left_hand_label(ui, "Data type") @@ -260,7 +268,7 @@ pub fn tensor_summary_ui_grid_contents( ui.end_row(); } - match data { + match &original_tensor.data { re_log_types::component_types::TensorData::U8(_) | re_log_types::component_types::TensorData::U16(_) | re_log_types::component_types::TensorData::U32(_) @@ -282,7 +290,10 @@ pub fn tensor_summary_ui_grid_contents( } } - let TensorStats { range } = tensor_stats; + let TensorStats { + range, + finite_range, + } = tensor_stats; if let Some((min, max)) = range { ui.label("Data range") @@ -294,18 +305,30 @@ pub fn tensor_summary_ui_grid_contents( )); ui.end_row(); } + // Show finite range only if it is different from the actual range. + if let (true, Some((min, max))) = (range != finite_range, finite_range) { + ui.label("Finite data range") + .on_hover_text("The finite values (ignoring all NaN & -Inf/+Inf) of the tensor range within these bounds."); + ui.monospace(format!( + "[{} - {}]", + re_format::format_f64(*min), + re_format::format_f64(*max) + )); + ui.end_row(); + } } pub fn tensor_summary_ui( re_ui: &re_ui::ReUi, ui: &mut egui::Ui, - tensor: &Tensor, + original_tensor: &Tensor, + tensor: &DecodedTensor, tensor_stats: &TensorStats, ) { egui::Grid::new("tensor_summary_ui") .num_columns(2) .show(ui, |ui| { - tensor_summary_ui_grid_contents(re_ui, ui, tensor, tensor_stats); + tensor_summary_ui_grid_contents(re_ui, ui, original_tensor, tensor, tensor_stats); }); } diff --git a/crates/re_data_ui/src/instance_path.rs b/crates/re_data_ui/src/instance_path.rs index 4f3256f3fc64..ae28214dc770 100644 --- a/crates/re_data_ui/src/instance_path.rs +++ b/crates/re_data_ui/src/instance_path.rs @@ -1,6 +1,6 @@ use re_data_store::InstancePath; use re_log_types::ComponentPath; -use re_query::{get_component_with_instances, QueryError}; +use re_query::get_component_with_instances; use re_viewer_context::{UiVerbosity, ViewerContext}; use super::DataUi; @@ -29,16 +29,14 @@ impl DataUi for InstancePath { .num_columns(2) .show(ui, |ui| { for component_name in components { - let component_data = get_component_with_instances( + let Some((_, component_data)) = get_component_with_instances( store, query, &self.entity_path, component_name, - ); - - if matches!(component_data, Err(QueryError::PrimaryNotFound)) { + ) else { continue; // no need to show components that are unset at this point in time - } + }; // Certain fields are hidden. if HIDDEN_COMPONENTS_FOR_ALL_VERBOSITY.contains(&component_name.as_str()) { @@ -62,34 +60,22 @@ impl DataUi for InstancePath { &ComponentPath::new(self.entity_path.clone(), component_name), ); - match component_data { - Err(err) => { - ui.label(ctx.re_ui.error_text(format!("Error: {err}"))); - } - Ok((_, component_data)) => { - if self.instance_key.is_splat() { - super::component::EntityComponentWithInstances { - entity_path: self.entity_path.clone(), - component_data, - } - .data_ui( - ctx, - ui, - UiVerbosity::Small, - query, - ); - } else { - ctx.component_ui_registry.ui( - ctx, - ui, - UiVerbosity::Small, - query, - &self.entity_path, - &component_data, - &self.instance_key, - ); - } + if self.instance_key.is_splat() { + super::component::EntityComponentWithInstances { + entity_path: self.entity_path.clone(), + component_data, } + .data_ui(ctx, ui, UiVerbosity::Small, query); + } else { + ctx.component_ui_registry.ui( + ctx, + ui, + UiVerbosity::Small, + query, + &self.entity_path, + &component_data, + &self.instance_key, + ); } ui.end_row(); diff --git a/crates/re_data_ui/src/lib.rs b/crates/re_data_ui/src/lib.rs index 4216db834ac0..0b0c1f35a026 100644 --- a/crates/re_data_ui/src/lib.rs +++ b/crates/re_data_ui/src/lib.rs @@ -17,6 +17,8 @@ mod instance_path; mod item; pub mod item_ui; mod log_msg; +mod pinhole; +mod transform3d; pub use crate::image::{ show_zoomed_image_region, show_zoomed_image_region_area_outline, @@ -156,12 +158,12 @@ pub fn annotations( let mut annotation_map = re_viewer_context::AnnotationMap::default(); let entity_paths: nohash_hasher::IntSet<_> = std::iter::once(entity_path.clone()).collect(); let entity_props_map = re_data_store::EntityPropertyMap::default(); - let scene_query = re_viewer_context::SceneQuery { - entity_paths: &entity_paths, - timeline: query.timeline, - latest_at: query.at, - entity_props_map: &entity_props_map, - }; + let scene_query = re_viewer_context::SceneQuery::new( + &entity_paths, + query.timeline, + query.at, + &entity_props_map, + ); annotation_map.load(ctx, &scene_query); annotation_map.find(entity_path) } diff --git a/crates/re_data_ui/src/pinhole.rs b/crates/re_data_ui/src/pinhole.rs new file mode 100644 index 000000000000..9abd37689da1 --- /dev/null +++ b/crates/re_data_ui/src/pinhole.rs @@ -0,0 +1,48 @@ +use re_log_types::component_types::Pinhole; +use re_viewer_context::{UiVerbosity, ViewerContext}; + +use crate::DataUi; + +impl DataUi for Pinhole { + fn data_ui( + &self, + ctx: &mut ViewerContext<'_>, + ui: &mut egui::Ui, + verbosity: UiVerbosity, + query: &re_arrow_store::LatestAtQuery, + ) { + match verbosity { + UiVerbosity::Small => { + ui.label("Pinhole transform").on_hover_ui(|ui| { + self.data_ui(ctx, ui, UiVerbosity::All, query); + }); + } + + UiVerbosity::All | UiVerbosity::Reduced => { + let Pinhole { + image_from_cam: image_from_view, + resolution, + } = self; + + ui.vertical(|ui| { + ui.label("Pinhole transform:"); + ui.indent("pinole", |ui| { + ui.horizontal(|ui| { + ui.label("resolution:"); + if let Some(re_log_types::component_types::Vec2D([x, y])) = resolution { + ui.monospace(format!("{x}x{y}")); + } else { + ui.weak("(none)"); + } + }); + + ui.label("image from view:"); + ui.indent("image_from_view", |ui| { + image_from_view.data_ui(ctx, ui, verbosity, query); + }); + }); + }); + } + } + } +} diff --git a/crates/re_data_ui/src/transform3d.rs b/crates/re_data_ui/src/transform3d.rs new file mode 100644 index 000000000000..6ff02ec9fcfc --- /dev/null +++ b/crates/re_data_ui/src/transform3d.rs @@ -0,0 +1,196 @@ +use re_log_types::component_types::{ + Angle, Rotation3D, RotationAxisAngle, Scale3D, Transform3D, Transform3DRepr, + TranslationAndMat3, TranslationRotationScale3D, +}; +use re_viewer_context::{UiVerbosity, ViewerContext}; + +use crate::DataUi; + +impl DataUi for Transform3D { + #[allow(clippy::only_used_in_recursion)] + fn data_ui( + &self, + ctx: &mut ViewerContext<'_>, + ui: &mut egui::Ui, + verbosity: UiVerbosity, + query: &re_arrow_store::LatestAtQuery, + ) { + match verbosity { + UiVerbosity::Small => { + // TODO(andreas): Preview some information instead of just a label with hover ui. + ui.label("3D transform").on_hover_ui(|ui| { + self.data_ui(ctx, ui, UiVerbosity::All, query); + }); + } + + UiVerbosity::All | UiVerbosity::Reduced => { + let dir_string = if self.from_parent { + "parent ➡ child" + } else { + "child ➡ parent" + }; + + ui.vertical(|ui| { + ui.label("3D transform"); + ui.indent("transform_repr", |ui| { + ui.label(dir_string); + self.transform.data_ui(ctx, ui, verbosity, query); + }); + }); + } + } + } +} + +impl DataUi for Transform3DRepr { + #[allow(clippy::only_used_in_recursion)] + fn data_ui( + &self, + ctx: &mut ViewerContext<'_>, + ui: &mut egui::Ui, + verbosity: UiVerbosity, + query: &re_arrow_store::LatestAtQuery, + ) { + match verbosity { + UiVerbosity::Small => { + ui.label("3D transform").on_hover_ui(|ui| { + self.data_ui(ctx, ui, UiVerbosity::All, query); + }); + } + + UiVerbosity::All | UiVerbosity::Reduced => match self { + Transform3DRepr::TranslationAndMat3(translation_matrix) => { + translation_matrix.data_ui(ctx, ui, verbosity, query); + } + Transform3DRepr::TranslationRotationScale(translation_rotation_scale) => { + translation_rotation_scale.data_ui(ctx, ui, verbosity, query); + } + }, + } + } +} + +impl DataUi for TranslationRotationScale3D { + fn data_ui( + &self, + ctx: &mut ViewerContext<'_>, + ui: &mut egui::Ui, + verbosity: UiVerbosity, + query: &re_arrow_store::LatestAtQuery, + ) { + let TranslationRotationScale3D { + translation, + rotation, + scale, + } = self; + + egui::Grid::new("translation_rotation_scale") + .num_columns(2) + .show(ui, |ui| { + // Unlike Rotation/Scale, we don't have a value that indicates that nothing was logged. + // We still skip zero translations though since they are typically not logged explicitly. + if let Some(translation) = translation { + ui.label("translation"); + translation.data_ui(ctx, ui, verbosity, query); + ui.end_row(); + } + + if let Some(rotation) = rotation { + ui.label("rotation"); + rotation.data_ui(ctx, ui, verbosity, query); + ui.end_row(); + } + + if let Some(scale) = scale { + ui.label("scale"); + scale.data_ui(ctx, ui, verbosity, query); + ui.end_row(); + } + }); + } +} + +impl DataUi for Rotation3D { + fn data_ui( + &self, + ctx: &mut ViewerContext<'_>, + ui: &mut egui::Ui, + verbosity: UiVerbosity, + query: &re_arrow_store::LatestAtQuery, + ) { + match self { + Rotation3D::Quaternion(q) => { + // TODO(andreas): Better formatting for quaternions. + ui.label(format!("{q:?}")); + } + Rotation3D::AxisAngle(RotationAxisAngle { axis, angle }) => { + egui::Grid::new("axis_angle").num_columns(2).show(ui, |ui| { + ui.label("axis"); + axis.data_ui(ctx, ui, verbosity, query); + ui.end_row(); + + ui.label("angle"); + match angle { + Angle::Radians(v) => { + ui.label(format!("{}rad", re_format::format_f32(*v))); + } + Angle::Degrees(v) => { + // TODO(andreas): Convert to arc minutes/seconds for very small angles. + // That code should be in re_format! + ui.label(format!("{}°", re_format::format_f32(*v),)); + } + } + ui.end_row(); + }); + } + } + } +} + +impl DataUi for Scale3D { + fn data_ui( + &self, + ctx: &mut ViewerContext<'_>, + ui: &mut egui::Ui, + verbosity: UiVerbosity, + query: &re_arrow_store::LatestAtQuery, + ) { + match self { + Scale3D::Uniform(scale) => { + ui.label(re_format::format_f32(*scale)); + } + Scale3D::ThreeD(v) => { + v.data_ui(ctx, ui, verbosity, query); + } + } + } +} + +impl DataUi for TranslationAndMat3 { + fn data_ui( + &self, + ctx: &mut ViewerContext<'_>, + ui: &mut egui::Ui, + verbosity: UiVerbosity, + query: &re_arrow_store::LatestAtQuery, + ) { + let TranslationAndMat3 { + translation, + matrix, + } = self; + + egui::Grid::new("translation_and_mat3") + .num_columns(2) + .show(ui, |ui| { + if let Some(translation) = translation { + ui.label("translation"); + translation.data_ui(ctx, ui, verbosity, query); + ui.end_row(); + } + + ui.label("matrix"); + matrix.data_ui(ctx, ui, verbosity, query); + ui.end_row(); + }); + } +} diff --git a/crates/re_error/src/lib.rs b/crates/re_error/src/lib.rs index e6f3e454a580..d3dc5b00a1c4 100644 --- a/crates/re_error/src/lib.rs +++ b/crates/re_error/src/lib.rs @@ -2,7 +2,7 @@ /// Format an error, including its chain of sources. /// -/// Always use this when displaying an error. +/// Always use this when displaying an error, especially `anyhow::Error`. pub fn format(error: impl AsRef) -> String { fn format_impl(error: &dyn std::error::Error) -> String { let mut string = error.to_string(); diff --git a/crates/re_log/Cargo.toml b/crates/re_log/Cargo.toml index c92748f9a42e..7a061ba8dcb7 100644 --- a/crates/re_log/Cargo.toml +++ b/crates/re_log/Cargo.toml @@ -31,4 +31,4 @@ env_logger = "0.10" # web dependencies: [target.'cfg(target_arch = "wasm32")'.dependencies] js-sys = "0.3" -wasm-bindgen = "0.2.86" +wasm-bindgen = "0.2.87" diff --git a/crates/re_log/src/setup.rs b/crates/re_log/src/setup.rs index d24d4e5d1597..ccec8c9324d6 100644 --- a/crates/re_log/src/setup.rs +++ b/crates/re_log/src/setup.rs @@ -21,6 +21,7 @@ fn log_filter() -> String { rust_log } +/// Directs [`log`] calls to stderr. #[cfg(not(target_arch = "wasm32"))] pub fn setup_native_logging() { if std::env::var("RUST_BACKTRACE").is_err() { diff --git a/crates/re_log_types/Cargo.toml b/crates/re_log_types/Cargo.toml index 4da5fef9ded8..f237428b8a4c 100644 --- a/crates/re_log_types/Cargo.toml +++ b/crates/re_log_types/Cargo.toml @@ -27,7 +27,7 @@ arrow_datagen = ["dep:rand"] ecolor = ["dep:ecolor"] ## Add support for some math operations using [`glam`](https://crates.io/crates/glam/). -glam = ["dep:glam", "dep:macaw"] +glam = ["dep:glam"] ## Integration with the [`image`](https://crates.io/crates/image/) crate. image = ["dep:ecolor", "dep:image"] @@ -84,7 +84,6 @@ glam = { workspace = true, optional = true } image = { workspace = true, optional = true, default-features = false, features = [ "jpeg", ] } -macaw = { workspace = true, optional = true } rand = { version = "0.8", optional = true } rmp-serde = { version = "1.1", optional = true } serde = { version = "1", optional = true, features = ["derive", "rc"] } diff --git a/crates/re_log_types/src/component_types/arrow.rs b/crates/re_log_types/src/component_types/arrow.rs index 0110f9c49303..05ef69ee1910 100644 --- a/crates/re_log_types/src/component_types/arrow.rs +++ b/crates/re_log_types/src/component_types/arrow.rs @@ -30,7 +30,7 @@ use crate::Component; /// ]) /// ); /// ``` -#[derive(Clone, Debug, ArrowField, ArrowSerialize, ArrowDeserialize, PartialEq)] +#[derive(Copy, Clone, Debug, ArrowField, ArrowSerialize, ArrowDeserialize, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Arrow3D { pub origin: Vec3D, diff --git a/crates/re_log_types/src/component_types/coordinates.rs b/crates/re_log_types/src/component_types/coordinates.rs index 9e11df9e5fa7..b19fb7dc1f9d 100644 --- a/crates/re_log_types/src/component_types/coordinates.rs +++ b/crates/re_log_types/src/component_types/coordinates.rs @@ -450,7 +450,7 @@ impl Handedness { #[cfg(feature = "glam")] #[test] -fn view_coordinatess() { +fn view_coordinates() { use glam::{vec3, Mat3}; { diff --git a/crates/re_log_types/src/component_types/disconnected_space.rs b/crates/re_log_types/src/component_types/disconnected_space.rs new file mode 100644 index 000000000000..07102ec26d57 --- /dev/null +++ b/crates/re_log_types/src/component_types/disconnected_space.rs @@ -0,0 +1,36 @@ +use arrow2_convert::{ArrowDeserialize, ArrowField, ArrowSerialize}; + +use crate::Component; + +/// Specifies that the entity path at which this is logged is disconnected from its parent. +/// +/// If a transform or pinhole is logged on the same path, this component will be ignored. +/// +/// This is useful for specifying that a subgraph is independent of the rest of the scene. +/// +/// This component is a "mono-component". See [the crate level docs](crate) for details. +#[derive(Copy, Clone, Debug, ArrowField, ArrowSerialize, ArrowDeserialize)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[arrow_field(transparent)] +#[repr(transparent)] +pub struct DisconnectedSpace(bool); + +impl DisconnectedSpace { + #[inline] + pub fn new() -> Self { + Self(false) + } +} + +impl Default for DisconnectedSpace { + fn default() -> Self { + Self::new() + } +} + +impl Component for DisconnectedSpace { + #[inline] + fn name() -> crate::ComponentName { + "rerun.disconnected_space".into() + } +} diff --git a/crates/re_log_types/src/component_types/draw_order.rs b/crates/re_log_types/src/component_types/draw_order.rs index 66d3d69fc5e3..9741d9413dab 100644 --- a/crates/re_log_types/src/component_types/draw_order.rs +++ b/crates/re_log_types/src/component_types/draw_order.rs @@ -10,6 +10,8 @@ use crate::Component; /// /// Draw order for entities with the same draw order is generally undefined. /// +/// This component is a "mono-component". See [the crate level docs](crate) for details. +/// /// ``` /// use re_log_types::component_types::DrawOrder; /// use arrow2_convert::field::ArrowField; @@ -17,7 +19,7 @@ use crate::Component; /// /// assert_eq!(DrawOrder::data_type(), DataType::Float32); /// ``` -#[derive(Debug, Clone, ArrowField, ArrowSerialize, ArrowDeserialize)] +#[derive(Debug, Clone, Copy, ArrowField, ArrowSerialize, ArrowDeserialize)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[arrow_field(transparent)] pub struct DrawOrder(pub f32); diff --git a/crates/re_log_types/src/component_types/mat.rs b/crates/re_log_types/src/component_types/mat.rs index 303f0c6bf9d9..973cabcb7754 100644 --- a/crates/re_log_types/src/component_types/mat.rs +++ b/crates/re_log_types/src/component_types/mat.rs @@ -27,6 +27,14 @@ use super::Vec3D; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Mat3x3([Vec3D; 3]); +impl Mat3x3 { + pub const IDENTITY: Mat3x3 = Mat3x3([ + Vec3D([1.0, 0.0, 0.0]), + Vec3D([0.0, 1.0, 0.0]), + Vec3D([0.0, 0.0, 1.0]), + ]); +} + impl std::ops::Index for Mat3x3 where Idx: std::slice::SliceIndex<[Vec3D]>, diff --git a/crates/re_log_types/src/component_types/mod.rs b/crates/re_log_types/src/component_types/mod.rs index 2eae0fc191a7..bd681e05ee6b 100644 --- a/crates/re_log_types/src/component_types/mod.rs +++ b/crates/re_log_types/src/component_types/mod.rs @@ -22,6 +22,7 @@ mod class_id; mod color; pub mod context; pub mod coordinates; +mod disconnected_space; mod draw_order; mod instance_key; mod keypoint_id; @@ -29,6 +30,7 @@ mod label; mod linestrip; mod mat; mod mesh3d; +mod pinhole; mod point; mod quaternion; mod radius; @@ -38,7 +40,7 @@ mod size; mod tensor; mod text_box; mod text_entry; -mod transform; +mod transform3d; mod vec; pub use arrow::Arrow3D; @@ -47,6 +49,7 @@ pub use class_id::ClassId; pub use color::ColorRGBA; pub use context::{AnnotationContext, AnnotationInfo, ClassDescription}; pub use coordinates::ViewCoordinates; +pub use disconnected_space::DisconnectedSpace; pub use draw_order::DrawOrder; pub use instance_key::InstanceKey; pub use keypoint_id::KeypointId; @@ -54,6 +57,7 @@ pub use label::Label; pub use linestrip::{LineStrip2D, LineStrip3D}; pub use mat::Mat3x3; pub use mesh3d::{EncodedMesh3D, Mesh3D, MeshFormat, MeshId, RawMesh3D}; +pub use pinhole::Pinhole; pub use point::{Point2D, Point3D}; pub use quaternion::Quaternion; pub use radius::Radius; @@ -68,24 +72,29 @@ pub use tensor::{ pub use tensor::{TensorImageLoadError, TensorImageSaveError}; pub use text_box::TextBox; pub use text_entry::TextEntry; -pub use transform::{Pinhole, Rigid3, Transform}; +pub use transform3d::{ + Angle, Rotation3D, RotationAxisAngle, Scale3D, Transform3D, Transform3DRepr, + TranslationAndMat3, TranslationRotationScale3D, +}; pub use vec::{Vec2D, Vec3D, Vec4D}; lazy_static! { //TODO(john): use a run-time type registry - static ref FIELDS: [Field; 27] = [ + static ref FIELDS: [Field; 29] = [ ::field(), ::field(), ::field(), ::field(), ::field(), ::field(), + ::field(), ::field(), ::field(),