ply3d 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. ply3d-0.1.0/.gitignore +106 -0
  2. ply3d-0.1.0/.gitlab-ci.yml +70 -0
  3. ply3d-0.1.0/PKG-INFO +65 -0
  4. ply3d-0.1.0/README.md +52 -0
  5. ply3d-0.1.0/docs/gen_pages.py +34 -0
  6. ply3d-0.1.0/docs/import.md +63 -0
  7. ply3d-0.1.0/docs/index.md +110 -0
  8. ply3d-0.1.0/docs/io.md +50 -0
  9. ply3d-0.1.0/docs/mesh.md +104 -0
  10. ply3d-0.1.0/docs/visualization.md +163 -0
  11. ply3d-0.1.0/environment.yml +16 -0
  12. ply3d-0.1.0/example_data/3Dhypocotyl.init +6315 -0
  13. ply3d-0.1.0/example_data/3Dhypocotyl.ply +4307 -0
  14. ply3d-0.1.0/example_data/CylinderCells.ply +1331 -0
  15. ply3d-0.1.0/example_data/PavementCellsMerged.ply +144566 -0
  16. ply3d-0.1.0/example_data/PavementCellsSeperated.ply +88131 -0
  17. ply3d-0.1.0/example_data/RadicleSmall.ply +649524 -0
  18. ply3d-0.1.0/example_data/dome3.init +0 -0
  19. ply3d-0.1.0/example_data/dome3D.ply +39821 -0
  20. ply3d-0.1.0/example_data/dome3D_test.ply +23 -0
  21. ply3d-0.1.0/example_data/hexagonal_prisms.ply +200 -0
  22. ply3d-0.1.0/example_data/hexagonal_prisms_triangulated.ply +608 -0
  23. ply3d-0.1.0/example_data/meristemE.init +3190 -0
  24. ply3d-0.1.0/example_data/meristemE.neigh +3191 -0
  25. ply3d-0.1.0/example_data/segmentation_topomesh.ply +8315 -0
  26. ply3d-0.1.0/example_data/teapot.obj +2090 -0
  27. ply3d-0.1.0/example_data/template2dFine.init +4329 -0
  28. ply3d-0.1.0/example_data/yr01_t081_seg_rot_simple_draco_topomesh.ply +8446 -0
  29. ply3d-0.1.0/example_data/yr01_t081_seg_rot_simple_draco_topomesh_new.ply +8446 -0
  30. ply3d-0.1.0/mkdocs.yml +67 -0
  31. ply3d-0.1.0/pyproject.toml +34 -0
  32. ply3d-0.1.0/setup.cfg +4 -0
  33. ply3d-0.1.0/src/ply3d/__init__.py +0 -0
  34. ply3d-0.1.0/src/ply3d/classes.py +123 -0
  35. ply3d-0.1.0/src/ply3d/cli/__init__.py +0 -0
  36. ply3d-0.1.0/src/ply3d/cli/converter_py.py +57 -0
  37. ply3d-0.1.0/src/ply3d/deprecated/__init__.py +0 -0
  38. ply3d-0.1.0/src/ply3d/deprecated/ply_parser_dict.py +326 -0
  39. ply3d-0.1.0/src/ply3d/deprecated/test.py +20 -0
  40. ply3d-0.1.0/src/ply3d/deprecated/test_ply_parser.py +21 -0
  41. ply3d-0.1.0/src/ply3d/deprecated/test_ply_parser_binary.py +22 -0
  42. ply3d-0.1.0/src/ply3d/deprecated/test_ply_parser_read.py +19 -0
  43. ply3d-0.1.0/src/ply3d/init_parser.py +158 -0
  44. ply3d-0.1.0/src/ply3d/init_plotter.py +41 -0
  45. ply3d-0.1.0/src/ply3d/mesh.py +534 -0
  46. ply3d-0.1.0/src/ply3d/meshio_import.py +368 -0
  47. ply3d-0.1.0/src/ply3d/ply_parser.py +690 -0
  48. ply3d-0.1.0/src/ply3d/ply_parser_string.py +134 -0
  49. ply3d-0.1.0/src/ply3d/test_output.ply +13 -0
  50. ply3d-0.1.0/src/ply3d/test_output_converted.ply +13 -0
  51. ply3d-0.1.0/src/ply3d/vtk_export.py +352 -0
  52. ply3d-0.1.0/src/ply3d/vtk_view.py +118 -0
  53. ply3d-0.1.0/src/ply3d.egg-info/PKG-INFO +65 -0
  54. ply3d-0.1.0/src/ply3d.egg-info/SOURCES.txt +58 -0
  55. ply3d-0.1.0/src/ply3d.egg-info/dependency_links.txt +1 -0
  56. ply3d-0.1.0/src/ply3d.egg-info/requires.txt +4 -0
  57. ply3d-0.1.0/src/ply3d.egg-info/top_level.txt +1 -0
  58. ply3d-0.1.0/test/test_meshio_import.py +22 -0
  59. ply3d-0.1.0/test/test_ply_mesh.py +30 -0
  60. ply3d-0.1.0/test/test_vtk_export.py +38 -0
