Line data Source code
1 48384 : rawtrianglenormal(g::AbstractGeometry, f::FHnd) =
2 : cross(rawtrianglebase(g, f)[2:3]...)
3 :
4 0 : rawtrianglenormal(m::Mesh, x, f::FHnd) = rawtrianglenormal(geometry(m, x), f)
5 :
6 161652 : function _safe_normalize(nrm::SVector{3, T}) where {T}
7 161652 : len = norm(nrm)
8 161652 : (len < eps(T)) && return zeros(SVector{3, T})
9 161652 : nrm / len
10 : end
11 :
12 : """
13 : nrm = rawtrianglenormal(mesh, x, f)
14 :
15 : g = geometry(mesh, x)
16 : nrm = rawtrianglenormal(g, x)
17 :
18 : Compute "unnormalized" normal vector to triangle `f`.
19 :
20 : !!! warning "precondition"
21 : Face `f` refers to a triangle.
22 :
23 : See also [`geometry`](@ref), [`rawtrianglebase`](@ref), [`trianglenormal`](@ref)
24 : """ rawtrianglenormal
25 :
26 0 : trianglenormal(g::AbstractGeometry, f::FHnd) =
27 : rawtrianglenormal(g, f) |> _safe_normalize
28 :
29 0 : trianglenormal(m::Mesh, x, f::FHnd) = trianglenormal(geometry(m, x), f)
30 :
31 : """
32 : nrm = trianglenormal(mesh, x, f)
33 :
34 : g = geometry(mesh, x)
35 : nrm = trianglenormal(g, f)
36 :
37 : Compute unit-length normal vector to triangle `f`.
38 :
39 : !!! warning "precondition"
40 : Face `f` refers to a triangle.
41 :
42 : !!! note
43 : The `trianglenormal` *always* returns a finite vector:
44 : For a degenerated triangle with zero area, its normal vector
45 : is *undefined*, and `trianglenormal` returns `zeros(..)`
46 : (*not= `[NaN,...]`).
47 :
48 : See also [`geometry`](@ref), [`rawtrianglenormal`](@ref)
49 : """ trianglenormal
50 :
51 48384 : function trianglenormalarea(g::AbstractGeometry, f::FHnd)
52 48384 : nrm = rawtrianglenormal(g, f)
53 48384 : len = norm(nrm)
54 :
55 48384 : nrm / len, len
56 : end
57 :
58 0 : trianglenormalarea(m::Mesh, x, f::FHnd) = trianglenormalarea(geometry(m, x), f)
59 :
60 :
61 : """
62 : nrm, ar = trianglenormalarea(mesh, x, f)
63 :
64 : g = geometry(mesh, x)
65 : nrm, ar = trianglenormalarea(g, f)
66 :
67 : Compute unit-length [`trianglenormal`](@ref) and [`trianglearea`](@ref).
68 :
69 : See also [`geometry`](@ref), [`trianglenormal`](@ref) and [`trianglearea`](@ref)
70 : """ trianglenormalarea
71 :
72 161652 : function facenormal(g::AbstractGeometry, f::FHnd)
73 : # _, u, v = rawfacebase(g, f)
74 : # _safe_normalize(u × v)
75 :
76 161652 : m = _mesh(g)
77 161652 : x = _vpos(g)
78 :
79 161652 : a, b, c, hnext = first3(m, f)
80 :
81 161652 : (hnext == NoH) && return _safe_normalize((x[b] - x[a]) × (x[c] - x[a]))
82 :
83 : # c = mean(x[v] for v in vertices(m, f))
84 78 : bc = (x[a] + x[b] + x[c]) / 3
85 :
86 : # NOTE: c cancels out below, but I prefer computing w/ local coordinates,
87 : # thus being independent of the absolute position of the face.
88 : # Any "anchor" is good (or possibly better than (0, 0, 0))
89 :
90 78 : nrm = sum((x[source(m, h)] - bc) × (x[destination(m, h)] - bc) for h in halfedges(m, f))
91 78 : _safe_normalize(nrm)
92 : end
93 :
94 0 : facenormal(m::Mesh, x, f::FHnd) = facenormal(geometry(m, x), f)
95 :
96 : """
97 : nrm = facenormal(mesh, x, f)
98 :
99 : g = geometry(mesh, x)
100 : nrm = facenormal(g, f)
101 :
102 : Compute face normal from [`rawfacebase`](@ref).
103 :
104 : See also [`geometry`](@ref), [`rawfacebase`](@ref), [`trianglenormal`](@ref)
105 : """ facenormal
106 :
107 48384 : facenormalarea(g::AbstractGeometry, f::FHnd) =
108 : facenormalarea(g, f, _istriangulation(g))
109 :
110 48384 : facenormalarea(g::AbstractGeometry, f::FHnd, ::IsTriangulation) =
111 : trianglenormalarea(g, f)
112 :
113 0 : facenormalarea(g::AbstractGeometry, f::FHnd, ::NoTriangulation) =
114 : (facenormal(g, f), facearea(g, f))
115 :
116 0 : facenormalarea(m::Mesh, x, f::FHnd) = facenormalarea(geometry(m, x), f)
|