Line data Source code
1 0 : localframe(g::AbstractGeometry, f::FHnd) =
2 : localframe(g::AbstractGeometry, f::FHnd, _has_vx(g), _has_fn(g))
3 :
4 0 : function localframe(g::AbstractGeometry, f::FHnd, ::HasVX, ::NoFN)
5 0 : x0, u, v = rawfacebase(g, f)
6 0 : u = normalize(u)
7 0 : nrm = normalize(u × v)
8 0 : v = normalize(u × nrm) # works w/o normalize up to rounding # TODO: check orientation
9 :
10 0 : x0, u, v, nrm
11 : end
12 :
13 0 : function localframe(g::AbstractGeometry, f::FHnd, ::HasVX, ::HasFN)
14 0 : h = halfedge(_mesh(g), f)
15 0 : u = edgevector(g, h)
16 0 : nrm = normal(g, f)
17 0 : @massert dot(u, nrm) ≈ 0
18 0 : u = normalize(u)
19 :
20 0 : _vpos(g)[source(h)], u, cross(u, nrm), nrm
21 : end
22 :
23 0 : localframe(g::AbstractGeometry, v::VHnd) =
24 : localframe(g, v, _has_vx(g), _has_vn(g))
25 :
26 0 : localframe(g::AbstractGeometry, v::VHnd, ::HasVX, ::HasVN) =
27 : _vlocalframe(g, v, _vnrm(g)[v])
28 :
29 0 : localframe(g::AbstractGeometry, v::VHnd, ::HasVX, ::NoVN) =
30 : _vlocalframe(g, v, normal(g, v))
31 :
32 0 : function _vlocalframe(g, v, nrm)
33 0 : h = halfedge(_mesh(g), v)
34 0 : x0 = _vpos(g)[v]
35 0 : u = _vpos(g)[destination(_mesh(g), h)] - x0
36 :
37 0 : u -= dot(u, nrm) * nrm
38 0 : u = normalize(u)
39 :
40 0 : x0, u, cross(u, nrm), nrm
41 : end
42 :
43 : """
44 : g = geometry(mesh, x, ...)
45 : x0, u, v = localframe(g, f)
46 :
47 : Compute orthonormal basis `u, v, n` such that `u, v` span plane of face
48 : `f` and `n` is the normal vector. The origin is shifted to `x0`.
49 :
50 : x0, u, v, n = localframe(g, v)
51 :
52 : Compute orthonormal basis `u, v, n` such that `u, v` span tangent plane
53 : defined by vertex normal `n`. Here, `x0` is the position of vertex `v`.
54 :
55 : !!! note
56 : This method uses stored [`normal`](@ref) if attribute is available.
57 :
58 : !!! note
59 : This method is similar to [`tangentspace`](@ref) but returns also
60 : the normal vector.
61 :
62 : See also [`geometry`](@ref), [`rawfacebase`](@ref), [`normal`](@ref),
63 : [`tangentspace`](@ref), [`tolocal`](@ref)
64 : """ localframe
65 :
66 0 : function tolocal(g::AbstractGeometry, h::Hnd)
67 0 : x0, u, v, n = localframe(g, h)
68 0 : A = [u'; v'; n']
69 0 : affinemap(A, A * x0)
70 : end
71 :
72 0 : function tolocal(g::AbstractGeometry, h::Hnd, x)
73 0 : x0, u, v, n = localframe(g, h)
74 0 : [u v n]' * (x - x0)
75 : end
76 :
77 : """
78 : g = geometry(mesh, x, ...)
79 : u = tolocal(g, f, z)
80 : u = tolocal(g, v, z)
81 :
82 : m = tolocal(g, f) # Provide callable object
83 : m = tolocal(g, v)
84 : u = m(z)
85 :
86 : invm = toworld(m)
87 : z = invm(u)
88 :
89 : Transform 3d point `x` to 3d local coordinates `u` defined by
90 : [`localframe`](@ref) of face `f` or vertex `v`.
91 :
92 : !!! note
93 : The local coordinate system for a vertex `v` has `x[v]` as
94 : origin, i.e., `x[v]` is mapped to the null vector.
95 :
96 : !!! tip
97 : Combine with [`positions`](@ref) to map, e.g., a 1-ring:
98 :
99 : ```julia
100 : us = map(tolocal(g, v) ∘ positions(g), ring(mesh, v))
101 : ```
102 :
103 : See also [`localframe`](@ref), [`toworld`](@ref),
104 : [`tolocal2d`](@ref), [`positions`](@ref)
105 : """ tolocal
106 :
107 0 : function tolocal2d(g::AbstractGeometry, h::Hnd)
108 0 : x0, u, v, _ = localframe(g, h)
109 0 : A = [u'; v']
110 0 : affinemap(A, A * x0)
111 : end
112 :
113 0 : function tolocal2d(g::AbstractGeometry, h::Hnd, x)
114 0 : x0, u, v = tangentspace(g, h)
115 0 : [u v]' * (x - x0)
116 : end
117 :
118 : """
119 : g = geometry(mesh, x, ...)
120 : u = tolocal2d(g, f, z)
121 : u = tolocal2d(g, v, z)
122 :
123 : f = tolocal2d(g, f) # Provide callable object
124 : f = tolocal2d(g, v)
125 : u = f(x)
126 :
127 : Transform point `x` 2d to local coordinates `u` defined by
128 : [`tangentspace`](@ref) of face `f` or vertex `v`.
129 :
130 : !!! note
131 : The local coordinate system for a vertex `v` has `x[v]` as
132 : origin, i.e., `x[v]` is mapped to the null vector.
133 :
134 : !!! tip
135 : Combine with [`positions`](@ref) to map, e.g., a 1-ring:
136 :
137 : ```julia
138 : us = map(tolocal2d(g, v) ∘ positions(g), ring(mesh, v))
139 : ```
140 :
141 : See also [`localframe`](@ref), [`tolocal`](@ref),
142 : [`positions`](@ref)
143 : """ tolocal2d
144 :
145 : """
146 : g = geometry(mesh, x, ...)
147 : m = tolocal(g, ...)
148 : im = toworld(m)
149 :
150 : u = m(z)
151 : z = im(u)
152 :
153 : Inverse map to affine map obtained from [`tolocal`](@ref) or
154 : [`tolocal2d`](@ref).
155 :
156 : !!! note
157 : [`toworld`](@ref) maps *points* in local coordinates to
158 : *points* in world coordinates by an *affine map*.
159 :
160 : Use [`linearmap`](@ref) or [`mapvector`](@ref) to obtain
161 : a *linear map* to map *vectors* in local coordinates to
162 : *vectors* in world coordinates.
163 :
164 : !!! warning "precondition"
165 : Requires *rigid* transformation as obtained
166 : from [`tolocal`](@ref), i.e., `A'A == I`.
167 :
168 : See also [`localframe`](@ref), [`tolocal`](@ref),
169 : [`tolocal2d`](@ref)
170 : """
171 0 : toworld(f::AffineMap) = affinemap(f.A', -(f.A' * f.b))
172 :
173 : """
174 : g = geometry(mesh, x, ...)
175 : x0, u, v = tangentspace(g, f)
176 :
177 : Compute orthonormal basis u, v, for plane spanning face `f` with origin
178 : shifted to `x0`.
179 :
180 : x0, u, v = tangentspace(g, v)
181 :
182 : Compute orthonormal basis for tangent plane defined by vertex normal. Here,
183 : `x0` is the position of vertex `v`.
184 :
185 : !!! note
186 : This method uses stored [`normal`](@ref) if attribute is available.
187 :
188 : !!! note
189 : This method is similar to [`localframe`](@ref) but does not return
190 : normal vector.
191 :
192 : See also [`geometry`](@ref), [`rawfacebase`](@ref), [`normal`](@ref),
193 : [`localframe`](@ref), [`projectintotangentspace`](@ref),
194 : [`tolocal2d`](@ref)
195 : """
196 0 : function tangentspace(g::AbstractGeometry, h::Hnd)
197 0 : x0, u, v, _ = localframe(g, h)
198 0 : x0, u, v
199 : end
200 :
201 0 : function projectintotangentspace(g::AbstractGeometry, f::FHnd, x)
202 0 : m = _mesh(g)
203 0 : h = halfedge(m, f)
204 0 : x0 = _vpos(g)[destination(m, h)]
205 0 : nrm = normal(g, f)
206 :
207 0 : x - dot(x - x0, nrm) * nrm
208 : end
209 :
210 0 : function projectintotangentspace(g::AbstractGeometry, v::VHnd, x)
211 0 : x0 = _vpos(g)[v]
212 0 : nrm = normal(g, v)
213 :
214 0 : x - dot(x - x0, nrm) * nrm
215 : end
216 :
217 : """
218 : g = geometry(mesh, x, ...)
219 : xhat = projectintotangentspace(g, f, x)
220 : xhat = projectintotangentspace(g, v, x)
221 :
222 : Project `x` into [`tangentspace`](@ref) of face `f` or vertex `v`. The
223 : projection `xhat` is a 3d vector.
224 :
225 : For a planar face `f`, its tangent space is the respective plane. For
226 : a vertex `v`, its tangent space is defined implicitly by the
227 : [`normal`](@ref) vector.
228 :
229 : !!! note
230 : This method uses the stored [`normal`](@ref) if attribute is
231 : available. It does require a basis, i.e., does *not* call
232 : [`tangentspace`](@ref).
233 :
234 : See also [`geometry`](@ref), [`normal`](@ref), [`tangentspace`](@ref)
235 : """
236 : projectintotangentspace
|