halfedge 0.7.0__tar.gz → 0.11.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 (30) hide show
  1. {halfedge-0.7.0/src/halfedge.egg-info → halfedge-0.11.0}/PKG-INFO +47 -37
  2. {halfedge-0.7.0 → halfedge-0.11.0}/README.md +41 -25
  3. halfedge-0.11.0/pyproject.toml +92 -0
  4. {halfedge-0.7.0 → halfedge-0.11.0}/src/halfedge/__init__.py +5 -1
  5. {halfedge-0.7.0 → halfedge-0.11.0}/src/halfedge/half_edge_constructors.py +5 -5
  6. {halfedge-0.7.0 → halfedge-0.11.0}/src/halfedge/half_edge_elements.py +6 -5
  7. {halfedge-0.7.0 → halfedge-0.11.0}/src/halfedge/half_edge_object.py +7 -0
  8. halfedge-0.11.0/src/halfedge/py.typed +5 -0
  9. {halfedge-0.7.0 → halfedge-0.11.0}/src/halfedge/type_attrib.py +48 -49
  10. {halfedge-0.7.0 → halfedge-0.11.0}/src/halfedge/validations.py +3 -1
  11. halfedge-0.7.0/.github/workflows/pypi-project.yml +0 -110
  12. halfedge-0.7.0/.gitignore +0 -1
  13. halfedge-0.7.0/.pre-commit-config.yaml +0 -146
  14. halfedge-0.7.0/PKG-INFO +0 -132
  15. halfedge-0.7.0/pyproject.toml +0 -72
  16. halfedge-0.7.0/setup.cfg +0 -4
  17. halfedge-0.7.0/src/halfedge/py.typed +0 -1
  18. halfedge-0.7.0/src/halfedge.egg-info/SOURCES.txt +0 -26
  19. halfedge-0.7.0/src/halfedge.egg-info/dependency_links.txt +0 -1
  20. halfedge-0.7.0/src/halfedge.egg-info/requires.txt +0 -9
  21. halfedge-0.7.0/src/halfedge.egg-info/top_level.txt +0 -1
  22. halfedge-0.7.0/tests/__init__.py +0 -1
  23. halfedge-0.7.0/tests/conftest.py +0 -270
  24. halfedge-0.7.0/tests/test_classes.py +0 -613
  25. halfedge-0.7.0/tests/test_constructors.py +0 -191
  26. halfedge-0.7.0/tests/test_elements.py +0 -78
  27. halfedge-0.7.0/tests/test_object_pickups.py +0 -74
  28. halfedge-0.7.0/tests/test_operations.py +0 -643
  29. halfedge-0.7.0/tests/test_validations.py +0 -69
  30. {halfedge-0.7.0 → halfedge-0.11.0}/src/halfedge/half_edge_querries.py +0 -0
@@ -1,19 +1,13 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: halfedge
3
- Version: 0.7.0
3
+ Version: 0.11.0
4
4
  Summary: A typical half-edge data structure with some padding
5
+ Author: Shay Hill
5
6
  Author-email: Shay Hill <shay_public@hotmail.com>
6
- License: MIT
7
- Requires-Python: >=3.8
7
+ License-Expression: MIT
8
+ Requires-Dist: paragraphs>=1.0.1
9
+ Requires-Python: >=3.11
8
10
  Description-Content-Type: text/markdown
9
- Requires-Dist: paragraphs
10
- Provides-Extra: dev
11
- Requires-Dist: commitizen; extra == "dev"
12
- Requires-Dist: coverage; extra == "dev"
13
- Requires-Dist: pre-commit; extra == "dev"
14
- Requires-Dist: pylint; extra == "dev"
15
- Requires-Dist: pytest; extra == "dev"
16
- Requires-Dist: tox; extra == "dev"
17
11
 
18
12
  # A typical halfedges data structure with some padding
19
13
 
@@ -35,11 +29,11 @@ mesh.remove_edge(edge)
35
29
 
