bluemesh2d 0.1.1.dev0__py3-none-any.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 (74) hide show
  1. bluemesh2d/_version.py +24 -0
  2. bluemesh2d/aabb_tree/findball.py +121 -0
  3. bluemesh2d/aabb_tree/findtria.py +299 -0
  4. bluemesh2d/aabb_tree/maketree.py +147 -0
  5. bluemesh2d/aabb_tree/mapvert.py +72 -0
  6. bluemesh2d/aabb_tree/queryset.py +83 -0
  7. bluemesh2d/aabb_tree/scantree.py +124 -0
  8. bluemesh2d/dependencies.py +83 -0
  9. bluemesh2d/feedback.py +142 -0
  10. bluemesh2d/geom_util/boundary_util.py +216 -0
  11. bluemesh2d/geom_util/getiso.py +194 -0
  12. bluemesh2d/geom_util/poly_util.py +795 -0
  13. bluemesh2d/geom_util/proj_util.py +250 -0
  14. bluemesh2d/geomesh_util/border_util.py +283 -0
  15. bluemesh2d/geomesh_util/depth_field.py +333 -0
  16. bluemesh2d/geomesh_util/grd_util.py +1000 -0
  17. bluemesh2d/geomesh_util/interpolation_mesh.py +318 -0
  18. bluemesh2d/geomesh_util/merge_circumcenters.py +268 -0
  19. bluemesh2d/geomesh_util/water_polygon.py +406 -0
  20. bluemesh2d/hfun_util/build_hfun.py +589 -0
  21. bluemesh2d/hfun_util/hfun_dispersion.py +96 -0
  22. bluemesh2d/hfun_util/lfshfn.py +110 -0
  23. bluemesh2d/hfun_util/limhfn.py +65 -0
  24. bluemesh2d/hfun_util/make_constant_hfun.py +32 -0
  25. bluemesh2d/hfun_util/make_depth_hfun.py +51 -0
  26. bluemesh2d/hfun_util/smooth_and_precomput.py +188 -0
  27. bluemesh2d/hfun_util/trihfn.py +84 -0
  28. bluemesh2d/hjac_util/limgrad.py +105 -0
  29. bluemesh2d/mesh_ball/cdtbal1.py +38 -0
  30. bluemesh2d/mesh_ball/cdtbal2.py +104 -0
  31. bluemesh2d/mesh_ball/inv_2x2.py +61 -0
  32. bluemesh2d/mesh_ball/inv_3x3.py +72 -0
  33. bluemesh2d/mesh_ball/pwrbal2.py +134 -0
  34. bluemesh2d/mesh_ball/tribal2.py +27 -0
  35. bluemesh2d/mesh_cost/relhfn.py +62 -0
  36. bluemesh2d/mesh_cost/triang.py +59 -0
  37. bluemesh2d/mesh_cost/triarea.py +51 -0
  38. bluemesh2d/mesh_cost/trideg.py +44 -0
  39. bluemesh2d/mesh_cost/triscr.py +43 -0
  40. bluemesh2d/mesh_file/bnd_util.py +664 -0
  41. bluemesh2d/mesh_file/loadmsh.py +165 -0
  42. bluemesh2d/mesh_file/ugrid.py +308 -0
  43. bluemesh2d/mesh_util/cfmtri.py +118 -0
  44. bluemesh2d/mesh_util/deltri.py +131 -0
  45. bluemesh2d/mesh_util/idxtri.py +53 -0
  46. bluemesh2d/mesh_util/isfeat.py +90 -0
  47. bluemesh2d/mesh_util/minlen.py +46 -0
  48. bluemesh2d/mesh_util/setset.py +49 -0
  49. bluemesh2d/mesh_util/tricon.py +90 -0
  50. bluemesh2d/mesh_util/tridiv.py +187 -0
  51. bluemesh2d/meshgen.py +202 -0
  52. bluemesh2d/ortho_merge/constants.py +27 -0
  53. bluemesh2d/ortho_merge/geometry.py +64 -0
  54. bluemesh2d/ortho_merge/ortho_merge_iter.py +812 -0
  55. bluemesh2d/ortho_merge/orthogonalize.py +2989 -0
  56. bluemesh2d/pipeline.py +277 -0
  57. bluemesh2d/poly_data/airfoil.msh +958 -0
  58. bluemesh2d/poly_data/channel.msh +212 -0
  59. bluemesh2d/poly_data/islands.msh +13819 -0
  60. bluemesh2d/poly_data/lake.msh +612 -0
  61. bluemesh2d/poly_data/river.msh +690 -0
  62. bluemesh2d/poly_test/inpoly.py +105 -0
  63. bluemesh2d/poly_test/inpoly_mat.py +104 -0
  64. bluemesh2d/refine.py +972 -0
  65. bluemesh2d/smood.py +623 -0
  66. bluemesh2d/smooth.py +522 -0
  67. bluemesh2d/tricost.py +426 -0
  68. bluemesh2d/tridemo.py +723 -0
  69. bluemesh2d/triread.py +53 -0
  70. bluemesh2d-0.1.1.dev0.dist-info/METADATA +139 -0
  71. bluemesh2d-0.1.1.dev0.dist-info/RECORD +74 -0
  72. bluemesh2d-0.1.1.dev0.dist-info/WHEEL +5 -0
  73. bluemesh2d-0.1.1.dev0.dist-info/licenses/LICENSE +674 -0
  74. bluemesh2d-0.1.1.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,104 @@
