mmgpy 0.5.0__cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

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 (109) hide show
  1. mmgpy/__init__.py +296 -0
  2. mmgpy/__main__.py +13 -0
  3. mmgpy/_io.py +535 -0
  4. mmgpy/_logging.py +290 -0
  5. mmgpy/_mesh.py +2286 -0
  6. mmgpy/_mmgpy.cpython-311-x86_64-linux-gnu.so +0 -0
  7. mmgpy/_mmgpy.pyi +2140 -0
  8. mmgpy/_options.py +304 -0
  9. mmgpy/_progress.py +850 -0
  10. mmgpy/_pyvista.py +410 -0
  11. mmgpy/_result.py +143 -0
  12. mmgpy/_transfer.py +273 -0
  13. mmgpy/_validation.py +669 -0
  14. mmgpy/_version.py +3 -0
  15. mmgpy/_version.py.in +3 -0
  16. mmgpy/bin/mmg2d_O3 +0 -0
  17. mmgpy/bin/mmg3d_O3 +0 -0
  18. mmgpy/bin/mmgs_O3 +0 -0
  19. mmgpy/interactive/__init__.py +24 -0
  20. mmgpy/interactive/sizing_editor.py +790 -0
  21. mmgpy/lagrangian.py +394 -0
  22. mmgpy/lib/libmmg2d.so +0 -0
  23. mmgpy/lib/libmmg2d.so.5 +0 -0
  24. mmgpy/lib/libmmg2d.so.5.8.0 +0 -0
  25. mmgpy/lib/libmmg3d.so +0 -0
  26. mmgpy/lib/libmmg3d.so.5 +0 -0
  27. mmgpy/lib/libmmg3d.so.5.8.0 +0 -0
  28. mmgpy/lib/libmmgs.so +0 -0
  29. mmgpy/lib/libmmgs.so.5 +0 -0
  30. mmgpy/lib/libmmgs.so.5.8.0 +0 -0
  31. mmgpy/lib/libvtkCommonColor-9.5.so.1 +0 -0
  32. mmgpy/lib/libvtkCommonComputationalGeometry-9.5.so.1 +0 -0
  33. mmgpy/lib/libvtkCommonCore-9.5.so.1 +0 -0
  34. mmgpy/lib/libvtkCommonDataModel-9.5.so.1 +0 -0
  35. mmgpy/lib/libvtkCommonExecutionModel-9.5.so.1 +0 -0
  36. mmgpy/lib/libvtkCommonMath-9.5.so.1 +0 -0
  37. mmgpy/lib/libvtkCommonMisc-9.5.so.1 +0 -0
  38. mmgpy/lib/libvtkCommonSystem-9.5.so.1 +0 -0
  39. mmgpy/lib/libvtkCommonTransforms-9.5.so.1 +0 -0
  40. mmgpy/lib/libvtkDICOMParser-9.5.so.1 +0 -0
  41. mmgpy/lib/libvtkFiltersCellGrid-9.5.so.1 +0 -0
  42. mmgpy/lib/libvtkFiltersCore-9.5.so.1 +0 -0
  43. mmgpy/lib/libvtkFiltersExtraction-9.5.so.1 +0 -0
  44. mmgpy/lib/libvtkFiltersGeneral-9.5.so.1 +0 -0
  45. mmgpy/lib/libvtkFiltersGeometry-9.5.so.1 +0 -0
  46. mmgpy/lib/libvtkFiltersHybrid-9.5.so.1 +0 -0
  47. mmgpy/lib/libvtkFiltersHyperTree-9.5.so.1 +0 -0
  48. mmgpy/lib/libvtkFiltersModeling-9.5.so.1 +0 -0
  49. mmgpy/lib/libvtkFiltersParallel-9.5.so.1 +0 -0
  50. mmgpy/lib/libvtkFiltersReduction-9.5.so.1 +0 -0
  51. mmgpy/lib/libvtkFiltersSources-9.5.so.1 +0 -0
  52. mmgpy/lib/libvtkFiltersStatistics-9.5.so.1 +0 -0
  53. mmgpy/lib/libvtkFiltersTexture-9.5.so.1 +0 -0
  54. mmgpy/lib/libvtkFiltersVerdict-9.5.so.1 +0 -0
  55. mmgpy/lib/libvtkIOCellGrid-9.5.so.1 +0 -0
  56. mmgpy/lib/libvtkIOCore-9.5.so.1 +0 -0
  57. mmgpy/lib/libvtkIOGeometry-9.5.so.1 +0 -0
  58. mmgpy/lib/libvtkIOImage-9.5.so.1 +0 -0
  59. mmgpy/lib/libvtkIOLegacy-9.5.so.1 +0 -0
  60. mmgpy/lib/libvtkIOParallel-9.5.so.1 +0 -0
  61. mmgpy/lib/libvtkIOParallelXML-9.5.so.1 +0 -0
  62. mmgpy/lib/libvtkIOXML-9.5.so.1 +0 -0
  63. mmgpy/lib/libvtkIOXMLParser-9.5.so.1 +0 -0
  64. mmgpy/lib/libvtkImagingCore-9.5.so.1 +0 -0
  65. mmgpy/lib/libvtkImagingSources-9.5.so.1 +0 -0
  66. mmgpy/lib/libvtkParallelCore-9.5.so.1 +0 -0
  67. mmgpy/lib/libvtkParallelDIY-9.5.so.1 +0 -0
  68. mmgpy/lib/libvtkRenderingCore-9.5.so.1 +0 -0
  69. mmgpy/lib/libvtkdoubleconversion-9.5.so.1 +0 -0
  70. mmgpy/lib/libvtkexpat-9.5.so.1 +0 -0
  71. mmgpy/lib/libvtkfmt-9.5.so.1 +0 -0
  72. mmgpy/lib/libvtkjpeg-9.5.so.1 +0 -0
  73. mmgpy/lib/libvtkjsoncpp-9.5.so.1 +0 -0
  74. mmgpy/lib/libvtkkissfft-9.5.so.1 +0 -0
  75. mmgpy/lib/libvtkloguru-9.5.so.1 +0 -0
  76. mmgpy/lib/libvtklz4-9.5.so.1 +0 -0
  77. mmgpy/lib/libvtklzma-9.5.so.1 +0 -0
  78. mmgpy/lib/libvtkmetaio-9.5.so.1 +0 -0
  79. mmgpy/lib/libvtkpng-9.5.so.1 +0 -0
  80. mmgpy/lib/libvtkpugixml-9.5.so.1 +0 -0
  81. mmgpy/lib/libvtksys-9.5.so.1 +0 -0
  82. mmgpy/lib/libvtktiff-9.5.so.1 +0 -0
  83. mmgpy/lib/libvtktoken-9.5.so.1 +0 -0
  84. mmgpy/lib/libvtkverdict-9.5.so.1 +0 -0
  85. mmgpy/lib/libvtkzlib-9.5.so.1 +0 -0
  86. mmgpy/metrics.py +596 -0
  87. mmgpy/progress.py +69 -0
  88. mmgpy/py.typed +0 -0
  89. mmgpy/repair/__init__.py +37 -0
  90. mmgpy/repair/_core.py +226 -0
  91. mmgpy/repair/_elements.py +241 -0
  92. mmgpy/repair/_vertices.py +219 -0
  93. mmgpy/sizing.py +370 -0
  94. mmgpy/ui/__init__.py +97 -0
  95. mmgpy/ui/__main__.py +87 -0
  96. mmgpy/ui/app.py +1837 -0
  97. mmgpy/ui/parsers.py +501 -0
  98. mmgpy/ui/remeshing.py +448 -0
  99. mmgpy/ui/samples.py +249 -0
  100. mmgpy/ui/utils.py +280 -0
  101. mmgpy/ui/viewer.py +587 -0
  102. mmgpy-0.5.0.dist-info/METADATA +186 -0
  103. mmgpy-0.5.0.dist-info/RECORD +109 -0
  104. mmgpy-0.5.0.dist-info/WHEEL +6 -0
  105. mmgpy-0.5.0.dist-info/entry_points.txt +13 -0
  106. mmgpy-0.5.0.dist-info/licenses/LICENSE +38 -0
  107. share/man/man1/mmg2d.1.gz +0 -0
  108. share/man/man1/mmg3d.1.gz +0 -0
  109. share/man/man1/mmgs.1.gz +0 -0
