Line data Source code
1 :
2 1 : centroid(m::Mesh, x, f::FHnd) = centroid(geometry(m, x), f)
3 :
4 31 : centroid(g::AbstractGeometry, f::FHnd,) =
5 : centroid(g, f, _istriangulation(g))
6 :
7 4 : centroid(g::AbstractGeometry, f::FHnd, :: IsTriangulation) =
8 : mean(position(g, v) for v in triangle(tessellation(g), f))
9 :
10 27 : centroid(g::AbstractGeometry, f::FHnd, :: NoTriangulation) =
11 : mean(position(g, v) for v in vertices(tessellation(g), f))
12 :
13 1 : centroid(m::Mesh, x) = centroid(geometry(m, x))
14 :
15 13 : function centroid(g::AbstractGeometry)
16 39 : function weightedcentroid(f)
17 26 : a = facearea(g, f)
18 26 : (a * centroid(g, f), a)
19 : end
20 :
21 13 : s = foldl(.+, (weightedcentroid(f) for f in faces(tessellation(g))))
22 :
23 13 : first(s) / last(s)
24 : end
25 :
26 : """
27 : g = geometry(mesh, x)
28 :
29 : c = centroid(g, f)
30 : c = centroid(mesh, x, f)
31 :
32 : c = centroid(g)
33 : c = centroid(mesh, x)
34 :
35 : Compute centroid of a single face `f` or of the entire surface `g`
36 : using area-weighted centroids of faces.
37 : """ centroid
38 :
39 7 : function Statistics.mean(g::AbstractGeometry)
40 7 : x = position(g)
41 :
42 7 : Statistics.mean(x[v] for v in vertices(tessellation(g)))
43 : end
44 :
45 1 : function Statistics.std(g::AbstractGeometry)
46 1 : x = position(g)
47 1 : Statistics.std(collect(x[v] for v in vertices(tessellation(g)));
48 : corrected=false)
49 : end
50 :
51 1 : function Statistics.cov(g::AbstractGeometry)
52 1 : x = position(g)
53 1 : Statistics.cov(collect(x[v] for v in vertices(tessellation(g)));
54 : corrected=false)
55 : end
56 :
57 : """
58 : g = geometry(mesh, x)
59 : centercentroid!(g)
60 :
61 : @assert centroid(g) ≈ zeros(eltype(position(g)))
62 :
63 : centercentroid!(g; origin = z)
64 :
65 : @assert centroid(g) ≈ z
66 :
67 : Shift vertex positions such that [`centroid`]@(ref) is located in the
68 : `origin`.
69 :
70 : See also [`centroid`]@(ref), [`centermean!`](@ref)
71 : """
72 4 : function centercentroid!(g::AbstractGeometry;
73 : origin = zeros(eltype(position(g))))
74 2 : x = position(g)
75 2 : c = centroid(g) - origin
76 :
77 4 : for v in vertices(tessellation(g))
78 12 : x[v] = x[v] - c
79 12 : end
80 :
81 0 : nothing
82 : end
83 :
84 : """
85 : g = geometry(mesh, x)
86 : centermean!(g)
87 :
88 : @assert Statistics.mean(g) ≈ zeros(eltype(position(g)))
89 :
90 : centermean!(g; origin = z)
91 :
92 : @assert Statistics.mean(g) ≈ z
93 :
94 : Shift vertex positions such that `Statistics.mean` is located in the
95 : `origin`.
96 :
97 : See also [`mean`]@(ref), [`centercentroid!`](@ref)
98 : """
99 4 : function centermean!(g::AbstractGeometry; origin = zeros(eltype(position(g))))
100 2 : x = position(g)
101 2 : c = Statistics.mean(g) - origin
102 :
103 4 : for v in vertices(tessellation(g))
104 12 : x[v] = x[v] - c
105 12 : end
106 :
107 0 : nothing
108 : end
109 :
110 :
111 : """
112 : g = geometry(mesh, x)
113 : U, λ, center = pca(mesh[; centroids=false])
114 :
115 : Compute Principle Component Analysis of either `position(g)` or
116 : [`centroid`](@ref)s (`centroids=true`).
117 :
118 : Compute the covariance matrix `C = (X .- center)'*(X .- center) / n`,
119 : such that
120 :
121 : C = U * Diagonal(λ) * U'
122 :
123 : with nonnegative eigenvalues `λ`. Here, `n` equals the number of
124 : vertices or the number of faces (`centroids=true`), and `center`
125 : equals the `mean` or the [`centroid`](@ref) (`centroids=true`).
126 :
127 : The additionally returned `center` is the `mean` or [`centroid`](@ref).
128 :
129 : See also [`centroid`](@ref)
130 : """
131 4 : function pca(g::AbstractGeometry; centroids::Bool=false)
132 2 : x = position(g)
133 2 : mesh = tessellation(g)
134 :
135 3 : center = centroids ? centroid(g) : Statistics.mean(g)
136 :
137 10 : xxt_c(x) = xxt(x - center)
138 10 : xxt(x) = x * x'
139 :
140 2 : C =
141 : if centroids
142 1 : mean(xxt_c(x[v]) for v in vertices(mesh))
143 : else
144 :
145 3 : mean(xxt_c(centroid(g, f)) for f in faces(mesh))
146 : end
147 :
148 2 : λ, U = eigen(Symmetric(C))
149 :
150 2 : U, λ, center
151 : end
152 :
153 : """
154 : g = geometry(mesh, x)
155 :
156 : xmin, xmax = extrema(g)
157 :
158 : Compute *axis aligned bounding box* spanned by extrema `xmin, xmax`.
159 :
160 : See also [`radius`](@ref)
161 : """
162 1 : function Base.extrema(g::AbstractGeometry)
163 1 : x = position(g)
164 1 : extrema(x[v] for v in vertices(tessellation(g)))
165 : end
166 :
167 : """
168 : g = geometry(mesh, x)
169 :
170 : r = radius(mesh[; center=mean(g)])
171 :
172 : Compute (maximum) radius of surface `mesh` w.r.t `center`.
173 :
174 : See also [`Base.extrema`](@ref), [`Statistics.mean`](@ref)
175 : """
176 2 : function radius(g::AbstractGeometry; center = Statistics.mean(g))
177 1 : x = position(g)
178 1 : maximum(norm(x[v] - center) for v in vertices(tessellation(g)))
179 : end
180 :
181 : # TODO: transform, see AffineMap: apply to property
182 :
183 : # TODO: bounding sphere, bounding ellipsoid
184 :
185 : # TODO: define norm as norm(-(extrema(g)...)); diameter
|