Outie
Turns each face of a triangle mesh to point out, even when the mesh is open.
Outie is A Simple Method for Correcting Facet Orientations in Polygon Meshes Based on Ray Casting (PDF) by Kenshi Takayama, Alec Jacobson, Ladislav Kavan and Olga Sorkine-Hornung, 2014, ported from libigl's reorient_facets_raycast to Rust and Embree. All credit goes to them and libigl's contributors. For a geometry processing library, use libigl. To only turn faces, outie is small, fast and has wheels for every system.
I personally use it on city massing datasets like Toronto's 3D Massing, drawn by many people in tools that hide which way faces point, and often not closed, so the usual repairs fail. With faces pointing out, a model needs no two-sided materials, and everything just works the way it should.
Figure 1. One mass, 29,878 triangles, as published and as each method leaves it, with the time each took.
| Method | Backfacingness | Time |
|---|---|---|
| As published | 0.5121 | |
trimesh fix_normals |
0.4169 | 0.77 s |
libigl orient_outward |
0.1991 | 0.01 s |
libigl reorient_facets_raycast, the paper's code |
0.0011 | 31.26 s |
| outie | 0.0011 | 0.24 s |
Table 1. The methods of Figure 1, libigl's and outie's with the same settings.
Use
pip install outie
import outie
# vertices: corner positions, n by 3 [[0, 0, 0], [1, 0, 0], [1, 1, 0], ...]
# faces: triangles, m by 3 [[0, 2, 1], [0, 3, 2], ...]
faces = outie.reorient(vertices, faces) # the same faces, each turned to point out
As in libigl's function, faces are triangles, and removing duplicate triangles, which the paper's command does with -u, is left to the caller.
To know which faces turned, the paper's function gives it per face, with the component each was decided with:
flip, component = outie.reorient_facets_raycast(vertices, faces) # [False, True, ...], [0, 1, ...]
| Option | Default | |
|---|---|---|
facet_wise |
True |
Decide each face alone. False decides faces joined by edges together. |
use_parity |
False |
Count the faces each ray crosses instead of whether it escapes. For closed meshes. |
rays_total |
100 a face | Fewer is faster, see Figure 4. |
rays_minimum |
10 |
Rays at least for each component. |
seed |
0 |
Repeats the random rays. |
outie.measure_backfacingness(vertices, faces) # the paper's measure: 0 when no face shows its back
Differences from libigl
- Speed. libigl's function finds every hit along each ray, though the vote uses only the first. Stopping at the first takes its C++ from 26 s to 2.5 s on Figure 1's mass. Outie does that and casts on every core.
- Names.
verticesandfacesfor libigl'sVandF, and component throughout for what the paper, and libigl in places, also call a patch. The options keep libigl's names. - Defaults.
facet_wise=True, as the paper's results are made. libigl's Python binding defaults toFalse.
Results
The data is 60 masses from the City of Toronto's 3D Massing, 318 to 49,118 triangles each, in data/.
Figure 2. Backfacingness: the share of a mesh, seen from six sides, that shows the backs of faces, blue.
| 60 masses | Backfacingness | Time |
|---|---|---|
| As published | 0.4233 ± 0.1590 | |
| outie | 0.0140 ± 0.0409 | 5.0 s |
facet_wise=False |
0.0233 ± 0.0528 | 5.5 s |
use_parity=True |
0.0426 ± 0.0489 | 26.4 s |
Table 2. Apple M1 Max, 10 cores. use_parity=True is slower because each ray counts every face it passes, not just the first it hits.
Figure 3. Every mass, as published and after outie. The few left high are mostly floorless masses: the view from beneath sees into them whichever way their faces turn. Seen from above, the worst, at 0.30, falls to 0.07, and the next four to under 0.05.
Figure 4. Rays a face against backfacingness and time, all 60 masses, with rays_minimum=1 so each setting's count is what it says.
Figure 5. The three masses outie improves most.
Figure 6. The three masses outie leaves worst: mostly thin, single-sided parts, where neither way round is better.
Figure 7. The largest mass, as published and after, whole above and cut open below: faces left inside a model are turned too, though not all of them correctly.
Method
Figure 8. How the default and use_parity=True decide. facet_wise=False is Figure 9.
Figure 9. facet_wise=False, left of each pair, against the default, right. As the paper found, how well joined faces vote together depends on how a model was built: the first building is joined badly, so one vote turns whole wrong groups, and deciding each face alone is better. The second is built cleanly, so joining works.
Acknowledgements
- Kenshi Takayama, Alec Jacobson, Ladislav Kavan and Olga Sorkine-Hornung, for the method and its code.
- libigl, whose code outie ports.
- Embree, which casts the rays.
- The City of Toronto. Contains information licensed under the Open Government Licence - Toronto.
Citation
@article{Takayama2014Orientation,
author = {Kenshi Takayama and Alec Jacobson and Ladislav Kavan and Olga Sorkine-Hornung},
title = {A Simple Method for Correcting Facet Orientations in Polygon Meshes Based on Ray Casting},
journal = {Journal of Computer Graphics Techniques (JCGT)},
volume = {3},
number = {4},
pages = {53--63},
year = {2014}
}
Licence
MPL-2.0, as libigl's. The wheels carry Embree, under Apache-2.0, LICENSE-EMBREE. The paper is under CC BY-ND 3.0, the data under the Open Government Licence - Toronto.
Metadata
Release files for outie 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| outie-0.2.1.tar.gz | 89.3 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| outie-0.2.1-cp314-cp314t-win_amd64.whl | CPython 3.14 | CPython 3.14 free-threading | Windows x86-64 | Details |
| outie-0.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl | CPython 3.14 | CPython 3.14 free-threading | Linux musl 1.2+ x86-64 | Details |
| outie-0.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl | CPython 3.14 | CPython 3.14 free-threading | Linux musl 1.2+ ARM64 | Details |
| outie-0.2.1-cp314-cp314t-manylinux_2_28_x86_64.whl | CPython 3.14 | CPython 3.14 free-threading | Linux glibc 2.28+ x86-64 | Details |
| outie-0.2.1-cp314-cp314t-manylinux_2_28_aarch64.whl | CPython 3.14 | CPython 3.14 free-threading | Linux glibc 2.28+ ARM64 | Details |
| outie-0.2.1-cp314-cp314t-macosx_11_0_arm64.whl | CPython 3.14 | CPython 3.14 free-threading | macOS 11.0+ ARM64 | Details |
| outie-0.2.1-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details |
| outie-0.2.1-cp312-abi3-musllinux_1_2_x86_64.whl | CPython 3.12 | abi3 | Linux musl 1.2+ x86-64 | Details |
| outie-0.2.1-cp312-abi3-musllinux_1_2_aarch64.whl | CPython 3.12 | abi3 | Linux musl 1.2+ ARM64 | Details |
| outie-0.2.1-cp312-abi3-manylinux_2_28_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.28+ x86-64 | Details |
| outie-0.2.1-cp312-abi3-manylinux_2_28_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.28+ ARM64 | Details |
| outie-0.2.1-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 41.8 MB
Release files / outie-0.2.1.tar.gz
| Download URL | outie-0.2.1.tar.gz |
|---|---|
| Size | 89.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4ddd45f22b24964c87ccb82adaabfa2f51ca15ecb32aafa072ea0122c33e1532
|
|
BLAKE2b-256 checksum How to use checksums |
f10208c060e24237acc8580e4f44d8a700fd7d2e3aac4ac4cf13f93532b723ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp314-cp314t-win_amd64.whl
| Download URL | outie-0.2.1-cp314-cp314t-win_amd64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading Windows x86-64 |
|
SHA-256 checksum How to use checksums |
c6626521df7f64456e744315c9661c988abdb33825cab8e211e4b98babcc5678
|
|
BLAKE2b-256 checksum How to use checksums |
323ead317f071c8f5892d9871356c77aff2267b01ac80b523ba351220d047978
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl
| Download URL | outie-0.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 8.5 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
cade8295ec621944975552021fe36b1d2a49a0dd01a660b60509124dcf7813bd
|
|
BLAKE2b-256 checksum How to use checksums |
903aaed6c488fd476bd7cb0bb83c982a026ca5aa831759b80eecd2bee43d4520
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl
| Download URL | outie-0.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 7.4 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux musl 1.2+ ARM64 |
|
SHA-256 checksum How to use checksums |
81b123c0be2d20ce4f1e38a15027caaca74f20fe3fbb151f3b65f1b440acd779
|
|
BLAKE2b-256 checksum How to use checksums |
0c70cc41fa882aca58252ab84fe275fcac6069e86dcc74729b2fe22f38382ba9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp314-cp314t-manylinux_2_28_x86_64.whl
| Download URL | outie-0.2.1-cp314-cp314t-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
86925edf2d2c72a819e0321cd85408bc0bbbd4978638d800b881666ee315f441
|
|
BLAKE2b-256 checksum How to use checksums |
7d9e7fdbaa8475a9c8a6edf22b27c8dd4dec8460f884348b80393428b59c88d0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp314-cp314t-manylinux_2_28_aarch64.whl
| Download URL | outie-0.2.1-cp314-cp314t-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 1.0 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
7aa216c96632ff6ec9b36ad060c606ba1cc05c430921f9b092850d6143830ae9
|
|
BLAKE2b-256 checksum How to use checksums |
e23fca1ad9082b13c79cc6345e93ee11a9862744dd70728965cef416f6e6571c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp314-cp314t-macosx_11_0_arm64.whl
| Download URL | outie-0.2.1-cp314-cp314t-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.0 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
45aa5a5bd19a18ac0fe95b2a7f26d1b534eca50b6664ab7e12c5f2f901fdcd50
|
|
BLAKE2b-256 checksum How to use checksums |
2f6568a31f2f77cf740cd50ad778ea920d2c461da1de1eb2fbfa3c7d8e2de007
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp312-abi3-win_amd64.whl
| Download URL | outie-0.2.1-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
24053d3a1dbbb676ab49435f33d15315b55619f9beee0745b8d93c53b3dc5b8b
|
|
BLAKE2b-256 checksum How to use checksums |
2c96456f4ca0572b7a8d1ec529cf8bf184718c3c7c367c9adf80125ee9d3294d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp312-abi3-musllinux_1_2_x86_64.whl
| Download URL | outie-0.2.1-cp312-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 8.5 MB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
2e9a108220009a93be4ee17da95cd3c0a8d338233f1c40a244898d7fcc26d09c
|
|
BLAKE2b-256 checksum How to use checksums |
879e39baf2d67f4480f949aef39012e541826f60f5235a8013844c47a3f0025f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp312-abi3-musllinux_1_2_aarch64.whl
| Download URL | outie-0.2.1-cp312-abi3-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 7.4 MB |
| Tags | CPython 3.12 Linux musl 1.2+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
620ed2c815626fce83766a165ccfd09530f1ff60fceac84e23de90e0a4eed37c
|
|
BLAKE2b-256 checksum How to use checksums |
3ee115114a449821f5cc577aa195f34cd1c864d23f8cf29e25c8f27422182195
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp312-abi3-manylinux_2_28_x86_64.whl
| Download URL | outie-0.2.1-cp312-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a7acc3f905119308ae39fa60969b7cf1ad62ebea338e4a5d128e685a75a6101f
|
|
BLAKE2b-256 checksum How to use checksums |
6c83864fb70eb6d4e3ae7288f00f61c789f09accc50462bbf92b1edeec0d74f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp312-abi3-manylinux_2_28_aarch64.whl
| Download URL | outie-0.2.1-cp312-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 1.0 MB |
| Tags | CPython 3.12 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
2218bd395a4fe262e7f18416bad51c6c7ac20ee058288d11a5eb2ead2d238e66
|
|
BLAKE2b-256 checksum How to use checksums |
45537371356ff8350cc5e7195aabc2bd3f4f5fb6a1d62449afa27b6afcca7cc0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outie-0.2.1-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | outie-0.2.1-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.0 MB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
da7f27a890e29eacd43a6af91bde6ab468808672d9241727ae0f0e16fd4d435c
|
|
BLAKE2b-256 checksum How to use checksums |
c5645a0e0df975c7beb3840988e8c4ddd58efde84345707f2b7e72280424b70a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency log