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  out << "0.000000 0.000000 0.000000 0.000000" << endl;
185 
186  for(k = 0; k < nchan; k++) {
187  point.clear();
188 
189  if(mirrorXAxis)
190  point.append(-(xx[k]-0.5*w));
191  else
192  point.append(xx[k]-0.5*w);
193 
194  if(mirrorYAxis)
195  point.append(-(yy[k]-0.5*h));
196  else
197  point.append(yy[k]-0.5*h);
198 
199  outputPoints.append(point);
200 
201  if(writeFile) {
202  if(k < names.size()) {
203  out << k+1 << " " << point[0] << " " << point[1] << " " << w << " " << h << " " << names.at(k) << endl;
204  } else {
205  out << k+1 << " " << point[0] << " " << point[1] << " " << w << " " << h <<endl;
206  }
207  }
208  }
209 
210  if(writeFile) {
211  std::cout << "Success while wrtiting to output file.\n";
212 
213  outFile.close();
214  }
215 
216  return true;
217 }
218 
219 //=============================================================================================================
220 
221 bool LayoutMaker::makeLayout(const std::vector<std::vector<float> > &inputPoints,
222  std::vector<std::vector<float> > &outputPoints,
223  const std::vector<std::string> &names,
224  const std::string& outFilePath,
225  bool do_fit,
226  float prad,
227  float w,
228  float h,
229  bool writeFile,
230  bool mirrorXAxis,
231  bool mirrorYAxis)
232 {
233  /*
234  * Automatically make a layout according to the
235  * channel locations in inputPoints
236  */
237  VectorXf r0(3);
238  VectorXf rr(3);
239  float rad,th,phi;
240 
241  float xmin,xmax,ymin,ymax;
242  int nchan = inputPoints.size();
243 
244  MatrixXf rrs(nchan,3);
245  VectorXf xx(nchan);
246  VectorXf yy(nchan);
247 
248  if (nchan <= 0) {
249  std::cout << "No input points to lay out.\n";
250  return false;
251  }
252 
253  //Fill matrix with 3D points
254  for(int k = 0; k < nchan; k++) {
255  rrs(k,0) = inputPoints.at(k)[0]; //x
256  rrs(k,1) = inputPoints.at(k)[1]; //y
257  rrs(k,2) = inputPoints.at(k)[2]; //z
258  }
259 
260  std::cout << "Channels found for layout: " << nchan << "\n";
261 
262  //Fit to sphere if wanted by the user
263  if (!do_fit) {
264  std::cout << "Using default origin:" << r0[0] << ", " << r0[1] << ", " << r0[2] << "\n";
265  }
266  else {
267  Sphere sphere = Sphere::fit_sphere_simplex(rrs, 0.05);
268 
269  r0 = sphere.center();
270  rad = sphere.radius();
271 
272  std::cout << "best fitting sphere:\n";
273  std::cout << "torigin: " << r0[0] << ", " << r0[1] << ", " << r0[2] << std::endl << "; tradius: " << rad << "\n";
274  }
275 
276  /*
277  * Do the azimuthal equidistant projection
278  */
279  for (int k = 0; k < nchan; k++) {
280  rr = r0 - static_cast<VectorXf>(rrs.row(k));
281  sphere_coord(rr[0],rr[1],rr[2],&rad,&th,&phi);
282  xx[k] = prad*(2.0*th/M_PI)*cos(phi);
283  yy[k] = prad*(2.0*th/M_PI)*sin(phi);
284  }
285 
286  /*
287  * Find suitable range of viewports
288  */
289  xmin = xmax = xx[0];
290  ymin = ymax = yy[0];
291 
292  for(int k = 1; k < nchan; k++) {
293  if (xx[k] > xmax)
294  xmax = xx[k];
295  else if (xx[k] < xmin)
296  xmin = xx[k];
297  if (yy[k] > ymax)
298  ymax = yy[k];
299  else if (yy[k] < ymin)
300  ymin = yy[k];
301  }
302 
303  if(xmin == xmax || ymin == ymax) {
304  std::cout<<"Cannot make a layout. All positions are identical\n";
305  return false;
306  }
307 
308  xmax = xmax + 0.6*w;
309  xmin = xmin - 0.6*w;
310 
311  ymax = ymax + 0.6*h;
312  ymin = ymin - 0.6*h;
313 
314  /*
315  * Compose the viewports
316  */
317  std::vector<float> point;
318  std::ofstream outFile;
319 
320  if(writeFile) {
321  outFile.open(outFilePath);
322  if (outFile.is_open()) {
323  std::cout << "Could not open output file!\n";
324  return false;
325  }
326  outFile << "0.000000 0.000000 0.000000 0.000000" << std::endl;
327  }
328 
329 
330  for(int k = 0; k < nchan; k++) {
331  point.clear();
332 
333  if(mirrorXAxis)
334  point.push_back(-(xx[k]-0.5*w));
335  else
336  point.push_back(xx[k]-0.5*w);
337 
338  if(mirrorYAxis)
339  point.push_back(-(yy[k]-0.5*h));
340  else
341  point.push_back(yy[k]-0.5*h);
342 
343  outputPoints.push_back(point);
344 
345  if(writeFile) {
346  if((k) < names.size()) {
347  outFile << k+1 << " " << point[0] << " " << point[1] << " " << w << " " << h << " " << names.at(k) << std::endl;
348  } else {
349  outFile << k+1 << " " << point[0] << " " << point[1] << " " << w << " " << h << std::endl;
350  }
351  }
352  }
353 
354  if(writeFile) {
355  std::cout << "Success while wrtiting to output file.\n";
356  }
357 
358  return true;
359 }
360 
361 //=============================================================================================================
362 
363 void LayoutMaker::sphere_coord (float x,
364  float y,
365  float z,
366  float *r,
367  float *theta,
368  float *phi)
369 {
370  /* Rectangular to spherical coordinates */
371  float rxy = sqrt(x*x+y*y);
372  if (rxy < EPS) { /* Let's hope this is reasonable */
373  *r = z;
374  *theta = 0.0;
375  *phi = 0.0;
376  }
377  else {
378  *r = sqrt(x*x+y*y+z*z);
379  *theta = acos(z/(*r));
380  *phi = atan2 (y,x);
381  if (*phi < 0.0)
382  *phi = *phi + 2.0*M_PI;
383  }
384 }
float & radius()
Definition: sphere.h:120
Eigen::Vector3f & center()
Definition: sphere.h:112
SimplexAlgorithm Template Implementation.
Describes a 3D sphere object.
Definition: sphere.h:72
Sphere class declaration.
LayoutLoader class declaration.
static Sphere fit_sphere_simplex(const Eigen::MatrixX3f &points, double simplex_size=2e-2)
Definition: sphere.cpp:112
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