36
30
  ## Particulars
37
31
 
38
- The idea (for 18 years and counting) has been to create an interface that is neither too complex, too verbose, nor too magical. I've been all over the place as to where that line should be. This is my current thinking.
32
+ The idea (for 19 years and counting) has been to create an interface that is neither too complex, too verbose, nor too magical. I've been all over the place as to where that line should be. This is my current thinking.
39
33
 
40
34
  ### Reflection
41
35
 
42
- If you set `edge_a.orig = vert_a`, then the `Edge.vert` setter will *automagically* set `vert_a.edge = edge_a`. This is true for any setter that might otherwise break the mesh. Sometimes, this reflection will happen when it isn't strictly necessary. Imagine you have `face_a` with three edges: `edge_a`, `edge_b` and `edge_c`. `face_a` has a pointer to `edge_a`, but it could point to any of the three edges and still be correct per the requirements of the halfedge data structure. If you directly set `edge_b.face = face_a`, everything would still be correct (`face_a.edge` would still be `edge_a` and that would still be correct), but the `Edge.edge` setter will nevertheless set `face_a.edge = edge_b`.
36
+ If you set `edge_a.orig = vert_a`, then the `Edge.vert` setter will *automagically* set `vert_a.edge = edge_a`. This is true for any setter that might otherwise break the mesh. Sometimes, this reflection will happen when it isn't strictly necessary. Imagine you have `face_a` with three edges: `edge_a`, `edge_b` and `edge_c`. `face_a` has a pointer to `edge_a`, but it could point to any of the three edges and still be correct per the requirements of the halfedge data structure. If you directly set `edge_b.face = face_a`, everything would still be correct (`face_a.edge` would still be `edge_a` and that would still be correct), but the `Edge.edge` setter will nevertheless "reflectively" set `face_a.edge = edge_b`.
43
37
 
44
38
  ### id
45
39
 
@@ -64,50 +58,66 @@ Face(
64
58
 
65
59
  The `is_hole` `__init__` kwarg is shorthand for
66
60
 
67
- class IsHole(ContagionAttribute):
68
- pass
61
+ ```python
62
+ class IsHole(ContagionAttribute):
63
+ pass
64
+
65
+ face = Face()
66
+ face.add_attrib(IsHole())
67
+ ```
69
68
 
70
- vert = Vert()
71
- vert.add_attrib(IsHole())
72
69
 
73
70
  The `face_instance.is_hole` property getter is shorthand for
74
71
 
75
- vert.get_attrib(IsHole())
72
+ ```python
73
+ vert.get_attrib(IsHole())
74
+ ```
76
75
 
77
76
  More on `Attrib` classes below and in `type_attrib.py`.
78
77
 
79
78
  ### Element Attributes
80
79
 
81
- By halfedge convention, each Vert instance holds a pointer to one Edge instance, each Face instance holds a pointer to one Edge instance, and each Edge instance holds four pointers (orig, pair, face, next). These describe the geometry of a mesh, but there may be other attributes you would like to assign to these instances. For example, each Face instance might have a color or each Vert instance an (x, y) coordinate. There is no objectively correct way define these attributes or to combine them when two elements are merged. If you assign position vertices to your verts, will they be xy tuples or numpy arrays? Do a red and a blue face behave like paint and combine to make a purple face? Or do they behave like DNA to make a red *or* blue face depending on which is dominant?
80
+ By halfedge convention
82
81
 
83
- These cannot be stored as simple attributes (e.g., `face.color`), because it wouldn't be clear what to do when two faces were combined--by, for instance, deleting a shared edge. Somewhere, you have to define a rule for how different colored faces merge or how coordinate locations combine when merging verts. So, properties like color must be defined here as `Attrib` instances. To create an attribute, inherit from `Attrib` or one of its children defined in `type_attrib.py`. Define `merge`, `split`, and `_infer_value` methods to determine how (for instance, face color) will behave when merged or cached.
82
+ - each Vert instance holds a pointer to one Edge instance;
83
+ - each Face instance holds a pointer to one Edge instance; and
84
+ - each Edge instance holds four pointers (orig, pair, face, next).
84
85
 
85
- You cannot assign these with `instance.attribute`. Instead assign with `vert.add_attrib(attrib_instance)`. This will add the Attrib to a `attrib` dict in Vert instance dict. Retrieve the value with `vert_instance.get_attrib(attrib_class)`. Everything will be keyed to the class name, so you will need a new ElemAttribBase descendant for each attribute type.
86
+ These describe the geometry of a mesh, but there may be other attributes you would like to assign to these instances. For example, each Face instance might have a color. There is no objectively correct way to define a face color, nor to merge colors when two faces are merged, nor to split a color when faces are split. Do a red and a blue face behave like paint and combine to make a purple face? Or do they behave like DNA to make a red *or* blue face depending on which is dominant? This library will not guess.
86
87
 
87
- class Coordinate(IncompatibleAttribute[Tuple[float, float]]):
88
- pass
88
+ For each such attribute, you will need to define `merge` and `split` methods to explicate how the attribute 1) combines when elements are merged; and 2) behaves when an element is split. Do this by creating a new descendent of `Attrib` or one of `Attrib`'s children defined in `type_attrib.py`. See the docstring in that file for more information.
89
89
 
