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.
- bluemesh2d/_version.py +24 -0
- bluemesh2d/aabb_tree/findball.py +121 -0
- bluemesh2d/aabb_tree/findtria.py +299 -0
- bluemesh2d/aabb_tree/maketree.py +147 -0
- bluemesh2d/aabb_tree/mapvert.py +72 -0
- bluemesh2d/aabb_tree/queryset.py +83 -0
- bluemesh2d/aabb_tree/scantree.py +124 -0
- bluemesh2d/dependencies.py +83 -0
- bluemesh2d/feedback.py +142 -0
- bluemesh2d/geom_util/boundary_util.py +216 -0
- bluemesh2d/geom_util/getiso.py +194 -0
- bluemesh2d/geom_util/poly_util.py +795 -0
- bluemesh2d/geom_util/proj_util.py +250 -0
- bluemesh2d/geomesh_util/border_util.py +283 -0
- bluemesh2d/geomesh_util/depth_field.py +333 -0
- bluemesh2d/geomesh_util/grd_util.py +1000 -0
- bluemesh2d/geomesh_util/interpolation_mesh.py +318 -0
- bluemesh2d/geomesh_util/merge_circumcenters.py +268 -0
- bluemesh2d/geomesh_util/water_polygon.py +406 -0
- bluemesh2d/hfun_util/build_hfun.py +589 -0
- bluemesh2d/hfun_util/hfun_dispersion.py +96 -0
- bluemesh2d/hfun_util/lfshfn.py +110 -0
- bluemesh2d/hfun_util/limhfn.py +65 -0
- bluemesh2d/hfun_util/make_constant_hfun.py +32 -0
- bluemesh2d/hfun_util/make_depth_hfun.py +51 -0
- bluemesh2d/hfun_util/smooth_and_precomput.py +188 -0
- bluemesh2d/hfun_util/trihfn.py +84 -0
- bluemesh2d/hjac_util/limgrad.py +105 -0
- bluemesh2d/mesh_ball/cdtbal1.py +38 -0
- bluemesh2d/mesh_ball/cdtbal2.py +104 -0
- bluemesh2d/mesh_ball/inv_2x2.py +61 -0
- bluemesh2d/mesh_ball/inv_3x3.py +72 -0
- bluemesh2d/mesh_ball/pwrbal2.py +134 -0
- bluemesh2d/mesh_ball/tribal2.py +27 -0
- bluemesh2d/mesh_cost/relhfn.py +62 -0
- bluemesh2d/mesh_cost/triang.py +59 -0
- bluemesh2d/mesh_cost/triarea.py +51 -0
- bluemesh2d/mesh_cost/trideg.py +44 -0
- bluemesh2d/mesh_cost/triscr.py +43 -0
- bluemesh2d/mesh_file/bnd_util.py +664 -0
- bluemesh2d/mesh_file/loadmsh.py +165 -0
- bluemesh2d/mesh_file/ugrid.py +308 -0
- bluemesh2d/mesh_util/cfmtri.py +118 -0
- bluemesh2d/mesh_util/deltri.py +131 -0
- bluemesh2d/mesh_util/idxtri.py +53 -0
- bluemesh2d/mesh_util/isfeat.py +90 -0
- bluemesh2d/mesh_util/minlen.py +46 -0
- bluemesh2d/mesh_util/setset.py +49 -0
- bluemesh2d/mesh_util/tricon.py +90 -0
- bluemesh2d/mesh_util/tridiv.py +187 -0
- bluemesh2d/meshgen.py +202 -0
- bluemesh2d/ortho_merge/constants.py +27 -0
- bluemesh2d/ortho_merge/geometry.py +64 -0
- bluemesh2d/ortho_merge/ortho_merge_iter.py +812 -0
- bluemesh2d/ortho_merge/orthogonalize.py +2989 -0
- bluemesh2d/pipeline.py +277 -0
- bluemesh2d/poly_data/airfoil.msh +958 -0
- bluemesh2d/poly_data/channel.msh +212 -0
- bluemesh2d/poly_data/islands.msh +13819 -0
- bluemesh2d/poly_data/lake.msh +612 -0
- bluemesh2d/poly_data/river.msh +690 -0
- bluemesh2d/poly_test/inpoly.py +105 -0
- bluemesh2d/poly_test/inpoly_mat.py +104 -0
- bluemesh2d/refine.py +972 -0
- bluemesh2d/smood.py +623 -0
- bluemesh2d/smooth.py +522 -0
- bluemesh2d/tricost.py +426 -0
- bluemesh2d/tridemo.py +723 -0
- bluemesh2d/triread.py +53 -0
- bluemesh2d-0.1.1.dev0.dist-info/METADATA +139 -0
- bluemesh2d-0.1.1.dev0.dist-info/RECORD +74 -0
- bluemesh2d-0.1.1.dev0.dist-info/WHEEL +5 -0
- bluemesh2d-0.1.1.dev0.dist-info/licenses/LICENSE +674 -0
- 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
|