mmgpy/__init__.py ADDED
@@ -0,0 +1,296 @@
1
+ """Python bindings for the MMG library."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import site
6
+ import subprocess
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ from ._logging import (
11
+ configure_logging,
12
+ disable_logging,
13
+ enable_debug,
14
+ get_log_file,
15
+ get_logger,
16
+ set_log_file,
17
+ set_log_level,
18
+ )
19
+
20
+ _logger = get_logger()
21
+
22
+ # Version info
23
+ try:
24
+ from . import _version # type: ignore[attr-defined]
25
+
26
+ __version__ = _version.__version__
27
+ except ImportError:
28
+ __version__ = "unknown"
29
+
30
+ # Core C++ bindings
31
+ from ._mmgpy import ( # type: ignore[attr-defined]
32
+ MMG_VERSION,
33
+ mmg2d, # noqa: F401 # Available for advanced users
34
+ mmg3d, # noqa: F401 # Available for advanced users
35
+ mmgs, # noqa: F401 # Available for advanced users
36
+ )
37
+
38
+
39
+ def _find_mmg_executable(base_name: str) -> str | None: # pragma: no cover
40
+ """Find an MMG executable in mmgpy/bin or venv bin directory.
41
+
42
+ Note: We do NOT use shutil.which() because it would find the Python
43
+ entry point scripts in venv/bin/, causing infinite recursion.
44
+
45
+ Args:
46
+ base_name: Base name of executable (e.g., "mmg3d_O3")
47
+
48
+ Returns:
49
+ Full path to executable, or None if not found
50
+
51
+ """
52
+ exe_name = f"{base_name}.exe" if sys.platform == "win32" else base_name
53
+
54
+ # Check mmgpy/bin relative to this package (works for wheel installs)
55
+ package_bin = Path(__file__).parent / "bin" / exe_name
56
+ if package_bin.exists():
57
+ return str(package_bin)
58
+
59
+ # Fall back to mmgpy/bin in site-packages (for editable installs)
60
+ site_packages_list = site.getsitepackages()
61
+ # On Windows, prefer the actual site-packages over the venv root
62
+ if sys.platform == "win32" and len(site_packages_list) > 1:
63
+ site_packages = Path(site_packages_list[1])
64
+ else:
65
+ site_packages = Path(site_packages_list[0])
66
+
67
+ exe_path = site_packages / "mmgpy" / "bin" / exe_name
68
+ if exe_path.exists():
69
+ return str(exe_path)
70
+
71
+ # Check venv bin/Scripts directory (executables copied there by CMake)
72
+ # This is the fallback for editable installs where CMake copies executables
73
+ venv_bin_name = "Scripts" if sys.platform == "win32" else "bin"
74
+ venv_bin = Path(sys.prefix) / venv_bin_name / exe_name
75
+ # Only use if it's an actual executable (not a Python entry point script)
76
+ # Native executables are typically larger than 1KB (Python scripts are ~300 bytes)
77
+ min_native_exe_size = 1024
78
+ if venv_bin.exists() and venv_bin.stat().st_size > min_native_exe_size:
79
+ return str(venv_bin)
80
+
81
+ # For editable installs, check the scikit-build-core build directory
82
+ # The build directory is typically at the project root (parent of src/)
83
+ package_dir = Path(__file__).parent
84
+ if "src" in str(package_dir):
85
+ # Editable install - look in build directory
86
+ project_root = package_dir.parent.parent # src/mmgpy -> src -> project_root
87
+ build_dir = project_root / "build"
88
+ if build_dir.exists():
89
+ # Search for executable in any build subdirectory
90
+ for build_subdir in build_dir.iterdir():
91
+ if build_subdir.is_dir():
92
+ exe_path = build_subdir / "mmgpy" / "bin" / exe_name
93
+ if exe_path.exists():
94
+ return str(exe_path)
95
+
96
+ return None
97
+
98
+
99
+ def _run_mmg2d() -> None: # pragma: no cover
100
+ """Run the mmg2d_O3 executable."""
101
+ exe_path = _find_mmg_executable("mmg2d_O3")
102
+ if exe_path:
103
+ subprocess.run([exe_path, *sys.argv[1:]], check=False)
104
+ else:
105
+ _logger.error("mmg2d_O3 executable not found in PATH or mmgpy/bin")
106
+ sys.exit(1)
107
+
108
+
109
+ def _run_mmg3d() -> None: # pragma: no cover
110
+ """Run the mmg3d_O3 executable."""
111
+ exe_path = _find_mmg_executable("mmg3d_O3")
112
+ if exe_path:
113
+ subprocess.run([exe_path, *sys.argv[1:]], check=False)
114
+ else:
115
+ _logger.error("mmg3d_O3 executable not found in PATH or mmgpy/bin")
116
+ sys.exit(1)
117
+
118
+
119
+ def _run_mmgs() -> None: # pragma: no cover
120
+ """Run the mmgs_O3 executable."""
121
+ exe_path = _find_mmg_executable("mmgs_O3")
122
+ if exe_path:
123
+ subprocess.run([exe_path, *sys.argv[1:]], check=False)
124
+ else:
125
+ _logger.error("mmgs_O3 executable not found in PATH or mmgpy/bin")
126
+ sys.exit(1)
127
+
128
+
129
+ def _run_mmg() -> None: # pragma: no cover
130
+ """Run the appropriate mmg executable based on auto-detected mesh type.
131
+
132
+ This unified command automatically detects the mesh type from the input file
133
+ and delegates to the appropriate mmg2d_O3, mmg3d_O3, or mmgs_O3 executable.
134
+ """
135
+ import meshio # noqa: PLC0415
136
+
137
+ from ._io import _detect_mesh_kind # noqa: PLC0415
138
+ from ._mesh import MeshKind # noqa: PLC0415
139
+
140
+ args = sys.argv[1:]
141
+ if not args or args[0] in ("-h", "--help"):
142
+ print( # noqa: T201
143
+ "mmg - Unified mesh remeshing tool with auto-detection\n\n"
144
+ "Usage: mmg <input_mesh> [options]\n\n"
145
+ "This command automatically detects the mesh type and delegates to:\n"
146
+ " - mmg2d (or mmg2d_O3) for 2D planar meshes (triangles with z~=0)\n"
147
+ " - mmg3d (or mmg3d_O3) for 3D volumetric meshes (tetrahedra)\n"
148
+ " - mmgs (or mmgs_O3) for 3D surface meshes (triangles in 3D space)\n\n"
149
+ "All standard mmg options are passed through to the executable.\n"
150
+ "Run 'mmg3d -h', 'mmg2d -h', or 'mmgs -h' for specific options.",
151
+ )
152
+ sys.exit(0)
153
+
154
+ if args[0] in ("-v", "--version"):
155
+ print(f"mmgpy {__version__}") # noqa: T201
156
+ print(f"MMG {MMG_VERSION}") # noqa: T201
157
+ sys.exit(0)
158
+
159
+ # MMG flags that take an argument (skip the next arg when detecting input file)
160
+ flags_with_args = {
161
+ "-o",
162
+ "-out",
163
+ "-sol",
164
+ "-met",
165
+ "-ls",
166
+ "-lag",
167
+ "-ar",
168
+ "-nr",
169
+ "-hmin",
170
+ "-hmax",
171
+ "-hsiz",
172
+ "-hausd",
173
+ "-hgrad",
174
+ "-hgradreq",
175
+ "-m",
176
+ "-v",
177
+ "-xreg",
178
+ "-nreg",
179
+ "-nsd",
180
+ }
181
+
182
+ # Find the input mesh file (first positional argument that's a file)
183
+ input_mesh = None
184
+ skip_next = False
185
+ for arg in args:
186
+ if skip_next:
187
+ skip_next = False
188
+ continue
189
+ if arg in flags_with_args:
190
+ skip_next = True
191
+ continue
192
+ if not arg.startswith("-") and Path(arg).exists():
193
+ input_mesh = arg
194
+ break
195
+
196
+ if input_mesh is None:
197
+ _logger.error("No input mesh file found in arguments")
198
+ sys.exit(1)
199
+
200
+ # Detect mesh type
201
+ try:
202
+ meshio_mesh = meshio.read(input_mesh)
203
+ mesh_kind = _detect_mesh_kind(meshio_mesh)
204
+ except Exception:
205
+ _logger.exception(
206
+ "Failed to detect mesh type from '%s'. "
207
+ "Try using a specific command instead: mmg3d, mmg2d, or mmgs",
208
+ input_mesh,
209
+ )
210
+ sys.exit(1)
211
+
212
+ # Map mesh kind to executable
213
+ exe_map = {
214
+ MeshKind.TETRAHEDRAL: ("mmg3d_O3", _run_mmg3d),
215
+ MeshKind.TRIANGULAR_2D: ("mmg2d_O3", _run_mmg2d),
216
+ MeshKind.TRIANGULAR_SURFACE: ("mmgs_O3", _run_mmgs),
217
+ }
218
+
219
+ exe_name, run_func = exe_map[mesh_kind]
220
+ _logger.info("Detected %s mesh, using %s", mesh_kind.value, exe_name)
221
+
222
+ # Delegate to the appropriate executable
223
+ run_func()
224
+
225
+
226
+ from . import interactive, lagrangian, metrics, progress, repair, sizing
227
+ from ._io import read
228
+ from ._mesh import Mesh, MeshCheckpoint, MeshKind
229
+ from ._options import Mmg2DOptions, Mmg3DOptions, MmgSOptions
230
+ from ._progress import CancellationError, ProgressEvent, rich_progress
231
+ from ._pyvista import from_pyvista, to_pyvista
232
+ from ._result import RemeshResult
233
+ from ._transfer import interpolate_field, transfer_fields
234
+ from ._validation import (
235
+ IssueSeverity,
236
+ QualityStats,
237
+ ValidationError,
238
+ ValidationIssue,
239
+ ValidationReport,
240
+ )
241
+ from .lagrangian import detect_boundary_vertices, move_mesh, propagate_displacement
242
+ from .sizing import (
243
+ BoxSize,
244
+ CylinderSize,
245
+ PointSize,
246
+ SizingConstraint,
247
+ SphereSize,
248
+ apply_sizing_constraints,
249
+ )
250
+
251
+ __all__ = [
252
+ "MMG_VERSION",
253
+ "BoxSize",
254
+ "CancellationError",
255
+ "CylinderSize",
256
+ "IssueSeverity",
257
+ "Mesh",
258
+ "MeshCheckpoint",
259
+ "MeshKind",
260
+ "Mmg2DOptions",
261
+ "Mmg3DOptions",
262
+ "MmgSOptions",
263
+ "PointSize",
264
+ "ProgressEvent",
265
+ "QualityStats",
266
+ "RemeshResult",
267
+ "SizingConstraint",
268
+ "SphereSize",
269
+ "ValidationError",
270
+ "ValidationIssue",
271
+ "ValidationReport",
272
+ "__version__",
273
+ "apply_sizing_constraints",
274
+ "configure_logging",
275
+ "detect_boundary_vertices",
276
+ "disable_logging",
277
+ "enable_debug",
278
+ "from_pyvista",
279
+ "get_log_file",
280
+ "get_logger",
281
+ "interactive",
282
+ "interpolate_field",
283
+ "lagrangian",
284
+ "metrics",
285
+ "move_mesh",
286
+ "progress",
287
+ "propagate_displacement",
288
+ "read",
289
+ "repair",
290
+ "rich_progress",
291
+ "set_log_file",
292
+ "set_log_level",
293
+ "sizing",
294
+ "to_pyvista",
295
+ "transfer_fields",
296
+ ]
mmgpy/__main__.py ADDED
@@ -0,0 +1,13 @@
1
+ """Entry point for running mmgpy as a module.
2
+
3
+ This enables usage like:
4
+ python -m mmgpy mesh.stl -o remeshed.stl
5
+ uvx mmgpy mesh.stl -o remeshed.stl
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from . import _run_mmg
11
+
12
+ if __name__ == "__main__":
13
+ _run_mmg()