shapemesh 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.
- shapemesh-0.1.0/.github/workflows/ci.yml +249 -0
- shapemesh-0.1.0/.gitignore +23 -0
- shapemesh-0.1.0/.python-version +1 -0
- shapemesh-0.1.0/AGENTS.md +122 -0
- shapemesh-0.1.0/CHANGELOG.md +16 -0
- shapemesh-0.1.0/COPYING +674 -0
- shapemesh-0.1.0/COPYING.LESSER +165 -0
- shapemesh-0.1.0/PKG-INFO +144 -0
- shapemesh-0.1.0/README.md +114 -0
- shapemesh-0.1.0/design-v1.md +666 -0
- shapemesh-0.1.0/docs/index.md +6 -0
- shapemesh-0.1.0/docs/labels.md +39 -0
- shapemesh-0.1.0/docs/release-review-0.1.0.md +552 -0
- shapemesh-0.1.0/docs/threading.md +28 -0
- shapemesh-0.1.0/docs/version-policy.md +10 -0
- shapemesh-0.1.0/examples/beam_with_hole.py +42 -0
- shapemesh-0.1.0/examples/frame.py +52 -0
- shapemesh-0.1.0/examples/pilecap.py +56 -0
- shapemesh-0.1.0/pyproject.toml +105 -0
- shapemesh-0.1.0/src/shapemesh/__init__.py +103 -0
- shapemesh-0.1.0/src/shapemesh/builder.py +301 -0
- shapemesh-0.1.0/src/shapemesh/constants.py +32 -0
- shapemesh-0.1.0/src/shapemesh/errors.py +62 -0
- shapemesh-0.1.0/src/shapemesh/mesh.py +1096 -0
- shapemesh-0.1.0/src/shapemesh/py.typed +0 -0
- shapemesh-0.1.0/src/shapemesh/settings.py +158 -0
- shapemesh-0.1.0/src/shapemesh/shapes.py +1007 -0
- shapemesh-0.1.0/tests/test_booleans.py +82 -0
- shapemesh-0.1.0/tests/test_mesh_io.py +458 -0
- shapemesh-0.1.0/tests/test_pipeline.py +349 -0
- shapemesh-0.1.0/tests/test_primitives.py +97 -0
- shapemesh-0.1.0/tests/test_settings.py +106 -0
- shapemesh-0.1.0/tests/test_shapes.py +310 -0
- shapemesh-0.1.0/tests/test_threading.py +59 -0
- shapemesh-0.1.0/uv.lock +232 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
tags:
|
|
8
|
+
- "v*"
|
|
9
|
+
pull_request:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
UV_VERSION: "0.13.5"
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
quality:
|
|
24
|
+
name: Lint, format, and type check
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
timeout-minutes: 15
|
|
27
|
+
env:
|
|
28
|
+
UV_PYTHON: "3.13"
|
|
29
|
+
steps:
|
|
30
|
+
- name: Check out repository
|
|
31
|
+
uses: actions/checkout@v7
|
|
32
|
+
with:
|
|
33
|
+
persist-credentials: false
|
|
34
|
+
|
|
35
|
+
- name: Install uv and Python
|
|
36
|
+
uses: astral-sh/setup-uv@v10.3.2
|
|
37
|
+
with:
|
|
38
|
+
version: ${{ env.UV_VERSION }}
|
|
39
|
+
python-version: "3.13"
|
|
40
|
+
enable-cache: true
|
|
41
|
+
cache-dependency-glob: uv.lock
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: uv sync --locked --python 3.13
|
|
45
|
+
|
|
46
|
+
- name: Check lockfile
|
|
47
|
+
run: uv lock --check
|
|
48
|
+
|
|
49
|
+
- name: Lint
|
|
50
|
+
run: uv run --no-sync ruff check .
|
|
51
|
+
|
|
52
|
+
- name: Check formatting
|
|
53
|
+
run: uv run --no-sync ruff format --check .
|
|
54
|
+
|
|
55
|
+
- name: Type check
|
|
56
|
+
run: uv run --no-sync pyright
|
|
57
|
+
|
|
58
|
+
test:
|
|
59
|
+
name: Test (${{ matrix.os }}, Python ${{ matrix.python-version }})
|
|
60
|
+
runs-on: ${{ matrix.os }}
|
|
61
|
+
timeout-minutes: 20
|
|
62
|
+
env:
|
|
63
|
+
UV_PYTHON: ${{ matrix.python-version }}
|
|
64
|
+
strategy:
|
|
65
|
+
fail-fast: false
|
|
66
|
+
matrix:
|
|
67
|
+
os:
|
|
68
|
+
- ubuntu-latest
|
|
69
|
+
- macos-latest
|
|
70
|
+
- windows-latest
|
|
71
|
+
python-version:
|
|
72
|
+
- "3.12"
|
|
73
|
+
- "3.13"
|
|
74
|
+
- "3.14"
|
|
75
|
+
- "3.15"
|
|
76
|
+
steps:
|
|
77
|
+
- name: Check out repository
|
|
78
|
+
uses: actions/checkout@v7
|
|
79
|
+
with:
|
|
80
|
+
persist-credentials: false
|
|
81
|
+
|
|
82
|
+
- name: Install Gmsh system libraries (Linux)
|
|
83
|
+
if: runner.os == 'Linux'
|
|
84
|
+
run: |
|
|
85
|
+
sudo apt-get update
|
|
86
|
+
sudo apt-get install --yes --no-install-recommends \
|
|
87
|
+
libglu1-mesa libgl1 libxrender1 libxcursor1 libxft2 \
|
|
88
|
+
libxinerama1 libfontconfig1
|
|
89
|
+
|
|
90
|
+
- name: Install uv and Python
|
|
91
|
+
uses: astral-sh/setup-uv@v10.3.2
|
|
92
|
+
with:
|
|
93
|
+
version: ${{ env.UV_VERSION }}
|
|
94
|
+
python-version: ${{ matrix.python-version }}
|
|
95
|
+
enable-cache: true
|
|
96
|
+
cache-dependency-glob: uv.lock
|
|
97
|
+
|
|
98
|
+
- name: Install dependencies
|
|
99
|
+
run: uv sync --locked --python ${{ matrix.python-version }}
|
|
100
|
+
|
|
101
|
+
- name: Verify Gmsh version
|
|
102
|
+
run: uv run --no-sync python -c "import gmsh; assert gmsh.__version__ == '4.15.2', gmsh.__version__"
|
|
103
|
+
|
|
104
|
+
- name: Run tests
|
|
105
|
+
run: uv run --no-sync pytest -q -W error
|
|
106
|
+
|
|
107
|
+
package:
|
|
108
|
+
name: Build and verify distributions
|
|
109
|
+
runs-on: ubuntu-latest
|
|
110
|
+
timeout-minutes: 20
|
|
111
|
+
env:
|
|
112
|
+
UV_PYTHON: "3.13"
|
|
113
|
+
steps:
|
|
114
|
+
- name: Check out repository
|
|
115
|
+
uses: actions/checkout@v7
|
|
116
|
+
with:
|
|
117
|
+
persist-credentials: false
|
|
118
|
+
|
|
119
|
+
- name: Install Gmsh system libraries (Linux)
|
|
120
|
+
run: |
|
|
121
|
+
sudo apt-get update
|
|
122
|
+
sudo apt-get install --yes --no-install-recommends \
|
|
123
|
+
libglu1-mesa libgl1 libxrender1 libxcursor1 libxft2 \
|
|
124
|
+
libxinerama1 libfontconfig1
|
|
125
|
+
|
|
126
|
+
- name: Install uv and Python
|
|
127
|
+
uses: astral-sh/setup-uv@v10.3.2
|
|
128
|
+
with:
|
|
129
|
+
version: ${{ env.UV_VERSION }}
|
|
130
|
+
python-version: "3.13"
|
|
131
|
+
enable-cache: true
|
|
132
|
+
cache-dependency-glob: uv.lock
|
|
133
|
+
|
|
134
|
+
- name: Install dependencies
|
|
135
|
+
run: uv sync --locked --python 3.13
|
|
136
|
+
|
|
137
|
+
- name: Build distributions
|
|
138
|
+
run: |
|
|
139
|
+
rm -rf dist
|
|
140
|
+
uv build
|
|
141
|
+
|
|
142
|
+
- name: Check distribution metadata
|
|
143
|
+
run: uvx twine check --strict dist/*
|
|
144
|
+
|
|
145
|
+
- name: Verify distribution contents
|
|
146
|
+
run: |
|
|
147
|
+
uv run --no-sync python - <<'PY'
|
|
148
|
+
import pathlib
|
|
149
|
+
import tarfile
|
|
150
|
+
import zipfile
|
|
151
|
+
|
|
152
|
+
dist = pathlib.Path("dist")
|
|
153
|
+
wheels = sorted(dist.glob("*.whl"))
|
|
154
|
+
sdists = sorted(dist.glob("*.tar.gz"))
|
|
155
|
+
assert len(wheels) == 1, wheels
|
|
156
|
+
assert len(sdists) == 1, sdists
|
|
157
|
+
wheel, sdist = wheels[0], sdists[0]
|
|
158
|
+
|
|
159
|
+
required_wheel = {
|
|
160
|
+
"shapemesh/__init__.py",
|
|
161
|
+
"shapemesh/builder.py",
|
|
162
|
+
"shapemesh/constants.py",
|
|
163
|
+
"shapemesh/errors.py",
|
|
164
|
+
"shapemesh/mesh.py",
|
|
165
|
+
"shapemesh/py.typed",
|
|
166
|
+
"shapemesh/settings.py",
|
|
167
|
+
"shapemesh/shapes.py",
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
with zipfile.ZipFile(wheel) as archive:
|
|
171
|
+
wheel_entries = {info.filename: info for info in archive.infolist()}
|
|
172
|
+
|
|
173
|
+
missing = required_wheel - wheel_entries.keys()
|
|
174
|
+
assert not missing, f"{wheel.name} is missing {sorted(missing)}"
|
|
175
|
+
for license_name in ("COPYING", "COPYING.LESSER"):
|
|
176
|
+
matches = [
|
|
177
|
+
info
|
|
178
|
+
for name, info in wheel_entries.items()
|
|
179
|
+
if name.endswith(f"dist-info/licenses/{license_name}")
|
|
180
|
+
]
|
|
181
|
+
assert matches, f"{wheel.name} is missing {license_name}"
|
|
182
|
+
assert all(info.file_size > 0 for info in matches)
|
|
183
|
+
|
|
184
|
+
required_sdist = {
|
|
185
|
+
"COPYING",
|
|
186
|
+
"COPYING.LESSER",
|
|
187
|
+
"README.md",
|
|
188
|
+
"pyproject.toml",
|
|
189
|
+
"examples/beam_with_hole.py",
|
|
190
|
+
"examples/frame.py",
|
|
191
|
+
"examples/pilecap.py",
|
|
192
|
+
"src/shapemesh/py.typed",
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
with tarfile.open(sdist) as archive:
|
|
196
|
+
sdist_entries = {member.name: member for member in archive.getmembers()}
|
|
197
|
+
|
|
198
|
+
for suffix in required_sdist:
|
|
199
|
+
matches = [
|
|
200
|
+
member
|
|
201
|
+
for name, member in sdist_entries.items()
|
|
202
|
+
if name == suffix or name.endswith(f"/{suffix}")
|
|
203
|
+
]
|
|
204
|
+
assert matches, f"{sdist.name} is missing {suffix}"
|
|
205
|
+
if suffix != "src/shapemesh/py.typed":
|
|
206
|
+
assert all(member.size > 0 for member in matches)
|
|
207
|
+
|
|
208
|
+
print(f"{wheel.name}: {len(wheel_entries)} entries")
|
|
209
|
+
print(f"{sdist.name}: {len(sdist_entries)} entries")
|
|
210
|
+
PY
|
|
211
|
+
|
|
212
|
+
- name: Install the built wheel
|
|
213
|
+
run: uv pip install --python .venv/bin/python --no-deps --force-reinstall dist/*.whl
|
|
214
|
+
|
|
215
|
+
- name: Verify the installed wheel
|
|
216
|
+
run: |
|
|
217
|
+
uv run --no-sync python - <<'PY'
|
|
218
|
+
import pathlib
|
|
219
|
+
|
|
220
|
+
import shapemesh
|
|
221
|
+
|
|
222
|
+
path = pathlib.Path(shapemesh.__file__).resolve()
|
|
223
|
+
assert "site-packages" in path.parts, f"imported the source tree instead: {path}"
|
|
224
|
+
print(f"Imported shapemesh {shapemesh.__version__} from {path}")
|
|
225
|
+
PY
|
|
226
|
+
|
|
227
|
+
- name: Run tests against the installed wheel
|
|
228
|
+
run: uv run --no-sync pytest -q -W error
|
|
229
|
+
|
|
230
|
+
- name: Smoke-test the examples
|
|
231
|
+
working-directory: ${{ runner.temp }}
|
|
232
|
+
run: |
|
|
233
|
+
set -euo pipefail
|
|
234
|
+
for example in "$GITHUB_WORKSPACE"/examples/*.py; do
|
|
235
|
+
echo "::group::$(basename "$example")"
|
|
236
|
+
"$GITHUB_WORKSPACE/.venv/bin/python" "$example"
|
|
237
|
+
echo "::endgroup::"
|
|
238
|
+
done
|
|
239
|
+
test -s beam_with_hole.msh
|
|
240
|
+
test -s frame.msh
|
|
241
|
+
test -s pilecap.msh
|
|
242
|
+
|
|
243
|
+
- name: Upload distributions
|
|
244
|
+
uses: actions/upload-artifact@v7
|
|
245
|
+
with:
|
|
246
|
+
name: distributions
|
|
247
|
+
path: dist/
|
|
248
|
+
if-no-files-found: error
|
|
249
|
+
retention-days: 7
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Byte-compiled / optimized / cache files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.mypy_cache/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
|
|
13
|
+
# Build artifacts
|
|
14
|
+
build/
|
|
15
|
+
dist/
|
|
16
|
+
*.egg-info/
|
|
17
|
+
.eggs/
|
|
18
|
+
|
|
19
|
+
# Editor settings
|
|
20
|
+
.vscode/settings.json
|
|
21
|
+
|
|
22
|
+
# Output files
|
|
23
|
+
*.msh
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for contributors and AI agents working in this repository.
|
|
4
|
+
|
|
5
|
+
## Design
|
|
6
|
+
|
|
7
|
+
The source of truth for the current scope is `design-v1.md`. Keep it up
|
|
8
|
+
to date as you implement within its scope.
|
|
9
|
+
|
|
10
|
+
## License
|
|
11
|
+
|
|
12
|
+
The project is LGPL-3.0-or-later. The license is split across two files because
|
|
13
|
+
the LGPL is the GPL plus additional permissions:
|
|
14
|
+
|
|
15
|
+
- `COPYING` — the GNU GPL-3.0 text.
|
|
16
|
+
- `COPYING.LESSER` — the LGPL-3.0 supplement.
|
|
17
|
+
|
|
18
|
+
Every new source file must start with the full notice below (copyright holder:
|
|
19
|
+
Mads Kruse). Files under `examples/` may instead use the short notice shown
|
|
20
|
+
after it, so documentation-focused examples stay concise:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
# Copyright (C) 2026 Mads Kruse
|
|
24
|
+
#
|
|
25
|
+
# This file is part of shapemesh.
|
|
26
|
+
#
|
|
27
|
+
# shapemesh is free software: you can redistribute it and/or modify it under
|
|
28
|
+
# the terms of the GNU Lesser General Public License as published by the Free
|
|
29
|
+
# Software Foundation, either version 3 of the License, or (at your option)
|
|
30
|
+
# any later version.
|
|
31
|
+
#
|
|
32
|
+
# shapemesh is distributed in the hope that it will be useful, but WITHOUT
|
|
33
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
34
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
35
|
+
# for more details.
|
|
36
|
+
#
|
|
37
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
38
|
+
# along with shapemesh. If not, see <https://www.gnu.org/licenses/>.
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The permitted short form for files under `examples/` is:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
# Copyright (C) 2026 Mads Kruse
|
|
45
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Docstrings
|
|
49
|
+
|
|
50
|
+
Public API docstrings use **Google style**:
|
|
51
|
+
|
|
52
|
+
- A one-line summary, then a blank line, then sections.
|
|
53
|
+
- Sections are ``Args:``, ``Returns:`` (or ``Yields:``), ``Raises:``, and
|
|
54
|
+
``Examples:``. Each entry is ``name: description``, indented 4 spaces, with
|
|
55
|
+
continuation lines indented to align under the description.
|
|
56
|
+
- Omit the type in ``Args``/``Returns`` when the signature already annotates it.
|
|
57
|
+
- Cross-reference project objects with single backticks (`` `Mesh` ``) and
|
|
58
|
+
inline code with double backticks (`` ``.msh`` ``). Do not use Sphinx roles
|
|
59
|
+
(``:class:``, ``:meth:``, ``:func:``).
|
|
60
|
+
- Document every public class, function, method, and property. Include a
|
|
61
|
+
``Raises:`` section whenever it can raise.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
def build(shapes, settings):
|
|
65
|
+
"""Realize ``shapes`` with Gmsh and return the resulting `Mesh`.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
shapes: A shape or a sequence of shapes to mesh.
|
|
69
|
+
settings: The mesh settings.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
The entity-classified mesh.
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
BuildError: If a Gmsh call fails.
|
|
76
|
+
"""
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Commit messages
|
|
80
|
+
|
|
81
|
+
We follow the spirit of [Common Changelog](https://common-changelog.org/):
|
|
82
|
+
commits and changelogs are written for humans, not machines.
|
|
83
|
+
|
|
84
|
+
- Write the subject in the **past tense, active voice**, leading with a verb:
|
|
85
|
+
`Added ...`, `Fixed ...`, `Refactored ...`, `Removed ...`, `Documented ...`,
|
|
86
|
+
`Bumped ...`.
|
|
87
|
+
- Capitalize the first word; no trailing period.
|
|
88
|
+
- Do **not** use Conventional Commits prefixes (`feat:`, `fix:`, `chore:`).
|
|
89
|
+
- Keep the subject to a single line; put the "why" and detail in the body.
|
|
90
|
+
- Lead with `Breaking:` when a change is breaking.
|
|
91
|
+
|
|
92
|
+
## Remote pushes
|
|
93
|
+
|
|
94
|
+
Never push commits, tags, or branches to a remote without explicit approval.
|
|
95
|
+
Prepare the commit locally, show it for review, and wait for the user to approve
|
|
96
|
+
the push. Approval applies only to the reviewed changes. Do not rewrite
|
|
97
|
+
published history or force-push without separate explicit approval.
|
|
98
|
+
|
|
99
|
+
## Changelog
|
|
100
|
+
|
|
101
|
+
`CHANGELOG.md` follows [Common Changelog](https://common-changelog.org/) and is
|
|
102
|
+
updated when a release is prepared, not with every commit. Do not add an
|
|
103
|
+
`Unreleased` section.
|
|
104
|
+
|
|
105
|
+
- Start each release with `## [VERSION] - YYYY-MM-DD` and link the version to
|
|
106
|
+
its GitHub release with a reference-style link at the bottom of the file.
|
|
107
|
+
- Add a one-sentence italic notice when useful. First releases use
|
|
108
|
+
`_First release._`.
|
|
109
|
+
- Group changes under `### Changed`, `### Added`, `### Removed`, and
|
|
110
|
+
`### Fixed`, in that order, and omit empty groups.
|
|
111
|
+
- Write each change in the imperative mood on one line, starting with a verb
|
|
112
|
+
such as `Add`, `Fix`, `Remove`, or `Refactor`.
|
|
113
|
+
- End each change with one or more Markdown links to the most relevant commits,
|
|
114
|
+
for example
|
|
115
|
+
``([`53bd922`](https://github.com/MEMAndersen/shapemesh/commit/53bd922))``.
|
|
116
|
+
- Add the author after the references, for example `(Mads Kruse)`.
|
|
117
|
+
- Follow [3.4. Merge related changes](https://common-changelog.org/#34-merge-related-changes):
|
|
118
|
+
merge commits that implement one change and leave out maintenance that does
|
|
119
|
+
not affect users. Keep the list short.
|
|
120
|
+
- Prefix breaking changes with `**Breaking:**` and list them first.
|
|
121
|
+
- Keep releases latest-first, and tag each release with the same version
|
|
122
|
+
(`vX.Y.Z`).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] - 2026-10-27
|
|
4
|
+
|
|
5
|
+
_First release._
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Add 12 shape primitives and n-ary `Union`, `Intersection`, and `Difference` with operator overloads ([`821888c`](https://github.com/MEMAndersen/shapemesh/commit/821888c), [`f315cf6`](https://github.com/MEMAndersen/shapemesh/commit/f315cf6)) (Mads Kruse)
|
|
10
|
+
- Add `build()` with label-preserving physical groups and `MeshSettings` for element size, element order, 2D and 3D algorithms, and advanced Gmsh options ([`821888c`](https://github.com/MEMAndersen/shapemesh/commit/821888c), [`647c5e5`](https://github.com/MEMAndersen/shapemesh/commit/647c5e5)) (Mads Kruse)
|
|
11
|
+
- Add MSH 4.1 ASCII I/O and the `Mesh` query and NumPy API ([`41efc2b`](https://github.com/MEMAndersen/shapemesh/commit/41efc2b), [`d02d866`](https://github.com/MEMAndersen/shapemesh/commit/d02d866)) (Mads Kruse)
|
|
12
|
+
- Add a typed public API with `py.typed` and a structured exception hierarchy ([`821888c`](https://github.com/MEMAndersen/shapemesh/commit/821888c), [`4e30f0e`](https://github.com/MEMAndersen/shapemesh/commit/4e30f0e)) (Mads Kruse)
|
|
13
|
+
- Add 1D, 2D, and 3D examples and documentation for labels, threading, and the Gmsh version policy ([`cde6dc0`](https://github.com/MEMAndersen/shapemesh/commit/cde6dc0), [`413dc02`](https://github.com/MEMAndersen/shapemesh/commit/413dc02)) (Mads Kruse)
|
|
14
|
+
- Support Python 3.12 through 3.15 on Linux, macOS, and Windows with Gmsh 4.0 or later ([`4f941e1`](https://github.com/MEMAndersen/shapemesh/commit/4f941e1), [`b605815`](https://github.com/MEMAndersen/shapemesh/commit/b605815)) (Mads Kruse)
|
|
15
|
+
|
|
16
|
+
[0.1.0]: https://github.com/MEMAndersen/shapemesh/releases/tag/v0.1.0
|