90
- vert = Vert()
91
- vert.add_attrib(Coordinate((1, 2)))
92
- assert vert.get_attrib(Coordinate).value == (1, 2)
90
+ ```python
91
+ # `Vector2Attrib` is a child of `Attrib` defined in `type_attrib.py`.
92
+ # It defines suitable (YMMV) `merge` (average) and `split` (fail) methods for
93
+ # an (x, y) coordinate.
94
+ class Coordinate(Vector2Attrib):
95
+ pass
96
+
97
+ vert = Vert()
98
+ vert.add_attrib(Coordinate((1, 2)))
99
+ assert vert.get_attrib(Coordinate).value == (1, 2)
100
+ ```
93
101
 
94
- These element attributes can also be passed at `__init__`
102
+ You cannot assign or access these attributes with `vert.attribute`. Instead assign with `vert.add_attrib(attrib_instance)`. Retrieve the value with `vert.get_attrib(attrib_class)`. Everything will be keyed to the class name, so you will need a new ElemAttribBase descendant for each attribute type.
95
103
 
96
- vert = Vert(Coordinate(1, 2))
97
- assert vert.get_attrib(Coordinate).value == (1, 2)
104
+ These element attributes can also be passed at `__init__`
98
105
 
99
- The Attrib classes and merge and split methods that will be called when two elements are merged (e.g., merge two faces when removing the edge between them) or split (e.g., split an edge into two edges).
106
+ ```python
107
+ vert = Vert(Coordinate(1, 2))
108
+ assert vert.get_attrib(Coordinate).value == (1, 2)
109
+ ```
100
110
 
101
111
  ### You Should Know
102
112
 
103
113
  A canonical half-edge data structure stores:
104
114
 
105
- * a set of verts (redundant)
106
- * for each vert, a pointer to an edge
107
- * a set of edges
108
- * for each edge, pointers to vert, pair, face, next
109
- * a set of faces (redundant)
110
- * for each face, a pointer to an edge
115
+ - a set of verts (redundant)
116
+ - for each vert, a pointer to an edge
117
+ - a set of edges
118
+ - for each edge, pointers to vert, pair, face, next
119
+ - a set of faces (redundant)
120
+ - for each face, a pointer to an edge
111
121
 
112
122
  This implementation only stores a set of edges. Sets of verts and faces are generated by iterating through references in edge instances. This makes for slower code, but does not violate DRY and makes for dramatically cleaner code.
113
123
 
@@ -18,11 +18,11 @@ mesh.remove_edge(edge)
18
18
 
19
19
  ## Particulars
20
20
 
21
- The idea (for 18 years and counting) has been to create an interface that is neither too complex, too verbose, nor too magical. I've been all over the place as to where that line should be. This is my current thinking.
21
+ The idea (for 19 years and counting) has been to create an interface that is neither too complex, too verbose, nor too magical. I've been all over the place as to where that line should be. This is my current thinking.
22
22
 
23
23
  ### Reflection
24
24
 
25
- If you set `edge_a.orig = vert_a`, then the `Edge.vert` setter will *automagically* set `vert_a.edge = edge_a`. This is true for any setter that might otherwise break the mesh. Sometimes, this reflection will happen when it isn't strictly necessary. Imagine you have `face_a` with three edges: `edge_a`, `edge_b` and `edge_c`. `face_a` has a pointer to `edge_a`, but it could point to any of the three edges and still be correct per the requirements of the halfedge data structure. If you directly set `edge_b.face = face_a`, everything would still be correct (`face_a.edge` would still be `edge_a` and that would still be correct), but the `Edge.edge` setter will nevertheless set `face_a.edge = edge_b`.
25
+ If you set `edge_a.orig = vert_a`, then the `Edge.vert` setter will *automagically* set `vert_a.edge = edge_a`. This is true for any setter that might otherwise break the mesh. Sometimes, this reflection will happen when it isn't strictly necessary. Imagine you have `face_a` with three edges: `edge_a`, `edge_b` and `edge_c`. `face_a` has a pointer to `edge_a`, but it could point to any of the three edges and still be correct per the requirements of the halfedge data structure. If you directly set `edge_b.face = face_a`, everything would still be correct (`face_a.edge` would still be `edge_a` and that would still be correct), but the `Edge.edge` setter will nevertheless "reflectively" set `face_a.edge = edge_b`.
26
26
 
27
27
  ### id
28
28
 
@@ -47,50 +47,66 @@ Face(
47
47
 
48
48
  The `is_hole` `__init__` kwarg is shorthand for
49
49
 
50
- class IsHole(ContagionAttribute):
51
- pass
50
+ ```python
51
+ class IsHole(ContagionAttribute):
52
+ pass
53
+
54
+ face = Face()
55
+ face.add_attrib(IsHole())
56
+ ```
52
57
 
53
- vert = Vert()
54
- vert.add_attrib(IsHole())
55
58
 
56
59
  The `face_instance.is_hole` property getter is shorthand for
57
60
 
58
- vert.get_attrib(IsHole())
61
+ ```python
62
+ vert.get_attrib(IsHole())
63
+ ```
59
64
 
60
65
  More on `Attrib` classes below and in `type_attrib.py`.
61
66
 
62
67
  ### Element Attributes
63
68
 
64
- By halfedge convention, each Vert instance holds a pointer to one Edge instance, each Face instance holds a pointer to one Edge instance, and each Edge instance holds four pointers (orig, pair, face, next). These describe the geometry of a mesh, but there may be other attributes you would like to assign to these instances. For example, each Face instance might have a color or each Vert instance an (x, y) coordinate. There is no objectively correct way define these attributes or to combine them when two elements are merged. If you assign position vertices to your verts, will they be xy tuples or numpy arrays? Do a red and a blue face behave like paint and combine to make a purple face? Or do they behave like DNA to make a red *or* blue face depending on which is dominant?
69
+ By halfedge convention
65
70
 
66
- These cannot be stored as simple attributes (e.g., `face.color`), because it wouldn't be clear what to do when two faces were combined--by, for instance, deleting a shared edge. Somewhere, you have to define a rule for how different colored faces merge or how coordinate locations combine when merging verts. So, properties like color must be defined here as `Attrib` instances. To create an attribute, inherit from `Attrib` or one of its children defined in `type_attrib.py`. Define `merge`, `split`, and `_infer_value` methods to determine how (for instance, face color) will behave when merged or cached.
71
+ - each Vert instance holds a pointer to one Edge instance;
72
+ - each Face instance holds a pointer to one Edge instance; and
73
+ - each Edge instance holds four pointers (orig, pair, face, next).
67
74
 
68
- You cannot assign these with `instance.attribute`. Instead assign with `vert.add_attrib(attrib_instance)`. This will add the Attrib to a `attrib` dict in Vert instance dict. Retrieve the value with `vert_instance.get_attrib(attrib_class)`. Everything will be keyed to the class name, so you will need a new ElemAttribBase descendant for each attribute type.
75
+ These describe the geometry of a mesh, but there may be other attributes you would like to assign to these instances. For example, each Face instance might have a color. There is no objectively correct way to define a face color, nor to merge colors when two faces are merged, nor to split a color when faces are split. Do a red and a blue face behave like paint and combine to make a purple face? Or do they behave like DNA to make a red *or* blue face depending on which is dominant? This library will not guess.
69
76
 
70
- class Coordinate(IncompatibleAttribute[Tuple[float, float]]):
71
- pass
77
+ For each such attribute, you will need to define `merge` and `split` methods to explicate how the attribute 1) combines when elements are merged; and 2) behaves when an element is split. Do this by creating a new descendent of `Attrib` or one of `Attrib`'s children defined in `type_attrib.py`. See the docstring in that file for more information.
72
78
 
