MNE-CPP 0.1.9
A Framework for Electrophysiology
Loading...
Searching...
No Matches
layoutmaker.cpp
Go to the documentation of this file.
1//=============================================================================================================
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include "layoutmaker.h"
42#include "simplex_algorithm.h"
43#include "sphere.h"
44
45#define _USE_MATH_DEFINES
46#include <math.h>
47#include <iostream>
48
49//=============================================================================================================
50// QT INCLUDES
51//=============================================================================================================
52
53#include <QTextStream>
54#include <QDebug>
55
56//=============================================================================================================
57// USED NAMESPACES
58//=============================================================================================================
59
60using namespace UTILSLIB;
61using namespace Eigen;
62
63//=============================================================================================================
64// DEFINES
65//=============================================================================================================
66
67#ifndef EPS
68#define EPS 1e-6
69#endif
70
71//=============================================================================================================
72// DEFINE MEMBER METHODS
73//=============================================================================================================
74
75bool LayoutMaker::makeLayout(const QList<QVector<float> > &inputPoints,
76 QList<QVector<float> > &outputPoints,
77 const QStringList &names,
78 QFile &outFile,
79 bool do_fit,
80 float prad,
81 float w,
82 float h,
83 bool writeFile,
84 bool mirrorXAxis,
85 bool mirrorYAxis)
86{
87 /*
88 * Automatically make a layout according to the
89 * channel locations in inputPoints
90 */
91 VectorXf r0(3);
92 VectorXf rr(3);
93 float rad,th,phi;
94
95 float xmin,xmax,ymin,ymax;
96 int k;
97 int nchan = inputPoints.size();
98
99 MatrixXf rrs(nchan,3);
100 VectorXf xx(nchan);
101 VectorXf yy(nchan);
102
103 if (nchan <= 0) {
104 std::cout << "No input points to lay out.\n";
105 return false;
106 }
107
108 //Fill matrix with 3D points
109 for(k = 0; k<nchan; k++) {
110 rrs(k,0) = inputPoints.at(k)[0]; //x
111 rrs(k,1) = inputPoints.at(k)[1]; //y
112 rrs(k,2) = inputPoints.at(k)[2]; //z
113 }
114
115 std::cout << "Channels found for layout: " << nchan << "\n";
116
117 //Fit to sphere if wanted by the user
118 if (!do_fit) {
119 std::cout << "Using default origin:" << r0[0] << ", " << r0[1] << ", " << r0[2] << "\n";
120 }
121 else {
122 Sphere sphere = Sphere::fit_sphere_simplex(rrs, 0.05);
123
124 r0 = sphere.center();
125 rad = sphere.radius();
126
127 std::cout << "best fitting sphere:\n";
128 std::cout << "torigin: " << r0[0] << ", " << r0[1] << ", " << r0[2] << std::endl << "; tradius: " << rad << "\n";
129 }
130
131 /*
132 * Do the azimuthal equidistant projection
133 */
134 for (k = 0; k < nchan; k++) {
135 rr = r0 - static_cast<VectorXf>(rrs.row(k));
136 sphere_coord(rr[0],rr[1],rr[2],&rad,&th,&phi);
137 xx[k] = prad*(2.0*th/M_PI)*cos(phi);
138 yy[k] = prad*(2.0*th/M_PI)*sin(phi);
139 }
140
141 /*
142 * Find suitable range of viewports
143 */
144 xmin = xmax = xx[0];
145 ymin = ymax = yy[0];
146
147 for(k = 1; k < nchan; k++) {
148 if (xx[k] > xmax)
149 xmax = xx[k];
150 else if (xx[k] < xmin)
151 xmin = xx[k];
152 if (yy[k] > ymax)
153 ymax = yy[k];
154 else if (yy[k] < ymin)
155 ymin = yy[k];
156 }
157
158 if(xmin == xmax || ymin == ymax) {
159 std::cout<<"Cannot make a layout. All positions are identical\n";
160 return false;
161 }
162
163 xmax = xmax + 0.6*w;
164 xmin = xmin - 0.6*w;
165
166 ymax = ymax + 0.6*h;
167 ymin = ymin - 0.6*h;
168
169 /*
170 * Compose the viewports
171 */
172 QVector<float> point;
173 QTextStream out;
174
175 if(writeFile) {
176 if (!outFile.open(QIODevice::WriteOnly)) {
177 std::cout << "Could not open output file!\n";
178 return false;
179 }
180
181 out.setDevice(&outFile);
182 }
183
184#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
185 using Qt::endl;
186#endif
187
188 out << "0.000000 0.000000 0.000000 0.000000" << endl;
189
190 for(k = 0; k < nchan; k++) {
191 point.clear();
192
193 if(mirrorXAxis)
194 point.append(-(xx[k]-0.5*w));
195 else
196 point.append(xx[k]-0.5*w);
197
198 if(mirrorYAxis)
199 point.append(-(yy[k]-0.5*h));
200 else
201 point.append(yy[k]-0.5*h);
202
203 outputPoints.append(point);
204
205 if(writeFile) {
206 if(k < names.size()) {
207 out << k+1 << " " << point[0] << " " << point[1] << " " << w << " " << h << " " << names.at(k) << endl;
208 } else {
209 out << k+1 << " " << point[0] << " " << point[1] << " " << w << " " << h << endl;
210 }
211 }
212 }
213
214 if(writeFile) {
215 std::cout << "Success while wrtiting to output file.\n";
216
217 outFile.close();
218 }
219
220 return true;
221}
222
223//=============================================================================================================
224
225bool LayoutMaker::makeLayout(const std::vector<std::vector<float> > &inputPoints,
226 std::vector<std::vector<float> > &outputPoints,
227 const std::vector<std::string> &names,
228 const std::string& outFilePath,
229 bool do_fit,
230 float prad,
231 float w,
232 float h,
233 bool writeFile,
234 bool mirrorXAxis,
235 bool mirrorYAxis)
236{
237 /*
238 * Automatically make a layout according to the
239 * channel locations in inputPoints
240 */
241 VectorXf r0(3);
242 VectorXf rr(3);
243 float rad,th,phi;
244
245 float xmin,xmax,ymin,ymax;
246 int nchan = inputPoints.size();
247
248 MatrixXf rrs(nchan,3);
249 VectorXf xx(nchan);
250 VectorXf yy(nchan);
251
252 if (nchan <= 0) {
253 std::cout << "No input points to lay out.\n";
254 return false;
255 }
256
257 //Fill matrix with 3D points
258 for(int k = 0; k < nchan; k++) {
259 rrs(k,0) = inputPoints.at(k)[0]; //x
260 rrs(k,1) = inputPoints.at(k)[1]; //y
261 rrs(k,2) = inputPoints.at(k)[2]; //z
262 }
263
264 std::cout << "Channels found for layout: " << nchan << "\n";
265
266 //Fit to sphere if wanted by the user
267 if (!do_fit) {
268 std::cout << "Using default origin:" << r0[0] << ", " << r0[1] << ", " << r0[2] << "\n";
269 }
270 else {
271 Sphere sphere = Sphere::fit_sphere_simplex(rrs, 0.05);
272
273 r0 = sphere.center();
274 rad = sphere.radius();
275
276 std::cout << "best fitting sphere:\n";
277 std::cout << "torigin: " << r0[0] << ", " << r0[1] << ", " << r0[2] << std::endl << "; tradius: " << rad << "\n";
278 }
279
280 /*
281 * Do the azimuthal equidistant projection
282 */
283 for (int k = 0; k < nchan; k++) {
284 rr = r0 - static_cast<VectorXf>(rrs.row(k));
285 sphere_coord(rr[0],rr[1],rr[2],&rad,&th,&phi);
286 xx[k] = prad*(2.0*th/M_PI)*cos(phi);
287 yy[k] = prad*(2.0*th/M_PI)*sin(phi);
288 }
289
290 /*
291 * Find suitable range of viewports
292 */
293 xmin = xmax = xx[0];
294 ymin = ymax = yy[0];
295
296 for(int k = 1; k < nchan; k++) {
297 if (xx[k] > xmax)
298 xmax = xx[k];
299 else if (xx[k] < xmin)
300 xmin = xx[k];
301 if (yy[k] > ymax)
302 ymax = yy[k];
303 else if (yy[k] < ymin)
304 ymin = yy[k];
305 }
306
307 if(xmin == xmax || ymin == ymax) {
308 std::cout<<"Cannot make a layout. All positions are identical\n";
309 return false;
310 }
311
312 xmax = xmax + 0.6*w;
313 xmin = xmin - 0.6*w;
314
315 ymax = ymax + 0.6*h;
316 ymin = ymin - 0.6*h;
317
318 /*
319 * Compose the viewports
320 */
321 std::vector<float> point;
322 std::ofstream outFile;
323
324 if(writeFile) {
325 outFile.open(outFilePath);
326 if (outFile.is_open()) {
327 std::cout << "Could not open output file!\n";
328 return false;
329 }
330 outFile << "0.000000 0.000000 0.000000 0.000000" << std::endl;
331 }
332
333 for(int k = 0; k < nchan; k++) {
334 point.clear();
335
336 if(mirrorXAxis)
337 point.push_back(-(xx[k]-0.5*w));
338 else
339 point.push_back(xx[k]-0.5*w);
340
341 if(mirrorYAxis)
342 point.push_back(-(yy[k]-0.5*h));
343 else
344 point.push_back(yy[k]-0.5*h);
345
346 outputPoints.push_back(point);
347
348 if(writeFile) {
349 if((k) < (int)names.size()) {
350 outFile << k+1 << " " << point[0] << " " << point[1] << " " << w << " " << h << " " << names.at(k) << std::endl;
351 } else {
352 outFile << k+1 << " " << point[0] << " " << point[1] << " " << w << " " << h << std::endl;
353 }
354 }
355 }
356
357 if(writeFile) {
358 std::cout << "Success while wrtiting to output file.\n";
359 }
360
361 return true;
362}
363
364//=============================================================================================================
365
366void LayoutMaker::sphere_coord (float x,
367 float y,
368 float z,
369 float *r,
370 float *theta,
371 float *phi)
372{
373 /* Rectangular to spherical coordinates */
374 float rxy = sqrt(x*x+y*y);
375 if (rxy < EPS) { /* Let's hope this is reasonable */
376 *r = z;
377 *theta = 0.0;
378 *phi = 0.0;
379 }
380 else {
381 *r = sqrt(x*x+y*y+z*z);
382 *theta = acos(z/(*r));
383 *phi = atan2 (y,x);
384 if (*phi < 0.0)
385 *phi = *phi + 2.0*M_PI;
386 }
387}
int k
Definition fiff_tag.cpp:324
SimplexAlgorithm Template Implementation.
LayoutLoader class declaration.
Sphere class declaration.
static bool makeLayout(const QList< QVector< float > > &inputPoints, QList< QVector< float > > &outputPoints, const QStringList &names, QFile &outFile, bool do_fit, float prad, float w, float h, bool writeFile=false, bool mirrorXAxis=false, bool mirrorYAxis=false)
Describes a 3D sphere object.
Definition sphere.h:73
static Sphere fit_sphere_simplex(const Eigen::MatrixX3f &points, double simplex_size=2e-2)
Definition sphere.cpp:112
Eigen::Vector3f & center()
Definition sphere.h:112
float & radius()
Definition sphere.h:120