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