-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
03e50c4
commit 5feccec
Showing
6 changed files
with
383 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
name: Build and upload | ||
|
||
on: | ||
pull_request: | ||
push: | ||
tags: | ||
- "*" | ||
branches: | ||
- "main" | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
build_wheels: | ||
name: Build wheels on ${{ matrix.os }} | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, windows-latest, macos-latest] | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
submodules: true | ||
|
||
- name: Build wheels | ||
uses: pypa/cibuildwheel@v2.14.1 | ||
|
||
- uses: actions/upload-artifact@v3 | ||
with: | ||
path: ./wheelhouse/*.whl | ||
|
||
build_sdist: | ||
name: Build source distribution | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
submodules: true | ||
|
||
- name: Build sdist | ||
run: pipx run build --sdist | ||
|
||
- uses: actions/upload-artifact@v3 | ||
with: | ||
path: dist/*.tar.gz | ||
|
||
upload_pypi: | ||
needs: [build_wheels, build_sdist] | ||
runs-on: ubuntu-latest | ||
# upload to PyPI on every tag | ||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') | ||
# alternatively, to publish when a GitHub Release is created, use the following rule: | ||
# if: github.event_name == 'release' && github.event.action == 'published' | ||
steps: | ||
- uses: actions/download-artifact@v3 | ||
with: | ||
name: artifact | ||
path: dist | ||
|
||
- uses: pypa/gh-action-pypi-publish@v1.8.6 | ||
with: | ||
user: __token__ | ||
password: ${{ secrets.PYPI_TOKEN }} | ||
|
||
- name: Release | ||
uses: softprops/action-gh-release@v1 | ||
with: | ||
generate_release_notes: true | ||
files: | | ||
./dist/*.whl |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
include pyminiply/wrapper.hpp | ||
include pyminiply/wrapper.pyx | ||
include pyminiply/miniply/miniply.cpp | ||
include pyminiply/miniply/miniply.h | ||
global-exclude pyminiply/_wrapper.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
########### | ||
pyminiply | ||
########### | ||
|
||
|pypi| |MIT| | ||
|
||
.. |pypi| image:: https://img.shields.io/pypi/v/pyminiply.svg?logo=python&logoColor=white | ||
:target: https://pypi.org/project/pyminiply/ | ||
|
||
.. |MIT| image:: https://img.shields.io/badge/License-MIT-yellow.svg | ||
:target: https://opensource.org/licenses/MIT | ||
|
||
``pyminiply`` is a Python library for rapidly reading PLY files. It is a | ||
Python wrapper around the fast C++ PLY reading library provided by | ||
`miniply <ehttps://github.com/vilya/miniply>`_. Thanks @vilya! | ||
|
||
The main advantage of ``pyminiply`` over other PLY reading libraries is | ||
its performance. See the benchmarks below for more details. | ||
|
||
************** | ||
Installation | ||
************** | ||
|
||
The recommended way to install ``pyminiply`` is via PyPI: | ||
|
||
.. code:: sh | ||
pip install pyminiply | ||
You can also clone the repository and install it from source: | ||
|
||
.. code:: sh | ||
git clone https://github.com/pyvista/pyminiply.git | ||
cd pyminiply | ||
git submodule update --init --recursive | ||
pip install . | ||
******* | ||
Usage | ||
******* | ||
|
||
Load in the vertices, indices, normals, UV, and color information from a | ||
PLY file: | ||
|
||
.. code:: pycon | ||
>>> import pyminiply | ||
>>> vertices, indices, normals, uv, color = pyminiply.read("example.ply") | ||
>>> vertices | ||
array([[ 5.0000000e-01, -5.0000000e-01, -5.5511151e-17], | ||
[ 4.0000001e-01, -5.0000000e-01, -4.4408922e-17], | ||
[ 3.0000001e-01, -5.0000000e-01, -3.3306692e-17], | ||
..., | ||
[-4.2500001e-01, 5.0000000e-01, 4.7184480e-17], | ||
[-4.7499999e-01, 4.4999999e-01, 5.2735593e-17], | ||
[-5.0000000e-01, 4.2500001e-01, 5.5511151e-17]], dtype=float32) | ||
>>> indices | ||
array([[ 0, 442, 441], | ||
[ 442, 122, 443], | ||
[ 443, 121, 441], | ||
..., | ||
[1677, 438, 1679], | ||
[1679, 439, 1676], | ||
[1677, 1679, 1676]], dtype=int32) | ||
>>> normals | ||
array([[-1.110223e-16, 0.000000e+00, -1.000000e+00], | ||
[-1.110223e-16, 0.000000e+00, -1.000000e+00], | ||
[-1.110223e-16, 0.000000e+00, -1.000000e+00], | ||
..., | ||
[-1.110223e-16, 0.000000e+00, -1.000000e+00], | ||
[-1.110223e-16, 0.000000e+00, -1.000000e+00], | ||
[-1.110223e-16, 0.000000e+00, -1.000000e+00]], dtype=float32) | ||
>>> uv | ||
array([[0. , 0. ], | ||
[0.1 , 0. ], | ||
[0.2 , 0. ], | ||
..., | ||
[0.92499995, 1. ], | ||
[0.975 , 0.95 ], | ||
[1. , 0.92499995]], dtype=float32) | ||
>>> color | ||
array([[ 0, 0, 0], | ||
[ 0, 0, 0], | ||
[ 0, 0, 0], | ||
..., | ||
[254, 254, 254], | ||
[254, 254, 254], | ||
[255, 255, 255]], dtype=uint8) | ||
You can also read in the PLY file as a `PyVista | ||
<https://github.com/pyvista>`_ PolyData and immediately plot it. | ||
|
||
.. code:: pycon | ||
>>> import pyminiply | ||
>>> mesh = pyminiply.read_as_mesh("example.ply") | ||
>>> mesh | ||
PolyData (0x7f0653579c00) | ||
N Cells: 200 | ||
N Points: 121 | ||
N Strips: 0 | ||
X Bounds: -5.000e-01, 5.000e-01 | ||
Y Bounds: -5.000e-01, 5.000e-01 | ||
Z Bounds: -5.551e-17, 5.551e-17 | ||
N Arrays: 2 | ||
>>> mesh.plot() | ||
.. image:: https://github.com/pyvista/pyminiply/raw/main/demo.png | ||
|
||
*********** | ||
Benchmark | ||
*********** | ||
|
||
The main reason behind writing yet another PLY file reader for Python is | ||
to leverage the highly performant ``miniply`` library. | ||
|
||
There is already an benchmark demonstrating how ``miniply`` outperforms | ||
in comparison to competing C and C++ libraries at `ply_io_benchmark | ||
<https://github.com/mhalber/ply_io_benchmark>`_ when reading PLY files. | ||
The benchmark here shows how ``pyminiply`` performs relative to other | ||
Python PLY file readers. | ||
|
||
Here are the timings from reading in a 1,000,000 point binary PLY file: | ||
|
||
+-------------+-----------------+ | ||
| Library | Time (seconds) | | ||
+=============+=================+ | ||
| pyminiply | 0.046 | | ||
+-------------+-----------------+ | ||
| open3d | 0.149 | | ||
+-------------+-----------------+ | ||
| PyVista | 0.409 | | ||
| (VTK) | | | ||
+-------------+-----------------+ | ||
| meshio | 0.512 | | ||
+-------------+-----------------+ | ||
| plyfile | 8.939 | | ||
+-------------+-----------------+ | ||
|
||
**Benchmark source:** | ||
|
||
.. code:: python | ||
import time | ||
import numpy as np | ||
import pyvista as pv | ||
import pyminiply | ||
import plyfile | ||
import meshio | ||
import open3d | ||
filename = 'tmp.ply' | ||
mesh = pv.Plane(i_resolution=999, j_resolution=999).triangulate() | ||
mesh.clear_data() | ||
mesh.save(filename) | ||
# pyminiply | ||
tstart = time.time() | ||
pyminiply.read(filename) | ||
tend = time.time() - tstart; print(f'pyminiply: {tend:.3f}') | ||
# open3d | ||
tstart = time.time() | ||
open3d.io.read_point_cloud(filename) | ||
tend = time.time() - tstart; print(f'open3d: {tend:.3f}') | ||
# VTK/PyVista | ||
tstart = time.time() | ||
pv.read(filename) | ||
tend = time.time() - tstart; print(f'VTK/PyVista: {tend:.3f}') | ||
tstart = time.time() | ||
meshio.read(filename) | ||
tend = time.time() - tstart; print(f'meshio: {tend:.3f}') | ||
# plyfile | ||
tstart = time.time() | ||
plyfile.PlyData.read(filename) | ||
tend = time.time() - tstart; print(f'plyfile: {tend:.3f}') | ||
Comparison with VTK and PyVista | ||
=============================== | ||
|
||
Here's an additional benchmark comparing VTK/PyVista with ``pyminiply``: | ||
|
||
.. code:: python | ||
import numpy as np | ||
import time | ||
import pyvista as pv | ||
import matplotlib.pyplot as plt | ||
import pyminiply | ||
times = [] | ||
filename = 'tmp.ply' | ||
for res in range(50, 800, 50): | ||
mesh = pv.Plane(i_resolution=res, j_resolution=res).triangulate().subdivide(2) | ||
mesh.clear_data() | ||
mesh.save(filename) | ||
tstart = time.time() | ||
pv_mesh = pv.read(filename) | ||
vtk_time = time.time() - tstart | ||
tstart = time.time() | ||
ply_mesh = pyminiply.read_as_mesh(filename) | ||
ply_reader_time = time.time() - tstart | ||
assert np.allclose(pv_mesh['Normals'], ply_mesh['Normals']) | ||
assert np.allclose(pv_mesh.points, ply_mesh.points) | ||
assert np.allclose(pv_mesh._connectivity_array, ply_mesh._connectivity_array) | ||
times.append([mesh.n_points, vtk_time, ply_reader_time]) | ||
print(times[-1]) | ||
times = np.array(times) | ||
plt.figure(1) | ||
plt.title('PLY load time') | ||
plt.plot(times[:, 0], times[:, 1], label='VTK') | ||
plt.plot(times[:, 0], times[:, 2], label='pyminiply') | ||
plt.xlabel('Number of Points') | ||
plt.ylabel('Time to Load (seconds)') | ||
plt.legend() | ||
plt.figure(2) | ||
plt.title('PLY load time (Log-Log)') | ||
plt.loglog(times[:, 0], times[:, 1], label='VTK') | ||
plt.loglog(times[:, 0], times[:, 2], label='pyminiply') | ||
plt.xlabel('Number of Points') | ||
plt.ylabel('Time to Load (seconds)') | ||
plt.legend() | ||
plt.show() | ||
.. image:: https://github.com/pyvista/pyminiply/raw/main/bench0.png | ||
|
||
.. image:: https://github.com/pyvista/pyminiply/raw/main/bench1.png | ||
|
||
***************************** | ||
License and Acknowledgments | ||
***************************** | ||
|
||
This project relies on ``miniply`` and credit goes to the original | ||
author for the excellent C++ library. That work is licensed under the | ||
MIT License. | ||
|
||
The work in this repository is also licensed under the MIT License. | ||
|
||
********* | ||
Support | ||
********* | ||
|
||
If you are having issues, please feel free to raise an `Issue | ||
<https://github.com/pyvista/pyminiply/issues>`_. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
[build-system] | ||
requires = [ | ||
"setuptools>=42", | ||
"wheel>=0.33.0", | ||
"cython>=3", | ||
"oldest-supported-numpy" | ||
] | ||
|
||
build-backend = "setuptools.build_meta" | ||
|
||
[tool.pytest.ini_options] | ||
junit_family= "legacy" | ||
filterwarnings = [ | ||
# bogus numpy ABI warning (see numpy/#432) | ||
"ignore:.*numpy.dtype size changed.*:RuntimeWarning", | ||
"ignore:.*numpy.ufunc size changed.*:RuntimeWarning" | ||
] | ||
|
||
[tool.cibuildwheel] | ||
archs = ["auto64"] # 64-bit only | ||
skip = "pp* *musllinux*" # disable PyPy and musl-based wheels | ||
test-requires = "pytest pyvista" | ||
test-command = "pytest {project}/tests" | ||
|
||
[tool.cibuildwheel.macos] | ||
# https://cibuildwheel.readthedocs.io/en/stable/faq/#apple-silicon | ||
archs = ["x86_64", "universal2"] | ||
test-skip = ["*_arm64", "*_universal2:arm64"] | ||
|
||
[tool.codespell] | ||
skip = '*.cxx,*.h,*.gif,*.png,*.jpg,*.js,*.html,*.doctree,*.ttf,*.woff,*.woff2,*.eot,*.mp4,*.inv,*.pickle,*.ipynb,flycheck*,./.git/*,./.hypothesis/*,*.yml,./doc/build/*,./doc/images/*,./dist/*,*~,.hypothesis*,*.cpp,*.c' | ||
quiet-level = 3 | ||
|
||
[tool.isort] | ||
profile = "black" | ||
force_sort_within_sections = true | ||
default_section = "THIRDPARTY" | ||
skip_glob = ["__init__.py"] | ||
src_paths = ["doc", "src", "tests"] | ||
|
||
[tool.black] | ||
line-length = 100 | ||
skip-string-normalization = true | ||
target-version = ['py39'] | ||
exclude='\.eggs|\.git|\.mypy_cache|\.tox|\.venv|_build|buck-out|build|dist|node_modules' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters