MNE-CPP  0.1.9
A Framework for Electrophysiology
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 
60 using namespace UTILSLIB;
61 using 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 
75 bool 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 
225 bool 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 
366 void 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 }
sphere.h
Sphere class declaration.
UTILSLIB::LayoutMaker::makeLayout
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)
Definition: layoutmaker.cpp:75
simplex_algorithm.h
SimplexAlgorithm Template Implementation.
UTILSLIB::Sphere
Describes a 3D sphere object.
Definition: sphere.h:72
UTILSLIB::Sphere::center
Eigen::Vector3f & center()
Definition: sphere.h:112
k
int k
Definition: fiff_tag.cpp:322
layoutmaker.h
LayoutLoader class declaration.
UTILSLIB::Sphere::radius
float & radius()
Definition: sphere.h:120
UTILSLIB::Sphere::fit_sphere_simplex
static Sphere fit_sphere_simplex(const Eigen::MatrixX3f &points, double simplex_size=2e-2)
Definition: sphere.cpp:112