v2.0.0
Loading...
Searching...
No Matches
mne_project_to_surface.cpp
Go to the documentation of this file.
1//=============================================================================================================
35
36//=============================================================================================================
37// INCLUDES
38//=============================================================================================================
39
41
42//=============================================================================================================
43// INCLUDES
44//=============================================================================================================
45
46#include <mne/mne_bem_surface.h>
47
48//=============================================================================================================
49// QT INCLUDES
50//=============================================================================================================
51
52//=============================================================================================================
53// EIGEN INCLUDES
54//=============================================================================================================
55
56#include <Eigen/Geometry>
57
58//=============================================================================================================
59// USED NAMESPACES
60//=============================================================================================================
61
62using namespace MNELIB;
63using namespace Eigen;
64
65//=============================================================================================================
66// DEFINE GLOBAL METHODS
67//=============================================================================================================
68
69//=============================================================================================================
70// DEFINE MEMBER METHODS
71//=============================================================================================================
72
74: r1(MatrixX3f::Zero(1,3))
75, r12(MatrixX3f::Zero(1,3))
76, r13(MatrixX3f::Zero(1,3))
77, nn(MatrixX3f::Zero(1,3))
78, a(VectorXf::Zero(1))
79, b(VectorXf::Zero(1))
80, c(VectorXf::Zero(1))
81, det(VectorXf::Zero(1))
82{
83}
84
85//=============================================================================================================
86
88: r1(MatrixX3f::Zero(p_MNEBemSurf.ntri,3))
89, r12(MatrixX3f::Zero(p_MNEBemSurf.ntri,3))
90, r13(MatrixX3f::Zero(p_MNEBemSurf.ntri,3))
91, nn(MatrixX3f::Zero(p_MNEBemSurf.ntri,3))
92, a(VectorXf::Zero(p_MNEBemSurf.ntri))
93, b(VectorXf::Zero(p_MNEBemSurf.ntri))
94, c(VectorXf::Zero(p_MNEBemSurf.ntri))
95, det(VectorXf::Zero(p_MNEBemSurf.ntri))
96{
97 for (int i = 0; i < p_MNEBemSurf.ntri; ++i)
98 {
99 r1.row(i) = p_MNEBemSurf.rr.row(p_MNEBemSurf.itris(i,0));
100 r12.row(i) = p_MNEBemSurf.rr.row(p_MNEBemSurf.itris(i,1)) - r1.row(i);
101 r13.row(i) = p_MNEBemSurf.rr.row(p_MNEBemSurf.itris(i,2)) - r1.row(i);
102 a(i) = r12.row(i) * r12.row(i).transpose();
103 b(i) = r13.row(i) * r13.row(i).transpose();
104 c(i) = r12.row(i) * r13.row(i).transpose();
105 }
106
107 if (!(p_MNEBemSurf.tri_nn.isZero(0)))
108 {
109 nn = p_MNEBemSurf.tri_nn.cast<float>();
110 }
111 else
112 {
113 for (int i = 0; i < p_MNEBemSurf.ntri; ++i)
114 {
115 nn.row(i) = r12.row(i).transpose().cross(r13.row(i).transpose()).transpose();
116 }
117 }
118 det = (a.array()*b.array() - c.array()*c.array()).matrix();
119}
120
121//=============================================================================================================
122
123bool MNEProjectToSurface::find_closest_on_surface(const MatrixXf &r, const int np, MatrixXf &rTri,
124 VectorXi &nearest, VectorXf &dist)
125{
126 // resize output
127 nearest.resize(np);
128 dist.resize(np);
129 rTri.resize(np,3);
130
131 if (this->r1.isZero(0))
132 {
133 qDebug() << "No surface loaded to make the projection./n";
134 return false;
135 }
136 int bestTri = -1;
137 float bestDist = -1;
138 Vector3f rTriK;
139 for (int k = 0; k < np; ++k)
140 {
141 /*
142 * To do: decide_search_restriction for the use in an iterative closest point to plane algorithm
143 * For now it's OK to go through all triangles.
144 */
145 if (!this->project_to_surface(r.row(k).transpose(), rTriK, bestTri, bestDist))
146 {
147 qDebug() << "The projection of point number " << k << " didn't work./n";
148 return false;
149 }
150 rTri.row(k) = rTriK.transpose();
151 nearest[k] = bestTri;
152 dist[k] = bestDist;
153 }
154 return true;
155}
156
157//=============================================================================================================
158
159bool MNEProjectToSurface::project_to_surface(const Vector3f &r, Vector3f &rTri, int &bestTri, float &bestDist)
160{
161 float p = 0, q = 0, p0 = 0, q0 = 0, dist0 = 0;
162 bestDist = 0.0f;
163 bestTri = -1;
164 for (int tri = 0; tri < a .size(); ++tri)
165 {
166 if (!this->nearest_triangle_point(r, tri, p0, q0, dist0))
167 {
168 qDebug() << "The projection on triangle " << tri << " didn't work./n";
169 return false;
170 }
171
172 if ((bestTri < 0) || (std::fabs(dist0) < std::fabs(bestDist)))
173 {
174 bestDist = dist0;
175 p = p0;
176 q = q0;
177 bestTri = tri;
178 }
179 }
180
181 if (bestTri >= 0)
182 {
183 if (!this->project_to_triangle(rTri, p, q, bestTri))
184 {
185 qDebug() << "The coordinate transform to cartesian system didn't work./n";
186 return false;
187 }
188 return true;
189 }
190
191 qDebug() << "No best Triangle found./n";
192 return false;
193}
194
195//=============================================================================================================
196
197bool MNEProjectToSurface::nearest_triangle_point(const Vector3f &r, const int tri, float &p, float &q, float &dist)
198{
199 //Calculate some helpers
200 Vector3f rr = r - this->r1.row(tri).transpose(); //Vector from triangle corner #1 to r
201 float v1 = this->r12.row(tri)*rr;
202 float v2 = this->r13.row(tri)*rr;
203
204 //Calculate the orthogonal projection of the point r on the plane
205 dist = this->nn.row(tri)*rr;
206 p = (this->b(tri)*v1 - this->c(tri)*v2)/det(tri);
207 q = (this->a(tri)*v2 - this->c(tri)*v1)/det(tri);
208
209 //If the point projects into the triangle we are done
210 if (p >= 0.0 && p <= 1.0 && q >= 0.0 && q <= 1.0 && (p+q) <= 1.0)
211 {
212 return true;
213 }
214
215 /*
216 * Tough: must investigate the sides
217 * We might do something intelligent here. However, for now it is ok
218 * to do it in the hard way
219 */
220 float p0, q0, t0, dist0, best, bestp, bestq;
221
222 /*
223 * Side 1 -> 2
224 */
225 p0 = p + (q * this->c(tri)) / this->a(tri);
226 // Place the point in the corner if it is not on the side
227 if (p0 < 0.0)
228 {
229 p0 = 0.0;
230 }
231 else if (p0 > 1.0)
232 {
233 p0 = 1.0;
234 }
235 q0 = 0;
236 // Distance
237 dist0 = sqrt((p-p0)*(p-p0)*this->a(tri) +
238 (q-q0)*(q-q0)*this->b(tri) +
239 2*(p-p0)*(q-q0)*this->c(tri) +
240 dist*dist);
241
242 best = dist0;
243 bestp = p0;
244 bestq = q0;
245 /*
246 * Side 2 -> 3
247 */
248 t0 = ((a(tri)-c(tri))*(-p) + (b(tri)-c(tri))*q)/(a(tri)+b(tri)-2*c(tri));
249 // Place the point in the corner if it is not on the side
250 if (t0 < 0.0)
251 {
252 t0 = 0.0;
253 }
254 else if (t0 > 1.0)
255 {
256 t0 = 1.0;
257 }
258 p0 = 1.0 - t0;
259 q0 = t0;
260 // Distance
261 dist0 = sqrt((p-p0)*(p-p0)*this->a(tri) +
262 (q-q0)*(q-q0)*this->b(tri) +
263 2*(p-p0)*(q-q0)*this->c(tri) +
264 dist*dist);
265 if (dist0 < best)
266 {
267 best = dist0;
268 bestp = p0;
269 bestq = q0;
270 }
271 /*
272 * Side 1 -> 3
273 */
274 p0 = 0.0;
275 q0 = q + (p * c(tri))/b(tri);
276 // Place the point in the corner if it is not on the side
277 if (q0 < 0.0)
278 {
279 q0 = 0.0;
280
281 }
282 else if (q0 > 1.0)
283 {
284 q0 = 1.0;
285 }
286 // Distance
287 dist0 = sqrt((p-p0)*(p-p0)*this->a(tri) +
288 (q-q0)*(q-q0)*this->b(tri) +
289 2*(p-p0)*(q-q0)*this->c(tri) +
290 dist*dist);
291 if (dist0 < best)
292 {
293 best = dist0;
294 bestp = p0;
295 bestq = q0;
296 }
297 dist = best;
298 p = bestp;
299 q = bestq;
300 return true;
301}
302
303//=============================================================================================================
304
305bool MNEProjectToSurface::project_to_triangle(Vector3f &rTri, const float p, const float q, const int tri)
306{
307 rTri = this->r1.row(tri) + p*this->r12.row(tri) + q*this->r13.row(tri);
308 return true;
309}
MNEBemSurface class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
BEM surface provides geometry information.
Eigen::MatrixX3d tri_nn
bool find_closest_on_surface(const Eigen::MatrixXf &r, const int np, Eigen::MatrixXf &rTri, Eigen::VectorXi &nearest, Eigen::VectorXf &dist)
find_closest_on_surface