1
+ import numpy as np
2
+
3
+ from .tribal2 import tribal2
4
+
5
+
6
+ def cdtbal2(pp, ee, tt):
7
+ """Compute clipped circumballs for a constrained Delaunay triangulation.
8
+
9
+ Start from triangle circumballs and replace any ball that extends outside
10
+ the domain with a smaller edge-centered diametric ball on a constrained
11
+ face.
12
+
13
+ Parameters
14
+ ----------
15
+ pp : ndarray of shape (N, 2)
16
+ Vertex coordinates.
17
+ ee : ndarray of shape (E, 5)
18
+ Edge connectivity from :func:`tricon`.
19
+ tt : ndarray of shape (T, 6)
20
+ Triangle connectivity from :func:`tricon`.
21
+
22
+ Returns
23
+ -------
24
+ cc : ndarray of shape (T, 3)
25
+ Clipped circumball parameters ``[xc, yc, r²]`` for each triangle.
26
+
27
+ References
28
+ ----------
29
+ Translation of the MESH2D function ``CDTBAL2``.
30
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
31
+ """
32
+
33
+ if not (
34
+ isinstance(pp, np.ndarray)
35
+ and isinstance(ee, np.ndarray)
36
+ and isinstance(tt, np.ndarray)
37
+ ):
38
+ raise TypeError("cdtbal2:incorrectInputClass")
39
+
40
+ if pp.ndim != 2 or ee.ndim != 2 or tt.ndim != 2:
41
+ raise ValueError("cdtbal2:incorrectDimensions")
42
+
43
+ if pp.shape[1] != 2 or ee.shape[1] < 5 or tt.shape[1] < 6:
44
+ raise ValueError("cdtbal2:incorrectDimensions")
45
+
46
+ cc = tribal2(pp, tt)
47
+
48
+ # Replace with face-balls if smaller
49
+ cc = minfac2(cc, pp, ee, tt, 0, 1, 2)
50
+ cc = minfac2(cc, pp, ee, tt, 1, 2, 0)
51
+ cc = minfac2(cc, pp, ee, tt, 2, 0, 1)
52
+
53
+ return cc
54
+
55
+
56
+ def minfac2(cc, pp, ee, tt, ni, nj, nk):
57
+ """Clip circumballs to constrained faces of a CDT.
58
+
59
+ Replace circumballs that extend beyond a constrained edge with the
60
+ diametric ball centered on that edge.
61
+
62
+ Parameters
63
+ ----------
64
+ cc : ndarray of shape (T, 3)
65
+ Circumball parameters ``[xc, yc, r²]``.
66
+ pp : ndarray of shape (N, 2)
67
+ Vertex coordinates.
68
+ ee : ndarray of shape (E, 5)
69
+ Edge connectivity from :func:`tricon`.
70
+ tt : ndarray of shape (T, 6)
71
+ Triangle connectivity from :func:`tricon`.
72
+ ni, nj, nk : int
73
+ Local vertex indices (0, 1, or 2) defining the edge ``[ni, nj]`` and
74
+ opposite vertex ``nk`` for the current face pass.
75
+
76
+ Returns
77
+ -------
78
+ cc : ndarray of shape (T, 3)
79
+ Updated circumball parameters.
80
+
81
+ References
82
+ ----------
83
+ Translation of the MESH2D function ``MINFAC2``.
84
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
85
+ """
86
+
87
+ EF = ee[tt[:, ni + 3], 4] > 0
88
+
89
+ bc = 0.5 * (pp[tt[EF, ni], :] + pp[tt[EF, nj], :])
90
+
91
+ br = np.sum((bc - pp[tt[EF, ni], :]) ** 2, axis=1) + np.sum(
92
+ (bc - pp[tt[EF, nj], :]) ** 2, axis=1
93
+ )
94
+ br = br * 0.5
95
+
96
+ ll = np.sum((bc - pp[tt[EF, nk], :]) ** 2, axis=1)
97
+
98
+ bi = (br >= ll) & (br <= cc[EF, 2])
99
+ ei = np.where(EF)[0]
100
+ ti = ei[bi]
101
+ cc[ti, 0:2] = bc[bi, :]
102
+ cc[ti, 2] = br[bi]
103
+
104
+ return cc
@@ -0,0 +1,61 @@
1
+ import numpy as np
2
+
3
+
4
+ def inv_2x2(AA):
5
+ """Compute determinant-scaled inverses for a block of 2×2 matrices.
6
+
7
+ Returns ``det(A) * inv(A)`` for numerical robustness. Divide by ``DA``
8
+ when solving linear systems.
9
+
10
+ Parameters
11
+ ----------
12
+ AA : ndarray of shape (2, 2, N)
13
+ Stack of ``N`` individual 2×2 matrices.
14
+
15
+ Returns
16
+ -------
17
+ II : ndarray of shape (2, 2, N)
18
+ Determinant-scaled inverse of each matrix.
19
+ DA : ndarray of shape (N,)
20
+ Determinant of each matrix.
21
+
22
+ References
23
+ ----------
24
+ Translation of the MESH2D function ``INV_2X2``.
25
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
26
+ """
27
+
28
+ if not isinstance(AA, np.ndarray):
29
+ raise TypeError("inv_2x2:incorrectInputClass")
30
+
31
+ if AA.ndim > 3:
32
+ raise ValueError("inv_2x2:incorrectDimensions")
33
+
34
+ if AA.shape[0] != 2 or AA.shape[1] != 2:
35
+ raise ValueError("inv_2x2:incorrectDimensions")
36
+
37
+ II = np.zeros_like(AA)
38
+ DA = det_2x2(AA)
39
+
40
+ II[0, 0, :] = AA[1, 1, :]
41
+ II[1, 1, :] = AA[0, 0, :]
42
+ II[0, 1, :] = -AA[0, 1, :]
43
+ II[1, 0, :] = -AA[1, 0, :]
44
+
45
+ return II, DA
46
+
47
+
48
+ def det_2x2(AA):
49
+ """Compute determinants for a block of 2×2 matrices.
50
+
51
+ Parameters
52
+ ----------
53
+ AA : ndarray of shape (2, 2, N)
54
+ Stack of ``N`` individual 2×2 matrices.
55
+
56
+ Returns
57
+ -------
58
+ DA : ndarray of shape (N,)
59
+ Determinant of each matrix.
60
+ """
61
+ return AA[0, 0, :] * AA[1, 1, :] - AA[0, 1, :] * AA[1, 0, :]
@@ -0,0 +1,72 @@
1
+ import numpy as np
2
+
3
+
4
+ def inv_3x3(AA):
5
+ """Compute determinant-scaled inverses for a block of 3×3 matrices.
6
+
7
+ Returns ``det(A) * inv(A)`` for numerical robustness. Divide by ``DA``
8
+ when solving linear systems.
9
+
10
+ Parameters
11
+ ----------
12
+ AA : ndarray of shape (3, 3, N)
13
+ Stack of ``N`` individual 3×3 matrices.
14
+
15
+ Returns
16
+ -------
17
+ II : ndarray of shape (3, 3, N)
18
+ Determinant-scaled inverse of each matrix.
19
+ DA : ndarray of shape (N,)
20
+ Determinant of each matrix.
21
+
22
+ References
23
+ ----------
24
+ Translation of the MESH2D function ``INV_3X3``.
25
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
26
+ """
27
+
28
+ if not isinstance(AA, np.ndarray):
29
+ raise TypeError("inv_3x3:incorrectInputClass")
30
+
31
+ if AA.ndim > 3:
32
+ raise ValueError("inv_3x3:incorrectDimensions")
33
+
34
+ if AA.shape[0] != 3 or AA.shape[1] != 3:
35
+ raise ValueError("inv_3x3:incorrectDimensions")
36
+
37
+ II = np.zeros_like(AA)
38
+ DA = det_3x3(AA)
39
+
40
+ II[0, 0, :] = AA[2, 2, :] * AA[1, 1, :] - AA[2, 1, :] * AA[1, 2, :]
41
+ II[0, 1, :] = AA[2, 1, :] * AA[0, 2, :] - AA[2, 2, :] * AA[0, 1, :]
42
+ II[0, 2, :] = AA[1, 2, :] * AA[0, 1, :] - AA[1, 1, :] * AA[0, 2, :]
43
+
44
+ II[1, 0, :] = AA[2, 0, :] * AA[1, 2, :] - AA[2, 2, :] * AA[1, 0, :]
45
+ II[1, 1, :] = AA[2, 2, :] * AA[0, 0, :] - AA[2, 0, :] * AA[0, 2, :]
46
+ II[1, 2, :] = AA[1, 0, :] * AA[0, 2, :] - AA[1, 2, :] * AA[0, 0, :]
47
+
48
+ II[2, 0, :] = AA[2, 1, :] * AA[1, 0, :] - AA[2, 0, :] * AA[1, 1, :]
49
+ II[2, 1, :] = AA[2, 0, :] * AA[0, 1, :] - AA[2, 1, :] * AA[0, 0, :]
50
+ II[2, 2, :] = AA[1, 1, :] * AA[0, 0, :] - AA[1, 0, :] * AA[0, 1, :]
51
+
52
+ return II, DA
53
+
54
+
55
+ def det_3x3(AA):
56
+ """Compute determinants for a block of 3×3 matrices.
57
+
58
+ Parameters
59
+ ----------
60
+ AA : ndarray of shape (3, 3, N)
61
+ Stack of ``N`` individual 3×3 matrices.
62
+
63
+ Returns
64
+ -------
65
+ DA : ndarray of shape (N,)
66
+ Determinant of each matrix.
67
+ """
68
+ return (
69
+ AA[0, 0, :] * (AA[1, 1, :] * AA[2, 2, :] - AA[1, 2, :] * AA[2, 1, :])
70
+ - AA[0, 1, :] * (AA[1, 0, :] * AA[2, 2, :] - AA[1, 2, :] * AA[2, 0, :])
71
+ + AA[0, 2, :] * (AA[1, 0, :] * AA[2, 1, :] - AA[1, 1, :] * AA[2, 0, :])
72
+ )
@@ -0,0 +1,134 @@
1
+ import numpy as np
2
+
3
+ from .inv_2x2 import inv_2x2
4
+ from .inv_3x3 import inv_3x3
5
+
6
+
7
+ def pwrbal2(pp, pw, tt):
8
+ """Compute power balls (orthoballs) for a weighted triangulation.
9
+
10
+ Parameters
11
+ ----------
12
+ pp : ndarray of shape (N, 2) or (N, 3)
13
+ Vertex coordinates.
14
+ pw : ndarray of shape (N, 1)
15
+ Vertex weights.
16
+ tt : ndarray of shape (T, 3)
17
+ Triangle connectivity.
18
+
19
+ Returns
20
+ -------
21
+ bb : ndarray of shape (T, 3) or (T, 4)
22
+ Power-ball parameters ``[xc, yc, r²]`` in 2D or ``[xc, yc, zc, r²]`` in 3D.
23
+
24
+ References
25
+ ----------
26
+ Translation of the MESH2D function ``PWRBAL2``.
27
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
28
+ """
29
+
30
+ if not (
31
+ isinstance(pp, np.ndarray)
32
+ and isinstance(pw, np.ndarray)
33
+ and isinstance(tt, np.ndarray)
34
+ ):
35
+ raise TypeError("pwrbal2:incorrectInputClass")
36
+
37
+ if pp.ndim != 2 or pw.ndim != 2 or tt.ndim != 2:
38
+ raise ValueError("pwrbal2:incorrectDimensions")
39
+
40
+ if pp.shape[0] != pw.shape[0] or tt.shape[1] < 3 or pp.shape[1] < 2:
41
+ raise ValueError("pwrbal2:incorrectDimensions")
42
+
43
+ dim = pp.shape[1]
44
+
45
+ if dim == 2:
46
+ bb = np.zeros((tt.shape[0], 3))
47
+
48
+ ab = pp[tt[:, 1], :] - pp[tt[:, 0], :]
49
+ ac = pp[tt[:, 2], :] - pp[tt[:, 0], :]
50
+
51
+ AA = np.zeros((2, 2, tt.shape[0]))
52
+ AA[0, 0, :] = ab[:, 0] * 2.0
53
+ AA[0, 1, :] = ab[:, 1] * 2.0
54
+ AA[1, 0, :] = ac[:, 0] * 2.0
55
+ AA[1, 1, :] = ac[:, 1] * 2.0
56
+
57
+ Rv = np.zeros((2, 1, tt.shape[0]))
58
+ Rv[0, 0, :] = np.sum(ab * ab, axis=1) - (pw[tt[:, 1], 0] - pw[tt[:, 0], 0])
59
+ Rv[1, 0, :] = np.sum(ac * ac, axis=1) - (pw[tt[:, 2], 0] - pw[tt[:, 0], 0])
60
+
61
+ II, dd = inv_2x2(AA)
62
+
63
+ bb[:, 0] = (II[0, 0, :] * Rv[0, 0, :] + II[0, 1, :] * Rv[1, 0, :]) / dd
64
+ bb[:, 1] = (II[1, 0, :] * Rv[0, 0, :] + II[1, 1, :] * Rv[1, 0, :]) / dd
65
+
66
+ bb[:, 0:2] = pp[tt[:, 0], :] + bb[:, 0:2]
67
+
68
+ r1 = np.sum((bb[:, 0:2] - pp[tt[:, 0], :]) ** 2, axis=1)
69
+ r2 = np.sum((bb[:, 0:2] - pp[tt[:, 1], :]) ** 2, axis=1)
70
+ r3 = np.sum((bb[:, 0:2] - pp[tt[:, 2], :]) ** 2, axis=1)
71
+
72
+ r1 -= pw[tt[:, 0], 0]
73
+ r2 -= pw[tt[:, 1], 0]
74
+ r3 -= pw[tt[:, 2], 0]
75
+
76
+ bb[:, 2] = (r1 + r2 + r3) / 3.0
77
+
78
+ elif dim == 3:
79
+ bb = np.zeros((tt.shape[0], 4))
80
+
81
+ ab = pp[tt[:, 1], :] - pp[tt[:, 0], :]
82
+ ac = pp[tt[:, 2], :] - pp[tt[:, 0], :]
83
+
84
+ AA = np.zeros((3, 3, tt.shape[0]))
85
+ AA[0, 0, :] = ab[:, 0] * 2.0
86
+ AA[0, 1, :] = ab[:, 1] * 2.0
87
+ AA[0, 2, :] = ab[:, 2] * 2.0
88
+ AA[1, 0, :] = ac[:, 0] * 2.0
89
+ AA[1, 1, :] = ac[:, 1] * 2.0
90
+ AA[1, 2, :] = ac[:, 2] * 2.0
91
+
92
+ nv = np.cross(ab, ac)
93
+ AA[2, 0, :] = nv[:, 0]
94
+ AA[2, 1, :] = nv[:, 1]
95
+ AA[2, 2, :] = nv[:, 2]
96
+
97
+ Rv = np.zeros((3, 1, tt.shape[0]))
98
+ Rv[0, 0, :] = np.sum(ab * ab, axis=1) - (pw[tt[:, 1], 0] - pw[tt[:, 0], 0])
99
+ Rv[1, 0, :] = np.sum(ac * ac, axis=1) - (pw[tt[:, 2], 0] - pw[tt[:, 0], 0])
100
+
101
+ II, dd = inv_3x3(AA)
102
+
103
+ bb[:, 0] = (
104
+ II[0, 0, :] * Rv[0, 0, :]
105
+ + II[0, 1, :] * Rv[1, 0, :]
106
+ + II[0, 2, :] * Rv[2, 0, :]
107
+ ) / dd
108
+ bb[:, 1] = (
109
+ II[1, 0, :] * Rv[0, 0, :]
110
+ + II[1, 1, :] * Rv[1, 0, :]
111
+ + II[1, 2, :] * Rv[2, 0, :]
112
+ ) / dd
113
+ bb[:, 2] = (
114
+ II[2, 0, :] * Rv[0, 0, :]
115
+ + II[2, 1, :] * Rv[1, 0, :]
116
+ + II[2, 2, :] * Rv[2, 0, :]
117
+ ) / dd
118
+
119
+ bb[:, 0:3] = pp[tt[:, 0], :] + bb[:, 0:3]
120
+
121
+ r1 = np.sum((bb[:, 0:3] - pp[tt[:, 0], :]) ** 2, axis=1)
122
+ r2 = np.sum((bb[:, 0:3] - pp[tt[:, 1], :]) ** 2, axis=1)
123
+ r3 = np.sum((bb[:, 0:3] - pp[tt[:, 2], :]) ** 2, axis=1)
124
+
125
+ r1 -= pw[tt[:, 0], 0]
126
+ r2 -= pw[tt[:, 1], 0]
127
+ r3 -= pw[tt[:, 2], 0]
128
+
129
+ bb[:, 3] = (r1 + r2 + r3) / 3.0
130
+
131
+ else:
132
+ raise ValueError("pwrbal2:unsupportedDimension")
133
+
134
+ return bb
@@ -0,0 +1,27 @@
1
+ import numpy as np
2
+ from .pwrbal2 import pwrbal2
3
+
4
+ def tribal2(pp, tt):
5
+ """Compute circumballs for triangles in R² or R³.
6
+
7
+ Equivalent to :func:`pwrbal2` with zero vertex weights.
8
+
9
+ Parameters
10
+ ----------
11
+ pp : ndarray of shape (N, 2) or (N, 3)
12
+ Vertex coordinates.
13
+ tt : ndarray of shape (T, 3)
14
+ Triangle connectivity.
15
+
16
+ Returns
17
+ -------
18
+ bb : ndarray of shape (T, 3) or (T, 4)
19
+ Circumball parameters ``[xc, yc, r²]`` in 2D or ``[xc, yc, zc, r²]`` in 3D.
20
+
21
+ References
22
+ ----------
23
+ Translation of the MESH2D function ``TRIBAL2``.
24
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
25
+ """
26
+
27
+ return pwrbal2(pp, np.zeros((pp.shape[0], 1)), tt)
@@ -0,0 +1,62 @@
1
+ import numpy as np
2
+
3
+
4
+ def relhfn(vert, tria, hvrt):
5
+ """Compute relative edge lengths against a mesh-size function.
6
+
7
+ For each unique mesh edge, return ``edge_length / mean(h at endpoints)``.
8
+ Values near 1 indicate good conformance to the sizing field.
9
+
10
+ Parameters
11
+ ----------
12
+ vert : ndarray of shape (V, 2)
13
+ Vertex coordinates.
14
+ tria : ndarray of shape (T, 3)
15
+ Triangle connectivity.
16
+ hvrt : ndarray of shape (V,)
17
+ Mesh-size function evaluated at vertices.
18
+
19
+ Returns
20
+ -------
21
+ hrel : ndarray of shape (E,)
22
+ Relative edge lengths for the unique edges in the triangulation.
23
+
24
+ References
25
+ ----------
26
+ Translation of the MESH2D function ``RELHFN2``.
27
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
28
+ """
29
+
30
+ if not (
31
+ isinstance(vert, np.ndarray)
32
+ and isinstance(tria, np.ndarray)
33
+ and isinstance(hvrt, np.ndarray)
34
+ ):
35
+ raise TypeError("relhfn:incorrectInputClass")
36
+
37
+ if vert.ndim != 2 or tria.ndim != 2:
38
+ raise ValueError("relhfn:incorrectDimensions")
39
+ if vert.shape[1] != 2 or tria.shape[1] < 3:
40
+ raise ValueError("relhfn:incorrectDimensions")
41
+ if len(hvrt.shape) != 1 or hvrt.shape[0] != vert.shape[0]:
42
+ raise ValueError("relhfn:incorrectDimensions")
43
+
44
+ nnod = vert.shape[0]
45
+
46
+ if np.min(tria[:, :3]) < 0 or np.max(tria[:, :3]) >= nnod:
47
+ raise ValueError("relhfn:invalidInputs")
48
+
49
+ eset = np.vstack([tria[:, [0, 1]], tria[:, [1, 2]], tria[:, [2, 0]]])
50
+
51
+ eset = np.sort(eset, axis=1)
52
+ eset = np.unique(eset, axis=0)
53
+
54
+ evec = vert[eset[:, 1], :] - vert[eset[:, 0], :]
55
+
56
+ elen = np.sqrt(np.sum(evec**2, axis=1))
57
+
58
+ hmid = hvrt[eset[:, 1]] + hvrt[eset[:, 0]]
59
+ hmid = 0.5 * hmid
60
+ hrel = elen / hmid
61
+
62
+ return hrel
@@ -0,0 +1,59 @@
1
+ import numpy as np
2
+
3
+
4
+ def triang(pp, tt):
5
+ """Compute internal triangle angles in degrees.
6
+
7
+ Parameters
8
+ ----------
9
+ pp : ndarray of shape (V, 2)
10
+ Vertex coordinates.
11
+ tt : ndarray of shape (T, 3)
12
+ Triangle connectivity.
13
+
14
+ Returns
15
+ -------
16
+ dcos : ndarray of shape (T, 3)
17
+ Internal angles at the three vertices of each triangle.
18
+
19
+ References
20
+ ----------
21
+ Translation of the MESH2D function ``TRIANG2``.
22
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
23
+ """
24
+
25
+ if not (isinstance(pp, np.ndarray) and isinstance(tt, np.ndarray)):
26
+ raise TypeError("triang:incorrectInputClass")
27
+
28
+ if pp.ndim != 2 or tt.ndim != 2:
29
+ raise ValueError("triang:incorrectDimensions")
30
+ if pp.shape[1] != 2 or tt.shape[1] < 3:
31
+ raise ValueError("triang:incorrectDimensions")
32
+
33
+ nnod = pp.shape[0]
34
+ if np.min(tt[:, :3]) < 0 or np.max(tt[:, :3]) >= nnod:
35
+ raise ValueError("triang:invalidInputs")
36
+
37
+ dcos = np.zeros((tt.shape[0], 3))
38
+
39
+ ev12 = pp[tt[:, 1], :] - pp[tt[:, 0], :]
40
+ ev23 = pp[tt[:, 2], :] - pp[tt[:, 1], :]
41
+ ev31 = pp[tt[:, 0], :] - pp[tt[:, 2], :]
42
+
43
+ lv11 = np.sqrt(np.sum(ev12**2, axis=1))
44
+ lv22 = np.sqrt(np.sum(ev23**2, axis=1))
45
+ lv33 = np.sqrt(np.sum(ev31**2, axis=1))
46
+
47
+ ev12 = ev12 / lv11[:, None]
48
+ ev23 = ev23 / lv22[:, None]
49
+ ev31 = ev31 / lv33[:, None]
50
+
51
+ dcos[:, 0] = np.sum(-ev12 * ev23, axis=1)
52
+ dcos[:, 1] = np.sum(-ev23 * ev31, axis=1)
53
+ dcos[:, 2] = np.sum(-ev31 * ev12, axis=1)
54
+
55
+ dcos = np.clip(dcos, -1.0, 1.0)
56
+
57
+ dcos = np.arccos(dcos) * 180.0 / np.pi
58
+
59
+ return dcos
@@ -0,0 +1,51 @@
1
+ import numpy as np
2
+
3
+
4
+ def triarea(pp, tt):
5
+ """Compute signed triangle areas.
6
+
7
+ Positive area indicates counter-clockwise vertex ordering in 2D.
8
+
9
+ Parameters
10
+ ----------
11
+ pp : ndarray of shape (V, 2) or (V, 3)
12
+ Vertex coordinates.
13
+ tt : ndarray of shape (T, 3)
14
+ Triangle connectivity.
15
+
16
+ Returns
17
+ -------
18
+ area : ndarray of shape (T,)
19
+ Signed triangle areas (2D) or Euclidean areas (3D).
20
+
21
+ References
22
+ ----------
23
+ Translation of the MESH2D function ``TRIAREA``.
24
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
25
+ """
26
+
27
+ if not (isinstance(pp, np.ndarray) and isinstance(tt, np.ndarray)):
28
+ raise TypeError("triarea:incorrectInputClass")
29
+
30
+ if pp.ndim != 2 or tt.ndim != 2:
31
+ raise ValueError("triarea:incorrectDimensions")
32
+ if pp.shape[1] not in (2, 3) or tt.shape[1] < 3:
33
+ raise ValueError("triarea:incorrectDimensions")
34
+
35
+ nnod = pp.shape[0]
36
+ if np.min(tt[:, :3]) < 0 or np.max(tt[:, :3]) >= nnod:
37
+ raise ValueError("triarea:invalidInputs")
38
+ ev12 = pp[tt[:, 1], :] - pp[tt[:, 0], :]
39
+ ev13 = pp[tt[:, 2], :] - pp[tt[:, 0], :]
40
+
41
+ if pp.shape[1] == 2:
42
+ area = ev12[:, 0] * ev13[:, 1] - ev12[:, 1] * ev13[:, 0]
43
+ area = 0.5 * area
44
+ elif pp.shape[1] == 3:
45
+ avec = np.cross(ev12, ev13)
46
+ area = np.sqrt(np.sum(avec**2, axis=1))
47
+ area = 0.5 * area
48
+ else:
49
+ raise ValueError("triarea:Unsupported dimension")
50
+
51
+ return area
@@ -0,0 +1,44 @@
1
+ import numpy as np
2
+
3
+
4
+ def trideg(pp, tt):
5
+ """Count incident triangles at each vertex.
6
+
7
+ Parameters
8
+ ----------
9
+ pp : ndarray of shape (V, D)
10
+ Vertex coordinates (``D >= 2``).
11
+ tt : ndarray of shape (T, 3)
12
+ Triangle connectivity.
13
+
14
+ Returns
15
+ -------
16
+ vdeg : ndarray of shape (V,), dtype int
17
+ Number of triangles incident to each vertex.
18
+
19
+ References
20
+ ----------
21
+ Translation of the MESH2D function ``TRIDEG2``.
22
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
23
+ """
24
+
25
+ if not (isinstance(pp, np.ndarray) and isinstance(tt, np.ndarray)):
26
+ raise TypeError("trideg:incorrectInputClass")
27
+
28
+ if pp.ndim != 2 or tt.ndim != 2:
29
+ raise ValueError("trideg:incorrectDimensions")
30
+ if pp.shape[1] < 2 or tt.shape[1] < 3:
31
+ raise ValueError("trideg:incorrectDimensions")
32
+
33
+ nvrt = pp.shape[0]
34
+ _ntri = tt.shape[0]
35
+
36
+ if np.min(tt[:, :3]) < 0 or np.max(tt[:, :3]) >= nvrt:
37
+ raise ValueError("trideg:invalidInputs")
38
+
39
+ vdeg = np.zeros(nvrt, dtype=int)
40
+
41
+ for tri in tt[:, :3]:
42
+ vdeg[tri] += 1
43
+
44
+ return vdeg
@@ -0,0 +1,43 @@
1
+ import numpy as np
2
+ from .triarea import triarea
3
+
4
+ def triscr(pp, tt):
5
+ """Compute scaled area-to-length ratios for mesh quality.
6
+
7
+ Higher values indicate more equilateral triangles. The scale factor
8
+ ``4*sqrt(3)/3`` normalizes an equilateral triangle to unity.
9
+
10
+ Parameters
11
+ ----------
12
+ pp : ndarray of shape (V, 2)
13
+ Vertex coordinates.
14
+ tt : ndarray of shape (T, 3)
15
+ Triangle connectivity.
16
+
17
+ Returns
18
+ -------
19
+ tscr : ndarray of shape (T,)
20
+ Area-to-mean-squared-edge-length ratio for each triangle.
21
+
22
+ References
23
+ ----------
24
+ Translation of the MESH2D function ``TRISCR2``.
25
+ Original MATLAB source: https://github.com/dengwirda/mesh2d
26
+ """
27
+
28
+ # Compute signed area-len. ratios
29
+ scal = 4.0 * np.sqrt(3.0) / 3.0
30
+
31
+ area = triarea(pp, tt) # also error checks!
32
+
33
+ lrms = (
34
+ np.sum((pp[tt[:, 1], :] - pp[tt[:, 0], :])**2, axis=1) +
35
+ np.sum((pp[tt[:, 2], :] - pp[tt[:, 1], :])**2, axis=1) +
36
+ np.sum((pp[tt[:, 2], :] - pp[tt[:, 0], :])**2, axis=1)
37
+ )
38
+
39
+ lrms = (lrms / 3.0) ** 1.0
40
+
41
+ tscr = scal * area / lrms
42
+
43
+ return tscr