Line data Source code
1 : """
2 : Affine map `f(x) = A * x - b`
3 :
4 : f = affinemap(A, b)
5 : f(x) == A * x - b
6 :
7 : g = linearmap(f) # linear part A * x
8 : g = mapvector(f) # same as linearmap(f)
9 : g = mapunitvector(f) # plus normalization
10 : g = mapnormal(f) # map unit normals inv(A)' * x
11 :
12 : See also [`affinemap`](@ref), [`LinearMap`](@ref)
13 : """
14 : struct AffineMap{M, N, T, MN}
15 : A::SMatrix{M, N, T, MN}
16 : b::SVector{M, T}
17 : end
18 :
19 : """
20 : f = affinemap(A, b)
21 : f(x) == A * x - b
22 :
23 : affinemap(f) == f
24 :
25 : Construct [`AffineMap`](@ref)
26 :
27 : See also [`AffineMap`](@ref), [`linearmap`](@ref)
28 : """
29 0 : affinemap(A::SMatrix{M, N, T, MN},
30 : b::SVector{M, T}) where {M, N, T, MN} =
31 : AffineMap{M, N, T, MN}(A, b)
32 :
33 0 : affinemap(t::AffineMap) = t
34 :
35 0 : (t::AffineMap{M, N, T, MN})(x) where {M, N, T, MN} =
36 : t.A * x - t.b # possibly more stable: A * (x - x0)
37 :
38 : """
39 : Linear map `f(x) = A * x`
40 :
41 : f = linearmap(A)
42 : f(x) == A * x
43 :
44 : linearmap(f) == f
45 :
46 : g = f' # adjoint
47 : g = inv(f) # inverse for maps (for quadratic A)
48 : g = inv(f')
49 : g = mapunitvector(f) # plus normalization
50 : g = mapnormal(f) # map unit normals inv(A)' * x
51 :
52 : See also [`AffineMap`](@ref), [`linearmap`](@ref)
53 : """
54 : struct LinearMap{M, N, T, MN}
55 : A::SMatrix{M, N, T, MN}
56 : end
57 :
58 0 : Base.inv(t::LinearMap{N, N, T, NN}) where {N, T, NN} =
59 : linearmap(inv(t.A))
60 :
61 0 : LinearAlgebra.adjoint(t::LinearMap{M, N, T, MN}) where {M, N, T, MN} =
62 : linearmap(t.A')
63 :
64 0 : linearmap(A::SMatrix{M, N, T, MN}) where {M, N, T, MN} =
65 : LinearMap{M, N, T, MN}(A)
66 :
67 0 : linearmap(t::AffineMap{M, N, T, MN}) where {M, N, T, MN} =
68 : linearmap(t.A)
69 :
70 0 : linearmap(t::LinearMap) = t
71 :
72 : """
73 : f = linearmap(A, b)
74 : f = linearmap(g::AffineMap)
75 : linearmap(f) == f
76 : f(x) == A * x
77 :
78 : Construct [`LinearMap`](@ref)
79 :
80 : See also [`LinearMap`](@ref), [`affinemap`](@ref)
81 : """ linearmap
82 :
83 0 : (t::LinearMap{M, N, T, MN})(x) where {M, N, T, MN} = t.A * x
84 :
85 0 : mapvector(t::AffineMap) = linearmap(t)
86 :
87 0 : mapvector(t::LinearMap) = t
88 :
89 : """
90 : f = affinemap(A, b)
91 : g = linearmap(f)
92 : g = mapvector(f)
93 :
94 : Synomym for [`linearmap`](@ref)
95 :
96 : See also [`LinearMap`](@ref), [`mapunitvector`](@ref),
97 : [`mapnormal`](@ref)
98 : """ mapvector
99 :
100 0 : function _normalized(x)
101 0 : len = norm(x)
102 0 : (len == 0) && return x
103 0 : x / len
104 : end
105 :
106 0 : mapunitvector(t::AffineMap) = _normalized ∘ mapvector(t)
107 :
108 0 : mapunitvector(t::LinearMap) = _normalized ∘ t'
109 :
110 : """
111 : f = affinemap(A, b)
112 : g = mapunitvector(f)
113 : g = mapunitvector(linearmap(f))
114 :
115 : *Nonlinear* map that composes [`linearmap`](@ref) and
116 : *normalization* of result.
117 :
118 : !!! note
119 : Null vectors are mapped to null vectors. They are
120 : *not* "normalized"!
121 :
122 : See also [`LinearMap`](@ref), [`mapvector`](@ref),
123 : [`mapnormal`](@ref)
124 : """ mapunitvector
125 :
126 :
127 0 : maptangentvector(t::AffineMap) = maptangentvector(linearmap(t))
128 :
129 0 : maptangentvector(t::LinearMap) = linearmap((t.A[@SVector([1, 2]), :]))'
130 :
131 : """
132 : Same as [`mapvector`](@ref) but use only dimensions `1:2`.
133 :
134 : Use case: [`tolocal`](@ref) maps to local `u,v,w` coordinates,
135 : map `u, v` to 3d vector in tangent space.
136 :
137 : See also [`mapvector`](@ref)
138 : """ maptangentvector
139 :
140 0 : maptangentunitvector(t::AffineMap) = _normalized ∘ maptangentvector(t)
141 :
142 0 : maptangentuntvector(t::LinearMap) = _normalized ∘ maptangentuntvector(t)
143 :
144 : """
145 : Same as [`mapunitvector`](@ref) but use only dimensions `1:2`.
146 :
147 : Use case: [`tolocal`](@ref) maps to local `u,v,w` coordinates,
148 : map `u, v` to 3d ("normalized") unit vector in tangent space.
149 :
150 : See also [`mapvector`](@ref)
151 : """ maptangentunitvector
152 :
153 0 : mapnormal(t::AffineMap{N, N, T, NN}) where {N, T, NN} =
154 : mapnormal(linearmap(t))
155 :
156 0 : mapnormal(t::LinearMap{N, N, T, NN}) where {N, T, NN} =
157 : linearmap(inv(t.A)')
158 :
159 : """
160 : f = affinemap(A, b)
161 : g = mapnormal(f)
162 : g = mapnormal(linearmap(f))
163 :
164 : *Nonlinear* map that maps normal vectors `n` with `inv(A)' * n`
165 : followed by *normalization*.
166 :
167 : !!! note
168 : Null vectors are mapped to null vectors. They are
169 : *not* "normalized"!
170 :
171 : See also [`LinearMap`](@ref), [`mapvector`](@ref),
172 : [`mapunitvector`](@ref)
173 : """ mapnormal
174 :
175 : """
176 : t = affinemap(A, b)
177 : mapvattr(t, mesh, Val(:x))
178 : mapvattr(mapnormal(t), mesh, Val(:n))
179 :
180 : mapvattr(x -> 2x, mesh, val(:myattr))
181 :
182 : Apply transformation on vertex attribute for all vertices.
183 :
184 : See also [`vattr`](@ref), [`affinemap`](@ref), [`linearmap`](@ref),
185 : [`mapunitvector`](@ref), [`normal`](@ref), [`maptangentvector`](@ref),
186 : [`maptangentunitvector`](@ref)
187 : """
188 0 : function mapvattr!(f, mesh::Mesh, ax)
189 0 : x = vattr(mesh, ax)
190 :
191 0 : for v in vertices(mesh)
192 0 : x[v] = f(x[v])
193 0 : end
194 : end
195 :
196 : # TODO: compose maps with ∘
|