ply3d-0.1.0/.gitignore ADDED
@@ -0,0 +1,106 @@
1
+ .idea/
2
+ *.swp
3
+
4
+ # Byte-compiled / optimized / DLL files
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+
9
+ # C extensions
10
+ *.so
11
+
12
+ # Distribution / packaging
13
+ .Python
14
+ build/
15
+ develop-eggs/
16
+ dist/
17
+ downloads/
18
+ eggs/
19
+ .eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ wheels/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ .hypothesis/
50
+
51
+ # Translations
52
+ *.mo
53
+ *.pot
54
+
55
+ # Django stuff:
56
+ *.log
57
+ local_settings.py
58
+
59
+ # Flask stuff:
60
+ instance/
61
+ .webassets-cache
62
+
63
+ # Scrapy stuff:
64
+ .scrapy
65
+
66
+ # Sphinx documentation
67
+ docs/_build/
68
+
69
+ # PyBuilder
70
+ target/
71
+
72
+ # Jupyter Notebook
73
+ .ipynb_checkpoints
74
+ .virtual_documents
75
+
76
+ # pyenv
77
+ .python-version
78
+
79
+ # celery beat schedule file
80
+ celerybeat-schedule
81
+
82
+ # SageMath parsed files
83
+ *.sage.py
84
+
85
+ # Environments
86
+ .env
87
+ .venv
88
+ env/
89
+ venv/
90
+ ENV/
91
+
92
+ # Spyder project settings
93
+ .spyderproject
94
+ .spyproject
95
+
96
+ # Rope project settings
97
+ .ropeproject
98
+
99
+ # mkdocs documentation
100
+ /site
101
+
102
+ # mypy
103
+ .mypy_cache/
104
+
105
+ # macos
106
+ .DS_Store
@@ -0,0 +1,70 @@
1
+ image: continuumio/miniconda3:latest
2
+ cache:
3
+ paths:
4
+ - .pip-cache/
5
+ before_script:
6
+ - python --version
7
+ - pip install --upgrade pip
8
+ - pip install build twine
9
+
10
+ stages:
11
+ - build
12
+ - test
13
+ - deploy
14
+
15
+ variables:
16
+ PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"
17
+
18
+ build:
19
+ stage: build
20
+ script:
21
+ - python -m build
22
+ artifacts:
23
+ paths:
24
+ - dist/
25
+ rules:
26
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
27
+ when: manual
28
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
29
+
30
+ test:
31
+ stage: test
32
+ script:
33
+ - pip install dist/*.whl
34
+ - pip install pytest pytest-cov
35
+ - pytest -v test/
36
+ rules:
37
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
38
+ when: manual
39
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
40
+
41
+ publish:
42
+ stage: deploy
43
+ script:
44
+ - TWINE_PASSWORD=${PYPI_TOKEN} TWINE_USERNAME=__token__ python -m twine upload --verbose --repository pypi dist/*
45
+ rules:
46
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
47
+
48
+ pages:
49
+ stage: deploy
50
+ script:
51
+ - apt-get update && apt-get install libxcursor-dev libgl1 libglx-mesa0 xvfb -y
52
+ - conda env create -f environment.yml
53
+ - source activate ply3d
54
+ - which pip
55
+ - export DISPLAY=:99.0
56
+ - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
57
+ - sleep 3
58
+ - pip install "mkdocs<=1.6.1" pymdown-extensions mkdocs-material "markdown-exec[ansi]"
59
+ - pip install "mkdocstrings[python]>=0.18" mkdocs-gen-files
60
+ - pip install mkdocs-literate-nav mkdocs-section-index
61
+ - pip install --no-deps .
62
+ - mkdocs build
63
+ - mv ./site public
64
+ artifacts:
65
+ paths:
66
+ - public
67
+ rules:
68
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
69
+ when: manual
70
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
ply3d-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,65 @@
1
+ Metadata-Version: 2.4
2
+ Name: ply3d
3
+ Version: 0.1.0
4
+ Summary: A Python library for manipulating PLY 3D geometries of multicellular tissues
5
+ Author-email: Ross Carter <ross.carter@slcu.cam.ac.uk>, John Fozard <john.fozard@jic.ac.uk>, Guillaume Cerutti <guillaume.cerutti@ens-lyon.fr>
6
+ Maintainer-email: Guillaume Cerutti <guillaume.cerutti@ens-lyon.fr>
7
+ Project-URL: Homepage, https://gitlab.com/morphodynamics/mesh/ply3d_python
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: matplotlib
10
+ Requires-Dist: meshio
11
+ Requires-Dist: pyvista[colormaps]
12
+ Requires-Dist: tqdm
13
+
14
+ # PLY 3D
15
+
16
+ A Python library for manipulating PLY 3D geometries of multicellular tissues.
17
+
18
+ ## Motivation
19
+
20
+ **PLY 3D** is an extension of the [PLY format](https://paulbourke.net/dataformats/ply/) introduced to store 3D meshes composed of interconnected, arbitrary polyhedral cells. While complying with the specifications of the original format, it introduces a number of specific syntaxes for mesh elements and properties.
21
+
22
+ ## Usage
23
+
24
+ In Python, you can use the library to load and manipulate such meshes, and visualize them with all their properties using `pyvista`:
25
+
26
+ ```python
27
+ from ply3d.ply_parser import read_ply_mesh
28
+
29
+ mesh = read_ply_mesh("example_data/CylinderCells.ply")
30
+ # mesh.vertices.points, mesh.volumes.face_indices, ...
31
+ ```
32
+
33
+ ```python
34
+ from ply3d.vtk_export import unstructured_grid_from_mesh
35
+
36
+ grid = unstructured_grid_from_mesh(mesh, elements_to_export=['volume'])
37
+ ```
38
+
39
+ ```python
40
+ import pyvista as pv
41
+
42
+ plotter = pv.Plotter()
43
+ plotter.add_mesh(
44
+ grid.shrink(0.9),
45
+ scalars='label', cmap='glasbey', clim=(0, 255), show_scalar_bar=False
46
+ )
47
+ plotter.show()
48
+ ```
49
+
50
+ ## Installation
51
+
52
+ `ply3d` is available on PyPI (the Python Package Index) and can be installed by running:
53
+
54
+ ```bash
55
+ pip install ply3d
56
+ ```
57
+
58
+ ## Documentation
59
+
60
+ Please take a look at the [documentation](https://morphodynamics.gitlab.io/mesh/ply3d_python/) for more information on installation and usage
61
+
62
+
63
+ ## Authors
64
+
65
+ This project is developed and maintained by the [Computational Morphodynamics Group](https://computationalmorphodynamics.org/); find out more about the [research groups](https://computationalmorphodynamics.org/research-groups/) involved.
ply3d-0.1.0/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # PLY 3D
2
+
3
+ A Python library for manipulating PLY 3D geometries of multicellular tissues.
4
+
5
+ ## Motivation
6
+
7
+ **PLY 3D** is an extension of the [PLY format](https://paulbourke.net/dataformats/ply/) introduced to store 3D meshes composed of interconnected, arbitrary polyhedral cells. While complying with the specifications of the original format, it introduces a number of specific syntaxes for mesh elements and properties.
8
+
9
+ ## Usage
10
+
11
+ In Python, you can use the library to load and manipulate such meshes, and visualize them with all their properties using `pyvista`:
12
+
13
+ ```python
14
+ from ply3d.ply_parser import read_ply_mesh
15
+
16
+ mesh = read_ply_mesh("example_data/CylinderCells.ply")
17
+ # mesh.vertices.points, mesh.volumes.face_indices, ...
18
+ ```
19
+
20
+ ```python
21
+ from ply3d.vtk_export import unstructured_grid_from_mesh
22
+
23
+ grid = unstructured_grid_from_mesh(mesh, elements_to_export=['volume'])
24
+ ```
25
+
26
+ ```python
27
+ import pyvista as pv
28
+
29
+ plotter = pv.Plotter()
30
+ plotter.add_mesh(
31
+ grid.shrink(0.9),
32
+ scalars='label', cmap='glasbey', clim=(0, 255), show_scalar_bar=False
33
+ )
34
+ plotter.show()
35
+ ```
36
+
37
+ ## Installation
38
+
39
+ `ply3d` is available on PyPI (the Python Package Index) and can be installed by running:
40
+
41
+ ```bash
42
+ pip install ply3d
43
+ ```
44
+
45
+ ## Documentation
46
+
47
+ Please take a look at the [documentation](https://morphodynamics.gitlab.io/mesh/ply3d_python/) for more information on installation and usage
48
+
49
+
50
+ ## Authors
51
+
52
+ This project is developed and maintained by the [Computational Morphodynamics Group](https://computationalmorphodynamics.org/); find out more about the [research groups](https://computationalmorphodynamics.org/research-groups/) involved.
@@ -0,0 +1,34 @@
1
+ """Generate the code reference pages."""
2
+
3
+ from pathlib import Path
4
+
5
+ import mkdocs_gen_files
6
+
7
+ nav = mkdocs_gen_files.Nav()
8
+
9
+ root = Path(__file__).parent.parent
10
+ print(root)
11
+ src = root / "src"
12
+
13
+ for path in sorted(src.rglob("*.py")):
14
+ module_path = path.relative_to(src).with_suffix("")
15
+ doc_path = path.relative_to(src).with_suffix(".md")
16
+ full_doc_path = Path("reference", doc_path)
17
+
18
+ parts = tuple(module_path.parts)
19
+
20
+ if parts[-1] == "__init__":
21
+ parts = parts[:-1]
22
+ doc_path = doc_path.with_name("index.md")
23
+ full_doc_path = full_doc_path.with_name("index.md")
24
+ elif parts[-1] == "__main__":
25
+ continue
26
+
27
+ with mkdocs_gen_files.open(full_doc_path, "w") as fd:
28
+ identifier = ".".join(parts)
29
+ print("::: " + identifier, file=fd)
30
+
31
+ mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root))
32
+
33
+ with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file:
34
+ nav_file.writelines(nav.build_literate_nav())
@@ -0,0 +1,63 @@
1
+ # Importing Meshes
2
+
3
+ There are dozens of existing mesh file formats that are used to store surfacic meshes or volumetric meshes, usually composed of standard volume elements (tetrahedra or hexahedra). Fortunately, the [`meshio`](https://pypi.org/project/meshio/) Python library almost supports them all!
4
+
5
+ ## Importing meshes using `meshio`
6
+
7
+ The `ply3d` library relies on `meshio` to provide a generic reader function ([`read_meshio_mesh`](reference/ply3d/meshio_import.md)) that reads virtually any commonly used mesh format and loads it as a [`Mesh`](reference/ply3d/mesh.md) object.
8
+
9
+ ```python exec="true" source="console" session="import"
10
+ from ply3d.meshio_import import read_meshio_mesh
11
+
12
+ mesh_filename = "example_data/teapot.obj"
13
+ mesh = read_meshio_mesh(mesh_filename)
14
+ ```
15
+
16
+ ```python exec="true" result='python' session="import"
17
+ print(mesh)
18
+ ```
19
+
20
+ ```python exec="true" session="import" html="true"
21
+ from io import StringIO
22
+
23
+ import pyvista as pv
24
+ import matplotlib.pyplot as plt
25
+
26
+ from ply3d.vtk_export import unstructured_grid_from_mesh
27
+
28
+ grid = unstructured_grid_from_mesh(mesh)
29
+
30
+ plotter = pv.Plotter(off_screen=True, window_size=(1500, 750))
31
+
32
+ figure = plt.figure(figsize=(9, 4.5))
33
+ ax = figure.gca()
34
+
35
+ plotter.clear_actors()
36
+ plotter.add_mesh(
37
+ grid, color='w'
38
+ )
39
+ plotter.add_mesh(
40
+ grid.extract_all_edges(), color='k',
41
+ render_lines_as_tubes=True, line_width=2
42
+ )
43
+ plotter.view_xy(negative=False)
44
+ plotter.zoom_camera(2.)
45
+
46
+ ax.imshow(plotter.screenshot())
47
+ ax.axis('off')
48
+
49
+ buffer = StringIO()
50
+ plt.savefig(buffer, format="svg")
51
+ print(buffer.getvalue())
52
+ ```
53
+
54
+ ### Volumetric meshes
55
+
56
+ In most mesh formats, volume elements (such as tetrahedra) are defined directly as lists of vertices. The PLY 3D format requires however volume elements to be defined by their bounding faces. When the mesh read through `meshio` contains volume elements but not their faces, those are created and appended to the `Mesh` face elements.
57
+
58
+ !!! warning "XDMF time series"
59
+
60
+ The XDMF mesh format supports time-indexed properties on the elements of a shared mesh. While supporting this format, only the data corresponding to the first time point will be stored as properties on the loaded `Mesh` object.
61
+
62
+
63
+ The obtained `Mesh` object can then be converted to a PLY 3D file using the [I/O writer functions](io.md).
@@ -0,0 +1,110 @@
1
+ # PLY 3D
2
+
3
+ A Python library for manipulating PLY 3D geometries of multicellular tissues.
4
+
5
+ ## What is PLY 3D?
6
+
7
+ The **PLY 3D** format is [a proposed extension](https://gitlab.com/morphodynamics/mesh/documentation/-/blob/master/PlyFormat.pdf?ref_type=heads) of the PLY Polygon File Format for meshes that allows to store 3D connected topological structures in a simple and efficient way. As it complies with [the specifications of the PLY format](https://paulbourke.net/dataformats/ply/) it uses the `.ply` extension. However, it introduces a number of specific syntaxes for mesh elements and properties, enabling to conveniently store 3D meshes composed of interconnected, arbitrary polyhedral cells - such as those used to represent multicellular biological tissues.
8
+
9
+ ```python exec="true" session="index" html="true"
10
+ from io import StringIO
11
+
12
+ import matplotlib.pyplot as plt
13
+ import pyvista as pv
14
+
15
+ from ply3d.ply_parser import read_ply_mesh
16
+ from ply3d.vtk_export import unstructured_grid_from_mesh
17
+
18
+
19
+ ply_filename = "example_data/CylinderCells.ply"
20
+ mesh = read_ply_mesh(ply_filename)
21
+ grid = unstructured_grid_from_mesh(mesh)
22
+
23
+ plotter = pv.Plotter(off_screen=True, window_size=(1500, 1500))
24
+
25
+
26
+ figure = plt.figure(figsize=(12, 6))
27
+ axes = figure.subplots(1, 2)
28
+
29
+ ax = axes[0]
30
+ plotter.clear_actors()
31
+ plotter.add_mesh(
32
+ grid.extract_cells_by_type(pv.CellType.POLYHEDRON).shrink(0.95),
33
+ scalars='label', cmap='glasbey', clim=(0, 255), show_scalar_bar=False
34
+ )
35
+ plotter.set_focus((0, 0, 0))
36
+ plotter.set_position((0, 1, 1), reset=True)
37
+ plotter.set_viewup((0, -1, 0))
38
+ plotter.zoom_camera(1.2)
39
+
40
+ ax.imshow(plotter.screenshot())
41
+ ax.axis('off')
42
+
43
+ ax = axes[1]
44
+ plotter.clear_actors()
45
+ plotter.add_mesh(grid.glyph(geom=pv.Sphere(radius=0.25), scale=False, orient=False), color='b')
46
+ plotter.add_mesh(grid.extract_cells_by_type(pv.CellType.LINE).extract_geometry().tube(radius=0.1), color='m')
47
+ plotter.add_mesh(
48
+ grid.extract_cells_by_type(pv.CellType.POLYGON).shrink(0.6),
49
+ color='limegreen', opacity=1.,
50
+ style='wireframe', line_width=3
51
+ )
52
+ plotter.add_mesh(
53
+ grid.extract_cells_by_type(pv.CellType.POLYHEDRON).shrink(0.95),
54
+ # scalars='display_label', cmap='glasbey', clim=(0, 255)
55
+ color='w', opacity=0.25
56
+ )
57
+
58
+ plotter.set_focus((0, 0, 0))
59
+ plotter.set_position((0, 1, 1), reset=True)
60
+ plotter.set_viewup((0, -1, 0))
61
+ plotter.zoom_camera(1.2)
62
+
63
+ ax.imshow(plotter.screenshot())
64
+ ax.axis('off')
65
+
66
+ figure.tight_layout()
67
+
68
+ buffer = StringIO()
69
+ plt.savefig(buffer, format="svg")
70
+ print(buffer.getvalue())
71
+ ```
72
+
73
+ The `ply3d` Python library is a tool for manipulating and interacting with such structures stored as **PLY 3D** files. It provides high-level functions to perform the following tasks:
74
+ <div class="grid cards" markdown>
75
+
76
+ - [:fontawesome-solid-folder-open: **I/O**](io.md)
77
+
78
+ Read and write meshes from / to files in the PLY 3D format
79
+
80
+ - [:fontawesome-solid-circle-nodes: **Data Structure**](mesh.md)
81
+
82
+ Inspect meshes and edit their elements and properties
83
+
84
+ - [:fontawesome-solid-eye: **Visualization**](visualization.md)
85
+
86
+ View meshes with their properties as [`pyvista`](https://pyvista.org/) (VTK) objects
87
+
88
+ - [:fontawesome-solid-file-import: **Conversion**](import.md)
89
+
90
+ Import meshes from other file formats through [`meshio`](https://pypi.org/project/meshio/)
91
+
92
+ </div>
93
+
94
+ ## Installation
95
+
96
+ `ply3d` is available on PyPI (the Python Package Index) and can be installed by running:
97
+
98
+ ```bash
99
+ pip install ply3d
100
+ ```
101
+
102
+ The library can also be installed [from sources](https://gitlab.com/morphodynamics/mesh/ply3d_python) after downloading it, by navigating to the project directory (potentially activating a virtual environment) and running:
103
+
104
+ ```bash
105
+ pip install -e .
106
+ ```
107
+
108
+ !!! info "See also"
109
+
110
+ A [C++ header-only parser for the PLY 3D format](https://gitlab.com/morphodynamics/mesh/ply3d) is also available; if this better suits your project's needs, please consider using it!
ply3d-0.1.0/docs/io.md ADDED
@@ -0,0 +1,50 @@
1
+ # PLY 3D I/O
2
+
3
+ The primary goal of the `ply3d` library is to provide a convenient way of reading PLY 3D mesh files, as well as to export geometries to that format.
4
+
5
+ ## Reading a PLY 3D mesh
6
+
7
+ The module [`ply3d.ply_parser`](reference/ply3d/ply_parser.md) provides a parser for both ASCII and binary formatted PLY 3D files, and allows to load them as [`Mesh`](reference/ply3d/mesh.md) objects:
8
+
9
+ ```python exec="true" source="console" session="io"
10
+ from ply3d.ply_parser import read_ply_mesh
11
+
12
+ ply_filename = "example_data/hexagonal_prisms.ply"
13
+ mesh = read_ply_mesh(ply_filename)
14
+ ```
15
+
16
+ ```python exec="true" result='python' session="io"
17
+ print(mesh)
18
+ ```
19
+
20
+ Python offers the possibility to dynamically inspect the data represented in the `Mesh` data structure. For instance, it is straightforward to access the mesh vertex positions as a Python dictionary (where the keys correspond to the vertex indices):
21
+
22
+ ```python exec="true" source="console" session="io"
23
+ mesh.vertices.points
24
+ ```
25
+
26
+ ```python exec="true" result='python' session="io"
27
+ print("{")
28
+ print(f" 0: {mesh.vertices.points[0]},")
29
+ print(f" 1: {mesh.vertices.points[1]},")
30
+ print(" ...")
31
+ print(f" {len(mesh.vertices)-2}: {mesh.vertices.points[len(mesh.vertices)-2]}")
32
+ print(f" {len(mesh.vertices)-1}: {mesh.vertices.points[len(mesh.vertices)-1]}")
33
+ print("}")
34
+ ```
35
+
36
+ Similarly, it is easy to access properties defined of the mesh elements as Python dictionaries. Note that these dictionaries are mutable, and that modifying them will change the data of the `Mesh`.
37
+
38
+ ```python exec="true" source="console" session="io"
39
+ mesh.faces.properties['area']
40
+ ```
41
+
42
+ ```python exec="true" result='python' session="io"
43
+ print("{")
44
+ print(f" 0: {mesh.faces.properties['area'][0]},")
45
+ print(f" 1: {mesh.faces.properties['area'][1]},")
46
+ print(" ...")
47
+ print(f" {len(mesh.faces)-2}: {mesh.faces.properties['area'][len(mesh.faces)-2]}")
48
+ print(f" {len(mesh.faces)-1}: {mesh.faces.properties['area'][len(mesh.faces)-1]}")
49
+ print("}")
50
+ ```
@@ -0,0 +1,104 @@
1
+ # Mesh Data Structure
2
+
3
+ Meshes in the PLY 3D format are defined by a set of **vertices**, each with a 3D position, together with collections of higher-dimension geometric elements built upon these vertices:
4
+
5
+ - **edges** with their extremities defined by exactly 2 vertices
6
+ - **faces** (polygonal) defined as an ordered list of vertices
7
+ - **volumes** (polyhedral) delimited by an oriented set of faces
8
+
9
+ ## Mesh elements
10
+
11
+ The structure of the central [`Mesh`](reference/ply3d/mesh.md) object in `ply3d` reflects this definition, and basically corresponds to a dictionary structure with 4 keys corresponding to the 4 mesh elements of increasing dimensions: `'vertex'`, `'edge'`, `'face'`and `'volume'`:
12
+
13
+ ```python exec="true" source="console" session="mesh"
14
+ from ply3d.mesh import Mesh
15
+
16
+ mesh = Mesh(
17
+ vertex_points=[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]],
18
+ face_vertex_indices=[[0, 1, 2], [1, 3, 2]]
19
+ )
20
+ ```
21
+
22
+ ```python exec="true" result='python' session="mesh"
23
+ print(mesh)
24
+ ```
25
+
26
+ These elements are accessible by their key, just as in a standard Python dictionary:
27
+
28
+ ```python exec="true" source="console" session="mesh"
29
+ mesh['vertex']
30
+ ```
31
+
32
+ ```python exec="true" result='python' session="mesh"
33
+ print(mesh['vertex'])
34
+ ```
35
+
36
+ But convenience accessors are also provided, using the plural of the element name:
37
+
38
+ ```python exec="true" source="console" session="mesh"
39
+ mesh.faces
40
+ ```
41
+
42
+ ```python exec="true" result='python' session="mesh"
43
+ print(mesh.faces)
44
+ ```
45
+
46
+ ## Element properties
47
+
48
+ Properties can be attached to the mesh elements, as dictionaries indexed by the element **indices**, and identified by a **property name**:
49
+
50
+ ```python exec="true" source="console" session="mesh"
51
+ from numpy.random import rand, randint
52
+
53
+ mesh.set_property(
54
+ element_name='face', property_name='random',
55
+ property_dict={f: rand() for f in mesh['face'].indices}
56
+ )
57
+
58
+ mesh.set_property(
59
+ element_name='face', property_name='random_list',
60
+ property_dict={f: [rand() for _ in range(randint(2, 5))] for f in mesh['face'].indices}
61
+ )
62
+
63
+ mesh.faces
64
+ ```
65
+
66
+ ```python exec="true" result='python' session="mesh"
67
+ print(mesh.faces)
68
+ ```
69
+
70
+ Properties attached to the mesh elements can be accessed just as a regular dictionary:
71
+
72
+ ```python exec="true" source="console" session="mesh"
73
+ mesh.faces.properties
74
+ ```
75
+
76
+ ```python exec="true" result='python' session="mesh"
77
+ print("{")
78
+ for i_p, (property_name, property_dict) in enumerate(mesh.faces.properties.items()):
79
+ print(f" '{property_name}': {{")
80
+ for i_v, (key, value) in enumerate(property_dict.items()):
81
+ print(f" {key}: {value}{',' if i_v < len(property_dict)-1 else ''}")
82
+ print(f" }}{',' if i_p < len(mesh.faces.properties)-1 else ''}")
83
+ print("}")
84
+ ```
85
+
86
+ But in addition, each property has a **type** (more precisely a list of type names) that corresponds to the way it would be typed in a PLY file header:
87
+
88
+ ```python exec="true" source="console" session="mesh"
89
+ mesh.faces.properties['random'].property_type
90
+ ```
91
+
92
+ ```python exec="true" result='python' session="mesh"
93
+ print(mesh.faces.properties['random'].property_type)
94
+ ```
95
+
96
+ The type can be passed when setting the property on the mesh, but if none is given, it is guessed from the values of the property dictionary:
97
+
98
+ ```python exec="true" source="console" session="mesh"
99
+ mesh.faces.properties['random_list'].property_type
100
+ ```
101
+
102
+ ```python exec="true" result='python' session="mesh"
103
+ print(mesh.faces.properties['random_list'].property_type)
104
+ ```