73
- vert = Vert()
74
- vert.add_attrib(Coordinate((1, 2)))
75
- assert vert.get_attrib(Coordinate).value == (1, 2)
79
+ ```python
80
+ # `Vector2Attrib` is a child of `Attrib` defined in `type_attrib.py`.
81
+ # It defines suitable (YMMV) `merge` (average) and `split` (fail) methods for
82
+ # an (x, y) coordinate.
83
+ class Coordinate(Vector2Attrib):
84
+ pass
85
+
86
+ vert = Vert()
87
+ vert.add_attrib(Coordinate((1, 2)))
88
+ assert vert.get_attrib(Coordinate).value == (1, 2)
89
+ ```
76
90
 
77
- These element attributes can also be passed at `__init__`
91
+ You cannot assign or access these attributes with `vert.attribute`. Instead assign with `vert.add_attrib(attrib_instance)`. Retrieve the value with `vert.get_attrib(attrib_class)`. Everything will be keyed to the class name, so you will need a new ElemAttribBase descendant for each attribute type.
78
92
 
79
- vert = Vert(Coordinate(1, 2))
80
- assert vert.get_attrib(Coordinate).value == (1, 2)
93
+ These element attributes can also be passed at `__init__`
81
94
 
82
- The Attrib classes and merge and split methods that will be called when two elements are merged (e.g., merge two faces when removing the edge between them) or split (e.g., split an edge into two edges).
95
+ ```python
96
+ vert = Vert(Coordinate(1, 2))
97
+ assert vert.get_attrib(Coordinate).value == (1, 2)
98
+ ```
83
99
 
84
100
  ### You Should Know
85
101
 
86
102
  A canonical half-edge data structure stores:
87
103
 
88
- * a set of verts (redundant)
89
- * for each vert, a pointer to an edge
90
- * a set of edges
91
- * for each edge, pointers to vert, pair, face, next
92
- * a set of faces (redundant)
93
- * for each face, a pointer to an edge
104
+ - a set of verts (redundant)
105
+ - for each vert, a pointer to an edge
106
+ - a set of edges
107
+ - for each edge, pointers to vert, pair, face, next
108
+ - a set of faces (redundant)
109
+ - for each face, a pointer to an edge
94
110
 
95
111
  This implementation only stores a set of edges. Sets of verts and faces are generated by iterating through references in edge instances. This makes for slower code, but does not violate DRY and makes for dramatically cleaner code.
96
112
 
@@ -0,0 +1,92 @@
1
+ [project]
2
+ name = "halfedge"
3
+ version = "0.11.0"
4
+ description = "A typical half-edge data structure with some padding"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "Shay Hill", email = "shay_public@hotmail.com" }
9
+ ]
10
+ requires-python = ">=3.11"
11
+ dependencies = [
12
+ "paragraphs>=1.0.1",
13
+ ]
14
+
15
+ [build-system]
16
+ requires = ["uv_build>=0.9.4,<0.10.0"]
17
+ build-backend = "uv_build"
18
+
19
+ [dependency-groups]
20
+ dev = [
21
+ "commitizen>=4.12.1",
22
+ "pre-commit>=4.5.1",
23
+ "pytest>=9.0.2",
24
+ "ruff>=0.14.14",
25
+ ]
26
+
27
+
28
+ [tool.commitizen]
29
+ kame = "cz_conventional_commits"
30
+ version = "0.11.0"
31
+ tag_format = "$version"
32
+ major-version-zero = true
33
+ version_files = ["pyproject.toml:^version"]
34
+
35
+
36
+ [tool.isort]
37
+ profile = "black"
38
+
39
+
40
+ [tool.pytest.ini_options]
41
+ addopts = "--doctest-modules"
42
+ pythonpath = "tests"
43
+ log_cli = true
44
+ testpaths = ["tests"]
45
+ norecursedirs = ["src", ".git", ".venv", "__pycache__", "*.egg"]
46
+
47
+
48
+ [tool.ruff.lint.pydocstyle]
49
+ convention = "pep257"
50
+
51
+ [tool.ruff.lint.per-file-ignores]
52
+ "tests/*.py" = [
53
+ "S101",
54
+ "D",
55
+ "F401",
56
+ ] # Ignore assertions, docstrings, unused imports in test files
57
+
58
+ [tool.ruff.format]
59
+ docstring-code-line-length = 88
60
+
61
+ [tool.ruff.lint]
62
+
63
+ select = ["ALL"]
64
+
65
+ ignore = [
66
+ "PLR", # magic values
67
+ "COM", # trailing commas
68
+ "ANN", # forbid Any
69
+ "S", # warnings about pickle, random, etc.
70
+ "N", # names
71
+ "B019", # memory leak warning for lru_cache
72
+ ]
73
+
74
+
75
+ [tool.pyright]
76
+ include = ["src"]
77
+ exclude = ["**/__pycache__.py"]
78
+
79
+ pythonVersion = "3.11"
80
+ pythonPlatform = "All"
81
+
82
+ typeCheckingMode = "strict"
83
+ reportCallInDefaultInitializer = true
84
+ reportImplicitStringConcatenation = true
85
+ # reportMissingSuperCall = true
86
+ reportPropertyTypeMismatch = true
87
+ reportUninitializedInstanceVariable = true
88
+ reportUnnecessaryTypeIgnoreComment = true
89
+ reportUnusedCallResult = true
90
+
91
+ venvPath = "."
92
+ venv = "./.venv"
@@ -1,4 +1,8 @@
1
- """Allow modules to be imported from top-level."""
1
+ """Import functions into the package namespace.
2
+
3
+ :author: Shay Hill
4
+ :created: 2026-01-25
5
+ """
2
6
 
3
7
  from halfedge.half_edge_constructors import BlindHalfEdges
4
8
  from halfedge.half_edge_elements import Edge, Face, MeshElementBase, Vert
@@ -23,20 +23,20 @@ then passing that raw data to mesh_from_vr would create a mesh with 6 faces and
23
23
  from __future__ import annotations
24
24
 
25
25
  from contextlib import suppress
26
- from typing import TYPE_CHECKING, Any, Iterable, Sequence, TypeVar
26
+ from typing import TYPE_CHECKING, Any, Self, TypeVar
27
27
 
28
28
  from paragraphs import par
29
29
 
30
30
  from halfedge.half_edge_elements import Edge, Face, ManifoldMeshError, Vert
31
31
 
32
32
  if TYPE_CHECKING:
33
+ from collections.abc import Iterable, Sequence
34
+
33
35
  from halfedge.type_attrib import Attrib, StaticAttrib
34
36
 
35
37
 
36
38
  _T = TypeVar("_T")
37
39
 
38
- _TBlindHalfEdges = TypeVar("_TBlindHalfEdges", bound="BlindHalfEdges")
39
-
40
40
 
41
41
  class BlindHalfEdges:
42
42
  """Half-edge structure with no lookups."""
@@ -189,11 +189,11 @@ class BlindHalfEdges:
189
189
 
190
190
  @classmethod
191
191
  def from_vlfi(
192
- cls: type[_TBlindHalfEdges],
192
+ cls,
193
193
  vl: Sequence[Vert],
194
194
  fi: Iterable[tuple[int, ...]],
195
195
  hi: Iterable[tuple[int, ...]] | None = None,
196
- ) -> _TBlindHalfEdges:
196
+ ) -> Self:
197
197
  """Create a set of half edges from a vertex list and face index.
198
198
 
199
199
  :param vl: (vertex list) a seq of vertices
@@ -38,14 +38,15 @@ from __future__ import annotations
38
38
 
39
39
  from contextlib import suppress
40
40
  from itertools import count
41
- from typing import TYPE_CHECKING, Any, Callable, TypeVar
41
+ from typing import TYPE_CHECKING, Any, Self, TypeVar
42
42
 
43
43
  from halfedge.type_attrib import Attrib, ContagionAttrib
44
44
 
45
45
  if TYPE_CHECKING:
46
+ from collections.abc import Callable
47
+
46
48
  from halfedge.half_edge_constructors import BlindHalfEdges
47
49
 
48
- _TMeshElem = TypeVar("_TMeshElem", bound="MeshElementBase")
49
50
 
50
51
  _T = TypeVar("_T")
51
52
 
@@ -141,7 +142,7 @@ class MeshElementBase:
141
142
  except AttributeError:
142
143
  return None
143
144
 
144
- def merge_from(self: _TMeshElem, *elements: _TMeshElem) -> _TMeshElem:
145
+ def merge_from(self, *elements: Self) -> Self:
145
146
  """Fill in missing references from other elements.
146
147
 
147
148
  :param elements: elements to merge from
@@ -165,7 +166,7 @@ class MeshElementBase:
165
166
  self.set_attrib(merged_attrib)
166
167
  return self
167
168
 
168
- def split_from(self: _TMeshElem, element: _TMeshElem) -> _TMeshElem:
169
+ def split_from(self, element: Self) -> Self:
169
170
  """Pass attributes when dividing or altering elements.
170
171
 
171
172
  :param element: element to split from
@@ -182,7 +183,7 @@ class MeshElementBase:
182
183
  self.set_attrib(splitted)
183
184
  return self
184
185
 
185
- def __lt__(self: _TMeshElem, other: _TMeshElem) -> bool:
186
+ def __lt__(self, other: Self) -> bool:
186
187
  """Sort by sn.
187
188
 
188
189
  You'll want to be able to sort Verts at least to make a vlvi (vertex list,
@@ -79,6 +79,13 @@ class HalfEdges(StaticHalfEdges):
79
79
  Able to infer from:
80
80
  * both verts on same face: that face
81
81
  * empty mesh: a new Hole
82
+
83
+ This is only called when inserting an edge into an existing face (or empty
84
+ mesh), so the orig and dest should always be connected to only one face (or
85
+ nothing, which is handled in this method).
86
+
87
+ Once the face is split, the two verts will form an edge that connects to two
88
+ faces.
82
89
  """
83
90
  if not self.edges:
84
91
  return self.new_hole()
@@ -0,0 +1,5 @@
1
+ """ This file is used to indicate to mypy that the package is typed.
2
+
3
+ Do not delete this comment, because empty files choke
4
+ some cloud drives on sync.
5
+ """