Commit 9d3ba0b10c295c9bd0a6a5b1be4779e482be4515

Authored by David Mayerich
1 parent 798cea97

added stim::hsi as a bridge, fixed warnings for a clean build of HSIproc

stim/envi/bil.h
... ... @@ -2,7 +2,7 @@
2 2 #define STIM_BIL_H
3 3  
4 4 #include "../envi/envi_header.h"
5   -#include "../envi/binary.h"
  5 +#include "../envi/hsi.h"
6 6 #include <cstring>
7 7 #include <utility>
8 8  
... ... @@ -19,28 +19,29 @@ namespace stim{
19 19  
20 20 template <typename T>
21 21  
22   -class bil: public binary<T> {
  22 +class bil: public hsi<T> {
23 23  
24 24 protected:
25 25  
26   - std::vector<double> w; //band wavelength
  26 + //std::vector<double> w; //band wavelengths
27 27  
28   - unsigned long X(){
  28 + /*unsigned long long X(){
29 29 return R[0];
30 30 }
31   - unsigned long Y(){
  31 + unsigned long long Y(){
32 32 return R[2];
33 33 }
34   - unsigned long Z(){
  34 + unsigned long long Z(){
35 35 return R[1];
36   - }
37   -
  36 + }*/
  37 + using hsi<T>::w; //use the wavelength array in stim::hsi
  38 + using hsi<T>::nnz;
38 39 using binary<T>::progress;
39 40  
40 41 /// Call the binary nnz() function for the BIL orientation
41   - unsigned long long nnz(unsigned char* mask){
42   - return binary<T>::nnz(mask, X()*Y());
43   - }
  42 + //unsigned long long nnz(unsigned char* mask){
  43 + // return binary<T>::nnz(mask, X()*Y());
  44 + //}
44 45  
45 46 public:
46 47  
... ... @@ -48,6 +49,8 @@ public:
48 49 using binary<T>::file;
49 50 using binary<T>::R;
50 51  
  52 + bil(){ hsi<T>::init_bil(); }
  53 +
51 54 /// Open a data file for reading using the class interface.
52 55  
53 56 /// @param filename is the name of the binary file on disk
... ... @@ -56,11 +59,16 @@ public:
56 59 /// @param B is the number of samples (bands) along dimension 3
57 60 /// @param header_offset is the number of bytes (if any) in the binary header
58 61 /// @param wavelengths is an optional STL vector of size B specifying a numerical label for each band
59   - bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int B, unsigned int header_offset, std::vector<double> wavelengths){
  62 + bool open(std::string filename,
  63 + unsigned long long X,
  64 + unsigned long long Y,
  65 + unsigned long long B,
  66 + unsigned long long header_offset,
  67 + std::vector<double> wavelengths){
60 68  
61 69 w = wavelengths;
62 70  
63   - return open(filename, vec<unsigned int>(X, B, Y), header_offset);
  71 + return open(filename, vec<unsigned long long>(X, B, Y), header_offset);
64 72  
65 73 }
66 74  
... ... @@ -68,12 +76,12 @@ public:
68 76  
69 77 /// @param p is a pointer to an allocated region of memory at least X * Y * sizeof(T) in size.
70 78 /// @param page <= B is the integer number of the band to be copied.
71   - bool band_index( T * p, unsigned int page, bool PROGRESS = false){
  79 + bool band_index( T * p, unsigned long long page, bool PROGRESS = false){
72 80 //return binary<T>::read_plane_1(p, page);
73 81  
74 82 if(PROGRESS) progress = 0;
75   - unsigned int L = X() * sizeof(T); //caculate the number of bytes in a sample line
76   - unsigned int jump = X() * (Z() - 1) * sizeof(T);
  83 + unsigned long long L = X() * sizeof(T); //caculate the number of bytes in a sample line
  84 + unsigned long long jump = X() * (Z() - 1) * sizeof(T);
77 85  
78 86 if (page >= Z()){ //make sure the bank number is right
79 87 std::cout<<"ERROR: page out of range"<<std::endl;
... ... @@ -81,7 +89,7 @@ public:
81 89 }
82 90  
83 91 file.seekg(X() * page * sizeof(T), std::ios::beg);
84   - for (unsigned i = 0; i < Y(); i++)
  92 + for (unsigned long long i = 0; i < Y(); i++)
85 93 {
86 94 file.read((char *)(p + i * X()), L);
87 95 file.seekg( jump, std::ios::cur);
... ... @@ -99,12 +107,12 @@ public:
99 107  
100 108 //if there are no wavelengths in the BSQ file
101 109 if(w.size() == 0)
102   - return band_index(p, (unsigned int)wavelength);
  110 + return band_index(p, (unsigned long long)wavelength);
103 111  
104   - unsigned int XY = X() * Y(); //calculate the number of pixels in a band
105   - unsigned int S = XY * sizeof(T); //calculate the number of bytes of a band
  112 + unsigned long long XY = X() * Y(); //calculate the number of pixels in a band
  113 + unsigned long long S = XY * sizeof(T); //calculate the number of bytes of a band
106 114  
107   - unsigned page=0; //bands around the wavelength
  115 + unsigned long long page=0; //bands around the wavelength
108 116  
109 117  
110 118 //get the bands numbers around the wavelength
... ... @@ -132,9 +140,9 @@ public:
132 140 p2=(T*)malloc(S);
133 141 band_index(p1, page - 1);
134 142 band_index(p2, page, PROGRESS);
135   - for(unsigned i=0; i < XY; i++){
136   - double r = (double) (wavelength - w[page-1]) / (double) (w[page] - w[page-1]);
137   - p[i] = (p2[i] - p1[i]) * r + p1[i];
  143 + for(unsigned long long i=0; i < XY; i++){
  144 + double r = (wavelength - w[page-1]) / (w[page] - w[page-1]);
  145 + p[i] = (T)(((double)p2[i] - (double)p1[i]) * r + (double)p1[i]);
138 146 }
139 147 free(p1);
140 148 free(p2);
... ... @@ -154,10 +162,10 @@ public:
154 162 /// @param wavelength is the wavelength to retrieve
155 163 bool read_x_from_xz(T* p, T* c, double wavelength)
156 164 {
157   - unsigned int B = Z();
158   - unsigned int L = X() * sizeof(T);
  165 + unsigned long long B = Z();
  166 + unsigned long long L = X() * sizeof(T);
159 167  
160   - unsigned page=0; //samples around the wavelength
  168 + unsigned long long page=0; //samples around the wavelength
161 169 T * p1;
162 170 T * p2;
163 171  
... ... @@ -186,9 +194,9 @@ public:
186 194 memcpy(p1, c + (page - 1) * X(), L);
187 195 memcpy(p2, c + page * X(), L);
188 196  
189   - for(unsigned i=0; i < X(); i++){
  197 + for(unsigned long long i=0; i < X(); i++){
190 198 double r = (double) (wavelength - w[page-1]) / (double) (w[page] - w[page-1]);
191   - p[i] = (p2[i] - p1[i]) * r + p1[i];
  199 + p[i] = (T)(((double)p2[i] - (double)p1[i]) * r + (double)p1[i]);
192 200 }
193 201 }
194 202 else //if the wavelength is equal to a wavelength in header file
... ... @@ -202,7 +210,7 @@ public:
202 210 /// @param p is a pointer to pre-allocated memory at least B * sizeof(T) in size.
203 211 /// @param x is the x-coordinate (dimension 1) of the spectrum.
204 212 /// @param y is the y-coordinate (dimension 2) of the spectrum.
205   - bool spectrum(T * p, unsigned x, unsigned y, bool PROGRESS = false){
  213 + bool spectrum(T * p, unsigned long long x, unsigned long long y, bool PROGRESS = false){
206 214 return binary<T>::read_line_1(p, x, y, PROGRESS);
207 215 }
208 216  
... ... @@ -210,18 +218,18 @@ public:
210 218  
211 219 /// @param p is a pointer to pre-allocated memory at least sizeof(T) in size.
212 220 /// @param n is an integer index to the pixel using linear array indexing.
213   - bool pixel(T * p, unsigned n){
  221 + bool pixel(T * p, unsigned long long n){
214 222  
215 223 //calculate the corresponding x, y
216   - unsigned int x = n % X();
217   - unsigned int y = n / X();
  224 + unsigned long long x = n % X();
  225 + unsigned long long y = n / X();
218 226  
219 227 //get the pixel
220 228 return spectrum(p, x, y);
221 229 }
222 230  
223 231 //given a Y ,return a XZ slice
224   - bool read_plane_y(T * p, unsigned y){
  232 + bool read_plane_y(T * p, unsigned long long y){
225 233 return binary<T>::read_plane_2(p, y);
226 234 }
227 235  
... ... @@ -232,15 +240,15 @@ public:
232 240 /// @param wls is the list of baseline points based on band labels.
233 241 bool baseline(std::string outname, std::vector<double> wls, unsigned char* mask = NULL, bool PROGRESS = false){
234 242  
235   - unsigned N = wls.size(); //get the number of baseline points
  243 + unsigned long long N = wls.size(); //get the number of baseline points
236 244  
237 245 std::ofstream target(outname.c_str(), std::ios::binary); //open the target binary file
238 246 std::string headername = outname + ".hdr"; //the header file name
239 247  
240 248 //simplify image resolution
241   - unsigned int ZX = Z() * X(); //calculate the number of points in a Y slice
242   - unsigned int L = ZX * sizeof(T); //calculate the number of bytes of a Y slice
243   - unsigned int B = Z();
  249 + unsigned long long ZX = Z() * X(); //calculate the number of points in a Y slice
  250 + unsigned long long L = ZX * sizeof(T); //calculate the number of bytes of a Y slice
  251 + unsigned long long B = Z();
244 252  
245 253 T* c; //pointer to the current Y slice
246 254 c = (T*)malloc(L); //memory allocation
... ... @@ -254,7 +262,7 @@ public:
254 262  
255 263 double ai, bi; //stores the two baseline points wavelength surrounding the current band
256 264 double ci; //stores the current band's wavelength
257   - unsigned control;
  265 + unsigned long long control;
258 266  
259 267 if (a == NULL || b == NULL || c == NULL){
260 268 std::cout<<"ERROR: error allocating memory";
... ... @@ -262,7 +270,7 @@ public:
262 270 }
263 271 // loop start correct every y slice
264 272  
265   - for (unsigned k =0; k < Y(); k++)
  273 + for (unsigned long long k =0; k < Y(); k++)
266 274 {
267 275 //get the current y slice
268 276 read_plane_y(c, k);
... ... @@ -287,7 +295,7 @@ public:
287 295  
288 296 //correct every YZ line
289 297  
290   - for(unsigned cii = 0; cii < B; cii++){
  298 + for(unsigned long long cii = 0; cii < B; cii++){
291 299  
292 300 //update baseline points, if necessary
293 301 if( w[cii] >= bi && cii != B - 1) {
... ... @@ -317,7 +325,7 @@ public:
317 325  
318 326 ci = w[cii];
319 327  
320   - unsigned jump = cii * X();
  328 + unsigned long long jump = cii * X();
321 329 //perform the baseline correction
322 330 for(unsigned i=0; i < X(); i++)
323 331 {
... ... @@ -347,11 +355,11 @@ public:
347 355 /// @param t is a threshold specified such that a spectrum with a value at w less than t is set to zero. Setting this threshold allows the user to limit division by extremely small numbers.
348 356 bool normalize(std::string outname, double w, unsigned char* mask = NULL, bool PROGRESS = false)
349 357 {
350   - unsigned int B = Z(); //calculate the number of bands
351   - unsigned int ZX = Z() * X();
352   - unsigned int XY = X() * Y(); //calculate the number of pixels in a band
353   - unsigned int S = XY * sizeof(T); //calculate the number of bytes in a band
354   - unsigned int L = ZX * sizeof(T);
  358 + unsigned long long B = Z(); //calculate the number of bands
  359 + unsigned long long ZX = Z() * X();
  360 + unsigned long long XY = X() * Y(); //calculate the number of pixels in a band
  361 + unsigned long long S = XY * sizeof(T); //calculate the number of bytes in a band
  362 + unsigned long long L = ZX * sizeof(T);
355 363  
356 364 std::ofstream target(outname.c_str(), std::ios::binary); //open the target binary file
357 365 std::string headername = outname + ".hdr"; //the header file name
... ... @@ -364,12 +372,12 @@ public:
364 372  
365 373 band(b, w); //get the certain band into memory
366 374  
367   - for(unsigned j = 0; j < Y(); j++)
  375 + for(unsigned long long j = 0; j < Y(); j++)
368 376 {
369 377 read_plane_y(c, j);
370   - for(unsigned i = 0; i < B; i++)
  378 + for(unsigned long long i = 0; i < B; i++)
371 379 {
372   - for(unsigned m = 0; m < X(); m++)
  380 + for(unsigned long long m = 0; m < X(); m++)
373 381 {
374 382 if( mask != NULL && !mask[m + j * X()] )
375 383 c[m + i * X()] = (T)0.0;
... ... @@ -393,7 +401,7 @@ public:
393 401 /// @param outname is the name of the output BSQ file to be saved to disk.
394 402 bool bsq(std::string outname, bool PROGRESS = false)
395 403 {
396   - unsigned int S = X() * Y() * sizeof(T); //calculate the number of bytes in a band
  404 + unsigned long long S = X() * Y() * sizeof(T); //calculate the number of bytes in a band
397 405  
398 406 std::ofstream target(outname.c_str(), std::ios::binary);
399 407 std::string headername = outname + ".hdr";
... ... @@ -401,7 +409,7 @@ public:
401 409 T * p; //pointer to the current band
402 410 p = (T*)malloc(S);
403 411  
404   - for ( unsigned i = 0; i < Z(); i++)
  412 + for ( unsigned long long i = 0; i < Z(); i++)
405 413 {
406 414 band_index(p, i);
407 415 target.write(reinterpret_cast<const char*>(p), S); //write a band data into target file
... ... @@ -429,13 +437,13 @@ public:
429 437 T * q; //pointer to the current ZX slice for bip file
430 438 q = (T*)malloc(S);
431 439  
432   - for ( unsigned i = 0; i < Y(); i++)
  440 + for ( unsigned long long i = 0; i < Y(); i++)
433 441 {
434 442 read_plane_y(p, i);
435   - for ( unsigned k = 0; k < Z(); k++)
  443 + for ( unsigned long long k = 0; k < Z(); k++)
436 444 {
437   - unsigned ks = k * X();
438   - for ( unsigned j = 0; j < X(); j++)
  445 + unsigned long long ks = k * X();
  446 + for ( unsigned long long j = 0; j < X(); j++)
439 447 q[k + j * Z()] = p[ks + j];
440 448  
441 449 if(PROGRESS) progress = (double)((i+1) * Z() + k+1) / (Z() * Y()) * 100; //store the progress for the current operation
... ... @@ -461,12 +469,12 @@ public:
461 469 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size.
462 470 bool baseline_band(double lb, double rb, T* lp, T* rp, double wavelength, T* result){
463 471  
464   - unsigned XY = X() * Y();
  472 + unsigned long long XY = X() * Y();
465 473 band(result, wavelength); //get band
466 474  
467 475 //perform the baseline correction
468 476 double r = (double) (wavelength - lb) / (double) (rb - lb);
469   - for(unsigned i=0; i < XY; i++){
  477 + for(unsigned long long i=0; i < XY; i++){
470 478 result[i] =(T) (result[i] - (rp[i] - lp[i]) * r - lp[i] );
471 479 }
472 480 return true;
... ... @@ -482,8 +490,8 @@ public:
482 490  
483 491 T* lp;
484 492 T* rp;
485   - unsigned XY = X() * Y();
486   - unsigned S = XY * sizeof(T);
  493 + unsigned long long XY = X() * Y();
  494 + unsigned long long S = XY * sizeof(T);
487 495 lp = (T*) malloc(S); //memory allocation
488 496 rp = (T*) malloc(S);
489 497  
... ... @@ -513,8 +521,8 @@ public:
513 521 T* cur; //current band 1
514 522 T* cur2; //current band 2
515 523  
516   - unsigned XY = X() * Y();
517   - unsigned S = XY * sizeof(T);
  524 + unsigned long long XY = X() * Y();
  525 + unsigned long long S = XY * sizeof(T);
518 526  
519 527 lp = (T*) malloc(S); //memory allocation
520 528 rp = (T*) malloc(S);
... ... @@ -524,9 +532,9 @@ public:
524 532 memset(result, (char)0, S);
525 533  
526 534 //find the wavelenght position in the whole band
527   - unsigned int n = w.size();
528   - unsigned int ai = 0; //left bound position
529   - unsigned int bi = n - 1; //right bound position
  535 + unsigned long long n = w.size();
  536 + unsigned long long ai = 0; //left bound position
  537 + unsigned long long bi = n - 1; //right bound position
530 538  
531 539  
532 540  
... ... @@ -555,23 +563,23 @@ public:
555 563 //calculate the beginning and the ending part
556 564 baseline_band(lb, rb, lp, rp, rab, cur2); //ending part
557 565 baseline_band(lb, rb, lp, rp, w[bi], cur);
558   - for(unsigned j = 0; j < XY; j++){
559   - result[j] += (rab - w[bi]) * (cur[j] + cur2[j]) / 2.0;
  566 + for(unsigned long long j = 0; j < XY; j++){
  567 + result[j] += (T)((rab - w[bi]) * ((double)cur[j] + (double)cur2[j]) / 2.0);
560 568 }
561 569 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
562 570 baseline_band(lb, rb, lp, rp, w[ai], cur);
563   - for(unsigned j = 0; j < XY; j++){
564   - result[j] += (w[ai] - lab) * (cur[j] + cur2[j]) / 2.0;
  571 + for(unsigned long long j = 0; j < XY; j++){
  572 + result[j] += (T)((w[ai] - lab) * ((double)cur[j] + (double)cur2[j]) / 2.0);
565 573 }
566 574  
567 575 //calculate the area
568 576 ai++;
569   - for(unsigned i = ai; i <= bi ;i++)
  577 + for(unsigned long long i = ai; i <= bi ;i++)
570 578 {
571 579 baseline_band(lb, rb, lp, rp, w[ai], cur2);
572   - for(unsigned j = 0; j < XY; j++)
  580 + for(unsigned long long j = 0; j < XY; j++)
573 581 {
574   - result[j] += (w[ai] - w[ai-1]) * (cur[j] + cur2[j]) / 2.0;
  582 + result[j] += (T)((w[ai] - w[ai-1]) * ((double)cur[j] + (double)cur2[j]) / 2.0);
575 583 }
576 584 std::swap(cur,cur2); //swap the band pointers
577 585 }
... ... @@ -601,7 +609,7 @@ public:
601 609 height(lb1, rb1, pos1, p1);
602 610 height(lb2, rb2, pos2, p2);
603 611 //calculate the ratio in result
604   - for(unsigned i = 0; i < X() * Y(); i++){
  612 + for(unsigned long long i = 0; i < X() * Y(); i++){
605 613 if(p1[i] == 0 && p2[i] ==0)
606 614 result[i] = 1;
607 615 else
... ... @@ -632,7 +640,7 @@ public:
632 640 area(lb1, rb1, lab1, rab1, p1);
633 641 height(lb2, rb2, pos, p2);
634 642 //calculate the ratio in result
635   - for(unsigned i = 0; i < X() * Y(); i++){
  643 + for(unsigned long long i = 0; i < X() * Y(); i++){
636 644 if(p1[i] == 0 && p2[i] ==0)
637 645 result[i] = 1;
638 646 else
... ... @@ -665,7 +673,7 @@ public:
665 673 area(lb1, rb1, lab1, rab1, p1);
666 674 area(lb2, rb2, lab2, rab2, p2);
667 675 //calculate the ratio in result
668   - for(unsigned i = 0; i < X() * Y(); i++){
  676 + for(unsigned long long i = 0; i < X() * Y(); i++){
669 677 if(p1[i] == 0 && p2[i] ==0)
670 678 result[i] = 1;
671 679 else
... ... @@ -690,8 +698,8 @@ public:
690 698 T* cur; //current band 1
691 699 T* cur2; //current band 2
692 700  
693   - unsigned XY = X() * Y();
694   - unsigned S = XY * sizeof(T);
  701 + unsigned long long XY = X() * Y();
  702 + unsigned long long S = XY * sizeof(T);
695 703  
696 704 lp = (T*) malloc(S); //memory allocation
697 705 rp = (T*) malloc(S);
... ... @@ -701,9 +709,9 @@ public:
701 709 memset(result, (char)0, S);
702 710  
703 711 //find the wavelenght position in the whole band
704   - unsigned int n = w.size();
705   - unsigned int ai = 0; //left bound position
706   - unsigned int bi = n - 1; //right bound position
  712 + unsigned long long n = w.size();
  713 + unsigned long long ai = 0; //left bound position
  714 + unsigned long long bi = n - 1; //right bound position
707 715  
708 716 //to make sure the left and the right bound are in the bandwidth
709 717 if (lb < w[0] || rb < w[0] || lb > w[n-1] || rb >w[n-1]){
... ... @@ -730,23 +738,23 @@ public:
730 738 //calculate the beginning and the ending part
731 739 baseline_band(lb, rb, lp, rp, rab, cur2); //ending part
732 740 baseline_band(lb, rb, lp, rp, w[bi], cur);
733   - for(unsigned j = 0; j < XY; j++){
734   - result[j] += (rab - w[bi]) * (rab + w[bi]) * (cur[j] + cur2[j]) / 4.0;
  741 + for(unsigned long long j = 0; j < XY; j++){
  742 + result[j] += (T)((rab - w[bi]) * (rab + w[bi]) * ((double)cur[j] + (double)cur2[j]) / 4.0);
735 743 }
736 744 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
737 745 baseline_band(lb, rb, lp, rp, w[ai], cur);
738   - for(unsigned j = 0; j < XY; j++){
739   - result[j] += (w[ai] - lab) * (w[ai] + lab) * (cur[j] + cur2[j]) / 4.0;
  746 + for(unsigned long long j = 0; j < XY; j++){
  747 + result[j] += (T)((w[ai] - lab) * (w[ai] + lab) * ((double)cur[j] + (double)cur2[j]) / 4.0);
740 748 }
741 749  
742 750 //calculate f(x) times x
743 751 ai++;
744   - for(unsigned i = ai; i <= bi ;i++)
  752 + for(unsigned long long i = ai; i <= bi ;i++)
745 753 {
746 754 baseline_band(lb, rb, lp, rp, w[ai], cur2);
747   - for(unsigned j = 0; j < XY; j++)
  755 + for(unsigned long long j = 0; j < XY; j++)
748 756 {
749   - result[j] += (w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * (cur[j] + cur2[j]) / 4.0;
  757 + result[j] += (T)((w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * ((double)cur[j] + (double)cur2[j]) / 4.0);
750 758 }
751 759 std::swap(cur,cur2); //swap the band pointers
752 760 }
... ... @@ -773,7 +781,7 @@ public:
773 781 x_area(lb, rb, lab, rab, p1);
774 782 area(lb, rb, lab, rab, p2);
775 783 //calculate the ratio in result
776   - for(unsigned i = 0; i < X() * Y(); i++){
  784 + for(unsigned long long i = 0; i < X() * Y(); i++){
777 785 if(p1[i] == 0 && p2[i] ==0)
778 786 result[i] = 1;
779 787 else
... ... @@ -797,7 +805,7 @@ public:
797 805 T* temp = (T*)malloc(X() * Y() * sizeof(T)); //allocate memory for the certain band
798 806 band(temp, mask_band, PROGRESS);
799 807  
800   - for (unsigned int i = 0; i < X() * Y(); i++) {
  808 + for (unsigned long long i = 0; i < X() * Y(); i++) {
801 809 if (temp[i] < threshold)
802 810 p[i] = 0;
803 811 else
... ... @@ -817,17 +825,17 @@ public:
817 825 std::ofstream target(outfile.c_str(), std::ios::binary);
818 826  
819 827 //I THINK THIS IS WRONG
820   - unsigned XZ = X() * Z(); //calculate the number of values in a page on disk
821   - unsigned L = XZ * sizeof(T); //calculate the size of the page (in bytes)
  828 + unsigned long long XZ = X() * Z(); //calculate the number of values in a page on disk
  829 + unsigned long long L = XZ * sizeof(T); //calculate the size of the page (in bytes)
822 830  
823 831 T * temp = (T*)malloc(L); //allocate memory for a temporary page
824 832  
825   - for (unsigned i = 0; i < Y(); i++) //for each value in Y() (BIP should be X)
  833 + for (unsigned long long i = 0; i < Y(); i++) //for each value in Y() (BIP should be X)
826 834 {
827 835 read_plane_y(temp, i); //retrieve an ZX slice, stored in temp
828   - for ( unsigned j = 0; j < Z(); j++) //for each Z() (Y)
  836 + for ( unsigned long long j = 0; j < Z(); j++) //for each Z() (Y)
829 837 {
830   - for (unsigned k = 0; k < X(); k++) //for each band
  838 + for (unsigned long long k = 0; k < X(); k++) //for each band
831 839 {
832 840 if(p[i * X() + k] == 0)
833 841 temp[j * X() + k] = 0;
... ... @@ -849,9 +857,9 @@ public:
849 857 std::ofstream target(outfile.c_str(), std::ios::binary);
850 858  
851 859 //for loading pages:
852   - unsigned long XZ = X() * Z(); //calculate the number of values in an XZ page on disk
853   - unsigned long B = Z(); //calculate the number of bands
854   - unsigned long L = XZ * sizeof(T); //calculate the size of the page (in bytes)
  860 + unsigned long long XZ = X() * Z(); //calculate the number of values in an XZ page on disk
  861 + unsigned long long B = Z(); //calculate the number of bands
  862 + unsigned long long L = XZ * sizeof(T); //calculate the size of the page (in bytes)
855 863  
856 864 //allocate temporary memory for a XZ slice
857 865 T* slice = (T*) malloc(L);
... ... @@ -860,18 +868,18 @@ public:
860 868 T* spec = (T*) malloc(B * sizeof(T));
861 869  
862 870 //for each slice along the y axis
863   - for (unsigned long y = 0; y < Y(); y++) //Select a page by choosing Y coordinate, Y()
  871 + for (unsigned long long y = 0; y < Y(); y++) //Select a page by choosing Y coordinate, Y()
864 872 {
865 873 read_plane_y(slice, y); //retrieve an ZX page, store in "slice"
866 874  
867 875 //for each sample along X
868   - for (unsigned long x = 0; x < X(); x++) //Select a pixel by choosing X coordinate in the page, X()
  876 + for (unsigned long long x = 0; x < X(); x++) //Select a pixel by choosing X coordinate in the page, X()
869 877 {
870 878 //if the mask != 0 at that xy pixel
871 879 if (p[y * X() + x] != 0) //if the mask != 0 at that XY pixel
872 880 {
873 881 //for each band at that pixel
874   - for (unsigned long b = 0; b < B; b++) //Select a voxel by choosing Z coordinate at the pixel
  882 + for (unsigned long long b = 0; b < B; b++) //Select a voxel by choosing Z coordinate at the pixel
875 883 {
876 884 spec[b] = slice[b*X() + x]; //Pass the correct spectral value from XZ page into the spectrum to be saved.
877 885 }
... ... @@ -896,20 +904,20 @@ public:
896 904 T* temp = (T*)malloc(sizeof(T) * XZ);
897 905 T* line = (T*)malloc(sizeof(T) * X());
898 906  
899   - for (unsigned i = 0; i < Y(); i++){
  907 + for (unsigned long long i = 0; i < Y(); i++){
900 908 getY(temp, i);
901 909 //initialize x-line
902   - for (unsigned j = 0; j < X(); j++){
  910 + for (unsigned long long j = 0; j < X(); j++){
903 911 line[j] = 0;
904 912 }
905   - unsigned c = 0;
906   - for (unsigned j = 0; j < Z(); j++){
907   - for (unsigned k = 0; k < X(); k++){
  913 + unsigned long long c = 0;
  914 + for (unsigned long long j = 0; j < Z(); j++){
  915 + for (unsigned long long k = 0; k < X(); k++){
908 916 line[k] += temp[c] / (T)Z();
909 917 c++;
910 918 }
911 919 }
912   - for (unsigned j = 0; j < X(); j++){
  920 + for (unsigned long long j = 0; j < X(); j++){
913 921 p[j + i * X()] = line[j];
914 922 }
915 923 }
... ... @@ -925,7 +933,7 @@ public:
925 933 unsigned long long XZ = X() * Z();
926 934 unsigned long long XY = X() * Y();
927 935 T* temp = (T*)malloc(sizeof(T) * XZ);
928   - for (unsigned j = 0; j < Z(); j++){
  936 + for (unsigned long long j = 0; j < Z(); j++){
929 937 p[j] = 0;
930 938 }
931 939 //calculate vaild number in a band
... ... @@ -1038,9 +1046,9 @@ public:
1038 1046 //set the start position for the cropped region
1039 1047 file.seekg((y0 * X() * Z() + b0 * X() + x0) * sizeof(T), std::ios::beg);
1040 1048  
1041   - for (unsigned x = 0; x < lines; x++)
  1049 + for (unsigned long long x = 0; x < lines; x++)
1042 1050 {
1043   - for (unsigned z = b0; z < b1; z++)
  1051 + for (unsigned long long z = b0; z < b1; z++)
1044 1052 {
1045 1053 file.read((char *)(temp + z * samples), sizeof(T) * samples);
1046 1054 file.seekg(jumpb, std::ios::cur); //go to the next band
... ...
stim/envi/binary.h
... ... @@ -25,7 +25,7 @@ protected:
25 25 std::string name; //file name
26 26  
27 27 unsigned long long R[D]; //resolution
28   - unsigned int header; //header size (in bytes)
  28 + unsigned long long header; //header size (in bytes)
29 29 unsigned char* mask; //pointer to a character array: 0 = background, 1 = foreground (or valid data)
30 30  
31 31 double progress; //stores the progress on the current operation (accessible using a thread)
... ... @@ -33,30 +33,13 @@ protected:
33 33  
34 34 /// Private initialization function used to set default parameters in the data structure.
35 35 void init(){
36   - memset(R, 0, sizeof(unsigned int) * D); //initialize the resolution to zero
  36 + memset(R, 0, sizeof(unsigned long long) * D); //initialize the resolution to zero
37 37 header = 0; //initialize the header size to zero
38 38 mask = NULL;
39 39  
40 40 progress = 0;
41 41 }
42 42  
43   - //calculate the number of non-zero pixels in a mask
44   - unsigned long long nnz(unsigned char* mask, unsigned long long N){
45   -
46   - unsigned long long n = 0; //initialize the counter to 0 (zero)
47   - if(mask == NULL) return N; //if the mask is NULL, assume all pixels are masked
48   -
49   - for(unsigned long long i = 0; i < N; i++){ //for each pixel
50   - if(mask[i] != 0) n++; //increment the counter for every non-zero pixel in the mask
51   - }
52   - return n; //return the number of nonzero pixels
53   - }
54   -
55   - /// Calculate the number of nonzero pixels in a mask over X-Y
56   - unsigned long long nnz(unsigned char* mask){
57   - return nnz(mask, R[0] * R[1]);
58   - }
59   -
60 43 /// Private helper function that returns the size of the file on disk using system functions.
61 44 long long int get_file_size(){
62 45 #ifdef _WIN32
... ... @@ -122,7 +105,7 @@ protected:
122 105  
123 106 public:
124 107  
125   - unsigned int get_progress(){
  108 + double get_progress(){
126 109 return progress;
127 110 }
128 111  
... ... @@ -135,9 +118,9 @@ public:
135 118 /// @param filename is the name of the binary file
136 119 /// @param r is a STIM vector specifying the size of the binary file along each dimension
137 120 /// @param h is the length (in bytes) of any header file (default zero)
138   - bool open(std::string filename, vec<unsigned int> r, unsigned int h = 0){
  121 + bool open(std::string filename, vec<unsigned long long> r, unsigned long long h = 0){
139 122  
140   - for(unsigned int i = 0; i < D; i++) //set the dimensions of the binary file object
  123 + for(unsigned long long i = 0; i < D; i++) //set the dimensions of the binary file object
141 124 R[i] = r[i];
142 125  
143 126 header = h; //save the header size
... ... @@ -154,17 +137,17 @@ public:
154 137 /// @param filename is the name of the binary file to be created
155 138 /// @param r is a STIM vector specifying the size of the file along each dimension
156 139 /// @offset specifies how many bytes to offset the file (used to leave room for a header)
157   - bool create(std::string filename, vec<unsigned int> r, unsigned int offset = 0){
  140 + bool create(std::string filename, vec<unsigned long long> r, unsigned long long offset = 0){
158 141  
159 142 std::ofstream target(filename.c_str(), std::ios::binary);
160 143  
161 144 //initialize binary file
162 145 T p = 0;
163   - for(unsigned int i =0; i < r[0] * r[1] * r[2]; i++){
  146 + for(unsigned long long i =0; i < r[0] * r[1] * r[2]; i++){
164 147 target.write((char*)(&p), sizeof(T));
165 148 }
166 149  
167   - for(unsigned int i = 0; i < D; i++) //set the dimensions of the binary file object
  150 + for(unsigned long long i = 0; i < D; i++) //set the dimensions of the binary file object
168 151 R[i] = r[i];
169 152  
170 153 header = offset; //save the header size
... ... @@ -178,7 +161,7 @@ public:
178 161  
179 162 /// @param p is a pointer to the data to be written
180 163 /// @param page is the page number (index of the highest-numbered dimension)
181   - bool write_page( T * p, unsigned int page){
  164 + bool write_page( T * p, unsigned long long page){
182 165  
183 166 if(p == NULL){
184 167 std::cout<<"ERROR: unable to write into file, empty pointer"<<std::endl;
... ... @@ -195,7 +178,7 @@ public:
195 178  
196 179 /// @param p is a pointer to pre-allocated memory equal to the page size
197 180 /// @param page is the index of the page
198   - bool read_page( T * p, unsigned int page, bool PROGRESS = false){
  181 + bool read_page( T * p, unsigned long long page, bool PROGRESS = false){
199 182  
200 183 if(PROGRESS) progress = 0;
201 184  
... ... @@ -217,8 +200,8 @@ public:
217 200 /// @param p is a pointer to pre-allocated memory equal to the line size R[2]
218 201 /// @param x is the x coordinate
219 202 /// @param y is the y coordinate
220   - bool read_line_2( T * p, unsigned int x, unsigned int y, bool PROGRESS = false){
221   - unsigned int i;
  203 + bool read_line_2( T * p, unsigned long long x, unsigned long long y, bool PROGRESS = false){
  204 + unsigned long long i;
222 205  
223 206 if(PROGRESS) progress = 0;
224 207  
... ... @@ -244,7 +227,7 @@ public:
244 227 /// @param p is a pointer to pre-allocated memory equal to the line size R[2]
245 228 /// @param x is the y coordinate
246 229 /// @param y is the z coordinate
247   - bool read_line_0(T * p, unsigned int y, unsigned int z, bool PROGRESS = false){
  230 + bool read_line_0(T * p, unsigned long long y, unsigned long long z, bool PROGRESS = false){
248 231 //test to make sure the specified value is within range
249 232 if( y >= R[1] || z >= R[2] ){
250 233 std::cout<<"ERROR: sample or line out of range"<<std::endl;
... ... @@ -262,7 +245,7 @@ public:
262 245 /// @param p is a pointer to pre-allocated memory equal to the line size R[2]
263 246 /// @param x is the y coordinate
264 247 /// @param z is the z coordinate
265   - bool read_line_1(T * p, unsigned int x, unsigned int z, bool PROGRESS = false){
  248 + bool read_line_1(T * p, unsigned long long x, unsigned long long z, bool PROGRESS = false){
266 249 if(PROGRESS) progress = 0;
267 250 //test to make sure the specified value is within range
268 251 if( x >= R[0] || z >= R[2] ){
... ... @@ -271,7 +254,7 @@ public:
271 254 }
272 255  
273 256 file.seekg((z * R[0] * R[1] + x) * sizeof(T), std::ios::beg); //seek to the start of the line
274   - for (unsigned int i = 0; i < R[1]; i++){ //for each pixel in the line
  257 + for (unsigned long long i = 0; i < R[1]; i++){ //for each pixel in the line
275 258 file.read((char *)(p + i), sizeof(T)); //read the pixel
276 259 file.seekg((R[0] - 1) * sizeof(T), std::ios::cur); //seek to the next pixel in the line
277 260 if(PROGRESS) progress = (double)i / (double)R[1] * 100;
... ... @@ -284,22 +267,22 @@ public:
284 267  
285 268 /// @param p is a pointer to pre-allocated memory of size R[1] * R[2] * sizeof(T)
286 269 /// @param n is the 0-axis coordinate used to retrieve the plane
287   - bool read_plane_0(T* p, unsigned int n, bool PROGRESS = false){
  270 + bool read_plane_0(T* p, unsigned long long n, bool PROGRESS = false){
288 271 if(PROGRESS) progress = 0;
289 272 if (n >= R[0]){ //make sure the number is within the possible range
290 273 std::cout<<"ERROR read_plane_0: page out of range"<<std::endl;
291 274 return false;
292 275 }
293   - unsigned int jump = (R[0] - 1) * sizeof(T); //number of bytes to skip between samples
  276 + unsigned long long jump = (R[0] - 1) * sizeof(T); //number of bytes to skip between samples
294 277  
295 278 //seek to the start of the plane
296 279 file.seekg(n * sizeof(T), std::ios::beg);
297 280  
298   - unsigned int N = R[1] * R[2];
299   - for(unsigned int i = 0; i<N; i++){
  281 + unsigned long long N = R[1] * R[2];
  282 + for(unsigned long long i = 0; i<N; i++){
300 283 file.read((char*)(p+i), sizeof(T));
301 284 file.seekg(jump, std::ios::cur);
302   - if(PROGRESS) progress = (double)i / N * 100;
  285 + if(PROGRESS) progress = (double)(i+1) / N * 100;
303 286 }
304 287  
305 288 if(PROGRESS) progress = 100;
... ... @@ -312,10 +295,10 @@ public:
312 295  
313 296 /// @param p is a pointer to pre-allocated memory of size R[0] * R[2] * sizeof(T)
314 297 /// @param n is the 1-axis coordinate used to retrieve the plane
315   - bool read_plane_1(T* p, unsigned int n, bool PROGRESS = false){
  298 + bool read_plane_1(T* p, unsigned long long n, bool PROGRESS = false){
316 299 if(PROGRESS) progress = 0;
317   - unsigned int L = R[0] * sizeof(T); //caculate the number of bytes in a sample line
318   - unsigned int jump = R[0] * (R[1] - 1) * sizeof(T);
  300 + unsigned long long L = R[0] * sizeof(T); //caculate the number of bytes in a sample line
  301 + unsigned long long jump = R[0] * (R[1] - 1) * sizeof(T);
319 302  
320 303 if (n >= R[1]){ //make sure the bank number is right
321 304 std::cout<<"ERROR read_plane_1: page out of range"<<std::endl;
... ... @@ -323,7 +306,7 @@ public:
323 306 }
324 307  
325 308 file.seekg(R[0] * n * sizeof(T), std::ios::beg);
326   - for (unsigned i = 0; i < R[2]; i++){
  309 + for (unsigned long long i = 0; i < R[2]; i++){
327 310 if(PROGRESS) progress = (double)i / R[2] * 100;
328 311 file.read((char *)(p + i * R[0]), L);
329 312 file.seekg( jump, std::ios::cur);
... ... @@ -338,7 +321,7 @@ public:
338 321  
339 322 /// @param p is a pointer to pre-allocated memory of size R[0] * R[1] * sizeof(T)
340 323 /// @param n is the 2-axis coordinate used to retrieve the plane
341   - bool read_plane_2(T* p, unsigned int n, bool PROGRESS = false){
  324 + bool read_plane_2(T* p, unsigned long long n, bool PROGRESS = false){
342 325 return read_page(p, n, PROGRESS);
343 326 }
344 327  
... ... @@ -346,7 +329,7 @@ public:
346 329  
347 330 /// @param p is a pointer to pre-allocated memory of size sizeof(T)
348 331 /// @param i is the index to the pixel using linear indexing
349   - bool read_pixel(T* p, unsigned int i){
  332 + bool read_pixel(T* p, unsigned long long i){
350 333 if(i >= R[0] * R[1] * R[2]){
351 334 std::cout<<"ERROR read_pixel: n is out of range"<<std::endl;
352 335 return false;
... ... @@ -363,14 +346,14 @@ public:
363 346 /// @param x is the x (0) axis coordinate
364 347 /// @param y is the y (1) axis coordinate
365 348 /// @param z is the z (2) axis coordinate
366   - bool read_pixel(T* p, unsigned int x, unsigned int y, unsigned int z){
  349 + bool read_pixel(T* p, unsigned long long x, unsigned long long y, unsigned long long z){
367 350  
368 351 if(x < 0 || x >= R[0] || y < 0 || y >= R[1] || z < 0 || z > R[2]){
369 352 std::cout<<"ERROR read_pixel: (x,y,z) is out of range"<<std::endl;
370 353 return false;
371 354 }
372 355  
373   - unsigned int i = z * R[0] * R[1] + y * R[0] + z;
  356 + unsigned long long i = z * R[0] * R[1] + y * R[0] + z;
374 357 return read_pixel(p, i);
375 358 }
376 359  
... ...
stim/envi/bip.h
... ... @@ -3,7 +3,7 @@
3 3  
4 4 #include "../envi/envi_header.h"
5 5 #include "../envi/bil.h"
6   -#include "../envi/binary.h"
  6 +#include "../envi/hsi.h"
7 7 #include <cstring>
8 8 #include <utility>
9 9  
... ... @@ -23,15 +23,15 @@ namespace stim{
23 23 */
24 24 template <typename T>
25 25  
26   -class bip: public binary<T> {
  26 +class bip: public hsi<T> {
27 27  
28 28 protected:
29 29  
30 30  
31   - std::vector<double> w; //band wavelength
32   - unsigned int offset; //header offset
  31 + //std::vector<double> w; //band wavelength
  32 + unsigned long long offset; //header offset
33 33  
34   - unsigned long long X(){
  34 + /*unsigned long long X(){
35 35 return R[1];
36 36 }
37 37 unsigned long long Y(){
... ... @@ -39,17 +39,18 @@ protected:
39 39 }
40 40 unsigned long long Z(){
41 41 return R[0];
42   - }
43   -
  42 + }*/
  43 + using hsi<T>::w; //use the wavelength array in stim::hsi
  44 + using hsi<T>::nnz;
44 45 using binary<T>::progress;
45 46  
46 47 /// Call the binary nnz() function for the BIP orientation
47   - unsigned long long nnz(unsigned char* mask){
48   - return binary<T>::nnz(mask, X()*Y());
49   - }
  48 + //unsigned long long nnz(unsigned char* mask){
  49 + // return binary<T>::nnz(mask, X()*Y());
  50 + //}
50 51  
51 52 /// Linear interpolation of a spectral value given the bounding spectral samples
52   - T lerp(double w, T low_v, double low_w, T high_v, double high_w){
  53 + /*T lerp(double w, T low_v, double low_w, T high_v, double high_w){
53 54 if(low_w == high_w) return low_v; //if the interval is of zero length, just return one of the bounds
54 55 double alpha = (w - low_w) / (high_w - low_w); //calculate the interpolation factor
55 56 return (1.0 - alpha) * low_v + alpha * high_v; //interpolate
... ... @@ -104,7 +105,7 @@ protected:
104 105 v[n] = interp_spectrum(s, wavelengths[n]); //interpolate the measurement
105 106 }
106 107 return v;
107   - }
  108 + }*/
108 109  
109 110 public:
110 111  
... ... @@ -113,6 +114,8 @@ public:
113 114 using binary<T>::R;
114 115 using binary<T>::read_line_0;
115 116  
  117 + bip(){ hsi<T>::init_bip(); }
  118 +
116 119 /// Open a data file for reading using the class interface.
117 120  
118 121 /// @param filename is the name of the binary file on disk
... ... @@ -121,14 +124,19 @@ public:
121 124 /// @param B is the number of samples (bands) along dimension 3
122 125 /// @param header_offset is the number of bytes (if any) in the binary header
123 126 /// @param wavelengths is an optional STL vector of size B specifying a numerical label for each band
124   - bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int B, unsigned int header_offset, std::vector<double> wavelengths){
  127 + bool open(std::string filename,
  128 + unsigned long long X,
  129 + unsigned long long Y,
  130 + unsigned long long B,
  131 + unsigned long long header_offset,
  132 + std::vector<double> wavelengths){
125 133  
126 134 //copy the wavelengths to the BSQ file structure
127 135 w = wavelengths;
128 136 //copy the offset to the structure
129 137 offset = header_offset;
130 138  
131   - return open(filename, vec<unsigned int>(B, X, Y), header_offset);
  139 + return open(filename, vec<unsigned long long>(B, X, Y), header_offset);
132 140  
133 141 }
134 142  
... ... @@ -136,7 +144,7 @@ public:
136 144  
137 145 /// @param p is a pointer to an allocated region of memory at least X * Y * sizeof(T) in size.
138 146 /// @param page <= B is the integer number of the band to be copied.
139   - bool band_index( T * p, unsigned int page, bool PROGRESS = false){
  147 + bool band_index( T * p, unsigned long long page, bool PROGRESS = false){
140 148 return binary<T>::read_plane_0(p, page, PROGRESS);
141 149 }
142 150  
... ... @@ -148,9 +156,9 @@ public:
148 156  
149 157 //if there are no wavelengths in the BSQ file
150 158 if(w.size() == 0)
151   - return band_index(p, (unsigned int)wavelength, PROGRESS);
  159 + return band_index(p, (unsigned long long)wavelength, PROGRESS);
152 160  
153   - unsigned int XY = X() * Y(); //calculate the number of pixels in a band
  161 + unsigned long long XY = X() * Y(); //calculate the number of pixels in a band
154 162  
155 163 unsigned page=0; //bands around the wavelength
156 164  
... ... @@ -180,9 +188,9 @@ public:
180 188 p2=(T*)malloc( XY * sizeof(T));
181 189 band_index(p1, page - 1);
182 190 band_index(p2, page, PROGRESS);
183   - for(unsigned i=0; i < XY; i++){
  191 + for(unsigned long long i=0; i < XY; i++){
184 192 double r = (double) (wavelength - w[page-1]) / (double) (w[page] - w[page-1]);
185   - p[i] = (p2[i] - p1[i]) * r + p1[i];
  193 + p[i] = (T)(((double)p2[i] - (double)p1[i]) * r + (double)p1[i]);
186 194 }
187 195 free(p1);
188 196 free(p2);
... ... @@ -200,7 +208,7 @@ public:
200 208 /// @param p is a pointer to pre-allocated memory at least B * sizeof(T) in size.
201 209 /// @param x is the x-coordinate (dimension 1) of the spectrum.
202 210 /// @param y is the y-coordinate (dimension 2) of the spectrum.
203   - bool spectrum(T * p, unsigned x, unsigned y, bool PROGRESS = false){
  211 + bool spectrum(T * p, unsigned long long x, unsigned long long y, bool PROGRESS = false){
204 212 return read_line_0(p, x, y, PROGRESS); //read a line in the binary YZ plane (dimension order for BIP is ZXY)
205 213 }
206 214  
... ... @@ -211,16 +219,16 @@ public:
211 219 /// @param wavelength is the wavelength of X values to retrieve
212 220 bool read_x_from_xz(T* p, T* c, double wavelength)
213 221 {
214   - unsigned int B = Z();
  222 + unsigned long long B = Z();
215 223  
216   - unsigned page=0; //samples around the wavelength
  224 + unsigned long long page=0; //samples around the wavelength
217 225  
218 226  
219 227 //get the bands numbers around the wavelength
220 228  
221 229 //if wavelength is smaller than the first one in header file
222 230 if ( w[page] > wavelength ){
223   - for(unsigned j = 0; j < X(); j++)
  231 + for(unsigned long long j = 0; j < X(); j++)
224 232 {
225 233 p[j] = c[j * B];
226 234 }
... ... @@ -232,7 +240,7 @@ public:
232 240 page++;
233 241 //if wavelength is larger than the last wavelength in header file
234 242 if (page == B) {
235   - for(unsigned j = 0; j < X(); j++)
  243 + for(unsigned long long j = 0; j < X(); j++)
236 244 {
237 245 p[j] = c[(j + 1) * B - 1];
238 246 }
... ... @@ -246,17 +254,17 @@ public:
246 254 p1=(T*)malloc( X() * sizeof(T)); //memory allocation
247 255 p2=(T*)malloc( X() * sizeof(T));
248 256 //band_index(p1, page - 1);
249   - for(unsigned j = 0; j < X(); j++)
  257 + for(unsigned long long j = 0; j < X(); j++)
250 258 {
251 259 p1[j] = c[j * B + page - 1];
252 260 }
253 261 //band_index(p2, page );
254   - for(unsigned j = 0; j < X(); j++)
  262 + for(unsigned long long j = 0; j < X(); j++)
255 263 {
256 264 p2[j] = c[j * B + page];
257 265 }
258 266  
259   - for(unsigned i=0; i < X(); i++){
  267 + for(unsigned long long i=0; i < X(); i++){
260 268 double r = (double) (wavelength - w[page-1]) / (double) (w[page] - w[page-1]);
261 269 p[i] = (p2[i] - p1[i]) * r + p1[i];
262 270 }
... ... @@ -266,7 +274,7 @@ public:
266 274 else //if the wavelength is equal to a wavelength in header file
267 275 {
268 276 //band_index(p, page);
269   - for(unsigned j = 0; j < X(); j++)
  277 + for(unsigned long long j = 0; j < X(); j++)
270 278 {
271 279 p[j] = c[j * B + page];
272 280 }
... ... @@ -276,29 +284,30 @@ public:
276 284 }
277 285  
278 286 /// Retrieve a single pixel and store it in a pre-allocated double array.
279   - bool pixeld(double* p, unsigned n){
280   - unsigned bandnum = X() * Y(); //calculate numbers in one band
  287 + bool pixeld(double* p, unsigned long long n){
  288 + unsigned long long bandnum = X() * Y(); //calculate numbers in one band
281 289 if ( n >= bandnum){ //make sure the pixel number is right
282 290 std::cout<<"ERROR: sample or line out of range"<<std::endl;
283 291 return false;
284 292 }
285   - unsigned B = Z();
  293 + unsigned long long B = Z();
286 294  
287 295 T* temp = (T*) malloc(B * sizeof(T)); //allocate space for the raw pixel data
288 296 file.seekg(n * B * sizeof(T), std::ios::beg); //point to the certain pixel
289 297 file.read((char *)temp, sizeof(T) * B); //read the spectrum from disk to the temp pointer
290 298  
291   - for(unsigned int i = 0; i < B; i++) //for each element of the spectrum
  299 + for(unsigned long long i = 0; i < B; i++) //for each element of the spectrum
292 300 p[i] = (double) temp[i]; //cast each element to a double value
  301 + return true;
293 302 }
294 303  
295 304 /// Retrieve a single pixel and stores it in pre-allocated memory.
296 305  
297 306 /// @param p is a pointer to pre-allocated memory at least sizeof(T) in size.
298 307 /// @param n is an integer index to the pixel using linear array indexing.
299   - bool pixel(T * p, unsigned n){
  308 + bool pixel(T * p, unsigned long long n){
300 309  
301   - unsigned N = X() * Y(); //calculate numbers in one band
  310 + unsigned long long N = X() * Y(); //calculate numbers in one band
302 311 if ( n >= N){ //make sure the pixel number is right
303 312 std::cout<<"ERROR: sample or line out of range"<<std::endl;
304 313 return false;
... ... @@ -310,7 +319,7 @@ public:
310 319 }
311 320  
312 321 //given a Y ,return a ZX slice
313   - bool read_plane_y(T * p, unsigned y){
  322 + bool read_plane_y(T * p, unsigned long long y){
314 323 return binary<T>::read_plane_2(p, y);
315 324 }
316 325  
... ... @@ -330,7 +339,6 @@ public:
330 339 std::vector<T> base_vals; //allocate space for the values at each baseline point
331 340 double aw, bw; //surrounding baseline point wavelengths
332 341 T av, bv; //surrounding baseline point values
333   - double alpha;
334 342 unsigned long long ai, bi; //surrounding baseline point band indices
335 343 for(unsigned long long n = 0; n < N; n++){ //for each pixel in the image
336 344 if(mask != NULL && !mask[n]){ //if the pixel isn't masked
... ... @@ -393,14 +401,14 @@ public:
393 401 T* s = (T*)malloc(sizeof(T) * B); //allocate memory to store a pixel
394 402 T nv; //stores the value of the normalized band
395 403 for(unsigned long long n = 0; n < N; n++){ //for each pixel in the image
396   - pixel(s, n); //retrieve the spectrum s
397   - nv = interp_spectrum(s, w); //find the value of the normalization band
398 404 if(mask != NULL && !mask[n]) //if the normalization band is below threshold
399 405 memset(s, 0, sizeof(T) * B); //set the output to zero
400 406 else{
401   - for(unsigned long long b = 0; b < B; b++){ //for each band in the spectrum
  407 + pixel(s, n); //retrieve the spectrum s
  408 + nv = interp_spectrum(s, w); //find the value of the normalization band
  409 +
  410 + for(unsigned long long b = 0; b < B; b++) //for each band in the spectrum
402 411 s[b] /= nv; //divide by the normalization value
403   - }
404 412 }
405 413  
406 414 if(PROGRESS) progress = (double)(n+1) / N * 100; //set the current progress
... ... @@ -419,23 +427,23 @@ public:
419 427 /// @param outname is the name of the output BIL file to be saved to disk.
420 428 bool bil(std::string outname, bool PROGRESS = false)
421 429 {
422   - unsigned int S = X() * Z() * sizeof(T); //calculate the number of bytes in a ZX slice
  430 + unsigned long long S = X() * Z() * sizeof(T); //calculate the number of bytes in a ZX slice
423 431  
424 432 std::ofstream target(outname.c_str(), std::ios::binary);
425   - std::string headername = outname + ".hdr";
  433 + //std::string headername = outname + ".hdr";
426 434  
427 435 T * p; //pointer to the current ZX slice for bip file
428 436 p = (T*)malloc(S);
429 437 T * q; //pointer to the current XZ slice for bil file
430 438 q = (T*)malloc(S);
431 439  
432   - for ( unsigned i = 0; i < Y(); i++)
  440 + for ( unsigned long long i = 0; i < Y(); i++)
433 441 {
434 442 read_plane_y(p, i);
435   - for ( unsigned k = 0; k < Z(); k++)
  443 + for ( unsigned long long k = 0; k < Z(); k++)
436 444 {
437   - unsigned ks = k * X();
438   - for ( unsigned j = 0; j < X(); j++)
  445 + unsigned long long ks = k * X();
  446 + for ( unsigned long long j = 0; j < X(); j++)
439 447 q[ks + j] = p[k + j * Z()];
440 448  
441 449 if(PROGRESS) progress = (double)(i * Z() + k+1) / (Y() * Z()) * 100;
... ... @@ -459,12 +467,12 @@ public:
459 467 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size.
460 468 bool baseline_band(double lb, double rb, T* lp, T* rp, double wavelength, T* result){
461 469  
462   - unsigned XY = X() * Y();
  470 + unsigned long long XY = X() * Y();
463 471 band(result, wavelength); //get band
464 472  
465 473 //perform the baseline correction
466 474 double r = (double) (wavelength - lb) / (double) (rb - lb);
467   - for(unsigned i=0; i < XY; i++){
  475 + for(unsigned long long i=0; i < XY; i++){
468 476 result[i] =(T) (result[i] - (rp[i] - lp[i]) * r - lp[i] );
469 477 }
470 478 return true;
... ... @@ -480,8 +488,8 @@ public:
480 488  
481 489 T* lp;
482 490 T* rp;
483   - unsigned XY = X() * Y();
484   - unsigned S = XY * sizeof(T);
  491 + unsigned long long XY = X() * Y();
  492 + unsigned long long S = XY * sizeof(T);
485 493 lp = (T*) malloc(S); //memory allocation
486 494 rp = (T*) malloc(S);
487 495  
... ... @@ -510,8 +518,8 @@ public:
510 518 T* cur; //current band 1
511 519 T* cur2; //current band 2
512 520  
513   - unsigned XY = X() * Y();
514   - unsigned S = XY * sizeof(T);
  521 + unsigned long long XY = X() * Y();
  522 + unsigned long long S = XY * sizeof(T);
515 523  
516 524 lp = (T*) malloc(S); //memory allocation
517 525 rp = (T*) malloc(S);
... ... @@ -521,9 +529,9 @@ public:
521 529 memset(result, (char)0, S);
522 530  
523 531 //find the wavelenght position in the whole band
524   - unsigned int n = w.size();
525   - unsigned int ai = 0; //left bound position
526   - unsigned int bi = n - 1; //right bound position
  532 + unsigned long long n = w.size();
  533 + unsigned long long ai = 0; //left bound position
  534 + unsigned long long bi = n - 1; //right bound position
527 535  
528 536  
529 537  
... ... @@ -552,23 +560,23 @@ public:
552 560 //calculate the beginning and the ending part
553 561 baseline_band(lb, rb, lp, rp, rab, cur2); //ending part
554 562 baseline_band(lb, rb, lp, rp, w[bi], cur);
555   - for(unsigned j = 0; j < XY; j++){
556   - result[j] += (rab - w[bi]) * (cur[j] + cur2[j]) / 2.0;
  563 + for(unsigned long long j = 0; j < XY; j++){
  564 + result[j] += (T)((rab - w[bi]) * ((double)cur[j] + (double)cur2[j]) / 2.0);
557 565 }
558 566 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
559 567 baseline_band(lb, rb, lp, rp, w[ai], cur);
560   - for(unsigned j = 0; j < XY; j++){
561   - result[j] += (w[ai] - lab) * (cur[j] + cur2[j]) / 2.0;
  568 + for(unsigned long long j = 0; j < XY; j++){
  569 + result[j] += (T)((w[ai] - lab) * ((double)cur[j] + (double)cur2[j]) / 2.0);
562 570 }
563 571  
564 572 //calculate the area
565 573 ai++;
566   - for(unsigned i = ai; i <= bi ;i++)
  574 + for(unsigned long long i = ai; i <= bi ;i++)
567 575 {
568 576 baseline_band(lb, rb, lp, rp, w[ai], cur2);
569   - for(unsigned j = 0; j < XY; j++)
  577 + for(unsigned long long j = 0; j < XY; j++)
570 578 {
571   - result[j] += (w[ai] - w[ai-1]) * (cur[j] + cur2[j]) / 2.0;
  579 + result[j] += (T)((w[ai] - w[ai-1]) * ((double)cur[j] + (double)cur2[j]) / 2.0);
572 580 }
573 581 std::swap(cur,cur2); //swap the band pointers
574 582 }
... ... @@ -598,7 +606,7 @@ public:
598 606 height(lb1, rb1, pos1, p1);
599 607 height(lb2, rb2, pos2, p2);
600 608 //calculate the ratio in result
601   - for(unsigned i = 0; i < X() * Y(); i++){
  609 + for(unsigned long long i = 0; i < X() * Y(); i++){
602 610 if(p1[i] == 0 && p2[i] ==0)
603 611 result[i] = 1;
604 612 else
... ... @@ -629,7 +637,7 @@ public:
629 637 area(lb1, rb1, lab1, rab1, p1);
630 638 height(lb2, rb2, pos, p2);
631 639 //calculate the ratio in result
632   - for(unsigned i = 0; i < X() * Y(); i++){
  640 + for(unsigned long long i = 0; i < X() * Y(); i++){
633 641 if(p1[i] == 0 && p2[i] ==0)
634 642 result[i] = 1;
635 643 else
... ... @@ -662,7 +670,7 @@ public:
662 670 area(lb1, rb1, lab1, rab1, p1);
663 671 area(lb2, rb2, lab2, rab2, p2);
664 672 //calculate the ratio in result
665   - for(unsigned i = 0; i < X() * Y(); i++){
  673 + for(unsigned long long i = 0; i < X() * Y(); i++){
666 674 if(p1[i] == 0 && p2[i] ==0)
667 675 result[i] = 1;
668 676 else
... ... @@ -687,8 +695,8 @@ public:
687 695 T* cur; //current band 1
688 696 T* cur2; //current band 2
689 697  
690   - unsigned XY = X() * Y();
691   - unsigned S = XY * sizeof(T);
  698 + unsigned long long XY = X() * Y();
  699 + unsigned long long S = XY * sizeof(T);
692 700  
693 701 lp = (T*) malloc(S); //memory allocation
694 702 rp = (T*) malloc(S);
... ... @@ -698,9 +706,9 @@ public:
698 706 memset(result, (char)0, S);
699 707  
700 708 //find the wavelenght position in the whole band
701   - unsigned int n = w.size();
702   - unsigned int ai = 0; //left bound position
703   - unsigned int bi = n - 1; //right bound position
  709 + unsigned long long n = w.size();
  710 + unsigned long long ai = 0; //left bound position
  711 + unsigned long long bi = n - 1; //right bound position
704 712  
705 713 //to make sure the left and the right bound are in the bandwidth
706 714 if (lb < w[0] || rb < w[0] || lb > w[n-1] || rb >w[n-1]){
... ... @@ -727,23 +735,23 @@ public:
727 735 //calculate the beginning and the ending part
728 736 baseline_band(lb, rb, lp, rp, rab, cur2); //ending part
729 737 baseline_band(lb, rb, lp, rp, w[bi], cur);
730   - for(unsigned j = 0; j < XY; j++){
731   - result[j] += (rab - w[bi]) * (rab + w[bi]) * (cur[j] + cur2[j]) / 4.0;
  738 + for(unsigned long long j = 0; j < XY; j++){
  739 + result[j] += (T)((rab - w[bi]) * (rab + w[bi]) * ((double)cur[j] + (double)cur2[j]) / 4.0);
732 740 }
733 741 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
734 742 baseline_band(lb, rb, lp, rp, w[ai], cur);
735   - for(unsigned j = 0; j < XY; j++){
736   - result[j] += (w[ai] - lab) * (w[ai] + lab) * (cur[j] + cur2[j]) / 4.0;
  743 + for(unsigned long long j = 0; j < XY; j++){
  744 + result[j] += (T)((w[ai] - lab) * (w[ai] + lab) * ((double)cur[j] + (double)cur2[j]) / 4.0);
737 745 }
738 746  
739 747 //calculate f(x) times x
740 748 ai++;
741   - for(unsigned i = ai; i <= bi ;i++)
  749 + for(unsigned long long i = ai; i <= bi ;i++)
742 750 {
743 751 baseline_band(lb, rb, lp, rp, w[ai], cur2);
744   - for(unsigned j = 0; j < XY; j++)
  752 + for(unsigned long long j = 0; j < XY; j++)
745 753 {
746   - result[j] += (w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * (cur[j] + cur2[j]) / 4.0;
  754 + result[j] += (T)((w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * ((double)cur[j] + (double)cur2[j]) / 4.0);
747 755 }
748 756 std::swap(cur,cur2); //swap the band pointers
749 757 }
... ... @@ -770,7 +778,7 @@ public:
770 778 x_area(lb, rb, lab, rab, p1);
771 779 area(lb, rb, lab, rab, p2);
772 780 //calculate the ratio in result
773   - for(unsigned i = 0; i < X() * Y(); i++){
  781 + for(unsigned long long i = 0; i < X() * Y(); i++){
774 782 if(p1[i] == 0 && p2[i] ==0)
775 783 result[i] = 1;
776 784 else
... ... @@ -794,7 +802,7 @@ public:
794 802 T* temp = (T*)malloc(X() * Y() * sizeof(T)); //allocate memory for the certain band
795 803 band(temp, mask_band, PROGRESS);
796 804  
797   - for (unsigned int i = 0; i < X() * Y();i++) {
  805 + for (unsigned long long i = 0; i < X() * Y();i++) {
798 806 if (temp[i] < threshold)
799 807 p[i] = 0;
800 808 else
... ... @@ -814,17 +822,17 @@ public:
814 822  
815 823 std::ofstream target(outfile.c_str(), std::ios::binary);
816 824  
817   - unsigned ZX = Z() * X(); //calculate the number of values in a page (XZ in BIP)
818   - unsigned L = ZX * sizeof(T); //calculate the number of bytes in a page
  825 + unsigned long long ZX = Z() * X(); //calculate the number of values in a page (XZ in BIP)
  826 + unsigned long long L = ZX * sizeof(T); //calculate the number of bytes in a page
819 827  
820 828 T * temp = (T*)malloc(L); //allocate space for that page
821 829  
822   - for (unsigned i = 0; i < Y(); i++) //for each page (Y in BIP)
  830 + for (unsigned long long i = 0; i < Y(); i++) //for each page (Y in BIP)
823 831 {
824 832 read_plane_y(temp, i); //load that page (it's pointed to by temp)
825   - for ( unsigned j = 0; j < X(); j++) //for each X value
  833 + for ( unsigned long long j = 0; j < X(); j++) //for each X value
826 834 {
827   - for (unsigned k = 0; k < Z(); k++) //for each B value (band)
  835 + for (unsigned long long k = 0; k < Z(); k++) //for each B value (band)
828 836 {
829 837 if (p[i * X() + j] == 0) //if the mask value is zero
830 838 temp[j * Z() + k] = 0; //set the pixel value to zero
... ... @@ -850,15 +858,15 @@ public:
850 858 std::ofstream target(outfile.c_str(), std::ios::binary);
851 859  
852 860 //allocate space for a single spectrum
853   - unsigned long B = Z();
  861 + unsigned long long B = Z();
854 862 T* spectrum = (T*) malloc(B * sizeof(T));
855 863  
856 864 //calculate the number of pixels in a band
857   - unsigned long XY = X() * Y();
  865 + unsigned long long XY = X() * Y();
858 866  
859 867 //for each pixel
860   - unsigned long skip = 0; //number of spectra to skip
861   - for(unsigned long x = 0; x < XY; x++){
  868 + unsigned long long skip = 0; //number of spectra to skip
  869 + for(unsigned long long x = 0; x < XY; x++){
862 870  
863 871 //if the current pixel isn't masked
864 872 if( mask[x] == 0){
... ... @@ -879,9 +887,8 @@ public:
879 887  
880 888 //write this pixel out
881 889 target.write((char *)spectrum, B * sizeof(T));
882   -
883   - if(PROGRESS) progress = (double) (x+1) / XY * 100;
884 890 }
  891 + if(PROGRESS) progress = (double) (x+1) / XY * 100;
885 892  
886 893 }
887 894  
... ... @@ -892,7 +899,7 @@ public:
892 899 return true;
893 900 }
894 901  
895   - bool unsift(std::string outfile, unsigned char* mask, unsigned int samples, unsigned int lines){
  902 + bool unsift(std::string outfile, unsigned char* mask, unsigned long long samples, unsigned long long lines){
896 903  
897 904 // open an output stream
898 905 std::ofstream target(outfile.c_str(), std::ios::binary);
... ... @@ -901,7 +908,7 @@ public:
901 908 file.seekg(0, std::ios::beg);
902 909  
903 910 //allocate space for a single spectrum
904   - unsigned long B = Z();
  911 + unsigned long long B = Z();
905 912 T* spectrum = (T*) malloc(B * sizeof(T));
906 913  
907 914 //allocate space for a spectrum of zeros
... ... @@ -909,11 +916,11 @@ public:
909 916 memset(zeros, 0, B * sizeof(T));
910 917  
911 918 //calculate the number of pixels in a band
912   - unsigned long XY = samples * lines;
  919 + unsigned long long XY = samples * lines;
913 920  
914 921 //for each pixel
915   - unsigned long skip = 0; //number of spectra to skip
916   - for(unsigned long x = 0; x < XY; x++){
  922 + unsigned long long skip = 0; //number of spectra to skip
  923 + for(unsigned long long x = 0; x < XY; x++){
917 924  
918 925 //if the current pixel isn't masked
919 926 if( mask[x] == 0){
... ... @@ -951,24 +958,23 @@ public:
951 958 /// @param p is a pointer to pre-allocated memory of size [B * sizeof(T)] that stores the mean spectrum
952 959 /// @param mask is a pointer to memory of size [X * Y] that stores the mask value at each pixel location
953 960 bool avg_band(double* p, unsigned char* mask = NULL, bool PROGRESS = false){
954   - unsigned long long XY = X() * Y();
955   - T* temp = (T*)malloc(sizeof(T) * Z());
956   - //Iinitialize
957   - for (unsigned j = 0; j < Z(); j++){
958   - p[j] = 0;
959   - }
960   - //calculate vaild number in a band
961   - unsigned count = nnz(mask);
962   -
963   - //calculate average number of a band
964   - for (unsigned i = 0; i < XY; i++){
965   - if (mask == NULL || mask[i] != 0){
966   - pixel(temp, i);
967   - for (unsigned j = 0; j < Z(); j++){
968   - p[j] += (double)temp[j] / (double)count;
  961 + unsigned long long XY = X() * Y(); //calculate the total number of pixels in the HSI
  962 + T* temp = (T*)malloc(sizeof(T) * Z()); //allocate space for the current spectrum to be read
  963 + memset(p, 0, sizeof(double) * Z()); //initialize the average spectrum to zero (0)
  964 + //for (unsigned j = 0; j < Z(); j++){
  965 + // p[j] = 0;
  966 + //}
  967 +
  968 + unsigned long long count = nnz(mask); //calculate the number of masked pixels
  969 +
  970 + for (unsigned long long i = 0; i < XY; i++){ //for each pixel in the HSI
  971 + if (mask == NULL || mask[i] != 0){ //if the pixel is masked
  972 + pixel(temp, i); //get the spectrum
  973 + for (unsigned long long j = 0; j < Z(); j++){ //for each spectral component
  974 + p[j] += (double)temp[j] / (double)count; //add the weighted value to the average
969 975 }
970 976 }
971   - if(PROGRESS) progress = (double)(i+1) / XY * 100;
  977 + if(PROGRESS) progress = (double)(i+1) / XY * 100; //increment the progress
972 978 }
973 979  
974 980 free(temp);
... ... @@ -976,6 +982,7 @@ public:
976 982 }
977 983 #ifdef CUDA_FOUND
978 984 /// Calculate the covariance matrix for masked pixels using cuBLAS
  985 + /// Note that cuBLAS only supports integer-sized arrays, so there may be issues with large spectra
979 986 bool co_matrix_cublas(double* co, double* avg, unsigned char *mask, bool PROGRESS = false){
980 987  
981 988 cudaError_t cudaStat;
... ... @@ -994,7 +1001,7 @@ public:
994 1001 cudaStat = cudaMalloc(&A_dev, B * B * sizeof(double)); //allocate space on the CUDA device for the covariance matrix
995 1002 cudaStat = cudaMemset(A_dev, 0, B * B * sizeof(double)); //initialize the covariance matrix to zero (0)
996 1003 cudaStat = cudaMalloc(&avg_dev, B * sizeof(double)); //allocate space on the CUDA device for the average spectrum
997   - stat = cublasSetVector(B, sizeof(double), avg, 1, avg_dev, 1); //copy the average spectrum to the CUDA device
  1004 + stat = cublasSetVector((int)B, sizeof(double), avg, 1, avg_dev, 1); //copy the average spectrum to the CUDA device
998 1005  
999 1006 double ger_alpha = 1.0/(double)XY; //scale the outer product by the inverse of the number of samples (mean outer product)
1000 1007 double axpy_alpha = -1; //multiplication factor for the average spectrum (in order to perform a subtraction)
... ... @@ -1007,22 +1014,22 @@ public:
1007 1014 for (unsigned long long xy = 0; xy < XY; xy++){ //for each pixel
1008 1015 if (mask == NULL || mask[xy] != 0){
1009 1016 pixeld(s, xy); //retreive the spectrum at the current xy pixel location
1010   - stat = cublasSetVector(B, sizeof(double), s, 1, s_dev, 1); //copy the spectrum from the host to the device
1011   - stat = cublasDaxpy(handle, B, &axpy_alpha, avg_dev, 1, s_dev, 1); //subtract the average spectrum
1012   - stat = cublasDsyr(handle, CUBLAS_FILL_MODE_UPPER, B, &ger_alpha, s_dev, 1, A_dev, B); //calculate the covariance matrix (symmetric outer product)
  1017 + stat = cublasSetVector((int)B, sizeof(double), s, 1, s_dev, 1); //copy the spectrum from the host to the device
  1018 + stat = cublasDaxpy(handle, (int)B, &axpy_alpha, avg_dev, 1, s_dev, 1); //subtract the average spectrum
  1019 + stat = cublasDsyr(handle, CUBLAS_FILL_MODE_UPPER, (int)B, &ger_alpha, s_dev, 1, A_dev, (int)B); //calculate the covariance matrix (symmetric outer product)
1013 1020 }
1014 1021 if(PROGRESS) progress = (double)(xy+1) / XY * 100; //record the current progress
1015 1022  
1016 1023 }
1017 1024  
1018   - cublasGetMatrix(B, B, sizeof(double), A_dev, B, co, B); //copy the result from the GPU to the CPU
  1025 + cublasGetMatrix((int)B, (int)B, sizeof(double), A_dev, (int)B, co, (int)B); //copy the result from the GPU to the CPU
1019 1026  
1020 1027 cudaFree(A_dev); //clean up allocated device memory
1021 1028 cudaFree(s_dev);
1022 1029 cudaFree(avg_dev);
1023 1030  
1024   - for(unsigned i = 0; i < B; i++){ //copy the upper triangular portion to the lower triangular portion
1025   - for(unsigned j = i+1; j < B; j++){
  1031 + for(unsigned long long i = 0; i < B; i++){ //copy the upper triangular portion to the lower triangular portion
  1032 + for(unsigned long long j = i+1; j < B; j++){
1026 1033 co[B * i + j] = co[B * j + i];
1027 1034 }
1028 1035 }
... ... @@ -1046,14 +1053,13 @@ public:
1046 1053 unsigned long long XY = X() * Y();
1047 1054 unsigned long long B = Z();
1048 1055 T* temp = (T*)malloc(sizeof(T) * B);
1049   - //count vaild pixels in a band
1050   - unsigned long long count = nnz(mask);
  1056 +
  1057 + unsigned long long count = nnz(mask); //count the number of masked pixels
1051 1058  
1052 1059 //initialize covariance matrix
1053 1060 memset(co, 0, B * B * sizeof(double));
1054 1061  
1055 1062 //calculate covariance matrix
1056   - T i_diff; //stores (temp[i] - avg[i]) to speed math
1057 1063 double* co_half = (double*) malloc(B * B * sizeof(double)); //allocate space for a higher-precision intermediate matrix
1058 1064 double* temp_precise = (double*) malloc(B * sizeof(double));
1059 1065 memset(co_half, 0, B * B * sizeof(double)); //initialize the high-precision matrix with zeros
... ... @@ -1083,10 +1089,10 @@ public:
1083 1089 return true;
1084 1090 }
1085 1091  
1086   - bool project(std::string outfile, double* center, double* basis, unsigned long long M, bool PROGRESS = false){
  1092 + bool project(std::string outfile, double* center, double* basis, unsigned long long M, unsigned char* mask = NULL, bool PROGRESS = false){
1087 1093  
1088 1094 std::ofstream target(outfile.c_str(), std::ios::binary); //open the target binary file
1089   - std::string headername = outfile + ".hdr"; //the header file name
  1095 + //std::string headername = outfile + ".hdr"; //the header file name
1090 1096  
1091 1097 //memory allocation
1092 1098 unsigned long long XY = X() * Y();
... ... @@ -1096,15 +1102,17 @@ public:
1096 1102 T* rs = (T*)malloc(sizeof(T) * M); //allocate space for the projected spectrum
1097 1103 double* bv; //pointer to the current projection vector
1098 1104 for(unsigned long long xy = 0; xy < XY; xy++){ //for each spectrum in the image
1099   - pixel(s, xy); //load the spectrum
1100   - memset(rs, 0, sizeof(T) * M); //initialize the rotated spectrum to zero (0)
1101   - for(unsigned long long m = 0; m < M; m++){ //for each basis vector
1102   - bv = &basis[m * B]; //assign 'bv' to the beginning of the basis vector
1103   - for(unsigned long long b = 0; b < B; b++){ //for each band
1104   - rs[m] += (s[b] - center[b]) * bv[b]; //center the spectrum and perform the projection
  1105 + memset(rs, 0, sizeof(T) * M);
  1106 + if(mask == NULL || mask[xy]){
  1107 + pixel(s, xy); //load the spectrum
  1108 + for(unsigned long long m = 0; m < M; m++){ //for each basis vector
  1109 + bv = &basis[m * B]; //assign 'bv' to the beginning of the basis vector
  1110 + for(unsigned long long b = 0; b < B; b++){ //for each band
  1111 + rs[m] += (T)(((double)s[b] - center[b]) * bv[b]); //center the spectrum and perform the projection
  1112 + }
1105 1113 }
1106 1114 }
1107   -
  1115 +
1108 1116 target.write(reinterpret_cast<const char*>(rs), sizeof(T) * M); //write the projected vector
1109 1117 if(PROGRESS) progress = (double)(xy+1) / XY * 100;
1110 1118 }
... ... @@ -1135,7 +1143,7 @@ public:
1135 1143 for(unsigned long long c = 0; c < C; c++){ //for each basis vector coefficient
1136 1144 bv = &basis[c * B]; //assign 'bv' to the beginning of the basis vector
1137 1145 for(unsigned long long b = 0; b < B; b++){ //for each component of the basis vector
1138   - s[b] += coeff[c] * bv[b] + center[b]; //calculate the contribution of each element of the basis vector in the final spectrum
  1146 + s[b] += (T)((double)coeff[c] * bv[b] + center[b]); //calculate the contribution of each element of the basis vector in the final spectrum
1139 1147 }
1140 1148 }
1141 1149  
... ...
stim/envi/bsq.h
... ... @@ -2,7 +2,7 @@
2 2 #define STIM_BSQ_H
3 3  
4 4 #include "../envi/envi_header.h"
5   -#include "../envi/binary.h"
  5 +#include "../envi/hsi.h"
6 6 #include "../envi/bil.h"
7 7 #include <cstring>
8 8 #include <utility>
... ... @@ -22,27 +22,27 @@ namespace stim{
22 22 */
23 23 template <typename T>
24 24  
25   -class bsq: public binary<T> {
  25 +class bsq: public hsi<T> {
26 26  
27 27  
28 28 protected:
29 29  
30   - std::vector<double> w; //band wavelengths
31   - unsigned int offset;
  30 + //std::vector<double> w; //band wavelengths
  31 + unsigned long long offset;
32 32  
33 33 using binary<T>::R;
34 34  
35   - unsigned long X(){
  35 + /*unsigned long long X(){
36 36 return R[0];
37 37 }
38   - unsigned long Y(){
  38 + unsigned long long Y(){
39 39 return R[1];
40 40 }
41   - unsigned long Z(){
  41 + unsigned long long Z(){
42 42 return R[2];
43   - }
44   -
45   - using binary<T>::nnz;
  43 + }*/
  44 + using hsi<T>::w; //use the wavelength array in stim::hsi
  45 + using hsi<T>::nnz;
46 46 using binary<T>::progress;
47 47  
48 48 public:
... ... @@ -51,8 +51,8 @@ public:
51 51 using binary<T>::file;
52 52 using binary<T>::read_line_2;
53 53 using binary<T>::read_plane_2;
54   - //using binary<T>::getSlice;
55 54  
  55 + bsq(){ hsi<T>::init_bsq(); }
56 56  
57 57 /// Open a data file for reading using the class interface.
58 58  
... ... @@ -62,21 +62,26 @@ public:
62 62 /// @param B is the number of samples (bands) along dimension 3
63 63 /// @param header_offset is the number of bytes (if any) in the binary header
64 64 /// @param wavelengths is an STL vector of size B specifying a numerical label for each band
65   - bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int B, unsigned int header_offset, std::vector<double> wavelengths){
  65 + bool open(std::string filename,
  66 + unsigned long long X,
  67 + unsigned long long Y,
  68 + unsigned long long B,
  69 + unsigned long long header_offset,
  70 + std::vector<double> wavelengths){
66 71  
67 72 //copy the wavelengths to the BSQ file structure
68 73 w = wavelengths;
69 74 //copy the wavelengths to the structure
70 75 offset = header_offset;
71 76  
72   - return open(filename, vec<unsigned int>(X, Y, B), header_offset);
  77 + return open(filename, vec<unsigned long long>(X, Y, B), header_offset);
73 78 }
74 79  
75 80 /// Retrieve a single band (based on index) and stores it in pre-allocated memory.
76 81  
77 82 /// @param p is a pointer to an allocated region of memory at least X * Y * sizeof(T) in size.
78 83 /// @param page <= B is the integer number of the band to be copied.
79   - bool band_index( T * p, unsigned int page){
  84 + bool band_index( T * p, unsigned long long page){
80 85 return read_plane_2(p, page); //call the binary read_plane function (don't let it update the progress)
81 86 }
82 87  
... ... @@ -88,10 +93,10 @@ public:
88 93 if(PROGRESS) progress = 0;
89 94 //if there are no wavelengths in the BSQ file
90 95 if(w.size() == 0)
91   - return band_index(p, (unsigned int)wavelength);
  96 + return band_index(p, (unsigned long long)wavelength);
92 97  
93   - unsigned int XY = X() * Y(); //calculate the number of pixels in a band
94   - unsigned page = 0;
  98 + unsigned long long XY = X() * Y(); //calculate the number of pixels in a band
  99 + unsigned long long page = 0;
95 100  
96 101  
97 102 //get the two neighboring bands (above and below 'wavelength')
... ... @@ -122,9 +127,9 @@ public:
122 127 p2=(T*)malloc( XY * sizeof(T));
123 128 band_index(p1, page - 1);
124 129 band_index(p2, page );
125   - for(unsigned i=0; i < XY; i++){
126   - double r = (double) (wavelength - w[page-1]) / (double) (w[page] - w[page-1]);
127   - p[i] = (p2[i] - p1[i]) * r + p1[i];
  130 + for(unsigned long long i=0; i < XY; i++){
  131 + double r = (wavelength - w[page-1]) / (w[page] - w[page-1]);
  132 + p[i] = (T)(((double)p2[i] - (double)p1[i]) * r + (double)p1[i]);
128 133 }
129 134 free(p1);
130 135 free(p2);
... ... @@ -142,7 +147,7 @@ public:
142 147 /// @param p is a pointer to pre-allocated memory at least B * sizeof(T) in size.
143 148 /// @param x is the x-coordinate (dimension 1) of the spectrum.
144 149 /// @param y is the y-coordinate (dimension 2) of the spectrum.
145   - bool spectrum(T * p, unsigned x, unsigned y, bool PROGRESS = false){
  150 + bool spectrum(T * p, unsigned long long x, unsigned long long y, bool PROGRESS = false){
146 151 return read_line_2(p, x, y, PROGRESS);
147 152 }
148 153  
... ... @@ -150,16 +155,16 @@ public:
150 155  
151 156 /// @param p is a pointer to pre-allocated memory at least sizeof(T) in size.
152 157 /// @param n is an integer index to the pixel using linear array indexing.
153   - bool pixel(T * p, unsigned n){
  158 + bool pixel(T * p, unsigned long long n){
154 159  
155   - unsigned bandnum = X() * Y(); //calculate numbers in one band
  160 + unsigned long long bandnum = X() * Y(); //calculate numbers in one band
156 161 if ( n >= bandnum){ //make sure the pixel number is right
157 162 std::cout<<"ERROR: sample or line out of range"<<std::endl;
158 163 return false;
159 164 }
160 165  
161 166 file.seekg(n * sizeof(T) + binary<T>::header, std::ios::beg); //point to the certain pixel
162   - for (unsigned i = 0; i < Z(); i++)
  167 + for (unsigned long long i = 0; i < Z(); i++)
163 168 {
164 169 file.read((char *)(p + i), sizeof(T));
165 170 file.seekg((bandnum - 1) * sizeof(T), std::ios::cur); //go to the next band
... ... @@ -174,20 +179,20 @@ public:
174 179 /// @param wls is the list of baseline points based on band labels.
175 180 bool baseline(std::string outname, std::vector<double> wls, unsigned char* mask = NULL, bool PROGRESS = false )
176 181 {
177   - unsigned N = wls.size(); //get the number of baseline points
  182 + size_t N = wls.size(); //get the number of baseline points
178 183  
179 184 std::ofstream target(outname.c_str(), std::ios::binary); //open the target binary file
180 185 std::string headername = outname + ".hdr"; //the header file name
181 186  
182 187 //simplify image resolution
183   - unsigned int B = Z(); //calculate the number of bands
184   - unsigned int XY = X() * Y(); //calculate the number of pixels in a band
185   - unsigned int S = XY * sizeof(T); //calculate the number of bytes in a band
  188 + unsigned long long B = Z(); //calculate the number of bands
  189 + unsigned long long XY = X() * Y(); //calculate the number of pixels in a band
  190 + unsigned long long S = XY * sizeof(T); //calculate the number of bytes in a band
186 191  
187 192 double ai, bi; //stores the two baseline points wavelength surrounding the current band
188 193 double ci; //stores the current band's wavelength
189 194  
190   - unsigned control=0;
  195 + unsigned long long control=0;
191 196  
192 197 T * a; //pointers to the high and low band images
193 198 T * b;
... ... @@ -222,7 +227,7 @@ public:
222 227 band(b, bi);
223 228  
224 229 //correct every band
225   - for(unsigned cii = 0; cii < B; cii++){
  230 + for(unsigned long long cii = 0; cii < B; cii++){
226 231  
227 232 //update baseline points, if necessary
228 233 if( w[cii] >= bi && cii != B - 1) {
... ... @@ -255,7 +260,7 @@ public:
255 260 ci = w[cii];
256 261  
257 262 //perform the baseline correction
258   - for(unsigned i=0; i < XY; i++){
  263 + for(unsigned long long i=0; i < XY; i++){
259 264 if(mask != NULL && !mask[i]) //if the pixel is excluded by a mask
260 265 c[i] = 0; //set the value to zero
261 266 else{
... ... @@ -287,9 +292,9 @@ public:
287 292 /// @param t is a threshold specified such that a spectrum with a value at w less than t is set to zero. Setting this threshold allows the user to limit division by extremely small numbers.
288 293 bool normalize(std::string outname, double w, unsigned char* mask = NULL, bool PROGRESS = false)
289 294 {
290   - unsigned int B = Z(); //calculate the number of bands
291   - unsigned int XY = X() * Y(); //calculate the number of pixels in a band
292   - unsigned int S = XY * sizeof(T); //calculate the number of bytes in a band
  295 + unsigned long long B = Z(); //calculate the number of bands
  296 + unsigned long long XY = X() * Y(); //calculate the number of pixels in a band
  297 + unsigned long long S = XY * sizeof(T); //calculate the number of bytes in a band
293 298  
294 299 std::ofstream target(outname.c_str(), std::ios::binary); //open the target binary file
295 300 std::string headername = outname + ".hdr"; //the header file name
... ... @@ -302,10 +307,10 @@ public:
302 307  
303 308 band(b, w); //get the certain band into memory
304 309  
305   - for(unsigned j = 0; j < B; j++)
  310 + for(unsigned long long j = 0; j < B; j++)
306 311 {
307 312 band_index(c, j); //get the current band into memory
308   - for(unsigned i = 0; i < XY; i++)
  313 + for(unsigned long long i = 0; i < XY; i++)
309 314 {
310 315 if(mask != NULL && !mask[i])
311 316 c[i] = (T)0.0;
... ... @@ -333,26 +338,24 @@ public:
333 338 bool bil(std::string outname, bool PROGRESS = false)
334 339 {
335 340 //simplify image resolution
336   - //unsigned int L = X() * Z() * sizeof(T); //calculate the number of bytes of a ZX slice
337   - unsigned int jump = (Y() - 1) * X() * sizeof(T);
  341 + unsigned long long jump = (Y() - 1) * X() * sizeof(T);
338 342  
339 343 std::ofstream target(outname.c_str(), std::ios::binary);
340 344 std::string headername = outname + ".hdr";
341 345  
342   - unsigned int L = X();
  346 + unsigned long long L = X();
343 347 T* line = (T*)malloc(sizeof(T) * L);
344 348  
345   - for ( unsigned y = 0; y < Y(); y++) //for each y position
  349 + for ( unsigned long long y = 0; y < Y(); y++) //for each y position
346 350 {
347 351 file.seekg(y * X() * sizeof(T), std::ios::beg); //seek to the beginning of the xz slice
348   - for ( unsigned z = 0; z < Z(); z++ ) //for each band
  352 + for ( unsigned long long z = 0; z < Z(); z++ ) //for each band
349 353 {
350 354 file.read((char *)line, sizeof(T) * X()); //read a line
351 355 target.write((char*)line, sizeof(T) * X()); //write the line to the output file
352 356 file.seekg(jump, std::ios::cur); //seek to the next band
353 357 if(PROGRESS) progress = (double)((y+1) * Z() + z + 1) / (Z() * Y()) * 100; //update the progress counter
354 358 }
355   - //std::cout<<progress<<": "<<y<<std::endl;
356 359 }
357 360  
358 361 free(line);
... ... @@ -371,12 +374,12 @@ public:
371 374 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size.
372 375 bool baseline_band(double lb, double rb, T* lp, T* rp, double wavelength, T* result){
373 376  
374   - unsigned XY = X() * Y();
  377 + unsigned long long XY = X() * Y();
375 378 band(result, wavelength); //get band
376 379  
377 380 //perform the baseline correction
378 381 double r = (double) (wavelength - lb) / (double) (rb - lb);
379   - for(unsigned i=0; i < XY; i++){
  382 + for(unsigned long long i=0; i < XY; i++){
380 383 result[i] =(T) (result[i] - (rp[i] - lp[i]) * r - lp[i] );
381 384 }
382 385 return true;
... ... @@ -392,8 +395,8 @@ public:
392 395  
393 396 T* lp;
394 397 T* rp;
395   - unsigned XY = X() * Y();
396   - unsigned S = XY * sizeof(T);
  398 + unsigned long long XY = X() * Y();
  399 + unsigned long long S = XY * sizeof(T);
397 400 lp = (T*) malloc(S); //memory allocation
398 401 rp = (T*) malloc(S);
399 402  
... ... @@ -422,8 +425,8 @@ public:
422 425 T* cur; //current band 1
423 426 T* cur2; //current band 2
424 427  
425   - unsigned XY = X() * Y();
426   - unsigned S = XY * sizeof(T);
  428 + unsigned long long XY = X() * Y();
  429 + unsigned long long S = XY * sizeof(T);
427 430  
428 431 lp = (T*) malloc(S); //memory allocation
429 432 rp = (T*) malloc(S);
... ... @@ -433,9 +436,9 @@ public:
433 436 memset(result, (char)0, S);
434 437  
435 438 //find the wavelenght position in the whole band
436   - unsigned int n = w.size();
437   - unsigned int ai = 0; //left bound position
438   - unsigned int bi = n - 1; //right bound position
  439 + unsigned long long n = w.size();
  440 + unsigned long long ai = 0; //left bound position
  441 + unsigned long long bi = n - 1; //right bound position
439 442  
440 443  
441 444  
... ... @@ -464,23 +467,23 @@ public:
464 467 //calculate the beginning and the ending part
465 468 baseline_band(lb, rb, lp, rp, rab, cur2); //ending part
466 469 baseline_band(lb, rb, lp, rp, w[bi], cur);
467   - for(unsigned j = 0; j < XY; j++){
468   - result[j] += (rab - w[bi]) * (cur[j] + cur2[j]) / 2.0;
  470 + for(unsigned long long j = 0; j < XY; j++){
  471 + result[j] += (T)((rab - w[bi]) * ((double)cur[j] + (double)cur2[j]) / 2.0);
469 472 }
470 473 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
471 474 baseline_band(lb, rb, lp, rp, w[ai], cur);
472   - for(unsigned j = 0; j < XY; j++){
473   - result[j] += (w[ai] - lab) * (cur[j] + cur2[j]) / 2.0;
  475 + for(unsigned long long j = 0; j < XY; j++){
  476 + result[j] += (T)((w[ai] - lab) * ((double)cur[j] + (double)cur2[j]) / 2.0);
474 477 }
475 478  
476 479 //calculate the area
477 480 ai++;
478   - for(unsigned i = ai; i <= bi ;i++)
  481 + for(unsigned long long i = ai; i <= bi ;i++)
479 482 {
480 483 baseline_band(lb, rb, lp, rp, w[ai], cur2);
481   - for(unsigned j = 0; j < XY; j++)
  484 + for(unsigned long long j = 0; j < XY; j++)
482 485 {
483   - result[j] += (w[ai] - w[ai-1]) * (cur[j] + cur2[j]) / 2.0;
  486 + result[j] += (T)((w[ai] - w[ai-1]) * ((double)cur[j] + (double)cur2[j]) / 2.0);
484 487 }
485 488 std::swap(cur,cur2); //swap the band pointers
486 489 }
... ... @@ -510,7 +513,7 @@ public:
510 513 height(lb1, rb1, pos1, p1);
511 514 height(lb2, rb2, pos2, p2);
512 515 //calculate the ratio in result
513   - for(unsigned i = 0; i < X() * Y(); i++){
  516 + for(unsigned long long i = 0; i < X() * Y(); i++){
514 517 if(p1[i] == 0 && p2[i] ==0)
515 518 result[i] = 1;
516 519 else
... ... @@ -541,7 +544,7 @@ public:
541 544 area(lb1, rb1, lab1, rab1, p1);
542 545 height(lb2, rb2, pos, p2);
543 546 //calculate the ratio in result
544   - for(unsigned i = 0; i < X() * Y(); i++){
  547 + for(unsigned long long i = 0; i < X() * Y(); i++){
545 548 if(p1[i] == 0 && p2[i] ==0)
546 549 result[i] = 1;
547 550 else
... ... @@ -574,7 +577,7 @@ public:
574 577 area(lb1, rb1, lab1, rab1, p1);
575 578 area(lb2, rb2, lab2, rab2, p2);
576 579 //calculate the ratio in result
577   - for(unsigned i = 0; i < X() * Y(); i++){
  580 + for(unsigned long long i = 0; i < X() * Y(); i++){
578 581 if(p1[i] == 0 && p2[i] ==0)
579 582 result[i] = 1;
580 583 else
... ... @@ -599,8 +602,8 @@ public:
599 602 T* cur; //current band 1
600 603 T* cur2; //current band 2
601 604  
602   - unsigned XY = X() * Y();
603   - unsigned S = XY * sizeof(T);
  605 + unsigned long long XY = X() * Y();
  606 + unsigned long long S = XY * sizeof(T);
604 607  
605 608 lp = (T*) malloc(S); //memory allocation
606 609 rp = (T*) malloc(S);
... ... @@ -610,9 +613,9 @@ public:
610 613 memset(result, (char)0, S);
611 614  
612 615 //find the wavelenght position in the whole band
613   - unsigned int n = w.size();
614   - unsigned int ai = 0; //left bound position
615   - unsigned int bi = n - 1; //right bound position
  616 + unsigned long long n = w.size();
  617 + unsigned long long ai = 0; //left bound position
  618 + unsigned long long bi = n - 1; //right bound position
616 619  
617 620 //to make sure the left and the right bound are in the bandwidth
618 621 if (lb < w[0] || rb < w[0] || lb > w[n-1] || rb >w[n-1]){
... ... @@ -639,23 +642,23 @@ public:
639 642 //calculate the beginning and the ending part
640 643 baseline_band(lb, rb, lp, rp, rab, cur2); //ending part
641 644 baseline_band(lb, rb, lp, rp, w[bi], cur);
642   - for(unsigned j = 0; j < XY; j++){
643   - result[j] += (rab - w[bi]) * (rab + w[bi]) * (cur[j] + cur2[j]) / 4.0;
  645 + for(unsigned long long j = 0; j < XY; j++){
  646 + result[j] += (T)((rab - w[bi]) * (rab + w[bi]) * ((double)cur[j] + (double)cur2[j]) / 4.0);
644 647 }
645 648 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
646 649 baseline_band(lb, rb, lp, rp, w[ai], cur);
647   - for(unsigned j = 0; j < XY; j++){
648   - result[j] += (w[ai] - lab) * (w[ai] + lab) * (cur[j] + cur2[j]) / 4.0;
  650 + for(unsigned long long j = 0; j < XY; j++){
  651 + result[j] += (T)((w[ai] - lab) * (w[ai] + lab) * ((double)cur[j] + (double)cur2[j]) / 4.0);
649 652 }
650 653  
651 654 //calculate f(x) times x
652 655 ai++;
653   - for(unsigned i = ai; i <= bi ;i++)
  656 + for(unsigned long long i = ai; i <= bi ;i++)
654 657 {
655 658 baseline_band(lb, rb, lp, rp, w[ai], cur2);
656   - for(unsigned j = 0; j < XY; j++)
  659 + for(unsigned long long j = 0; j < XY; j++)
657 660 {
658   - result[j] += (w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * (cur[j] + cur2[j]) / 4.0;
  661 + result[j] += (T)((w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * ((double)cur[j] + (double)cur2[j]) / 4.0);
659 662 }
660 663 std::swap(cur,cur2); //swap the band pointers
661 664 }
... ... @@ -682,7 +685,7 @@ public:
682 685 x_area(lb, rb, lab, rab, p1);
683 686 area(lb, rb, lab, rab, p2);
684 687 //calculate the ratio in result
685   - for(unsigned i = 0; i < X() * Y(); i++){
  688 + for(unsigned long long i = 0; i < X() * Y(); i++){
686 689 if(p1[i] == 0 && p2[i] ==0)
687 690 result[i] = 1;
688 691 else
... ... @@ -706,13 +709,13 @@ public:
706 709 T* temp = (T*)malloc(X() * Y() * sizeof(T)); //allocate memory for the certain band
707 710 band(temp, mask_band);
708 711  
709   - for (unsigned int i = 0; i < X() * Y(); i++) {
  712 + for (unsigned long long i = 0; i < X() * Y(); i++) {
710 713 if (temp[i] < threshold)
711 714 p[i] = 0;
712 715 else
713 716 p[i] = 255;
714 717  
715   - if(PROGRESS) progress = (double) (i+1) / (X() * Y());
  718 + if(PROGRESS) progress = (double) (i+1) / (X() * Y()) * 100;
716 719 }
717 720  
718 721 free(temp);
... ... @@ -728,15 +731,15 @@ public:
728 731  
729 732 std::ofstream target(outfile.c_str(), std::ios::binary);
730 733  
731   - unsigned XY = X() * Y(); //calculate number of a band
732   - unsigned L = XY * sizeof(T);
  734 + unsigned long long XY = X() * Y(); //calculate number of a band
  735 + unsigned long long L = XY * sizeof(T);
733 736  
734 737 T * temp = (T*)malloc(L);
735 738  
736   - for (unsigned i = 0; i < Z(); i++) //for each spectral bin
  739 + for (unsigned long long i = 0; i < Z(); i++) //for each spectral bin
737 740 {
738 741 band_index(temp, i); //get the specified band (by index)
739   - for ( unsigned j = 0; j < XY; j++) // for each pixel
  742 + for ( unsigned long long j = 0; j < XY; j++) // for each pixel
740 743 {
741 744 if(p[j] == 0){ //if the mask is 0 at that pixel
742 745 temp[j] = 0; //set temp to zero
... ... @@ -787,56 +790,24 @@ public:
787 790  
788 791 return true;
789 792 }
790   -
791   - /// Saves only those spectra corresponding to mask value != 0 to pre-allocated memory
792   - /// @param matrix is the destination for the sifted pixels
793   - /// @param p is the mask file used for sifting
794   - /*bool sift(T* matrix, unsigned char* p){
795   -
796   - // open a band (XY plane)
797   - unsigned long XY = X() * Y(); //Number of XY pixels
798   - unsigned long L = XY * sizeof(T); //size of XY pixels
799   -
800   - //count the number of masked pixels
801   - unsigned long P = 0; //allocate space for the number of pixels
802   - for(unsigned long xy = 0; xy < XY; xy++){ //count the number of pixels
803   - if(p[xy] != 0) P++;
804   - }
805   -
806   - T* bandvals = (T*) malloc(sizeof(T) * P); //allocate a temporary array to store the pixels for a single band
807   - memset(matrix, 0, sizeof(T) * P * Z());
808   - for (unsigned long z = 0; z < Z(); z++){ //for each band
809   -
810   - if(!sift_band(bandvals, z, p)){
811   - std::cout<<"ERROR sifting band index "<<z<<std::endl;
812   - exit(1);
813   - }
814   -
815   - for(unsigned long p = 0; p < P; p++) //for each pixel in the array representing a single band
816   - matrix[p * Z() + z] = bandvals[p]; //copy it to the appropriate location in the matrix
817   - }
818   -
819   - free(bandvals); //clean up temporary memory
820   - return true;
821   - }*/
822   -
  793 +
823 794 /// Saves to disk only those spectra corresponding to mask values != 0
824 795 /// @param outfile is the name of the sifted ENVI file to be written to disk
825 796 /// @param unsigned char* p is the mask file used for sifting
826 797 bool sift(std::string outfile, unsigned char* p, bool PROGRESS = false){
827 798 std::ofstream target(outfile.c_str(), std::ios::binary);
828 799 // open a band (XY plane)
829   - unsigned long XY = X() * Y(); //Number of XY pixels
830   - unsigned long L = XY * sizeof(T); //size of XY pixels
  800 + unsigned long long XY = X() * Y(); //Number of XY pixels
  801 + unsigned long long L = XY * sizeof(T); //size of XY pixels
831 802 unsigned long long B = Z();
832 803  
833 804 T * temp = (T*)malloc(L); //allocate memory for a band
834 805 T * temp_vox = (T*)malloc(sizeof(T)); //allocate memory for one voxel
835 806  
836   - for (unsigned long i = 0; i < B; i++) //for each spectral bin
  807 + for (unsigned long long i = 0; i < B; i++) //for each spectral bin
837 808 {
838 809 band_index(temp, i); //get the specified band (XY sheet by index)
839   - for (unsigned long j = 0; j < XY; j++) // for each pixel
  810 + for (unsigned long long j = 0; j < XY; j++) // for each pixel
840 811 {
841 812 if (p[j] != 0){ //if the mask is != 0 at that pixel
842 813 temp_vox[0] = temp[j];
... ... @@ -844,9 +815,7 @@ public:
844 815 }
845 816 else{
846 817 continue;
847   - }
848   -
849   -
  818 + }
850 819 }
851 820 if(PROGRESS) progress = (double)(i+1)/ B * 100;
852 821 }
... ... @@ -859,7 +828,7 @@ public:
859 828 }
860 829  
861 830 /// Generates a spectral image from a matrix of spectral values in lexicographic order and a mask
862   - bool unsift(std::string outfile, unsigned char* p, unsigned int samples, unsigned int lines){
  831 + bool unsift(std::string outfile, unsigned char* p, unsigned long long samples, unsigned long long lines){
863 832  
864 833 //create a binary output stream
865 834 std::ofstream target(outfile.c_str(), std::ios::binary);
... ... @@ -873,9 +842,9 @@ public:
873 842 std::cout<<"started sifting"<<std::endl;
874 843  
875 844 //get the number of pixels and bands in the input image
876   - unsigned long P = X(); //Number of pixels
877   - unsigned long B = Z(); //number of bands
878   - unsigned long XY = samples * lines; //total number of pixels in an unsifted image
  845 + unsigned long long P = X(); //Number of pixels
  846 + unsigned long long B = Z(); //number of bands
  847 + unsigned long long XY = samples * lines; //total number of pixels in an unsifted image
879 848  
880 849 // allocate memory for a sifted band
881 850 T * sifted = (T*)malloc(P * sizeof(T)); //allocate memory for a band
... ... @@ -884,16 +853,16 @@ public:
884 853 T* unsifted = (T*) malloc(XY * sizeof(T));
885 854  
886 855 //for each band
887   - for(unsigned long b = 0; b < B; b++){
  856 + for(unsigned long long b = 0; b < B; b++){
888 857  
889 858 //set the unsifted index value to zero
890   - unsigned long i = 0;
  859 + unsigned long long i = 0;
891 860  
892 861 //retrieve the sifted band (masked pixels only)
893 862 band_index(sifted, b);
894 863  
895 864 //for each pixel in the final image (treat it as a 1D image)
896   - for(unsigned long xi = 0; xi < XY; xi++){
  865 + for(unsigned long long xi = 0; xi < XY; xi++){
897 866 if( p[xi] == 0 )
898 867 unsifted[xi] = 0;
899 868 else{
... ... @@ -923,13 +892,13 @@ public:
923 892 T* temp = (T*)malloc(sizeof(T) * XY);
924 893 //initialize p
925 894 band_index(p, 0);
926   - for (unsigned j = 0; j < XY; j++){
  895 + for (unsigned long long j = 0; j < XY; j++){
927 896 p[j] /= (T)Z();
928 897 }
929 898 //get every band and add them all
930   - for (unsigned i = 1; i < Z(); i++){
  899 + for (unsigned long long i = 1; i < Z(); i++){
931 900 band_index(temp, i);
932   - for (unsigned j = 0; j < XY; j++){
  901 + for (unsigned long long j = 0; j < XY; j++){
933 902 p[j] += temp[j]/(T)Z();
934 903 }
935 904 }
... ... @@ -966,54 +935,7 @@ public:
966 935 free(temp);
967 936 return true;
968 937 }
969   -
970   - /// Calculate the covariance matrix for all masked pixels in the image.
971   -
972   - /// @param co is a pointer to pre-allocated memory of size [B * B] that stores the resulting covariance matrix
973   - /// @param avg is a pointer to memory of size B that stores the average spectrum
974   - /// @param mask is a pointer to memory of size [X * Y] that stores the mask value at each pixel location
975   - /*bool co_matrix(double* co, double* avg, unsigned char *mask){
976   - progress = 0; //initialize thread data for timers and progress bars
977   - //memory allocation
978   - unsigned long long xy = X() * Y();
979   - unsigned long long B = Z();
980   - T* bandi = (T*)malloc(sizeof(T) * xy);
981   - T* bandj = (T*)malloc(sizeof(T) * xy);
982   -
983   - //count vaild pixels in a band
984   - unsigned long long count = 0;
985   - for (unsigned long long j = 0; j < xy; j++){
986   - if (mask == NULL || mask[j] != 0){
987   - count++;
988   - }
989   - }
990   - //calculate correlation coefficient matrix
991   - for (unsigned long long i = 0; i < B; i++)
992   - {
993   - band_index(bandi, i);
994   - for (unsigned long long j = i; j < B; j++){
995   - band_index(bandj, j);
996   - double numerator = 0; //to calculate element in correlation coefficient matrix, numerator part
997   - //calculate the R(i,j) in correlation coeffient matrix
998   - for (unsigned long long k = 0; k < xy; k++){
999   - if (mask == NULL || mask[k] != 0){
1000   - numerator += ((double)bandi[k] - (double)avg[i]) * ((double)bandj[k] - (double)avg[j]) / (double)count;
1001   - }
1002   - }
1003   - co[i*B + j] = numerator;
1004   - co[j*B + i] = numerator; //because correlated matrix is a symmetric matrix
1005   - }
1006   - progress = (double)i / B * 100;
1007   - }
1008   - free(bandi);
1009   - free(bandj);
1010   -
1011   - progress = 100; //processing complete
1012   -
1013   - return true;
1014   - }*/
1015   -
1016   -
  938 +
1017 939 /// Crop a region of the image and save it to a new file.
1018 940  
1019 941 /// @param outfile is the file name for the new cropped image
... ... @@ -1055,7 +977,7 @@ public:
1055 977 //for each band
1056 978 for (unsigned long long z = b0; z < b1; z++)
1057 979 {
1058   - for (unsigned y = 0; y < lines; y++)
  980 + for (unsigned long long y = 0; y < lines; y++)
1059 981 {
1060 982 file.read((char *)(temp + y * samples), sizeof(T) * samples);
1061 983 file.seekg(jumpl, std::ios::cur); //go to the next band
... ...
stim/envi/envi.h
... ... @@ -69,7 +69,7 @@ public:
69 69 }
70 70  
71 71 /// Returns the progress of the current processing operation as a percentage
72   - unsigned int progress(){
  72 + double progress(){
73 73  
74 74 if(header.interleave == envi_header::BSQ){ //if the infile is bsq file
75 75 if(header.data_type ==envi_header::float32)
... ... @@ -105,31 +105,29 @@ public:
105 105 }
106 106  
107 107 /// Allocate memory for a new ENVI file based on the current interleave format (BIP, BIL, BSQ) and data type.
108   - bool allocate(){
  108 + void allocate(){
109 109  
110 110 file = NULL; //set file to a NULL pointer
111 111  
112 112 if(header.interleave == envi_header::BSQ){
113 113 if(header.data_type ==envi_header::float32)
114   - return(file = new bsq<float>());
  114 + file = new bsq<float>();
115 115 else if(header.data_type == envi_header::float64)
116   - return(file = new bsq<double>());
  116 + file = new bsq<double>();
117 117 }
118 118 else if(header.interleave == envi_header::BIP){
119 119 if(header.data_type ==envi_header::float32)
120   - return(file = new bip<float>());
  120 + file = new bip<float>();
121 121 else if(header.data_type == envi_header::float64)
122   - return(file = new bip<double>());
  122 + file = new bip<double>();
123 123 }
124 124 else if(header.interleave == envi_header::BIL){
125 125 if(header.data_type ==envi_header::float32)
126   - return(file = new bil<float>());
  126 + file = new bil<float>();
127 127 else if(header.data_type == envi_header::float64)
128   - return(file = new bil<double>());
  128 + file = new bil<double>();
129 129 }
130 130  
131   - exit(1); //if the function hasn't already returned, we don't handle this state
132   -
133 131 }
134 132  
135 133 /// Open a previously opened ENVI file
... ... @@ -179,11 +177,13 @@ public:
179 177 /// @param filename is the name of the ENVI binary file
180 178 /// @param header is an ENVI header structure
181 179 bool open(std::string filename, stim::envi_header h){
182   - allocate();
  180 +
183 181  
184 182 header = h; //store the header
185 183 fname = filename; //save the filename
186 184  
  185 + allocate();
  186 +
187 187 return open(); //open the ENVI file;
188 188  
189 189  
... ... @@ -294,7 +294,7 @@ public:
294 294 }
295 295 }
296 296  
297   - void project(std::string outfile, double* center, double* basis, unsigned long long M, bool PROGRESS = false){
  297 + void project(std::string outfile, double* center, double* basis, unsigned long long M, unsigned char* mask, bool PROGRESS = false){
298 298 if(header.interleave == envi_header::BSQ){ //if the infile is bsq file
299 299 std::cout<<"ERROR: BSQ projection not supported"<<std::endl;
300 300 exit(1);
... ... @@ -307,9 +307,9 @@ public:
307 307  
308 308 else if(header.interleave == envi_header::BIP){ //if the infile is bip file
309 309 if(header.data_type ==envi_header::float32)
310   - ((bip<float>*)file)->project(outfile, center, basis, M, PROGRESS);
  310 + ((bip<float>*)file)->project(outfile, center, basis, M, mask, PROGRESS);
311 311 else if(header.data_type == envi_header::float64)
312   - ((bip<double>*)file)->project(outfile, center, basis, M, PROGRESS);
  312 + ((bip<double>*)file)->project(outfile, center, basis, M, mask, PROGRESS);
313 313 else{
314 314 std::cout<<"ERROR: unidentified data type"<<std::endl;
315 315 exit(1);
... ... @@ -318,6 +318,8 @@ public:
318 318  
319 319 stim::envi_header out_hdr = header;
320 320 out_hdr.bands = M; //set the number of bands in the output header
  321 + out_hdr.wavelength.clear();
  322 + out_hdr.band_names.clear();
321 323 out_hdr.save(outfile + ".hdr"); //save the output header
322 324 }
323 325  
... ... @@ -577,9 +579,9 @@ public:
577 579 {
578 580  
579 581 //calculate the number of non-zero values in the mask
580   - unsigned int nnz = 0;
581   - unsigned int npixels = header.lines * header.samples;
582   - for(unsigned int i = 0; i < npixels; i++)
  582 + unsigned long long nnz = 0;
  583 + unsigned long long npixels = header.lines * header.samples;
  584 + for(unsigned long long i = 0; i < npixels; i++)
583 585 if( p[i] > 0 ) nnz++;
584 586  
585 587 //create a new header
... ... @@ -625,12 +627,10 @@ public:
625 627 std::cout << "ERROR: unidentified file type" << std::endl;
626 628 exit(1);
627 629 }
628   -
629   -
630 630 return false;
631 631 }
632 632  
633   - bool unsift(std::string outfile, unsigned char* mask, unsigned int samples, unsigned int lines){
  633 + bool unsift(std::string outfile, unsigned char* mask, unsigned long long samples, unsigned long long lines){
634 634  
635 635 //create a new header
636 636 envi_header new_header = header;
... ... @@ -976,7 +976,7 @@ public:
976 976 /// @param ptr is a pointer to pre-allocated memory of size B*sizeof(T)
977 977 /// @param x is the x-coordinate of the spectrum
978 978 /// @param y is the y-coordinate of the spectrum
979   - bool spectrum(void* ptr, unsigned int x, unsigned int y, bool PROGRESS = false){
  979 + bool spectrum(void* ptr, unsigned long long x, unsigned long long y, bool PROGRESS = false){
980 980  
981 981 if(header.interleave == envi_header::BSQ){ //if the infile is bsq file
982 982 if(header.data_type ==envi_header::float32)
... ... @@ -1015,7 +1015,7 @@ public:
1015 1015  
1016 1016 /// @param p is a pointer to an allocated region of memory at least X * Y * sizeof(T) in size.
1017 1017 /// @param page <= B is the integer number of the band to be copied.
1018   - bool band_index(void* ptr, unsigned int b){
  1018 + bool band_index(void* ptr, unsigned long long b){
1019 1019 if (header.interleave == envi_header::BSQ){ //if the infile is bsq file
1020 1020 if (header.data_type == envi_header::float32)
1021 1021 return ((bsq<float>*)file)->band_index((float*)ptr, b);
... ...
stim/envi/envi_header.h
... ... @@ -23,10 +23,10 @@ struct envi_header
23 23  
24 24 std::string description;
25 25  
26   - unsigned int samples; //x-axis
27   - unsigned int lines; //y-axis
28   - unsigned int bands; //spectral axis
29   - unsigned int header_offset; //header offset for binary file (in bytes)
  26 + unsigned long long samples; //x-axis
  27 + unsigned long long lines; //y-axis
  28 + unsigned long long bands; //spectral axis
  29 + unsigned long long header_offset; //header offset for binary file (in bytes)
30 30 std::string file_type; //should be "ENVI Standard"
31 31  
32 32 envi_header::dataType data_type; //data representation; common value is 4 (32-bit float)
... ... @@ -81,7 +81,7 @@ struct envi_header
81 81 if(line.length() == 0)
82 82 return line;
83 83 //trims whitespace from the beginning and end of line
84   - unsigned int start_i, end_i;
  84 + size_t start_i, end_i;
85 85 for(start_i=0; start_i < line.length(); start_i++)
86 86 if(line[start_i] != 32)
87 87 {
... ... @@ -307,7 +307,7 @@ struct envi_header
307 307 }
308 308  
309 309 //make sure the number of bands matches the number of wavelengths
310   - unsigned int wavelengths = wavelength.size();
  310 + size_t wavelengths = wavelength.size();
311 311 if(wavelengths && bands != wavelengths)
312 312 {
313 313 std::cout<<"ENVI Header Error -- Number of wavelengths doesn't match the number of bands. Bands = "<<bands<<", Wavelengths = "<<wavelength.size()<<std::endl;
... ...
stim/envi/hsi.h 0 โ†’ 100644
  1 +#ifndef STIM_HSI_H
  2 +#define STIM_HSI_H
  3 +
  4 +#include "../envi/envi_header.h"
  5 +#include "../envi/binary.h"
  6 +#include <cstring>
  7 +#include <utility>
  8 +
  9 +namespace stim{
  10 +
  11 +/**
  12 + The BIL class represents a 3-dimensional binary file stored using band interleaved by line (BIL) image encoding. The binary file is stored
  13 + such that X-Z "frames" are stored sequentially to form an image stack along the y-axis. When accessing the data sequentially on disk,
  14 + the dimensions read, from fastest to slowest, are X, Z, Y.
  15 +
  16 + This class is optimized for data streaming, and therefore supports extremely large (terabyte-scale) files. Data is loaded from disk
  17 + on request. Functions used to access data are written to support efficient reading.
  18 +*/
  19 +
  20 +template <typename T>
  21 +class hsi: public binary<T> {
  22 +
  23 +protected:
  24 + unsigned char O[3]; //order of dimensions (orientation on disk)
  25 + //[X Y B]: [0 1 2] = bsq, [0 2 1] = bil, [1 2 0] = bip
  26 +
  27 + std::vector<double> w; //band wavelengths
  28 +
  29 + unsigned long long X(){ return R[O[0]]; }
  30 + unsigned long long Y(){ return R[O[1]]; }
  31 + unsigned long long Z(){ return R[O[2]]; }
  32 +
  33 + /// Initialize axis orders based on common interleave formats
  34 + void init_bsq(){ O[0] = 0; O[1] = 1; O[2] = 2; }
  35 + void init_bil(){ O[0] = 0; O[1] = 2; O[2] = 1; }
  36 + void init_bip(){ O[0] = 1; O[1] = 2; O[2] = 0; }
  37 +
  38 + /// Calculate the number of masked pixels in a given mask
  39 + unsigned long long nnz(unsigned char* mask){
  40 + unsigned long long XY = X() * Y(); //calculate the total number of pixels in the HSI
  41 + if(mask == NULL) return XY; //if the mask is null, assume that all of the pixels are masked
  42 +
  43 + unsigned long long n = 0; //initialize the number of masked pixels to zero (0)
  44 + for(unsigned long long xy = 0; xy < XY; xy++) //for each pixel in the HSI
  45 + if(mask[xy]) n++; //if the mask value is nonzero, increment the number of masked pixels
  46 + return n; //return the number of masked pixels
  47 + }
  48 +
  49 + T lerp(double w, T low_v, double low_w, T high_v, double high_w){
  50 + if(low_w == high_w) return low_v; //if the interval is of zero length, just return one of the bounds
  51 + double alpha = (w - low_w) / (high_w - low_w); //calculate the interpolation factor
  52 + return (T)((1.0 - alpha) * low_v + alpha * high_v); //interpolate
  53 + }
  54 +
  55 + /// Gets the two band indices surrounding a given wavelength
  56 + void band_bounds(double wavelength, unsigned long long& low, unsigned long long& high){
  57 + unsigned long long B = Z();
  58 + for(high = 0; high < B; high++){
  59 + if(w[high] > wavelength) break;
  60 + }
  61 + low = 0;
  62 + if(high > 0)
  63 + low = high-1;
  64 + }
  65 +
  66 + /// Get the list of band numbers that bound a list of wavelengths
  67 + void band_bounds(std::vector<double> wavelengths,
  68 + std::vector<unsigned long long>& low_bands,
  69 + std::vector<unsigned long long>& high_bands){
  70 +
  71 + unsigned long long W = w.size(); //get the number of wavelengths in the list
  72 + low_bands.resize(W); //pre-allocate space for the band lists
  73 + high_bands.resize(W);
  74 +
  75 + for(unsigned long long wl = 0; wl < W; wl++){ //for each wavelength
  76 + band_bounds(wavelengths[wl], low_bands[wl], high_bands[wl]); //find the low and high bands
  77 + }
  78 + }
  79 +
  80 + /// Returns the interpolated in the given spectrum based on the given wavelength
  81 +
  82 + /// @param s is the spectrum in main memory of length Z()
  83 + /// @param wavelength is the wavelength value to interpolate out
  84 + T interp_spectrum(T* s, double wavelength){
  85 + unsigned long long low, high; //indices for the bands surrounding wavelength
  86 + band_bounds(wavelength, low, high); //get the surrounding band indices
  87 +
  88 + if(high == w.size()) return s[w.size()-1]; //if the high band is above the wavelength range, return the highest wavelength value
  89 +
  90 + return lerp(wavelength, s[low], w[low], s[high], w[high]);
  91 + }
  92 +
  93 + /// Returns the interpolated value corresponding to the given list of wavelengths
  94 + std::vector<T> interp_spectrum(T* s, std::vector<double> wavelengths){
  95 +
  96 + unsigned long long N = wavelengths.size(); //get the number of wavelength measurements
  97 +
  98 + std::vector<T> v; //allocate space for the resulting values
  99 + v.resize(wavelengths.size());
  100 + for(unsigned long long n = 0; n < N; n++){ //for each measurement
  101 + v[n] = interp_spectrum(s, wavelengths[n]); //interpolate the measurement
  102 + }
  103 + return v;
  104 + }
  105 +};
  106 +
  107 +} //end namespace STIM
  108 +
  109 +#endif
0 110 \ No newline at end of file
... ...
stim/image/CImg.h
... ... @@ -54,7 +54,7 @@
54 54  
55 55 // Set version number of the library.
56 56 #ifndef cimg_version
57   -#define cimg_version 169
  57 +#define cimg_version 170
58 58  
59 59 /*-----------------------------------------------------------
60 60 #
... ... @@ -2340,7 +2340,7 @@ namespace cimg_library_suffixed {
2340 2340 char *_message;
2341 2341 CImgException() { _message = new char[1]; *_message = 0; }
2342 2342 CImgException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgException",true); }
2343   - CImgException(const CImgException& e) {
  2343 + CImgException(const CImgException& e):std::exception(e) {
2344 2344 const int size = std::strlen(e._message);
2345 2345 _message = new char[size + 1];
2346 2346 std::strncpy(_message,e._message,size);
... ... @@ -2364,7 +2364,7 @@ namespace cimg_library_suffixed {
2364 2364 char *_message;
2365 2365 CImgAbortException() { _message = new char[1]; *_message = 0; }
2366 2366 CImgAbortException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgAbortException",true); }
2367   - CImgAbortException(const CImgAbortException& e) {
  2367 + CImgAbortException(const CImgAbortException& e):std::exception(e) {
2368 2368 const int size = std::strlen(e._message);
2369 2369 _message = new char[size + 1];
2370 2370 std::strncpy(_message,e._message,size);
... ... @@ -2442,7 +2442,7 @@ namespace cimg_library_suffixed {
2442 2442 static bool is_inf(const T) { return false; }
2443 2443 static bool is_nan(const T) { return false; }
2444 2444 static T min() { return ~max(); }
2445   - static T max() { return (T)(1UL<<(8*sizeof(T) - 1)); }
  2445 + static T max() { return (T)1<<(8*sizeof(T) - 1); }
2446 2446 static T inf() { return max(); }
2447 2447 static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; }
2448 2448 static const char* format() { return "%s"; }
... ... @@ -13726,8 +13726,9 @@ namespace cimg_library_suffixed {
13726 13726 char *user_function;
13727 13727  
13728 13728 unsigned int mempos, mem_img_median, debug_indent, init_size, result_dim;
  13729 + bool is_parallelizable, need_input_copy;
13729 13730 double *result;
13730   - const char *const calling_function;
  13731 + const char *const calling_function, *s_op, *ss_op;
13731 13732 typedef double (*mp_func)(_cimg_math_parser&);
13732 13733  
13733 13734 #define _cimg_mp_is_constant(arg) (memtype[arg]==1) // Is constant?
... ... @@ -13737,12 +13738,14 @@ namespace cimg_library_suffixed {
13737 13738 #define _cimg_mp_is_vector(arg) (memtype[arg]>1) // Is vector?
13738 13739 #define _cimg_mp_vector_size(arg) (_cimg_mp_is_scalar(arg)?0U:(unsigned int)memtype[arg] - 1) // Vector size
13739 13740 #define _cimg_mp_calling_function calling_function_s()._data
13740   -#define _cimg_mp_check_type(arg,n_arg,s_op,mode,N) check_type(arg,n_arg,s_op,mode,N,ss,se,saved_char)
13741   -#define _cimg_mp_check_constant(arg,n_arg,s_op,is_strict) check_constant(arg,n_arg,s_op,is_strict,ss,se,saved_char)
13742   -#define _cimg_mp_check_matrix_square(arg,n_arg,s_op) check_matrix_square(arg,n_arg,s_op,ss,se,saved_char)
13743   -#define _cimg_mp_check_vector0(dim,s_op) check_vector0(dim,s_op,ss,se,saved_char)
  13741 +#define _cimg_mp_op(s) s_op = s; ss_op = ss
  13742 +#define _cimg_mp_check_type(arg,n_arg,mode,N) check_type(arg,n_arg,mode,N,ss,se,saved_char)
  13743 +#define _cimg_mp_check_constant(arg,n_arg,is_strict) check_constant(arg,n_arg,is_strict,ss,se,saved_char)
  13744 +#define _cimg_mp_check_matrix_square(arg,n_arg) check_matrix_square(arg,n_arg,ss,se,saved_char)
  13745 +#define _cimg_mp_check_vector0(dim) check_vector0(dim,ss,se,saved_char)
  13746 +#define _cimg_mp_check_list(is_out) check_list(is_out,ss,se,saved_char)
13744 13747 #define _cimg_mp_defunc(mp) (*(mp_func)(*(mp).opcode))(mp)
13745   -#define _cimg_mp_return(x) { *se = saved_char; return x; }
  13748 +#define _cimg_mp_return(x) { *se = saved_char; s_op = previous_s_op; ss_op = previous_ss_op; return x; }
13746 13749 #define _cimg_mp_constant(val) _cimg_mp_return(constant(val))
13747 13750 #define _cimg_mp_scalar0(op) _cimg_mp_return(scalar0(op))
13748 13751 #define _cimg_mp_scalar1(op,i1) _cimg_mp_return(scalar1(op,i1))
... ... @@ -13763,19 +13766,22 @@ namespace cimg_library_suffixed {
13763 13766 code(_code),imgin(img_input),listin(list_input?*list_input:CImgList<T>::const_empty()),
13764 13767 imgout(img_output?*img_output:CImg<T>::empty()),listout(list_output?*list_output:CImgList<T>::empty()),
13765 13768 img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),user_function(0),
13766   - mem_img_median(~0U),debug_indent(0),init_size(0),result_dim(0),
13767   - calling_function(funcname?funcname:"cimg_math_parser") {
  13769 + mem_img_median(~0U),debug_indent(0),init_size(0),result_dim(0),is_parallelizable(true),
  13770 + need_input_copy(false),calling_function(funcname?funcname:"cimg_math_parser") {
13768 13771 if (!expression || !*expression)
13769 13772 throw CImgArgumentException("[_cimg_math_parser] "
13770 13773 "CImg<%s>::%s: Empty expression.",
13771 13774 pixel_type(),_cimg_mp_calling_function);
13772 13775 const char *_expression = expression;
13773   - while (*_expression && *_expression<=' ') ++_expression;
  13776 + while (*_expression && (*_expression<=' ' || *_expression==';')) ++_expression;
13774 13777 CImg<charT>::string(_expression).move_to(expr);
  13778 + char *ps = &expr.back() - 1;
  13779 + while (ps>expr._data && (*ps==' ' || *ps==';')) --ps;
  13780 + *(++ps) = 0; expr._width = ps - expr._data + 1;
13775 13781  
13776 13782 // Ease the retrieval of previous non-space characters afterwards.
13777 13783 pexpr.assign(expr._width);
13778   - const char *ps;
  13784 +
13779 13785 char c, *pe = pexpr._data;
13780 13786 for (ps = expr._data, c = ' '; *ps; ++ps) {
13781 13787 if (*ps!=' ') c = *ps;
... ... @@ -13854,6 +13860,7 @@ namespace cimg_library_suffixed {
13854 13860 // [11] = xm, [12] = ym, [13] = zm, [14] = cm, [15] = xM, [16] = yM, [17] = zM, [18]=cM, [19]=i0...[28]=i9,
13855 13861  
13856 13862 // Compile expression into a serie of opcodes.
  13863 + s_op = ""; ss_op = expr._data;
13857 13864 const unsigned int ind_result = compile(expr._data,expr._data + expr._width - 1,0,0);
13858 13865 p_code_end = code.end();
13859 13866  
... ... @@ -13867,6 +13874,7 @@ namespace cimg_library_suffixed {
13867 13874 reserved_label.assign();
13868 13875 expr.assign();
13869 13876 pexpr.assign();
  13877 + opcode.assign();
13870 13878 opcode._width = opcode._depth = opcode._spectrum = 1;
13871 13879 opcode._is_shared = true;
13872 13880  
... ... @@ -13888,7 +13896,7 @@ namespace cimg_library_suffixed {
13888 13896 imgin(CImg<T>::const_empty()),listin(CImgList<T>::const_empty()),
13889 13897 imgout(CImg<T>::empty()),listout(CImgList<T>::empty()),
13890 13898 img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),debug_indent(0),
13891   - result_dim(0),calling_function(0) {
  13899 + result_dim(0),is_parallelizable(true),need_input_copy(false),calling_function(0) {
13892 13900 mem.assign(1 + _cimg_mp_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()()
13893 13901 result = mem._data;
13894 13902 }
... ... @@ -13896,8 +13904,9 @@ namespace cimg_library_suffixed {
13896 13904 _cimg_math_parser(const _cimg_math_parser& mp):
13897 13905 mem(mp.mem),code(mp.code),p_code_begin(mp.p_code_begin),p_code_end(mp.p_code_end),
13898 13906 imgin(mp.imgin),listin(mp.listin),imgout(mp.imgout),listout(mp.listout),img_stats(mp.img_stats),
13899   - list_stats(mp.list_stats),list_median(mp.list_median),debug_indent(0),
13900   - result_dim(mp.result_dim), result(mem._data + (mp.result - mp.mem._data)),calling_function(0) {
  13907 + list_stats(mp.list_stats),list_median(mp.list_median),debug_indent(0),result_dim(mp.result_dim),
  13908 + is_parallelizable(mp.is_parallelizable), need_input_copy(mp.need_input_copy),
  13909 + result(mem._data + (mp.result - mp.mem._data)),calling_function(0) {
13901 13910 #ifdef cimg_use_openmp
13902 13911 mem[17] = omp_get_thread_num();
13903 13912 #endif
... ... @@ -13905,30 +13914,8 @@ namespace cimg_library_suffixed {
13905 13914 opcode._is_shared = true;
13906 13915 }
13907 13916  
13908   - // Return 'true' is the specified mathematical expression requires the input image to be copied.
13909   - // Set 'is_parallelizable' to 'false' if expression should be evaluated with a single thread.
13910   - static bool needs_input_copy(const char *expression, bool &is_parallelizable) {
13911   - if (!expression || *expression=='>' || *expression=='<') return is_parallelizable = false;
13912   - for (const char *s = expression; *s; ++s)
13913   - if ((*s=='i' || *s=='j' || *s=='I' || *s=='J') && (s[1]=='(' || s[1]=='[')) {
13914   - if (s[2]=='#') is_parallelizable = false;
13915   - else {
13916   - const char opening = s[1], ending = opening=='('?')':']';
13917   - const char *ns;
13918   - int level = 0;
13919   - for (ns = s + 2; *ns; ++ns) { // Find ending ')' or ']'.
13920   - if (*ns==ending && !level) break;
13921   - if (*ns==opening) ++level; else if (*ns==ending) --level;
13922   - }
13923   - if (*ns && (ns[1]!='=' || ns[2]=='=')) return true;
13924   - }
13925   - } else if (((*s=='R' || *s=='G' || *s=='B' || *s=='A' || *s=='I' || *s=='J') && s[1]!='#') ||
13926   - (*s=='i' && s[1]>='0' && s[1]<='7' && s[2]!='#')) return true;
13927   - return false;
13928   - }
13929   -
13930 13917 // Compilation procedure.
13931   - unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *p_ref) {
  13918 + unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *const p_ref) {
13932 13919 if (depth>256) {
13933 13920 cimg::strellipsize(expr,64);
13934 13921 throw CImgArgumentException("[_cimg_math_parser] "
... ... @@ -13954,10 +13941,15 @@ namespace cimg_library_suffixed {
13954 13941 if (se<=ss || !*ss) {
13955 13942 cimg::strellipsize(expr,64);
13956 13943 throw CImgArgumentException("[_cimg_math_parser] "
13957   - "CImg<%s>::%s: Missing item, in expression '%s'.",
13958   - pixel_type(),_cimg_mp_calling_function,
13959   - expr._data);
  13944 + "CImg<%s>::%s: %s%s Missing %s, in expression '%s%s%s'.",
  13945 + pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
  13946 + *s_op=='F'?"argument":"item",
  13947 + (ss_op - 4)>expr._data?"...":"",
  13948 + (ss_op - 4)>expr._data?ss_op - 4:expr._data,
  13949 + ss_op + std::strlen(ss_op)<&expr.back()?"...":"");
13960 13950 }
  13951 +
  13952 + const char *const previous_s_op = s_op, *const previous_ss_op = ss_op;
13961 13953 const unsigned int depth1 = depth + 1;
13962 13954 unsigned int pos, p1, p2, p3, arg1, arg2, arg3, arg4, arg5, arg6;
13963 13955 char
... ... @@ -13966,7 +13958,6 @@ namespace cimg_library_suffixed {
13966 13958 *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7, *const ss8 = ss + 8,
13967 13959 *s, *ps, *ns, *s0, *s1, *s2, *s3, sep = 0, end = 0;
13968 13960 double val, val1, val2;
13969   - const char *s_op;
13970 13961 mp_func op;
13971 13962  
13972 13963 // 'p_ref' is a 'unsigned int[7]' used to return a reference to an image or vector value
... ... @@ -14022,22 +14013,28 @@ namespace cimg_library_suffixed {
14022 14013 if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']);
14023 14014 _cimg_mp_scalar0(mp_i);
14024 14015 case 'I' :
  14016 + _cimg_mp_op("Variable 'I'");
14025 14017 if (reserved_label['I']!=~0U) _cimg_mp_return(reserved_label['I']);
14026   - _cimg_mp_check_vector0(imgin._spectrum,"variable 'I'");
  14018 + _cimg_mp_check_vector0(imgin._spectrum);
  14019 + need_input_copy = true;
14027 14020 pos = vector(imgin._spectrum);
14028 14021 CImg<uptrT>::vector((uptrT)mp_Joff,pos,0,0).move_to(code);
14029 14022 _cimg_mp_return(pos);
14030 14023 case 'R' :
14031 14024 if (reserved_label['R']!=~0U) _cimg_mp_return(reserved_label['R']);
  14025 + need_input_copy = true;
14032 14026 _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,0,0,0);
14033 14027 case 'G' :
14034 14028 if (reserved_label['G']!=~0U) _cimg_mp_return(reserved_label['G']);
  14029 + need_input_copy = true;
14035 14030 _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,1,0,0);
14036 14031 case 'B' :
14037 14032 if (reserved_label['B']!=~0U) _cimg_mp_return(reserved_label['B']);
  14033 + need_input_copy = true;
14038 14034 _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,2,0,0);
14039 14035 case 'A' :
14040 14036 if (reserved_label['A']!=~0U) _cimg_mp_return(reserved_label['A']);
  14037 + need_input_copy = true;
14041 14038 _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,3,0,0);
14042 14039 }
14043 14040 else if (ss2==se) { // Two-chars variable
... ... @@ -14048,6 +14045,7 @@ namespace cimg_library_suffixed {
14048 14045 if (*ss1>='0' && *ss1<='9') { // i0...i9
14049 14046 pos = 19 + *ss1 - '0';
14050 14047 if (reserved_label[pos]!=~0U) _cimg_mp_return(reserved_label[pos]);
  14048 + need_input_copy = true;
14051 14049 _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,pos - 19,0,0);
14052 14050 }
14053 14051 switch (*ss1) {
... ... @@ -14109,7 +14107,7 @@ namespace cimg_library_suffixed {
14109 14107 cimg::strpare(variable_name);
14110 14108 const unsigned int l_variable_name = (unsigned int)std::strlen(variable_name);
14111 14109 char *const ve1 = ss + l_variable_name - 1;
14112   - s_op = "Operator '='";
  14110 + _cimg_mp_op("Operator '='");
14113 14111  
14114 14112 // Assign image value (direct).
14115 14113 if (l_variable_name>2 && (*ss=='i' || *ss=='j' || *ss=='I' || *ss=='J') && (*ss1=='(' || *ss1=='[') &&
... ... @@ -14117,9 +14115,11 @@ namespace cimg_library_suffixed {
14117 14115 is_relative = *ss=='j' || *ss=='J';
14118 14116  
14119 14117 if (*ss1=='[' && *ve1==']') { // i/j/I/J[_#ind,offset] = value
  14118 + is_parallelizable = false;
14120 14119 if (*ss2=='#') { // Index specified
14121 14120 s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
14122 14121 p1 = compile(ss3,s0++,depth1,0);
  14122 + _cimg_mp_check_list(true);
14123 14123 } else { p1 = ~0U; s0 = ss2; }
14124 14124 arg1 = compile(s0,ve1,depth1,0); // Offset
14125 14125 arg2 = compile(s + 1,se,depth1,0); // Value to assign
... ... @@ -14130,9 +14130,9 @@ namespace cimg_library_suffixed {
14130 14130 p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
14131 14131 p2 = listin[p3]._spectrum;
14132 14132 }
14133   - _cimg_mp_check_vector0(p2,s_op);
  14133 + _cimg_mp_check_vector0(p2);
14134 14134 } else p2 = 0;
14135   - _cimg_mp_check_type(arg2,2,s_op,*ss>='i'?1:3,p2);
  14135 + _cimg_mp_check_type(arg2,2,*ss>='i'?1:3,p2);
14136 14136  
14137 14137 if (p_ref) {
14138 14138 *p_ref = _cimg_mp_is_vector(arg2)?4:2;
... ... @@ -14172,9 +14172,11 @@ namespace cimg_library_suffixed {
14172 14172 }
14173 14173  
14174 14174 if (*ss1=='(' && *ve1==')') { // i/j/I/J(_#ind,_x,_y,_z,_c) = value
  14175 + is_parallelizable = false;
14175 14176 if (*ss2=='#') { // Index specified
14176 14177 s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
14177 14178 p1 = compile(ss3,s0++,depth1,0);
  14179 + _cimg_mp_check_list(true);
14178 14180 } else { p1 = ~0U; s0 = ss2; }
14179 14181 arg1 = is_relative?0U:(unsigned int)_cimg_mp_x;
14180 14182 arg2 = is_relative?0U:(unsigned int)_cimg_mp_y;
... ... @@ -14184,9 +14186,9 @@ namespace cimg_library_suffixed {
14184 14186 if (s0<ve1) { // X or [ X,_Y,_Z,_C ]
14185 14187 s1 = s0; while (s1<ve1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
14186 14188 arg1 = compile(s0,s1,depth1,0);
14187   - if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z,C]
  14189 + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
14188 14190 p2 = _cimg_mp_vector_size(arg1); // Vector size
14189   - arg1 = arg1 + 1;
  14191 + ++arg1;
14190 14192 if (p2>1) {
14191 14193 arg2 = arg1 + 1;
14192 14194 if (p2>2) {
... ... @@ -14212,9 +14214,9 @@ namespace cimg_library_suffixed {
14212 14214 p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
14213 14215 p2 = listin[p3]._spectrum;
14214 14216 }
14215   - _cimg_mp_check_vector0(p2,s_op);
  14217 + _cimg_mp_check_vector0(p2);
14216 14218 } else p2 = 0;
14217   - _cimg_mp_check_type(arg5,2,s_op,*ss>='i'?1:3,p2);
  14219 + _cimg_mp_check_type(arg5,2,*ss>='i'?1:3,p2);
14218 14220  
14219 14221 if (p_ref) {
14220 14222 *p_ref = _cimg_mp_is_vector(arg5)?5:3;
... ... @@ -14272,7 +14274,7 @@ namespace cimg_library_suffixed {
14272 14274 arg1 = ~0U; // Vector slot
14273 14275 arg2 = compile(++s0,ve1,depth1,0); // Index
14274 14276 arg3 = compile(s + 1,se,depth1,0); // Value to assign
14275   - _cimg_mp_check_type(arg3,2,s_op,1,0);
  14277 + _cimg_mp_check_type(arg3,2,1,0);
14276 14278  
14277 14279 if (variable_name[1]) { // Multi-char variable
14278 14280 cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i])) {
... ... @@ -14307,8 +14309,8 @@ namespace cimg_library_suffixed {
14307 14309 }
14308 14310 }
14309 14311  
14310   - // Assign user-defined function.
14311   - if (l_variable_name>3 && *ve1==')' && *ss!='(') {
  14312 + // Assign user-defined macro.
  14313 + if (l_variable_name>2 && *ve1==')' && *ss!='(') {
14312 14314 s0 = ve1; while (s0>ss && *s0!='(') --s0;
14313 14315 is_sth = std::strncmp(variable_name,"debug(",6) &&
14314 14316 std::strncmp(variable_name,"print(",6); // is_valid_function_name?
... ... @@ -14454,7 +14456,7 @@ namespace cimg_library_suffixed {
14454 14456 }
14455 14457  
14456 14458 } else { // Variable already exists -> assign a new value
14457   - _cimg_mp_check_type(arg2,2,s_op,_cimg_mp_is_vector(arg1)?3:1,0);
  14459 + _cimg_mp_check_type(arg2,2,_cimg_mp_is_vector(arg1)?3:1,_cimg_mp_vector_size(arg1));
14458 14460 if (_cimg_mp_is_vector(arg1)) { // Vector
14459 14461 if (_cimg_mp_is_vector(arg2)) // From vector
14460 14462 CImg<uptrT>::vector((uptrT)mp_vector_copy,arg1,arg2,(uptrT)_cimg_mp_vector_size(arg1)).
... ... @@ -14478,7 +14480,7 @@ namespace cimg_library_suffixed {
14478 14480 arg2 = compile(s + 1,se,depth1,0); // Value to assign
14479 14481  
14480 14482 if (*ref==1) { // Vector value (scalar): V[k] = scalar
14481   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14483 + _cimg_mp_check_type(arg2,2,1,0);
14482 14484 arg3 = ref[1]; // Vector slot
14483 14485 arg4 = ref[2]; // Index
14484 14486 if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
... ... @@ -14488,7 +14490,8 @@ namespace cimg_library_suffixed {
14488 14490 }
14489 14491  
14490 14492 if (*ref==2) { // Image value (scalar): i/j[_#ind,off] = scalar
14491   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14493 + _cimg_mp_check_type(arg2,2,1,0);
  14494 + is_parallelizable = false;
14492 14495 p1 = ref[1]; // Index
14493 14496 is_relative = (bool)ref[2];
14494 14497 arg3 = ref[3]; // Offset
... ... @@ -14506,7 +14509,8 @@ namespace cimg_library_suffixed {
14506 14509 }
14507 14510  
14508 14511 if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) = scalar
14509   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14512 + _cimg_mp_check_type(arg2,2,1,0);
  14513 + is_parallelizable = false;
14510 14514 p1 = ref[1]; // Index
14511 14515 is_relative = (bool)ref[2];
14512 14516 arg3 = ref[3]; // X
... ... @@ -14527,7 +14531,8 @@ namespace cimg_library_suffixed {
14527 14531 }
14528 14532  
14529 14533 if (*ref==4) { // Image value (vector): I/J[_#ind,off] = value
14530   - _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14534 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
  14535 + is_parallelizable = false;
14531 14536 p1 = ref[1]; // Index
14532 14537 is_relative = (bool)ref[2];
14533 14538 arg3 = ref[3]; // Offset
... ... @@ -14553,7 +14558,8 @@ namespace cimg_library_suffixed {
14553 14558 }
14554 14559  
14555 14560 if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) = value
14556   - _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14561 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
  14562 + is_parallelizable = false;
14557 14563 p1 = ref[1]; // Index
14558 14564 is_relative = (bool)ref[2];
14559 14565 arg3 = ref[3]; // X
... ... @@ -14581,7 +14587,7 @@ namespace cimg_library_suffixed {
14581 14587 }
14582 14588  
14583 14589 if (_cimg_mp_is_vector(arg1)) { // Vector variable: V = value
14584   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14590 + _cimg_mp_check_type(arg2,2,1,0);
14585 14591 if (_cimg_mp_is_vector(arg2)) // From vector
14586 14592 CImg<uptrT>::vector((uptrT)mp_vector_copy,arg1,arg2,(uptrT)_cimg_mp_vector_size(arg1)).
14587 14593 move_to(code);
... ... @@ -14592,7 +14598,7 @@ namespace cimg_library_suffixed {
14592 14598 }
14593 14599  
14594 14600 if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s = scalar
14595   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14601 + _cimg_mp_check_type(arg2,2,1,0);
14596 14602 CImg<uptrT>::vector((uptrT)mp_copy,arg1,arg2).move_to(code);
14597 14603 _cimg_mp_return(arg1);
14598 14604  
... ... @@ -14615,28 +14621,28 @@ namespace cimg_library_suffixed {
14615 14621 for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1
14616 14622 if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps &&
14617 14623 level[s - expr._data]==clevel) { // Self-operators for complex numbers only (**=,//=,^^=)
14618   - s_op = *ps=='*'?"Operator '**='":*ps=='/'?"Operator '//='":"Operator '^^='";
  14624 + _cimg_mp_op(*ps=='*'?"Operator '**='":*ps=='/'?"Operator '//='":"Operator '^^='");
14619 14625  
14620 14626 ref.assign(7);
14621 14627 arg1 = compile(ss,ns,depth1,ref); // Vector slot
14622 14628 arg2 = compile(s + 1,se,depth1,0); // Right operand
14623 14629 if (*ps!='*') {
14624   - _cimg_mp_check_type(arg1,2,s_op,2,2);
14625   - _cimg_mp_check_type(arg2,2,s_op,2,2);
  14630 + _cimg_mp_check_type(arg1,2,2,2);
  14631 + _cimg_mp_check_type(arg2,2,2,2);
14626 14632 }
14627 14633 if (_cimg_mp_is_vector(arg2)) { // Complex **= complex or Matrix **= matrix
14628 14634 if (*ps=='*') {
14629 14635 if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2)
14630 14636 CImg<uptrT>::vector((uptrT)mp_complex_mul,arg1,arg1,arg2).move_to(code);
14631 14637 else {
14632   - _cimg_mp_check_matrix_square(arg2,2,s_op);
  14638 + _cimg_mp_check_matrix_square(arg2,2);
14633 14639 p3 = _cimg_mp_vector_size(arg1);
14634 14640 p2 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg2));
14635 14641 p1 = p3/p2;
14636 14642 if (p1*p2!=p3) {
14637 14643 *se = saved_char; cimg::strellipsize(expr,64);
14638 14644 throw CImgArgumentException("[_cimg_math_parser] "
14639   - "CImg<%s>::%s: %s: Sizes of left-hand and right-hand operands "
  14645 + "CImg<%s>::%s: %s: Types of left-hand and right-hand operands "
14640 14646 "('%s' and '%s') do not match, in expression '%s%s%s'.",
14641 14647 pixel_type(),_cimg_mp_calling_function,s_op,
14642 14648 s_type(arg1)._data,s_type(arg2)._data,
... ... @@ -14651,16 +14657,14 @@ namespace cimg_library_suffixed {
14651 14657 else
14652 14658 CImg<uptrT>::vector((uptrT)mp_complex_pow_vv,arg1,arg1,arg2).move_to(code);
14653 14659 } else { // Complex **= scalar
14654   - if (*ps=='*')
14655   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,2,(uptrT)mp_self_mul,arg2).move_to(code);
14656   - else if (*ps=='/')
14657   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,2,(uptrT)mp_self_div,arg2).move_to(code);
14658   - else
14659   - CImg<uptrT>::vector((uptrT)mp_complex_pow_vs,arg1,arg1,arg2).move_to(code);
  14660 + if (*ps=='*') self_vector_s(arg1,mp_self_mul,arg2);
  14661 + else if (*ps=='/') self_vector_s(arg1,mp_self_div,arg2);
  14662 + else CImg<uptrT>::vector((uptrT)mp_complex_pow_vs,arg1,arg1,arg2).move_to(code);
14660 14663 }
14661 14664  
14662 14665 // Write computed value back in image if necessary.
14663 14666 if (*ref==4) { // Image value (vector): I/J[_#ind,off] **= value
  14667 + is_parallelizable = false;
14664 14668 p1 = ref[1]; // Index
14665 14669 is_relative = (bool)ref[2];
14666 14670 arg3 = ref[3]; // Offset
... ... @@ -14676,6 +14680,7 @@ namespace cimg_library_suffixed {
14676 14680 }
14677 14681  
14678 14682 } else if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) **= value
  14683 + is_parallelizable = false;
14679 14684 p1 = ref[1]; // Index
14680 14685 is_relative = (bool)ref[2];
14681 14686 arg3 = ref[3]; // X
... ... @@ -14702,16 +14707,16 @@ namespace cimg_library_suffixed {
14702 14707 (*ps=='>' && *ns=='>') || (*ps=='<' && *ns=='<')) &&
14703 14708 level[s - expr._data]==clevel) { // Self-operators (+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=)
14704 14709 switch (*ps) {
14705   - case '+' : op = mp_self_add; s_op = "Operator '+='"; break;
14706   - case '-' : op = mp_self_sub; s_op = "Operator '-='"; break;
14707   - case '*' : op = mp_self_mul; s_op = "Operator '*='"; break;
14708   - case '/' : op = mp_self_div; s_op = "Operator '/='"; break;
14709   - case '%' : op = mp_self_modulo; s_op = "Operator '%='"; break;
14710   - case '<' : op = mp_self_bitwise_left_shift; s_op = "Operator '<<='"; break;
14711   - case '>' : op = mp_self_bitwise_right_shift; s_op = "Operator '>=='"; break;
14712   - case '&' : op = mp_self_bitwise_and; s_op = "Operator '&='"; break;
14713   - case '|' : op = mp_self_bitwise_or; s_op = "Operator '|='"; break;
14714   - default : op = mp_self_pow; s_op = "Operator '^='"; break;
  14710 + case '+' : op = mp_self_add; _cimg_mp_op("Operator '+='"); break;
  14711 + case '-' : op = mp_self_sub; _cimg_mp_op("Operator '-='"); break;
  14712 + case '*' : op = mp_self_mul; _cimg_mp_op("Operator '*='"); break;
  14713 + case '/' : op = mp_self_div; _cimg_mp_op("Operator '/='"); break;
  14714 + case '%' : op = mp_self_modulo; _cimg_mp_op("Operator '%='"); break;
  14715 + case '<' : op = mp_self_bitwise_left_shift; _cimg_mp_op("Operator '<<='"); break;
  14716 + case '>' : op = mp_self_bitwise_right_shift; _cimg_mp_op("Operator '>=='"); break;
  14717 + case '&' : op = mp_self_bitwise_and; _cimg_mp_op("Operator '&='"); break;
  14718 + case '|' : op = mp_self_bitwise_or; _cimg_mp_op("Operator '|='"); break;
  14719 + default : op = mp_self_pow; _cimg_mp_op("Operator '^='"); break;
14715 14720 }
14716 14721 s1 = *ps=='>' || *ps=='<'?ns:ps;
14717 14722  
... ... @@ -14725,7 +14730,7 @@ namespace cimg_library_suffixed {
14725 14730 }
14726 14731  
14727 14732 if (*ref==1) { // Vector value (scalar): V[k] += scalar
14728   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14733 + _cimg_mp_check_type(arg2,2,1,0);
14729 14734 arg3 = ref[1]; // Vector slot
14730 14735 arg4 = ref[2]; // Index
14731 14736 if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
... ... @@ -14736,7 +14741,8 @@ namespace cimg_library_suffixed {
14736 14741 }
14737 14742  
14738 14743 if (*ref==2) { // Image value (scalar): i/j[_#ind,off] += scalar
14739   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14744 + _cimg_mp_check_type(arg2,2,1,0);
  14745 + is_parallelizable = false;
14740 14746 p1 = ref[1]; // Index
14741 14747 is_relative = (bool)ref[2];
14742 14748 arg3 = ref[3]; // Offset
... ... @@ -14755,7 +14761,8 @@ namespace cimg_library_suffixed {
14755 14761 }
14756 14762  
14757 14763 if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) += scalar
14758   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14764 + _cimg_mp_check_type(arg2,2,1,0);
  14765 + is_parallelizable = false;
14759 14766 p1 = ref[1]; // Index
14760 14767 is_relative = (bool)ref[2];
14761 14768 arg3 = ref[3]; // X
... ... @@ -14777,17 +14784,13 @@ namespace cimg_library_suffixed {
14777 14784 }
14778 14785  
14779 14786 if (*ref==4) { // Image value (vector): I/J[_#ind,off] += value
14780   - _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14787 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
  14788 + is_parallelizable = false;
14781 14789 p1 = ref[1]; // Index
14782 14790 is_relative = (bool)ref[2];
14783 14791 arg3 = ref[3]; // Offset
14784 14792 if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
14785   - if (_cimg_mp_is_scalar(arg2))
14786   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
14787   - move_to(code);
14788   - else
14789   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_v,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
14790   - move_to(code);
  14793 + if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2);
14791 14794 if (p1!=~0U) {
14792 14795 if (!listout) _cimg_mp_return(arg1);
14793 14796 CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
... ... @@ -14800,20 +14803,16 @@ namespace cimg_library_suffixed {
14800 14803 _cimg_mp_return(arg1);
14801 14804 }
14802 14805  
14803   - if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) = value
14804   - _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14806 + if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) += value
  14807 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
  14808 + is_parallelizable = false;
14805 14809 p1 = ref[1]; // Index
14806 14810 is_relative = (bool)ref[2];
14807 14811 arg3 = ref[3]; // X
14808 14812 arg4 = ref[4]; // Y
14809 14813 arg5 = ref[5]; // Z
14810 14814 if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
14811   - if (_cimg_mp_is_scalar(arg2))
14812   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
14813   - move_to(code);
14814   - else
14815   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_v,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
14816   - move_to(code);
  14815 + if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2);
14817 14816 if (p1!=~0U) {
14818 14817 if (!listout) _cimg_mp_return(arg1);
14819 14818 CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
... ... @@ -14827,18 +14826,14 @@ namespace cimg_library_suffixed {
14827 14826 }
14828 14827  
14829 14828 if (_cimg_mp_is_vector(arg1)) { // Vector variable: V += value
14830   - _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
14831   - if (_cimg_mp_is_vector(arg2)) // Vector += vector
14832   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_v,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
14833   - move_to(code);
14834   - else // Vector += scalar
14835   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
14836   - move_to(code);
  14829 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
  14830 + if (_cimg_mp_is_vector(arg2)) self_vector_v(arg1,op,arg2); // Vector += vector
  14831 + else self_vector_s(arg1,op,arg2); // Vector += scalar
14837 14832 _cimg_mp_return(arg1);
14838 14833 }
14839 14834  
14840 14835 if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s += scalar
14841   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14836 + _cimg_mp_check_type(arg2,2,1,0);
14842 14837 CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code);
14843 14838 _cimg_mp_return(arg1);
14844 14839 }
... ... @@ -14857,17 +14852,19 @@ namespace cimg_library_suffixed {
14857 14852  
14858 14853 for (s = ss1; s<se1; ++s)
14859 14854 if (*s=='?' && level[s - expr._data]==clevel) { // Ternary operator 'cond?expr1:expr2'
14860   - s_op = "Operator '?:'";
  14855 + _cimg_mp_op("Operator '?:'");
14861 14856 s1 = s + 1; while (s1<se1 && (*s1!=':' || level[s1 - expr._data]!=clevel)) ++s1;
14862 14857 arg1 = compile(ss,s,depth1,0);
  14858 + _cimg_mp_check_type(arg1,1,1,0);
  14859 + if (_cimg_mp_is_constant(arg1)) {
  14860 + if ((bool)mem[arg1]) return compile(s + 1,*s1!=':'?se:s1,depth1,0);
  14861 + else return *s1!=':'?0:compile(++s1,se,depth1,0);
  14862 + }
14863 14863 p2 = code._width;
14864 14864 arg2 = compile(s + 1,*s1!=':'?se:s1,depth1,0);
14865 14865 p3 = code._width;
14866   - arg3 = *s1!=':'?0:compile(s1 + 1,se,depth1,0);
14867   - _cimg_mp_check_type(arg1,1,s_op,1,0);
14868   - _cimg_mp_check_type(arg3,3,s_op,_cimg_mp_is_vector(arg2)?2:1,_cimg_mp_vector_size(arg2));
14869   - if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))
14870   - _cimg_mp_constant(mem[arg1]?mem[arg2]:mem[arg3]);
  14866 + arg3 = *s1==':'?compile(++s1,se,depth1,0):_cimg_mp_is_vector(arg2)?vector(_cimg_mp_vector_size(arg2),0):0;
  14867 + _cimg_mp_check_type(arg3,3,_cimg_mp_is_vector(arg2)?2:1,_cimg_mp_vector_size(arg2));
14871 14868 arg4 = _cimg_mp_is_vector(arg2)?_cimg_mp_vector_size(arg2):0; // Output vector size (or 0 if scalar)
14872 14869 if (arg4) pos = vector(arg4); else pos = scalar();
14873 14870 CImg<uptrT>::vector((uptrT)mp_if,pos,arg1,arg2,arg3,
... ... @@ -14877,12 +14874,12 @@ namespace cimg_library_suffixed {
14877 14874  
14878 14875 for (s = se3, ns = se2; s>ss; --s, --ns)
14879 14876 if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { // Logical or ('||')
14880   - s_op = "Operator '||'";
  14877 + _cimg_mp_op("Operator '||'");
14881 14878 arg1 = compile(ss,s,depth1,0);
14882 14879 p2 = code._width;
14883 14880 arg2 = compile(s + 2,se,depth1,0);
14884   - _cimg_mp_check_type(arg1,1,s_op,1,0);
14885   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14881 + _cimg_mp_check_type(arg1,1,1,0);
  14882 + _cimg_mp_check_type(arg2,2,1,0);
14886 14883 if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
14887 14884 _cimg_mp_constant(mem[arg1] || mem[arg2]);
14888 14885 pos = scalar();
... ... @@ -14893,12 +14890,12 @@ namespace cimg_library_suffixed {
14893 14890  
14894 14891 for (s = se3, ns = se2; s>ss; --s, --ns)
14895 14892 if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { // Logical and ('&&')
14896   - s_op = "Operator '&&'";
  14893 + _cimg_mp_op("Operator '&&'");
14897 14894 arg1 = compile(ss,s,depth1,0);
14898 14895 p2 = code._width;
14899 14896 arg2 = compile(s + 2,se,depth1,0);
14900   - _cimg_mp_check_type(arg1,1,s_op,1,0);
14901   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  14897 + _cimg_mp_check_type(arg1,1,1,0);
  14898 + _cimg_mp_check_type(arg2,2,1,0);
14902 14899 if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
14903 14900 _cimg_mp_constant(mem[arg1] && mem[arg2]);
14904 14901 pos = scalar();
... ... @@ -14909,9 +14906,10 @@ namespace cimg_library_suffixed {
14909 14906  
14910 14907 for (s = se2; s>ss; --s)
14911 14908 if (*s=='|' && level[s - expr._data]==clevel) { // Bitwise or ('|')
  14909 + _cimg_mp_op("Operator '|'");
14912 14910 arg1 = compile(ss,s,depth1,0);
14913 14911 arg2 = compile(s + 1,se,depth1,0);
14914   - _cimg_mp_check_type(arg2,2,"operator '|'",3,_cimg_mp_vector_size(arg1));
  14912 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
14915 14913 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_or,arg1,arg2);
14916 14914 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_or,arg1,arg2);
14917 14915 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_or,arg1,arg2);
... ... @@ -14922,9 +14920,10 @@ namespace cimg_library_suffixed {
14922 14920  
14923 14921 for (s = se2; s>ss; --s)
14924 14922 if (*s=='&' && level[s - expr._data]==clevel) { // Bitwise and ('&')
  14923 + _cimg_mp_op("Operator '&'");
14925 14924 arg1 = compile(ss,s,depth1,0);
14926 14925 arg2 = compile(s + 1,se,depth1,0);
14927   - _cimg_mp_check_type(arg2,2,"operator '&'",3,_cimg_mp_vector_size(arg1));
  14926 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
14928 14927 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_and,arg1,arg2);
14929 14928 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_and,arg1,arg2);
14930 14929 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_and,arg1,arg2);
... ... @@ -14935,9 +14934,10 @@ namespace cimg_library_suffixed {
14935 14934  
14936 14935 for (s = se3, ns = se2; s>ss; --s, --ns)
14937 14936 if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) { // Not equal to ('!=')
  14937 + _cimg_mp_op("Operator '!='");
14938 14938 arg1 = compile(ss,s,depth1,0);
14939 14939 arg2 = compile(s + 2,se,depth1,0);
14940   - _cimg_mp_check_type(arg2,2,"operator '!='",3,_cimg_mp_vector_size(arg1));
  14940 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
14941 14941 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_neq,arg1,arg2);
14942 14942 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_neq,arg1,arg2);
14943 14943 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_neq,arg1,arg2);
... ... @@ -14947,9 +14947,10 @@ namespace cimg_library_suffixed {
14947 14947  
14948 14948 for (s = se3, ns = se2; s>ss; --s, --ns)
14949 14949 if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) { // Equal to ('==')
  14950 + _cimg_mp_op("Operator '=='");
14950 14951 arg1 = compile(ss,s,depth1,0);
14951 14952 arg2 = compile(s + 2,se,depth1,0);
14952   - _cimg_mp_check_type(arg2,2,"operator '=='",3,_cimg_mp_vector_size(arg1));
  14953 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
14953 14954 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_eq,arg1,arg2);
14954 14955 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_eq,arg1,arg2);
14955 14956 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_eq,arg1,arg2);
... ... @@ -14959,9 +14960,10 @@ namespace cimg_library_suffixed {
14959 14960  
14960 14961 for (s = se3, ns = se2; s>ss; --s, --ns)
14961 14962 if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) { // Less or equal than ('<=')
  14963 + _cimg_mp_op("Operator '<='");
14962 14964 arg1 = compile(ss,s,depth1,0);
14963 14965 arg2 = compile(s + 2,se,depth1,0);
14964   - _cimg_mp_check_type(arg2,2,"operator '<='",3,_cimg_mp_vector_size(arg1));
  14966 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
14965 14967 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lte,arg1,arg2);
14966 14968 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lte,arg1,arg2);
14967 14969 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lte,arg1,arg2);
... ... @@ -14971,9 +14973,10 @@ namespace cimg_library_suffixed {
14971 14973  
14972 14974 for (s = se3, ns = se2; s>ss; --s, --ns)
14973 14975 if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) { // Greater or equal than ('>=')
  14976 + _cimg_mp_op("Operator '>='");
14974 14977 arg1 = compile(ss,s,depth1,0);
14975 14978 arg2 = compile(s + 2,se,depth1,0);
14976   - _cimg_mp_check_type(arg2,2,"operator '>='",3,_cimg_mp_vector_size(arg1));
  14979 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
14977 14980 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gte,arg1,arg2);
14978 14981 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gte,arg1,arg2);
14979 14982 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gte,arg1,arg2);
... ... @@ -14983,9 +14986,10 @@ namespace cimg_library_suffixed {
14983 14986  
14984 14987 for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps)
14985 14988 if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) { // Less than ('<')
  14989 + _cimg_mp_op("Operator '<'");
14986 14990 arg1 = compile(ss,s,depth1,0);
14987 14991 arg2 = compile(s + 1,se,depth1,0);
14988   - _cimg_mp_check_type(arg2,2,"operator '<'",3,_cimg_mp_vector_size(arg1));
  14992 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
14989 14993 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lt,arg1,arg2);
14990 14994 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lt,arg1,arg2);
14991 14995 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lt,arg1,arg2);
... ... @@ -14995,9 +14999,10 @@ namespace cimg_library_suffixed {
14995 14999  
14996 15000 for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps)
14997 15001 if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) { // Greather than ('>')
  15002 + _cimg_mp_op("Operator '>'");
14998 15003 arg1 = compile(ss,s,depth1,0);
14999 15004 arg2 = compile(s + 1,se,depth1,0);
15000   - _cimg_mp_check_type(arg2,2,"operator '>'",3,_cimg_mp_vector_size(arg1));
  15005 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15001 15006 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gt,arg1,arg2);
15002 15007 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gt,arg1,arg2);
15003 15008 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gt,arg1,arg2);
... ... @@ -15007,9 +15012,10 @@ namespace cimg_library_suffixed {
15007 15012  
15008 15013 for (s = se3, ns = se2; s>ss; --s, --ns)
15009 15014 if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) { // Left bit shift ('<<')
  15015 + _cimg_mp_op("Operator '<<'");
15010 15016 arg1 = compile(ss,s,depth1,0);
15011 15017 arg2 = compile(s + 2,se,depth1,0);
15012   - _cimg_mp_check_type(arg2,2,"operator '<<'",3,_cimg_mp_vector_size(arg1));
  15018 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15013 15019 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2))
15014 15020 _cimg_mp_vector2_vv(mp_bitwise_left_shift,arg1,arg2);
15015 15021 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2))
... ... @@ -15023,9 +15029,10 @@ namespace cimg_library_suffixed {
15023 15029  
15024 15030 for (s = se3, ns = se2; s>ss; --s, --ns)
15025 15031 if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) { // Right bit shift ('>>')
  15032 + _cimg_mp_op("Operator '>>'");
15026 15033 arg1 = compile(ss,s,depth1,0);
15027 15034 arg2 = compile(s + 2,se,depth1,0);
15028   - _cimg_mp_check_type(arg2,2,"operator '>>'",3,_cimg_mp_vector_size(arg1));
  15035 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15029 15036 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2))
15030 15037 _cimg_mp_vector2_vv(mp_bitwise_right_shift,arg1,arg2);
15031 15038 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2))
... ... @@ -15043,9 +15050,10 @@ namespace cimg_library_suffixed {
15043 15050 (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' &&
15044 15051 *(ps - 1)<='9')))) &&
15045 15052 level[s - expr._data]==clevel) { // Addition ('+')
  15053 + _cimg_mp_op("Operator '+'");
15046 15054 arg1 = compile(ss,s,depth1,0);
15047 15055 arg2 = compile(s + 1,se,depth1,0);
15048   - _cimg_mp_check_type(arg2,2,"operator '+'",3,_cimg_mp_vector_size(arg1));
  15056 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15049 15057 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_add,arg1,arg2);
15050 15058 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_add,arg1,arg2);
15051 15059 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_add,arg1,arg2);
... ... @@ -15061,9 +15069,10 @@ namespace cimg_library_suffixed {
15061 15069 (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' &&
15062 15070 *(ps - 1)<='9')))) &&
15063 15071 level[s - expr._data]==clevel) { // Subtraction ('-')
  15072 + _cimg_mp_op("Operator '-'");
15064 15073 arg1 = compile(ss,s,depth1,0);
15065 15074 arg2 = compile(s + 1,se,depth1,0);
15066   - _cimg_mp_check_type(arg2,2,"operator '-'",3,_cimg_mp_vector_size(arg1));
  15075 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15067 15076 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_sub,arg1,arg2);
15068 15077 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_sub,arg1,arg2);
15069 15078 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_sub,arg1,arg2);
... ... @@ -15074,7 +15083,7 @@ namespace cimg_library_suffixed {
15074 15083  
15075 15084 for (s = se3, ns = se2; s>ss; --s, --ns)
15076 15085 if (*s=='*' && *ns=='*' && level[s - expr._data]==clevel) { // Complex/matrix multiplication ('**')
15077   - s_op = "Operator '**'";
  15086 + _cimg_mp_op("Operator '**'");
15078 15087 arg1 = compile(ss,s,depth1,0);
15079 15088 arg2 = compile(s + 2,se,depth1,0);
15080 15089 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
... ... @@ -15089,7 +15098,7 @@ namespace cimg_library_suffixed {
15089 15098 if (arg4*p2!=p1) {
15090 15099 *se = saved_char; cimg::strellipsize(expr,64);
15091 15100 throw CImgArgumentException("[_cimg_math_parser] "
15092   - "CImg<%s>::%s: %s: Sizes of left-hand and right-hand operands "
  15101 + "CImg<%s>::%s: %s: Types of left-hand and right-hand operands "
15093 15102 "('%s' and '%s') do not match, in expression '%s%s%s'.",
15094 15103 pixel_type(),_cimg_mp_calling_function,s_op,
15095 15104 s_type(arg1)._data,s_type(arg2)._data,
... ... @@ -15110,11 +15119,11 @@ namespace cimg_library_suffixed {
15110 15119  
15111 15120 for (s = se3, ns = se2; s>ss; --s, --ns)
15112 15121 if (*s=='/' && *ns=='/' && level[s - expr._data]==clevel) { // Complex division ('//')
15113   - s_op = "Operator '//'";
  15122 + _cimg_mp_op("Operator '//'");
15114 15123 arg1 = compile(ss,s,depth1,0);
15115 15124 arg2 = compile(s + 2,se,depth1,0);
15116   - _cimg_mp_check_type(arg1,1,s_op,3,2);
15117   - _cimg_mp_check_type(arg2,2,s_op,3,2);
  15125 + _cimg_mp_check_type(arg1,1,3,2);
  15126 + _cimg_mp_check_type(arg2,2,3,2);
15118 15127 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
15119 15128 pos = vector(2);
15120 15129 CImg<uptrT>::vector((uptrT)mp_complex_div_vv,pos,arg1,arg2).move_to(code);
... ... @@ -15131,9 +15140,10 @@ namespace cimg_library_suffixed {
15131 15140 }
15132 15141  
15133 15142 for (s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { // Multiplication ('*')
  15143 + _cimg_mp_op("Operator '*'");
15134 15144 arg1 = compile(ss,s,depth1,0);
15135 15145 arg2 = compile(s + 1,se,depth1,0);
15136   - _cimg_mp_check_type(arg2,2,"operator '*'",3,_cimg_mp_vector_size(arg1));
  15146 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15137 15147 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_mul,arg1,arg2);
15138 15148 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2);
15139 15149 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2);
... ... @@ -15143,9 +15153,10 @@ namespace cimg_library_suffixed {
15143 15153  
15144 15154  
15145 15155 for (s = se2; s>ss; --s) if (*s=='/' && level[s - expr._data]==clevel) { // Division ('/')
  15156 + _cimg_mp_op("Operator '/'");
15146 15157 arg1 = compile(ss,s,depth1,0);
15147 15158 arg2 = compile(s + 1,se,depth1,0);
15148   - _cimg_mp_check_type(arg2,2,"operator '/'",3,_cimg_mp_vector_size(arg1));
  15159 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15149 15160 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_div,arg1,arg2);
15150 15161 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2);
15151 15162 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_div,arg1,arg2);
... ... @@ -15155,9 +15166,10 @@ namespace cimg_library_suffixed {
15155 15166  
15156 15167 for (s = se2, ns = se1; s>ss; --s, --ns)
15157 15168 if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) { // Modulo ('%')
  15169 + _cimg_mp_op("Operator '%'");
15158 15170 arg1 = compile(ss,s,depth1,0);
15159 15171 arg2 = compile(s + 1,se,depth1,0);
15160   - _cimg_mp_check_type(arg2,2,"operator '%'",3,_cimg_mp_vector_size(arg1));
  15172 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15161 15173 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_modulo,arg1,arg2);
15162 15174 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_modulo,arg1,arg2);
15163 15175 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_modulo,arg1,arg2);
... ... @@ -15167,10 +15179,13 @@ namespace cimg_library_suffixed {
15167 15179 }
15168 15180  
15169 15181 if (se1>ss) {
15170   - if (*ss=='+' && (*ss1!='+' || (ss2<se && *ss2>='0' && *ss2<='9'))) // Unary plus ('+')
  15182 + if (*ss=='+' && (*ss1!='+' || (ss2<se && *ss2>='0' && *ss2<='9'))) { // Unary plus ('+')
  15183 + _cimg_mp_op("Operator '+'");
15171 15184 _cimg_mp_return(compile(ss1,se,depth1,0));
  15185 + }
15172 15186  
15173 15187 if (*ss=='-' && (*ss1!='-' || (ss2<se && *ss2>='0' && *ss2<='9'))) { // Unary minus ('-')
  15188 + _cimg_mp_op("Operator '-'");
15174 15189 arg1 = compile(ss1,se,depth1,0);
15175 15190 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_minus,arg1);
15176 15191 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(-mem[arg1]);
... ... @@ -15178,6 +15193,7 @@ namespace cimg_library_suffixed {
15178 15193 }
15179 15194  
15180 15195 if (*ss=='!') { // Logical not ('!')
  15196 + _cimg_mp_op("Operator '!'");
15181 15197 arg1 = compile(ss1,se,depth1,0);
15182 15198 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_logical_not,arg1);
15183 15199 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(!mem[arg1]);
... ... @@ -15185,6 +15201,7 @@ namespace cimg_library_suffixed {
15185 15201 }
15186 15202  
15187 15203 if (*ss=='~') { // Bitwise not ('~')
  15204 + _cimg_mp_op("Operator '~'");
15188 15205 arg1 = compile(ss1,se,depth1,0);
15189 15206 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bitwise_not,arg1);
15190 15207 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(~(unsigned long)mem[arg1]);
... ... @@ -15194,11 +15211,11 @@ namespace cimg_library_suffixed {
15194 15211  
15195 15212 for (s = se3, ns = se2; s>ss; --s, --ns)
15196 15213 if (*s=='^' && *ns=='^' && level[s - expr._data]==clevel) { // Complex power ('^^')
15197   - s_op = "Operator '^^'";
  15214 + _cimg_mp_op("Operator '^^'");
15198 15215 arg1 = compile(ss,s,depth1,0);
15199 15216 arg2 = compile(s + 2,se,depth1,0);
15200   - _cimg_mp_check_type(arg1,1,s_op,3,2);
15201   - _cimg_mp_check_type(arg2,2,s_op,3,2);
  15217 + _cimg_mp_check_type(arg1,1,3,2);
  15218 + _cimg_mp_check_type(arg2,2,3,2);
15202 15219 pos = (_cimg_mp_is_vector(arg1) || _cimg_mp_is_vector(arg2))?vector(2):0;
15203 15220 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
15204 15221 CImg<uptrT>::vector((uptrT)mp_complex_pow_vv,pos,arg1,arg2).move_to(code);
... ... @@ -15226,9 +15243,10 @@ namespace cimg_library_suffixed {
15226 15243  
15227 15244 for (s = se2; s>ss; --s)
15228 15245 if (*s=='^' && level[s - expr._data]==clevel) { // Power ('^')
  15246 + _cimg_mp_op("Operator '^'");
15229 15247 arg1 = compile(ss,s,depth1,0);
15230 15248 arg2 = compile(s + 1,se,depth1,0);
15231   - _cimg_mp_check_type(arg2,2,"operator '^'",3,_cimg_mp_vector_size(arg1));
  15249 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15232 15250 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_pow,arg1,arg2);
15233 15251 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_pow,arg1,arg2);
15234 15252 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_pow,arg1,arg2);
... ... @@ -15246,9 +15264,13 @@ namespace cimg_library_suffixed {
15246 15264  
15247 15265 is_sth = ss1<se1 && (*ss=='+' || *ss=='-') && *ss1==*ss; // is pre-?
15248 15266 if (is_sth || (se2>ss && (*se1=='+' || *se1=='-') && *se2==*se1)) { // Pre/post-decrement and increment
15249   - if ((is_sth && *ss=='+') || (!is_sth && *se1=='+')) { op = mp_self_increment; s_op = "Operator '++'"; }
15250   - else { op = mp_self_decrement; s_op = "Operator '--'"; }
15251   -
  15267 + if ((is_sth && *ss=='+') || (!is_sth && *se1=='+')) {
  15268 + _cimg_mp_op("Operator '++'");
  15269 + op = mp_self_increment;
  15270 + } else {
  15271 + _cimg_mp_op("Operator '--'");
  15272 + op = mp_self_decrement;
  15273 + }
15252 15274 ref.assign(7);
15253 15275 arg1 = is_sth?compile(ss2,se,depth1,ref):compile(ss,se2,depth1,ref); // Variable slot
15254 15276  
... ... @@ -15274,6 +15296,7 @@ namespace cimg_library_suffixed {
15274 15296 }
15275 15297  
15276 15298 if (*ref==2) { // Image value (scalar): i/j[_#ind,off]++
  15299 + is_parallelizable = false;
15277 15300 p1 = ref[1]; // Index
15278 15301 is_relative = (bool)ref[2];
15279 15302 arg3 = ref[3]; // Offset
... ... @@ -15292,6 +15315,7 @@ namespace cimg_library_suffixed {
15292 15315 }
15293 15316  
15294 15317 if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c)++
  15318 + is_parallelizable = false;
15295 15319 p1 = ref[1]; // Index
15296 15320 is_relative = (bool)ref[2];
15297 15321 arg3 = ref[3]; // X
... ... @@ -15313,13 +15337,12 @@ namespace cimg_library_suffixed {
15313 15337 }
15314 15338  
15315 15339 if (*ref==4) { // Image value (vector): I/J[_#ind,off]++
  15340 + is_parallelizable = false;
15316 15341 p1 = ref[1]; // Index
15317 15342 is_relative = (bool)ref[2];
15318 15343 arg3 = ref[3]; // Offset
15319 15344 if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
15320   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),
15321   - (uptrT)(op==mp_self_increment?mp_self_add:mp_self_sub),1).
15322   - move_to(code);
  15345 + self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);
15323 15346 if (p1!=~0U) {
15324 15347 if (!listout) _cimg_mp_return(pos);
15325 15348 CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
... ... @@ -15333,15 +15356,14 @@ namespace cimg_library_suffixed {
15333 15356 }
15334 15357  
15335 15358 if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c)++
  15359 + is_parallelizable = false;
15336 15360 p1 = ref[1]; // Index
15337 15361 is_relative = (bool)ref[2];
15338 15362 arg3 = ref[3]; // X
15339 15363 arg4 = ref[4]; // Y
15340 15364 arg5 = ref[5]; // Z
15341 15365 if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
15342   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),
15343   - (uptrT)(op==mp_self_increment?mp_self_add:mp_self_sub),1).
15344   - move_to(code);
  15366 + self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);
15345 15367 if (p1!=~0U) {
15346 15368 if (!listout) _cimg_mp_return(pos);
15347 15369 CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
... ... @@ -15355,9 +15377,7 @@ namespace cimg_library_suffixed {
15355 15377 }
15356 15378  
15357 15379 if (_cimg_mp_is_vector(arg1)) { // Vector variable: V++
15358   - CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),
15359   - (uptrT)(op==mp_self_increment?mp_self_add:mp_self_sub),1).
15360   - move_to(code);
  15380 + self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);
15361 15381 _cimg_mp_return(pos);
15362 15382 }
15363 15383  
... ... @@ -15382,7 +15402,7 @@ namespace cimg_library_suffixed {
15382 15402  
15383 15403 // Array-like access to vectors and image values 'i/j[_#ind,offset,_boundary]' and 'vector[offset]'.
15384 15404 if (*se1==']' && *ss!='[') {
15385   - s_op = "Operator '[]'";
  15405 + _cimg_mp_op("Operator '[]'");
15386 15406 is_relative = *ss=='j' || *ss=='J';
15387 15407  
15388 15408 if ((*ss=='I' || *ss=='J') && *ss1=='[' &&
... ... @@ -15390,10 +15410,11 @@ namespace cimg_library_suffixed {
15390 15410 if (*ss2=='#') { // Index specified
15391 15411 s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
15392 15412 p1 = compile(ss3,s0++,depth1,0);
  15413 + _cimg_mp_check_list(false);
15393 15414 } else { p1 = ~0U; s0 = ss2; }
15394 15415 s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15395 15416 arg1 = compile(s0,s1,depth1,0); // Offset
15396   - arg2 = s1<se1?compile(s1 + 1,se1,depth1,0):~0U; // Boundary
  15417 + arg2 = s1<se1?compile(++s1,se1,depth1,0):~0U; // Boundary
15397 15418 if (p_ref && arg2==~0U) {
15398 15419 *p_ref = 4;
15399 15420 p_ref[1] = p1;
... ... @@ -15408,12 +15429,13 @@ namespace cimg_library_suffixed {
15408 15429 p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
15409 15430 p2 = listin[p3]._spectrum;
15410 15431 }
15411   - _cimg_mp_check_vector0(p2,s_op);
  15432 + _cimg_mp_check_vector0(p2);
15412 15433 pos = vector(p2);
15413 15434 if (p1!=~0U) {
15414 15435 CImg<uptrT>::vector((uptrT)(is_relative?mp_list_Joff:mp_list_Ioff),
15415 15436 pos,p1,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code);
15416 15437 } else {
  15438 + need_input_copy = true;
15417 15439 CImg<uptrT>::vector((uptrT)(is_relative?mp_Joff:mp_Ioff),
15418 15440 pos,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code);
15419 15441 }
... ... @@ -15428,7 +15450,7 @@ namespace cimg_library_suffixed {
15428 15450 } else { p1 = ~0U; s0 = ss2; }
15429 15451 s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15430 15452 arg1 = compile(s0,s1,depth1,0); // Offset
15431   - arg2 = s1<se1?compile(s1 + 1,se1,depth1,0):~0U; // Boundary
  15453 + arg2 = s1<se1?compile(++s1,se1,depth1,0):~0U; // Boundary
15432 15454 if (p_ref && arg2==~0U) {
15433 15455 *p_ref = 2;
15434 15456 p_ref[1] = p1;
... ... @@ -15442,6 +15464,7 @@ namespace cimg_library_suffixed {
15442 15464 pos = scalar3(is_relative?mp_list_joff:mp_list_ioff,p1,arg1,arg2==~0U?reserved_label[30]:arg2);
15443 15465 } else {
15444 15466 if (!imgin) _cimg_mp_return(0);
  15467 + need_input_copy = true;
15445 15468 pos = scalar2(is_relative?mp_joff:mp_ioff,arg1,arg2==~0U?reserved_label[30]:arg2);
15446 15469 }
15447 15470 memtype[pos] = -1; // Create it as a variable to prevent from being used in further optimization
... ... @@ -15456,8 +15479,8 @@ namespace cimg_library_suffixed {
15456 15479 if (s1<se1) { // Two arguments -> sub-vector extraction
15457 15480 arg2 = compile(++s0,s1,depth1,0);
15458 15481 arg3 = compile(++s1,se1,depth1,0);
15459   - _cimg_mp_check_constant(arg2,1,s_op,false);
15460   - _cimg_mp_check_constant(arg3,2,s_op,false);
  15482 + _cimg_mp_check_constant(arg2,1,false);
  15483 + _cimg_mp_check_constant(arg3,2,false);
15461 15484 p1 = (unsigned int)mem[arg2];
15462 15485 p2 = (unsigned int)mem[arg3];
15463 15486 p3 = _cimg_mp_vector_size(arg1);
... ... @@ -15527,12 +15550,14 @@ namespace cimg_library_suffixed {
15527 15550 if (*se1==')') {
15528 15551 if (*ss=='(') _cimg_mp_return(compile(ss1,se1,depth1,p_ref)); // Simple parentheses
15529 15552 is_relative = *ss=='j' || *ss=='J';
  15553 + _cimg_mp_op("Operator '()'");
15530 15554  
15531   - // I/J(_#ind,_x,_y,_z,_c,_interpolation,_boundary)
  15555 + // I/J(_#ind,_x,_y,_z,_interpolation,_boundary)
15532 15556 if ((*ss=='I' || *ss=='J') && *ss1=='(') { // Image value as scalar
15533 15557 if (*ss2=='#') { // Index specified
15534 15558 s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
15535 15559 p1 = compile(ss3,s0++,depth1,0);
  15560 + _cimg_mp_check_list(false);
15536 15561 } else { p1 = ~0U; s0 = ss2; }
15537 15562 arg1 = is_relative?0U:(unsigned int)_cimg_mp_x;
15538 15563 arg2 = is_relative?0U:(unsigned int)_cimg_mp_y;
... ... @@ -15541,9 +15566,9 @@ namespace cimg_library_suffixed {
15541 15566 if (s0<se1) {
15542 15567 s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15543 15568 arg1 = compile(s0,s1,depth1,0);
15544   - if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z]
  15569 + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
15545 15570 p2 = _cimg_mp_vector_size(arg1);
15546   - arg1 = arg1 + 1;
  15571 + ++arg1;
15547 15572 if (p2>1) {
15548 15573 arg2 = arg1 + 1;
15549 15574 if (p2>2) arg3 = arg2 + 1;
... ... @@ -15551,7 +15576,7 @@ namespace cimg_library_suffixed {
15551 15576 if (s1<se1) {
15552 15577 s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
15553 15578 arg4 = compile(s1,s2,depth1,0);
15554   - if (s2<se1) arg5 = compile(++s2,se1,depth1,0);
  15579 + arg5 = s2<se1?compile(++s2,se1,depth1,0):~0U;
15555 15580 }
15556 15581 } else if (s1<se1) {
15557 15582 s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
... ... @@ -15562,7 +15587,7 @@ namespace cimg_library_suffixed {
15562 15587 if (s3<se1) {
15563 15588 s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
15564 15589 arg4 = compile(s3,s2,depth1,0);
15565   - if (s2<se1) arg5 = compile(++s2,se1,depth1,0);
  15590 + arg5 = s2<se1?compile(++s2,se1,depth1,0):~0U;
15566 15591 }
15567 15592 }
15568 15593 }
... ... @@ -15585,18 +15610,20 @@ namespace cimg_library_suffixed {
15585 15610 p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
15586 15611 p2 = listin[p3]._spectrum;
15587 15612 }
15588   - _cimg_mp_check_vector0(p2,"operator '()'");
  15613 + _cimg_mp_check_vector0(p2);
15589 15614 pos = vector(p2);
15590 15615 if (p1!=~0U)
15591 15616 CImg<uptrT>::vector((uptrT)(is_relative?mp_list_Jxyz:mp_list_Ixyz),
15592 15617 pos,p1,arg1,arg2,arg3,
15593 15618 arg4==~0U?reserved_label[29]:arg4,
15594 15619 arg5==~0U?reserved_label[30]:arg5).move_to(code);
15595   - else
  15620 + else {
  15621 + need_input_copy = true;
15596 15622 CImg<uptrT>::vector((uptrT)(is_relative?mp_Jxyz:mp_Ixyz),
15597 15623 pos,arg1,arg2,arg3,
15598 15624 arg4==~0U?reserved_label[29]:arg4,
15599 15625 arg5==~0U?reserved_label[30]:arg5).move_to(code);
  15626 + }
15600 15627 _cimg_mp_return(pos);
15601 15628 }
15602 15629  
... ... @@ -15614,9 +15641,9 @@ namespace cimg_library_suffixed {
15614 15641 if (s0<se1) {
15615 15642 s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15616 15643 arg1 = compile(s0,s1,depth1,0);
15617   - if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z,C]
  15644 + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
15618 15645 p2 = _cimg_mp_vector_size(arg1);
15619   - arg1 = arg1 + 1;
  15646 + ++arg1;
15620 15647 if (p2>1) {
15621 15648 arg2 = arg1 + 1;
15622 15649 if (p2>2) {
... ... @@ -15627,7 +15654,7 @@ namespace cimg_library_suffixed {
15627 15654 if (s1<se1) {
15628 15655 s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
15629 15656 arg5 = compile(s1,s2,depth1,0);
15630   - if (s2<se1) arg6 = compile(++s2,se1,depth1,0);
  15657 + arg6 = s2<se1?compile(++s2,se1,depth1,0):~0U;
15631 15658 }
15632 15659 } else if (s1<se1) {
15633 15660 s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
... ... @@ -15641,7 +15668,7 @@ namespace cimg_library_suffixed {
15641 15668 if (s2<se1) {
15642 15669 s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
15643 15670 arg5 = compile(s2,s3,depth1,0);
15644   - if (s3<se1) arg6 = compile(++s3,se1,depth1,0);
  15671 + arg6 = s3<se1?compile(++s3,se1,depth1,0):~0U;
15645 15672 }
15646 15673 }
15647 15674 }
... ... @@ -15670,6 +15697,7 @@ namespace cimg_library_suffixed {
15670 15697 arg6==~0U?reserved_label[30]:arg6);
15671 15698 } else {
15672 15699 if (!imgin) _cimg_mp_return(0);
  15700 + need_input_copy = true;
15673 15701 pos = scalar6(is_relative?mp_jxyzc:mp_ixyzc,
15674 15702 arg1,arg2,arg3,arg4,
15675 15703 arg5==~0U?reserved_label[29]:arg5,
... ... @@ -15683,6 +15711,7 @@ namespace cimg_library_suffixed {
15683 15711 switch (*ss) {
15684 15712 case 'a' :
15685 15713 if (!std::strncmp(ss,"abs(",4)) { // Absolute value
  15714 + _cimg_mp_op("Function 'abs()'");
15686 15715 arg1 = compile(ss4,se1,depth1,0);
15687 15716 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_abs,arg1);
15688 15717 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::abs(mem[arg1]));
... ... @@ -15690,6 +15719,7 @@ namespace cimg_library_suffixed {
15690 15719 }
15691 15720  
15692 15721 if (!std::strncmp(ss,"acos(",5)) { // Arccos
  15722 + _cimg_mp_op("Function 'acos()'");
15693 15723 arg1 = compile(ss5,se1,depth1,0);
15694 15724 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_acos,arg1);
15695 15725 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::acos(mem[arg1]));
... ... @@ -15697,6 +15727,7 @@ namespace cimg_library_suffixed {
15697 15727 }
15698 15728  
15699 15729 if (!std::strncmp(ss,"asin(",5)) { // Arcsin
  15730 + _cimg_mp_op("Function 'asin()'");
15700 15731 arg1 = compile(ss5,se1,depth1,0);
15701 15732 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_asin,arg1);
15702 15733 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::asin(mem[arg1]));
... ... @@ -15704,6 +15735,7 @@ namespace cimg_library_suffixed {
15704 15735 }
15705 15736  
15706 15737 if (!std::strncmp(ss,"atan(",5)) { // Arctan
  15738 + _cimg_mp_op("Function 'atan()'");
15707 15739 arg1 = compile(ss5,se1,depth1,0);
15708 15740 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_atan,arg1);
15709 15741 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::atan(mem[arg1]));
... ... @@ -15711,10 +15743,11 @@ namespace cimg_library_suffixed {
15711 15743 }
15712 15744  
15713 15745 if (!std::strncmp(ss,"atan2(",6)) { // Arctan2
  15746 + _cimg_mp_op("Function 'atan2()'");
15714 15747 s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15715 15748 arg1 = compile(ss6,s1,depth1,0);
15716   - arg2 = compile(s1 + 1,se1,depth1,0);
15717   - _cimg_mp_check_type(arg2,2,"Function 'atan2()'",3,_cimg_mp_vector_size(arg1));
  15749 + arg2 = compile(++s1,se1,depth1,0);
  15750 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
15718 15751 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_atan2,arg1,arg2);
15719 15752 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_atan2,arg1,arg2);
15720 15753 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_atan2,arg1,arg2);
... ... @@ -15726,18 +15759,21 @@ namespace cimg_library_suffixed {
15726 15759  
15727 15760 case 'c' :
15728 15761 if (!std::strncmp(ss,"cabs(",5)) { // Complex absolute value
  15762 + _cimg_mp_op("Function 'cabs()'");
15729 15763 arg1 = compile(ss5,se1,depth1,0);
15730   - _cimg_mp_check_type(arg1,0,"Function 'cabs()'",2,2);
  15764 + _cimg_mp_check_type(arg1,0,2,2);
15731 15765 _cimg_mp_scalar2(mp_hypot,arg1 + 1,arg1 + 2);
15732 15766 }
15733 15767  
15734 15768 if (!std::strncmp(ss,"carg(",5)) { // Complex argument
  15769 + _cimg_mp_op("Function 'carg()'");
15735 15770 arg1 = compile(ss5,se1,depth1,0);
15736   - _cimg_mp_check_type(arg1,0,"Function 'carg()'",2,2);
  15771 + _cimg_mp_check_type(arg1,0,2,2);
15737 15772 _cimg_mp_scalar2(mp_atan2,arg1 + 2,arg1 + 1);
15738 15773 }
15739 15774  
15740 15775 if (!std::strncmp(ss,"cbrt(",5)) { // Cubic root
  15776 + _cimg_mp_op("Function 'cbrt()'");
15741 15777 arg1 = compile(ss5,se1,depth1,0);
15742 15778 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cbrt,arg1);
15743 15779 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::pow(mem[arg1],1.0/3));
... ... @@ -15745,30 +15781,66 @@ namespace cimg_library_suffixed {
15745 15781 }
15746 15782  
15747 15783 if (!std::strncmp(ss,"cconj(",6)) { // Complex conjugate
  15784 + _cimg_mp_op("Function 'cconj()'");
15748 15785 arg1 = compile(ss6,se1,depth1,0);
15749   - _cimg_mp_check_type(arg1,0,"Function 'cconj()'",2,2);
  15786 + _cimg_mp_check_type(arg1,0,2,2);
15750 15787 pos = vector(2);
15751 15788 CImg<uptrT>::vector((uptrT)mp_complex_conj,pos,arg1).move_to(code);
15752 15789 _cimg_mp_return(pos);
15753 15790 }
15754 15791  
15755 15792 if (!std::strncmp(ss,"cexp(",5)) { // Complex exponential
  15793 + _cimg_mp_op("Function 'cexp()'");
15756 15794 arg1 = compile(ss5,se1,depth1,0);
15757   - _cimg_mp_check_type(arg1,0,"Function 'cexp()'",2,2);
  15795 + _cimg_mp_check_type(arg1,0,2,2);
15758 15796 pos = vector(2);
15759 15797 CImg<uptrT>::vector((uptrT)mp_complex_exp,pos,arg1).move_to(code);
15760 15798 _cimg_mp_return(pos);
15761 15799 }
15762 15800  
15763 15801 if (!std::strncmp(ss,"clog(",5)) { // Complex logarithm
  15802 + _cimg_mp_op("Function 'clog()'");
15764 15803 arg1 = compile(ss5,se1,depth1,0);
15765   - _cimg_mp_check_type(arg1,0,"Function 'clog()'",2,2);
  15804 + _cimg_mp_check_type(arg1,0,2,2);
15766 15805 pos = vector(2);
15767 15806 CImg<uptrT>::vector((uptrT)mp_complex_log,pos,arg1).move_to(code);
15768 15807 _cimg_mp_return(pos);
15769 15808 }
15770 15809  
  15810 + if (!std::strncmp(ss,"copy(",5)) { // Memory copy
  15811 + _cimg_mp_op("Function 'copy()'");
  15812 + ref.assign(14);
  15813 + s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15814 + arg1 = p1 = compile(ss5,s1,depth1,ref);
  15815 + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15816 + arg2 = compile(s1,s2,depth1,ref._data + 7);
  15817 + arg3 = ~0U; arg4 = arg5 = 1;
  15818 + if (s2<se1) {
  15819 + s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
  15820 + arg3 = compile(s2,s3,depth1,0);
  15821 + if (s3<se1) {
  15822 + s1 = ++s3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15823 + arg4 = compile(s3,s1,depth1,0);
  15824 + arg5 = s1<se1?compile(++s1,se1,depth1,0):1;
  15825 + }
  15826 + }
  15827 + if (_cimg_mp_is_vector(arg1) && !ref[0]) ++arg1;
  15828 + if (_cimg_mp_is_vector(arg2)) {
  15829 + if (arg3==~0U) arg3 = _cimg_mp_vector_size(arg2);
  15830 + if (!ref[7]) ++arg2;
  15831 + }
  15832 + if (arg3==~0U) arg3 = 1;
  15833 + _cimg_mp_check_type(arg3,3,1,0);
  15834 + _cimg_mp_check_type(arg4,4,1,0);
  15835 + _cimg_mp_check_type(arg5,5,1,0);
  15836 + CImg<uptrT>(1,21).move_to(code);
  15837 + code.back().get_shared_rows(0,6).fill((uptrT)mp_memcopy,p1,arg1,arg2,arg3,arg4,arg5);
  15838 + code.back().get_shared_rows(7,20).fill(ref);
  15839 + _cimg_mp_return(p1);
  15840 + }
  15841 +
15771 15842 if (!std::strncmp(ss,"cos(",4)) { // Cosine
  15843 + _cimg_mp_op("Function 'cos()'");
15772 15844 arg1 = compile(ss4,se1,depth1,0);
15773 15845 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cos,arg1);
15774 15846 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cos(mem[arg1]));
... ... @@ -15776,30 +15848,161 @@ namespace cimg_library_suffixed {
15776 15848 }
15777 15849  
15778 15850 if (!std::strncmp(ss,"cosh(",5)) { // Hyperbolic cosine
  15851 + _cimg_mp_op("Function 'cosh()'");
15779 15852 arg1 = compile(ss5,se1,depth1,0);
15780 15853 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cosh,arg1);
15781 15854 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cosh(mem[arg1]));
15782 15855 _cimg_mp_scalar1(mp_cosh,arg1);
15783 15856 }
15784 15857  
  15858 + if (!std::strncmp(ss,"crop(",5)) { // Image crop
  15859 + _cimg_mp_op("Function 'crop()'");
  15860 + if (*ss5=='#') { // Index specified
  15861 + s0 = ss6; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  15862 + p1 = compile(ss6,s0++,depth1,0);
  15863 + _cimg_mp_check_list(false);
  15864 + } else { p1 = ~0U; s0 = ss5; need_input_copy = true; }
  15865 + pos = 0;
  15866 + is_sth = false; // Coordinates specified as a vector?
  15867 + if (ss5<se1) for (s = s0; s<se; ++s, ++pos) {
  15868 + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
  15869 + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
  15870 + arg1 = compile(s,ns,depth1,0);
  15871 + if (!pos && _cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
  15872 + opcode = CImg<uptrT>::sequence((uptrT)_cimg_mp_vector_size(arg1),arg1 + 1,
  15873 + arg1 + (uptrT)_cimg_mp_vector_size(arg1));
  15874 + opcode.resize(1,cimg::min(opcode._height,4U),1,1,0).move_to(_opcode);
  15875 + is_sth = true;
  15876 + } else {
  15877 + _cimg_mp_check_type(arg1,pos + 1,1,0);
  15878 + CImg<uptrT>::vector(arg1).move_to(_opcode);
  15879 + }
  15880 + s = ns;
  15881 + }
  15882 + (_opcode>'y').move_to(opcode);
  15883 +
  15884 + arg1 = 0; arg2 = p1!=~0U?1:0;
  15885 + switch (opcode._height) {
  15886 + case 0 : case 1 :
  15887 + CImg<uptrT>::vector(0,0,0,0,~0U,~0U,~0U,~0U,0).move_to(opcode);
  15888 + break;
  15889 + case 2 :
  15890 + CImg<uptrT>::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,reserved_label[30]).move_to(opcode);
  15891 + arg1 = arg2?3:2;
  15892 + break;
  15893 + case 3 :
  15894 + CImg<uptrT>::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,opcode[2]).move_to(opcode);
  15895 + arg1 = arg2?3:2;
  15896 + break;
  15897 + case 4 :
  15898 + CImg<uptrT>::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,reserved_label[30]).
  15899 + move_to(opcode);
  15900 + arg1 = (is_sth?2:1) + arg2;
  15901 + break;
  15902 + case 5 :
  15903 + CImg<uptrT>::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,opcode[4]).
  15904 + move_to(opcode);
  15905 + arg1 = (is_sth?2:1) + arg2;
  15906 + break;
  15907 + case 6 :
  15908 + CImg<uptrT>::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U,
  15909 + reserved_label[30]).move_to(opcode);
  15910 + arg1 = (is_sth?2:4) + arg2;
  15911 + break;
  15912 + case 7 :
  15913 + CImg<uptrT>::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U,
  15914 + opcode[6]).move_to(opcode);
  15915 + arg1 = (is_sth?2:4) + arg2;
  15916 + break;
  15917 + case 8 :
  15918 + CImg<uptrT>::vector(*opcode,opcode[1],opcode[2],opcode[3],opcode[4],opcode[5],opcode[6],
  15919 + opcode[7],reserved_label[30]).move_to(opcode);
  15920 + arg1 = (is_sth?2:5) + arg2;
  15921 + break;
  15922 + case 9 :
  15923 + arg1 = (is_sth?2:5) + arg2;
  15924 + break;
  15925 + default : // Error -> too much arguments
  15926 + throw CImgArgumentException("[_cimg_math_parser] "
  15927 + "CImg<%s>::%s: %s: Too much arguments specified, "
  15928 + "in expression '%s%s%s'.",
  15929 + pixel_type(),_cimg_mp_calling_function,s_op,
  15930 + (ss - 4)>expr._data?"...":"",
  15931 + (ss - 4)>expr._data?ss - 4:expr._data,
  15932 + se<&expr.back()?"...":"");
  15933 + }
  15934 + _cimg_mp_check_type(*opcode,arg2 + 1,1,0);
  15935 + _cimg_mp_check_type(opcode[1],arg2 + (is_sth?0:1),1,0);
  15936 + _cimg_mp_check_type(opcode[2],arg2 + (is_sth?0:2),1,0);
  15937 + _cimg_mp_check_type(opcode[3],arg2 + (is_sth?0:3),1,0);
  15938 +
  15939 + if (opcode[4]!=(uptrT)~0U) {
  15940 + _cimg_mp_check_constant(opcode[4],arg1,true);
  15941 + opcode[4] = (uptrT)mem[opcode[4]];
  15942 + }
  15943 + if (opcode[5]!=(uptrT)~0U) {
  15944 + _cimg_mp_check_constant(opcode[5],arg1 + 1,true);
  15945 + opcode[5] = (uptrT)mem[opcode[5]];
  15946 + }
  15947 + if (opcode[6]!=(uptrT)~0U) {
  15948 + _cimg_mp_check_constant(opcode[6],arg1 + 2,true);
  15949 + opcode[6] = (uptrT)mem[opcode[6]];
  15950 + }
  15951 + if (opcode[7]!=(uptrT)~0U) {
  15952 + _cimg_mp_check_constant(opcode[7],arg1 + 3,true);
  15953 + opcode[7] = (uptrT)mem[opcode[7]];
  15954 + }
  15955 + _cimg_mp_check_type(opcode[8],arg1 + 4,1,0);
  15956 +
  15957 + if (opcode[4]==(uptrT)~0U || opcode[5]==(uptrT)~0U ||
  15958 + opcode[6]==(uptrT)~0U || opcode[7]==(uptrT)~0U) {
  15959 + if (p1!=~0U) {
  15960 + _cimg_mp_check_constant(p1,1,false);
  15961 + p1 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
  15962 + }
  15963 + const CImg<T> &img = p1!=~0U?listin[p1]:imgin;
  15964 + if (!img)
  15965 + throw CImgArgumentException("[_cimg_math_parser] "
  15966 + "CImg<%s>::%s: %s: Cannot crop empty image when "
  15967 + "some xyzc-coordinates are unspecified, in expression '%s%s%s'.",
  15968 + pixel_type(),_cimg_mp_calling_function,s_op,
  15969 + (ss - 4)>expr._data?"...":"",
  15970 + (ss - 4)>expr._data?ss - 4:expr._data,
  15971 + se<&expr.back()?"...":"");
  15972 + if (opcode[4]==(uptrT)~0U) opcode[4] = (uptrT)img._width;
  15973 + if (opcode[5]==(uptrT)~0U) opcode[5] = (uptrT)img._height;
  15974 + if (opcode[6]==(uptrT)~0U) opcode[6] = (uptrT)img._depth;
  15975 + if (opcode[7]==(uptrT)~0U) opcode[7] = (uptrT)img._spectrum;
  15976 + }
  15977 +
  15978 + pos = vector(opcode[4]*opcode[5]*opcode[6]*opcode[7]);
  15979 + CImg<uptrT>::vector((uptrT)mp_crop,
  15980 + pos,p1,
  15981 + *opcode,opcode[1],opcode[2],opcode[3],
  15982 + opcode[4],opcode[5],opcode[6],opcode[7],
  15983 + opcode[8]).move_to(code);
  15984 + _cimg_mp_return(pos);
  15985 + }
  15986 +
15785 15987 if (!std::strncmp(ss,"cross(",6)) { // Cross product
15786   - s_op = "Function 'cross()";
  15988 + _cimg_mp_op("Function 'cross()'");
15787 15989 s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15788 15990 arg1 = compile(ss6,s1,depth1,0);
15789   - arg2 = compile(s1 + 1,se1,depth1,0);
15790   - _cimg_mp_check_type(arg1,1,s_op,2,3);
15791   - _cimg_mp_check_type(arg2,2,s_op,2,3);
  15991 + arg2 = compile(++s1,se1,depth1,0);
  15992 + _cimg_mp_check_type(arg1,1,2,3);
  15993 + _cimg_mp_check_type(arg2,2,2,3);
15792 15994 pos = vector(3);
15793 15995 CImg<uptrT>::vector((uptrT)mp_cross,pos,arg1,arg2).move_to(code);
15794 15996 _cimg_mp_return(pos);
15795 15997 }
15796 15998  
15797 15999 if (!std::strncmp(ss,"cut(",4)) { // Cut
  16000 + _cimg_mp_op("Function 'cut()'");
15798 16001 s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15799   - arg1 = compile(ss4,s1==se2?++s1:s1,depth1,0);
  16002 + arg1 = compile(ss4,s1,depth1,0);
15800 16003 s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
15801   - arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
15802   - arg3 = compile(s2 + 1,se1,depth1,0);
  16004 + arg2 = compile(++s1,s2,depth1,0);
  16005 + arg3 = compile(++s2,se1,depth1,0);
15803 16006 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_cut,arg1,arg2,arg3);
15804 16007 if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3)) {
15805 16008 val = mem[arg1];
... ... @@ -15813,6 +16016,7 @@ namespace cimg_library_suffixed {
15813 16016  
15814 16017 case 'd' :
15815 16018 if (!std::strncmp(ss,"date(",5)) { // Date and file date
  16019 + _cimg_mp_op("Function 'date()'");
15816 16020 s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15817 16021 arg1 = 0;
15818 16022 is_sth = s1!=se1; // is_fdate
... ... @@ -15820,12 +16024,13 @@ namespace cimg_library_suffixed {
15820 16024 (cimg_sscanf(ss5,"%u%c",&arg1,&sep)!=2 || sep!=')')) is_sth = true;
15821 16025 if (is_sth) {
15822 16026 if (cimg_sscanf(ss5,"%u%c",&arg1,&sep)!=2 || sep!=',') { arg1 = 0; s1 = ss4; }
15823   - *se1 = 0; val = (double)cimg::fdate(s1 + 1,arg1); *se1 = ')';
  16027 + *se1 = 0; val = (double)cimg::fdate(++s1,arg1); *se1 = ')';
15824 16028 } else val = (double)cimg::date(arg1);
15825 16029 _cimg_mp_constant(val);
15826 16030 }
15827 16031  
15828 16032 if (!std::strncmp(ss,"debug(",6)) { // Print debug info
  16033 + _cimg_mp_op("Function 'debug()'");
15829 16034 p1 = code._width;
15830 16035 arg1 = compile(ss6,se1,depth1,p_ref);
15831 16036 *se1 = 0;
... ... @@ -15835,52 +16040,233 @@ namespace cimg_library_suffixed {
15835 16040 _cimg_mp_return(arg1);
15836 16041 }
15837 16042  
  16043 + if (!std::strncmp(ss,"det(",4)) { // Matrix determinant
  16044 + _cimg_mp_op("Function 'det()'");
  16045 + arg1 = compile(ss4,se1,depth1,0);
  16046 + _cimg_mp_check_matrix_square(arg1,1);
  16047 + p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
  16048 + _cimg_mp_scalar2(mp_det,arg1,p1);
  16049 + }
  16050 +
  16051 + if (!std::strncmp(ss,"diag(",5)) { // Diagonal matrix
  16052 + _cimg_mp_op("Function 'diag()'");
  16053 + arg1 = compile(ss5,se1,depth1,0);
  16054 + _cimg_mp_check_type(arg1,1,2,0);
  16055 + p1 = _cimg_mp_vector_size(arg1);
  16056 + pos = vector(p1*p1);
  16057 + CImg<uptrT>::vector((uptrT)mp_diag,pos,arg1,p1).move_to(code);
  16058 + _cimg_mp_return(pos);
  16059 + }
  16060 +
15838 16061 if (!std::strncmp(ss,"dot(",4)) { // Dot product
15839   - s_op = "Function 'dot()'";
  16062 + _cimg_mp_op("Function 'dot()'");
15840 16063 s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15841 16064 arg1 = compile(ss4,s1,depth1,0);
15842   - arg2 = compile(s1 + 1,se1,depth1,0);
15843   - _cimg_mp_check_type(arg1,1,s_op,2,0);
15844   - _cimg_mp_check_type(arg2,2,s_op,2,0);
  16065 + arg2 = compile(++s1,se1,depth1,0);
  16066 + _cimg_mp_check_type(arg1,1,2,0);
  16067 + _cimg_mp_check_type(arg2,2,2,0);
15845 16068 if (_cimg_mp_is_vector(arg1)) _cimg_mp_scalar3(mp_dot,arg1,arg2,_cimg_mp_vector_size(arg1));
15846 16069 _cimg_mp_scalar2(mp_mul,arg1,arg2);
15847 16070 }
15848 16071  
15849 16072 if (!std::strncmp(ss,"dowhile",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // Do..while
  16073 + _cimg_mp_op("Function 'dowhile()'");
15850 16074 if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace
15851 16075 s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15852 16076 p1 = code._width;
15853 16077 arg1 = compile(ss8,s1,depth1,0);
15854   - if (s1<se1) arg2 = compile(s1 + 1,se1,depth1,0);
15855   - else arg2 = arg1;
15856   - _cimg_mp_check_type(arg2,2,"Function 'dowhile()'",1,0);
  16078 + arg2 = s1<se1?compile(++s1,se1,depth1,0):arg1;
  16079 + _cimg_mp_check_type(arg2,2,1,0);
15857 16080 CImg<uptrT>::vector((uptrT)mp_dowhile,arg1,arg2,code._width - p1).move_to(code,p1);
15858 16081 _cimg_mp_return(arg1);
15859 16082 }
  16083 +
  16084 + if (!std::strncmp(ss,"draw(",5)) { // Draw image
  16085 + _cimg_mp_op("Function 'draw()'");
  16086 + is_parallelizable = false;
  16087 + if (*ss5=='#') { // Index specified
  16088 + s0 = ss6; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  16089 + p1 = compile(ss6,s0++,depth1,0);
  16090 + _cimg_mp_check_list(true);
  16091 + } else { p1 = ~0U; s0 = ss5; }
  16092 + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16093 + arg1 = compile(s0,s1,depth1,0);
  16094 + arg2 = is_relative?0U:(unsigned int)_cimg_mp_x;
  16095 + arg3 = is_relative?0U:(unsigned int)_cimg_mp_y;
  16096 + arg4 = is_relative?0U:(unsigned int)_cimg_mp_z;
  16097 + arg5 = is_relative?0U:(unsigned int)_cimg_mp_c;
  16098 + if (s1<se1) {
  16099 + s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  16100 + arg2 = compile(++s1,s0,depth1,0);
  16101 + if (_cimg_mp_is_vector(arg2)) { // Coordinates specified as a vector
  16102 + p2 = _cimg_mp_vector_size(arg2);
  16103 + ++arg2;
  16104 + if (p2>1) {
  16105 + arg3 = arg2 + 1;
  16106 + if (p2>2) {
  16107 + arg4 = arg3 + 1;
  16108 + if (p2>3) arg5 = arg4 + 1;
  16109 + }
  16110 + }
  16111 + ++s0;
  16112 + is_sth = true;
  16113 + } else {
  16114 + if (s0<se1) {
  16115 + is_sth = p1!=~0U;
  16116 + s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16117 + arg3 = compile(++s0,s1,depth1,0);
  16118 + _cimg_mp_check_type(arg3,is_sth?4:3,1,0);
  16119 + if (s1<se1) {
  16120 + s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  16121 + arg4 = compile(++s1,s0,depth1,0);
  16122 + _cimg_mp_check_type(arg4,is_sth?5:4,1,0);
  16123 + if (s0<se1) {
  16124 + s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16125 + arg5 = compile(++s0,s1,depth1,0);
  16126 + _cimg_mp_check_type(arg5,is_sth?6:5,1,0);
  16127 + s0 = ++s1;
  16128 + }
  16129 + }
  16130 + }
  16131 + is_sth = false;
  16132 + }
  16133 + }
  16134 +
  16135 + CImg<uptrT>::vector((uptrT)mp_draw,arg1,p1,arg2,arg3,arg4,arg5,0,0,0,0,1,(uptrT)-1,0,1).
  16136 + move_to(opcode);
  16137 +
  16138 + arg2 = arg3 = arg4 = arg5 = ~0U;
  16139 + p2 = p1!=~0U?0:1;
  16140 + if (s0<se1) {
  16141 + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16142 + arg2 = compile(s0,s1,depth1,0);
  16143 + _cimg_mp_check_constant(arg2,p2 + (is_sth?3:6),true);
  16144 + arg2 = (unsigned int)mem[arg2];
  16145 + if (s1<se1) {
  16146 + s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  16147 + arg3 = compile(++s1,s0,depth1,0);
  16148 + _cimg_mp_check_constant(arg3,p2 + (is_sth?4:7),true);
  16149 + arg3 = (unsigned int)mem[arg3];
  16150 + if (s0<se1) {
  16151 + s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16152 + arg4 = compile(++s0,s1,depth1,0);
  16153 + _cimg_mp_check_constant(arg4,p2 + (is_sth?5:8),true);
  16154 + arg4 = (unsigned int)mem[arg4];
  16155 + if (s1<se1) {
  16156 + s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  16157 + arg5 = compile(++s1,s0,depth1,0);
  16158 + _cimg_mp_check_constant(arg5,p2 + (is_sth?6:9),true);
  16159 + arg5 = (unsigned int)mem[arg5];
  16160 + }
  16161 + }
  16162 + }
  16163 + }
  16164 + if (s0<s1) s0 = s1;
  16165 + if (arg2==~0U || arg3==~0U || arg4==~0U || arg5==~0U) {
  16166 + if (p1!=~0U) {
  16167 + _cimg_mp_check_constant(p1,1,false);
  16168 + p1 = (unsigned int)cimg::mod((int)mem[p1],listout.width());
  16169 + }
  16170 + const CImg<T> &img = p1!=~0U?listout[p1]:imgout;
  16171 + if (arg2==~0U) arg2 = img._width;
  16172 + if (arg3==~0U) arg3 = img._height;
  16173 + if (arg4==~0U) arg4 = img._depth;
  16174 + if (arg5==~0U) arg5 = img._spectrum;
  16175 + }
  16176 + if (arg2*arg3*arg4*arg5!=_cimg_mp_vector_size(arg1)) {
  16177 + *se = saved_char; cimg::strellipsize(expr,64);
  16178 + throw CImgArgumentException("[_cimg_math_parser] "
  16179 + "CImg<%s>::%s: %s: Type of %s argument ('%s') and specified size "
  16180 + "(%u,%u,%u,%u) do not match, in expression '%s%s%s'.",
  16181 + pixel_type(),_cimg_mp_calling_function,s_op,
  16182 + p1==~0U?"first":"second",s_type(arg1)._data,
  16183 + arg2,arg3,arg4,arg5,
  16184 + (ss - 4)>expr._data?"...":"",
  16185 + (ss - 4)>expr._data?ss - 4:expr._data,
  16186 + se<&expr.back()?"...":"");
  16187 + }
  16188 + opcode[7] = (uptrT)arg2;
  16189 + opcode[8] = (uptrT)arg3;
  16190 + opcode[9] = (uptrT)arg4;
  16191 + opcode[10] = (uptrT)arg5;
  16192 +
  16193 + if (s0<se1) {
  16194 + s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16195 + arg6 = compile(++s0,s1,depth1,0);
  16196 + _cimg_mp_check_type(arg6,0,1,0);
  16197 + opcode[11] = arg6;
  16198 + if (s1<se1) {
  16199 + s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  16200 + p2 = compile(++s1,s0,depth1,0);
  16201 + _cimg_mp_check_type(p2,0,2,0);
  16202 + if (arg2*arg3*arg4%_cimg_mp_vector_size(p2)) {
  16203 + *se = saved_char; cimg::strellipsize(expr,64);
  16204 + throw CImgArgumentException("[_cimg_math_parser] "
  16205 + "CImg<%s>::%s: %s: Type of opacity mask ('%s') and specified size "
  16206 + "(%u,%u,%u,%u) do not match, in expression '%s%s%s'.",
  16207 + pixel_type(),_cimg_mp_calling_function,s_op,
  16208 + s_type(p2)._data,
  16209 + arg2,arg3,arg4,arg5,
  16210 + (ss - 4)>expr._data?"...":"",
  16211 + (ss - 4)>expr._data?ss - 4:expr._data,
  16212 + se<&expr.back()?"...":"");
  16213 + }
  16214 + opcode[12] = p2;
  16215 + opcode[13] = _cimg_mp_vector_size(p2)/(arg2*arg3*arg4);
  16216 + p3 = s0<se1?compile(++s0,se1,depth1,0):1;
  16217 + _cimg_mp_check_type(p3,0,1,0);
  16218 + opcode[14] = p3;
  16219 + }
  16220 + }
  16221 + opcode.move_to(code);
  16222 + _cimg_mp_return(arg1);
  16223 + }
15860 16224 break;
15861 16225  
15862 16226 case 'e' :
  16227 + if (!std::strncmp(ss,"eig(",4)) { // Matrix eigenvalues/eigenvector
  16228 + _cimg_mp_op("Function 'eig()'");
  16229 + arg1 = compile(ss4,se1,depth1,0);
  16230 + _cimg_mp_check_matrix_square(arg1,1);
  16231 + p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
  16232 + pos = vector((p1 + 1)*p1);
  16233 + CImg<uptrT>::vector((uptrT)mp_eig,pos,arg1,p1).move_to(code);
  16234 + _cimg_mp_return(pos);
  16235 + }
  16236 +
15863 16237 if (!std::strncmp(ss,"exp(",4)) { // Exponential
  16238 + _cimg_mp_op("Function 'exp()'");
15864 16239 arg1 = compile(ss4,se1,depth1,0);
15865 16240 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_exp,arg1);
15866 16241 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::exp(mem[arg1]));
15867 16242 _cimg_mp_scalar1(mp_exp,arg1);
15868 16243 }
  16244 +
  16245 + if (!std::strncmp(ss,"eye(",4)) { // Identity matrix
  16246 + _cimg_mp_op("Function 'eye()'");
  16247 + arg1 = compile(ss4,se1,depth1,0);
  16248 + _cimg_mp_check_constant(arg1,1,true);
  16249 + p1 = (unsigned int)mem[arg1];
  16250 + pos = vector(p1*p1);
  16251 + CImg<uptrT>::vector((uptrT)mp_eye,pos,p1).move_to(code);
  16252 + _cimg_mp_return(pos);
  16253 + }
15869 16254 break;
15870 16255  
15871 16256 case 'f' :
15872 16257 if (*ss1=='o' && *ss2=='r' && (*ss3=='(' || (*ss3 && *ss3<=' ' && *ss4=='('))) { // For loop
  16258 + _cimg_mp_op("Function 'for()'");
15873 16259 if (*ss3<=' ') cimg::swap(*ss3,*ss4); // Allow space before opening brace
15874 16260 s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15875 16261 s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
15876 16262 s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
15877 16263 compile(ss4,s1,depth1,0);
15878 16264 p1 = code._width;
15879   - arg1 = compile(s1 + 1,s2,depth1,0);
  16265 + arg1 = compile(++s1,s2,depth1,0);
15880 16266 p2 = code._width;
15881   - if (s3<se1) { pos = compile(s3 + 1,se1,depth1,0); compile(s2 + 1,s3,depth1,0); } // Body + proc
15882   - else pos = compile(s2 + 1,se1,depth1,0); // Proc only
15883   - _cimg_mp_check_type(arg1,2,"Function 'for()'",1,0);
  16267 + if (s3<se1) { pos = compile(s3 + 1,se1,depth1,0); compile(++s2,s3,depth1,0); } // Body + proc
  16268 + else pos = compile(++s2,se1,depth1,0); // Proc only
  16269 + _cimg_mp_check_type(arg1,2,1,0);
15884 16270 arg2 = _cimg_mp_is_vector(pos)?_cimg_mp_vector_size(pos):0; // Output vector size (or 0 if scalar)
15885 16271 CImg<uptrT>::vector((uptrT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1);
15886 16272 _cimg_mp_return(pos);
... ... @@ -15889,14 +16275,11 @@ namespace cimg_library_suffixed {
15889 16275  
15890 16276 case 'g' :
15891 16277 if (!std::strncmp(ss,"gauss(",6)) { // Gaussian function
  16278 + _cimg_mp_op("Function 'gauss()'");
15892 16279 s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15893 16280 arg1 = compile(ss6,s1,depth1,0);
15894   - arg2 = 1;
15895   - if (s1<se1) {
15896   - s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
15897   - arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
15898   - }
15899   - _cimg_mp_check_type(arg2,2,"Function 'gauss()'",1,0);
  16281 + arg2 = s1<se1?compile(++s1,se1,depth1,0):1;
  16282 + _cimg_mp_check_type(arg2,2,1,0);
15900 16283 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(mp_gauss,arg1,arg2);
15901 16284 if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) {
15902 16285 val1 = mem[arg1];
... ... @@ -15909,12 +16292,12 @@ namespace cimg_library_suffixed {
15909 16292  
15910 16293 case 'h' :
15911 16294 if (!std::strncmp(ss,"hypot(",6)) { // Hypothenuse
15912   - s_op = "Function 'hypot()'";
  16295 + _cimg_mp_op("Function 'hypot()'");
15913 16296 s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15914 16297 arg1 = compile(ss6,s1,depth1,0);
15915   - arg2 = compile(s1 + 1,se1,depth1,0);
15916   - _cimg_mp_check_type(arg1,1,s_op,1,0);
15917   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  16298 + arg2 = compile(++s1,se1,depth1,0);
  16299 + _cimg_mp_check_type(arg1,1,1,0);
  16300 + _cimg_mp_check_type(arg2,2,1,0);
15918 16301 if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) {
15919 16302 val1 = cimg::abs(mem[arg1]);
15920 16303 val2 = cimg::abs(mem[arg2]);
... ... @@ -15928,19 +16311,21 @@ namespace cimg_library_suffixed {
15928 16311  
15929 16312 case 'i' :
15930 16313 if (*ss1=='f' && (*ss2=='(' || (*ss2 && *ss2<=' ' && *ss3=='('))) { // If..then[..else.]
15931   - s_op = "Function 'if()'";
  16314 + _cimg_mp_op("Function 'if()'");
15932 16315 if (*ss2<=' ') cimg::swap(*ss2,*ss3); // Allow space before opening brace
15933 16316 s1 = ss3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15934 16317 s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
15935 16318 arg1 = compile(ss3,s1,depth1,0);
  16319 + _cimg_mp_check_type(arg1,1,1,0);
  16320 + if (_cimg_mp_is_constant(arg1)) {
  16321 + if ((bool)mem[arg1]) return compile(++s1,s2,depth1,0);
  16322 + else return s2<se1?compile(++s2,se1,depth1,0):0;
  16323 + }
15936 16324 p2 = code._width;
15937   - arg2 = compile(s1 + 1,s2,depth1,0);
  16325 + arg2 = compile(++s1,s2,depth1,0);
15938 16326 p3 = code._width;
15939   - arg3 = s2>=se1?0:compile(s2 + 1,se1,depth1,0);
15940   - _cimg_mp_check_type(arg1,1,s_op,1,0);
15941   - _cimg_mp_check_type(arg3,3,s_op,3,_cimg_mp_vector_size(arg2));
15942   - if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))
15943   - _cimg_mp_constant(mem[arg1]?mem[arg2]:mem[arg3]);
  16327 + arg3 = s2<se1?compile(++s2,se1,depth1,0):_cimg_mp_is_vector(arg2)?vector(_cimg_mp_vector_size(arg2),0):0;
  16328 + _cimg_mp_check_type(arg3,3,_cimg_mp_is_vector(arg2)?2:1,_cimg_mp_vector_size(arg2));
15944 16329 arg4 = _cimg_mp_is_vector(arg2)?_cimg_mp_vector_size(arg2):0; // Output vector size (or 0 if scalar)
15945 16330 if (arg4) pos = vector(arg4); else pos = scalar();
15946 16331 CImg<uptrT>::vector((uptrT)mp_if,pos,arg1,arg2,arg3,
... ... @@ -15949,12 +16334,13 @@ namespace cimg_library_suffixed {
15949 16334 }
15950 16335  
15951 16336 if (!std::strncmp(ss,"init(",5)) { // Init
  16337 + _cimg_mp_op("Function 'init()'");
15952 16338 if (ss0!=expr._data || code.width()) { // (only allowed as the first instruction)
15953 16339 *se = saved_char; cimg::strellipsize(expr,64);
15954 16340 throw CImgArgumentException("[_cimg_math_parser] "
15955   - "CImg<%s>::%s: Function 'init()': Init invokation not done at the "
  16341 + "CImg<%s>::%s: %s: Init invokation not done at the "
15956 16342 "beginning of expression '%s%s%s'.",
15957   - pixel_type(),_cimg_mp_calling_function,
  16343 + pixel_type(),_cimg_mp_calling_function,s_op,
15958 16344 (ss - 4)>expr._data?"...":"",
15959 16345 (ss - 4)>expr._data?ss - 4:expr._data,
15960 16346 se<&expr.back()?"...":"");
... ... @@ -15965,15 +16351,27 @@ namespace cimg_library_suffixed {
15965 16351 }
15966 16352  
15967 16353 if (!std::strncmp(ss,"int(",4)) { // Integer cast
  16354 + _cimg_mp_op("Function 'int()'");
15968 16355 arg1 = compile(ss4,se1,depth1,0);
15969 16356 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_int,arg1);
15970 16357 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant((long)mem[arg1]);
15971 16358 _cimg_mp_scalar1(mp_int,arg1);
15972 16359 }
15973 16360  
  16361 + if (!std::strncmp(ss,"inv(",4)) { // Matrix/scalar inversion
  16362 + _cimg_mp_op("Function 'inv()'");
  16363 + arg1 = compile(ss4,se1,depth1,0);
  16364 + _cimg_mp_check_matrix_square(arg1,1);
  16365 + p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
  16366 + pos = vector(p1*p1);
  16367 + CImg<uptrT>::vector((uptrT)mp_inv,pos,arg1,p1).move_to(code);
  16368 + _cimg_mp_return(pos);
  16369 + }
  16370 +
15974 16371 if (*ss1=='s') { // Family of 'is_?()' functions
15975 16372  
15976 16373 if (!std::strncmp(ss,"isbool(",7)) { // Is boolean?
  16374 + _cimg_mp_op("Function 'isbool()'");
15977 16375 if (ss7==se1) _cimg_mp_return(0);
15978 16376 arg1 = compile(ss7,se1,depth1,0);
15979 16377 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isbool,arg1);
... ... @@ -15982,6 +16380,7 @@ namespace cimg_library_suffixed {
15982 16380 }
15983 16381  
15984 16382 if (!std::strncmp(ss,"isdir(",6)) { // Is directory?
  16383 + _cimg_mp_op("Function 'isdir()'");
15985 16384 *se1 = 0;
15986 16385 is_sth = cimg::is_directory(ss6);
15987 16386 *se1 = ')';
... ... @@ -15989,6 +16388,7 @@ namespace cimg_library_suffixed {
15989 16388 }
15990 16389  
15991 16390 if (!std::strncmp(ss,"isfile(",7)) { // Is file?
  16391 + _cimg_mp_op("Function 'isfile()'");
15992 16392 *se1 = 0;
15993 16393 is_sth = cimg::is_file(ss7);
15994 16394 *se1 = ')';
... ... @@ -15996,6 +16396,8 @@ namespace cimg_library_suffixed {
15996 16396 }
15997 16397  
15998 16398 if (!std::strncmp(ss,"isin(",5)) { // Is in sequence/vector?
  16399 + if (ss5>=se1) _cimg_mp_return(0);
  16400 + _cimg_mp_op("Function 'isin()'");
15999 16401 pos = scalar();
16000 16402 CImg<uptrT>::vector((uptrT)mp_isin,pos).move_to(_opcode);
16001 16403 for (s = ss5; s<se; ++s) {
... ... @@ -16014,6 +16416,7 @@ namespace cimg_library_suffixed {
16014 16416 }
16015 16417  
16016 16418 if (!std::strncmp(ss,"isinf(",6)) { // Is infinite?
  16419 + _cimg_mp_op("Function 'isinf()'");
16017 16420 if (ss6==se1) _cimg_mp_return(0);
16018 16421 arg1 = compile(ss6,se1,depth1,0);
16019 16422 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isinf,arg1);
... ... @@ -16022,6 +16425,7 @@ namespace cimg_library_suffixed {
16022 16425 }
16023 16426  
16024 16427 if (!std::strncmp(ss,"isint(",6)) { // Is integer?
  16428 + _cimg_mp_op("Function 'isint()'");
16025 16429 if (ss6==se1) _cimg_mp_return(0);
16026 16430 arg1 = compile(ss6,se1,depth1,0);
16027 16431 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isint,arg1);
... ... @@ -16030,6 +16434,7 @@ namespace cimg_library_suffixed {
16030 16434 }
16031 16435  
16032 16436 if (!std::strncmp(ss,"isnan(",6)) { // Is NaN?
  16437 + _cimg_mp_op("Function 'isnan()'");
16033 16438 if (ss6==se1) _cimg_mp_return(0);
16034 16439 arg1 = compile(ss6,se1,depth1,0);
16035 16440 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isnan,arg1);
... ... @@ -16038,6 +16443,7 @@ namespace cimg_library_suffixed {
16038 16443 }
16039 16444  
16040 16445 if (!std::strncmp(ss,"isval(",6)) { // Is value?
  16446 + _cimg_mp_op("Function 'isval()'");
16041 16447 val = 0;
16042 16448 if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1);
16043 16449 _cimg_mp_return(0);
... ... @@ -16048,6 +16454,7 @@ namespace cimg_library_suffixed {
16048 16454  
16049 16455 case 'l' :
16050 16456 if (!std::strncmp(ss,"log(",4)) { // Natural logarithm
  16457 + _cimg_mp_op("Function 'log()'");
16051 16458 arg1 = compile(ss4,se1,depth1,0);
16052 16459 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log,arg1);
16053 16460 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log(mem[arg1]));
... ... @@ -16055,6 +16462,7 @@ namespace cimg_library_suffixed {
16055 16462 }
16056 16463  
16057 16464 if (!std::strncmp(ss,"log2(",5)) { // Base-2 logarithm
  16465 + _cimg_mp_op("Function 'log2()'");
16058 16466 arg1 = compile(ss5,se1,depth1,0);
16059 16467 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log2,arg1);
16060 16468 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::log2(mem[arg1]));
... ... @@ -16062,6 +16470,7 @@ namespace cimg_library_suffixed {
16062 16470 }
16063 16471  
16064 16472 if (!std::strncmp(ss,"log10(",6)) { // Base-10 logarithm
  16473 + _cimg_mp_op("Function 'log10()'");
16065 16474 arg1 = compile(ss6,se1,depth1,0);
16066 16475 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log10,arg1);
16067 16476 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log10(mem[arg1]));
... ... @@ -16070,59 +16479,16 @@ namespace cimg_library_suffixed {
16070 16479 break;
16071 16480  
16072 16481 case 'm' :
16073   - if (!std::strncmp(ss,"mdet(",5)) { // Matrix determinant
16074   - arg1 = compile(ss5,se1,depth1,0);
16075   - _cimg_mp_check_matrix_square(arg1,1,"Function 'mdet()'");
16076   - p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
16077   - _cimg_mp_scalar2(mp_matrix_det,arg1,p1);
16078   - }
16079   -
16080   - if (!std::strncmp(ss,"mdiag(",5)) { // Diagonal matrix
16081   - arg1 = compile(ss6,se1,depth1,0);
16082   - _cimg_mp_check_type(arg1,1,"Function 'mdiag()'",2,0);
16083   - p1 = _cimg_mp_vector_size(arg1);
16084   - pos = vector(p1*p1);
16085   - CImg<uptrT>::vector((uptrT)mp_matrix_diag,pos,arg1,p1).move_to(code);
16086   - _cimg_mp_return(pos);
16087   - }
16088   -
16089   - if (!std::strncmp(ss,"meig(",5)) { // Matrix eigenvalues/eigenvector
16090   - arg1 = compile(ss5,se1,depth1,0);
16091   - _cimg_mp_check_matrix_square(arg1,1,"Function 'meig()'");
16092   - p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
16093   - pos = vector((p1 + 1)*p1);
16094   - CImg<uptrT>::vector((uptrT)mp_matrix_eig,pos,arg1,p1).move_to(code);
16095   - _cimg_mp_return(pos);
16096   - }
16097   -
16098   - if (!std::strncmp(ss,"meye(",5)) { // Matrix eigenvalues/eigenvector
16099   - arg1 = compile(ss5,se1,depth1,0);
16100   - _cimg_mp_check_constant(arg1,1,"Function 'meye()'",true);
16101   - p1 = (unsigned int)mem[arg1];
16102   - pos = vector(p1*p1);
16103   - CImg<uptrT>::vector((uptrT)mp_matrix_eye,pos,p1).move_to(code);
16104   - _cimg_mp_return(pos);
16105   - }
16106   -
16107   - if (!std::strncmp(ss,"minv(",5)) { // Matrix inversion
16108   - arg1 = compile(ss5,se1,depth1,0);
16109   - _cimg_mp_check_matrix_square(arg1,1,"Function 'minv()'");
16110   - p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
16111   - pos = vector(p1*p1);
16112   - CImg<uptrT>::vector((uptrT)mp_matrix_inv,pos,arg1,p1).move_to(code);
16113   - _cimg_mp_return(pos);
16114   - }
16115   -
16116   - if (!std::strncmp(ss,"mmul(",5)) { // Matrix multiplication
16117   - s_op = "Function 'mmul()'";
16118   - s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
16119   - arg1 = compile(ss5,s1==se2?++s1:s1,depth1,0);
  16482 + if (!std::strncmp(ss,"mul(",4)) { // Matrix multiplication
  16483 + _cimg_mp_op("Function 'mul()'");
  16484 + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16485 + arg1 = compile(ss4,s1,depth1,0);
16120 16486 s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
16121   - arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
16122   - if (s2<se1) arg3 = compile(++s2,se1,depth1,0); else arg3 = 1;
16123   - _cimg_mp_check_type(arg1,1,s_op,2,0);
16124   - _cimg_mp_check_type(arg2,2,s_op,2,0);
16125   - _cimg_mp_check_constant(arg3,3,s_op,true);
  16487 + arg2 = compile(++s1,s2,depth1,0);
  16488 + arg3 = s2<se1?compile(++s2,se1,depth1,0):1;
  16489 + _cimg_mp_check_type(arg1,1,2,0);
  16490 + _cimg_mp_check_type(arg2,2,2,0);
  16491 + _cimg_mp_check_constant(arg3,3,true);
16126 16492 p1 = _cimg_mp_vector_size(arg1);
16127 16493 p2 = _cimg_mp_vector_size(arg2);
16128 16494 p3 = (unsigned int)mem[arg3];
... ... @@ -16131,7 +16497,7 @@ namespace cimg_library_suffixed {
16131 16497 if (arg4*arg5!=p1 || arg5*p3!=p2) {
16132 16498 *se = saved_char; cimg::strellipsize(expr,64);
16133 16499 throw CImgArgumentException("[_cimg_math_parser] "
16134   - "CImg<%s>::%s: %s: Sizes of first and second arguments ('%s' and '%s') "
  16500 + "CImg<%s>::%s: %s: Types of first and second arguments ('%s' and '%s') "
16135 16501 "do not match for third argument 'nb_colsB=%u', "
16136 16502 "in expression '%s%s%s'.",
16137 16503 pixel_type(),_cimg_mp_calling_function,s_op,
... ... @@ -16144,95 +16510,12 @@ namespace cimg_library_suffixed {
16144 16510 CImg<uptrT>::vector((uptrT)mp_matrix_mul,pos,arg1,arg2,arg4,arg5,p3).move_to(code);
16145 16511 _cimg_mp_return(pos);
16146 16512 }
16147   -
16148   - if (!std::strncmp(ss,"mrot(",5)) { // Rotation matrix
16149   - s_op = "Function 'mrot()'";
16150   - s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
16151   - arg1 = compile(ss5,s1==se2?++s1:s1,depth1,0);
16152   - s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
16153   - arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
16154   - s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
16155   - arg3 = compile(s2 + 1,s3==se2?++s3:s3,depth1,0);
16156   - arg4 = compile(++s3,se1,depth1,0);
16157   - _cimg_mp_check_type(arg1,1,s_op,1,0);
16158   - _cimg_mp_check_type(arg2,2,s_op,1,0);
16159   - _cimg_mp_check_type(arg3,3,s_op,1,0);
16160   - _cimg_mp_check_type(arg4,4,s_op,1,0);
16161   - pos = vector(9);
16162   - CImg<uptrT>::vector((uptrT)mp_matrix_rot,pos,arg1,arg2,arg3,arg4).move_to(code);
16163   - _cimg_mp_return(pos);
16164   - }
16165   -
16166   - if (!std::strncmp(ss,"msolve(",7)) { // Solve linear system
16167   - s_op = "Function 'msolve()'";
16168   - s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
16169   - arg1 = compile(ss7,s1==se2?++s1:s1,depth1,0);
16170   - s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
16171   - arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
16172   - if (s2<se1) arg3 = compile(++s2,se1,depth1,0); else arg3 = 1;
16173   - _cimg_mp_check_type(arg1,1,s_op,2,0);
16174   - _cimg_mp_check_type(arg2,2,s_op,2,0);
16175   - _cimg_mp_check_constant(arg3,3,s_op,true);
16176   - p1 = _cimg_mp_vector_size(arg1);
16177   - p2 = _cimg_mp_vector_size(arg2);
16178   - p3 = (unsigned int)mem[arg3];
16179   - arg5 = p2/p3;
16180   - arg4 = p1/arg5;
16181   - if (arg4*arg5!=p1 || arg4*p3!=p2) {
16182   - *se = saved_char; cimg::strellipsize(expr,64);
16183   - throw CImgArgumentException("[_cimg_math_parser] "
16184   - "CImg<%s>::%s: %s: Sizes of first and second arguments ('%s' and '%s') "
16185   - "do not match for third argument 'nb_colsB=%u', "
16186   - "in expression '%s%s%s'.",
16187   - pixel_type(),_cimg_mp_calling_function,s_op,
16188   - s_type(arg1)._data,s_type(arg2)._data,p3,
16189   - (ss - 4)>expr._data?"...":"",
16190   - (ss - 4)>expr._data?ss - 4:expr._data,
16191   - se<&expr.back()?"...":"");
16192   - }
16193   - pos = vector(arg5*p3);
16194   - CImg<uptrT>::vector((uptrT)mp_matrix_solve,pos,arg1,arg2,arg4,arg5,p3).move_to(code);
16195   - _cimg_mp_return(pos);
16196   - }
16197   -
16198   - if (!std::strncmp(ss,"mtrace(",7)) { // Matrix trace
16199   - arg1 = compile(ss7,se1,depth1,0);
16200   - _cimg_mp_check_matrix_square(arg1,1,"Function 'mtrace()'");
16201   - p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
16202   - _cimg_mp_scalar2(mp_matrix_trace,arg1,p1);
16203   - }
16204   -
16205   - if (!std::strncmp(ss,"mtrans(",7)) { // Matrix transpose
16206   - s_op = "Function 'mtrans()'";
16207   - s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
16208   - arg1 = compile(ss7,s1==se2?++s1:s1,depth1,0);
16209   - arg2 = compile(++s1,se1,depth1,0);
16210   - _cimg_mp_check_type(arg1,1,s_op,2,0);
16211   - _cimg_mp_check_constant(arg2,2,s_op,true);
16212   - p1 = _cimg_mp_vector_size(arg1);
16213   - p2 = (unsigned int)mem[arg2];
16214   - p3 = p1/p2;
16215   - if (p2*p3!=p1) {
16216   - *se = saved_char; cimg::strellipsize(expr,64);
16217   - throw CImgArgumentException("[_cimg_math_parser] "
16218   - "CImg<%s>::%s: %s: Size of first argument ('%s') does not match"
16219   - "for second specified argument 'nb_cols=%u', "
16220   - "in expression '%s%s%s'.",
16221   - pixel_type(),_cimg_mp_calling_function,s_op,
16222   - s_type(arg1)._data,p2,
16223   - (ss - 4)>expr._data?"...":"",
16224   - (ss - 4)>expr._data?ss - 4:expr._data,
16225   - se<&expr.back()?"...":"");
16226   - }
16227   - pos = vector(p3*p2);
16228   - CImg<uptrT>::vector((uptrT)mp_matrix_trans,pos,arg1,p2,p3).move_to(code);
16229   - _cimg_mp_return(pos);
16230   - }
16231 16513 break;
16232 16514  
16233 16515 case 'n' :
16234 16516 if (!std::strncmp(ss,"narg(",5)) { // Number of arguments
16235   - if (*ss5==')') _cimg_mp_return(0);
  16517 + _cimg_mp_op("Function 'narg()'");
  16518 + if (ss5>=se1) _cimg_mp_return(0);
16236 16519 arg1 = 0;
16237 16520 for (s = ss5; s<se; ++s) {
16238 16521 ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
... ... @@ -16244,6 +16527,7 @@ namespace cimg_library_suffixed {
16244 16527  
16245 16528 if ((cimg_sscanf(ss,"norm%u%c",&(arg1=~0U),&sep)==2 && sep=='(') ||
16246 16529 !std::strncmp(ss,"norminf(",8)) { // Lp norm
  16530 + _cimg_mp_op("Function 'normP()'");
16247 16531 pos = scalar();
16248 16532 switch (arg1) {
16249 16533 case 0 : CImg<uptrT>::vector((uptrT)mp_norm0,pos).move_to(_opcode); break;
... ... @@ -16272,6 +16556,7 @@ namespace cimg_library_suffixed {
16272 16556  
16273 16557 case 'p' :
16274 16558 if (!std::strncmp(ss,"print(",6)) { // Print expression
  16559 + _cimg_mp_op("Function 'print()'");
16275 16560 pos = compile(ss6,se1,depth1,p_ref);
16276 16561 *se1 = 0;
16277 16562 if (_cimg_mp_is_vector(pos)) // Vector
... ... @@ -16287,14 +16572,11 @@ namespace cimg_library_suffixed {
16287 16572  
16288 16573 case 'r' :
16289 16574 if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { // Bitwise rotation
  16575 + _cimg_mp_op(ss[2]=='l'?"Function 'rol()'":"Function 'ror()'");
16290 16576 s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
16291   - arg1 = compile(ss4,s1==se2?++s1:s1,depth1,0);
16292   - arg2 = 1;
16293   - if (s1<se1) {
16294   - s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2;
16295   - arg2 = compile(s1 + 1,se1,depth1,0);
16296   - }
16297   - _cimg_mp_check_type(arg2,2,"Function 'rol()'",1,0);
  16577 + arg1 = compile(ss4,s1,depth1,0);
  16578 + arg2 = s1<se1?compile(++s1,se1,depth1,0):1;
  16579 + _cimg_mp_check_type(arg2,2,1,0);
16298 16580 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(*ss2=='l'?mp_rol:mp_ror,arg1,arg2);
16299 16581 if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16300 16582 _cimg_mp_constant(*ss2=='l'?cimg::rol(mem[arg1],(unsigned int)mem[arg2]):
... ... @@ -16302,19 +16584,56 @@ namespace cimg_library_suffixed {
16302 16584 _cimg_mp_scalar2(*ss2=='l'?mp_rol:mp_ror,arg1,arg2);
16303 16585 }
16304 16586  
  16587 + if (!std::strncmp(ss,"rot(",4)) { // 2d/3d rotation matrix
  16588 + _cimg_mp_op("Function 'rot()'");
  16589 + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16590 + arg1 = compile(ss4,s1,depth1,0);
  16591 + if (s1<se1) { // 3d rotation
  16592 + _cimg_mp_check_type(arg1,1,3,3);
  16593 + is_sth = false; // Is coordinates as vector?
  16594 + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
  16595 + is_sth = true;
  16596 + p2 = _cimg_mp_vector_size(arg1);
  16597 + ++arg1;
  16598 + arg2 = arg3 = 0;
  16599 + if (p2>1) {
  16600 + arg2 = arg1 + 1;
  16601 + if (p2>2) arg3 = arg2 + 1;
  16602 + }
  16603 + arg4 = compile(++s1,se1,depth1,0);
  16604 + } else {
  16605 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  16606 + arg2 = compile(++s1,s2,depth1,0);
  16607 + s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
  16608 + arg3 = compile(++s2,s3,depth1,0);
  16609 + arg4 = compile(++s3,se1,depth1,0);
  16610 + _cimg_mp_check_type(arg2,2,1,0);
  16611 + _cimg_mp_check_type(arg3,3,1,0);
  16612 + }
  16613 + _cimg_mp_check_type(arg4,is_sth?2:4,1,0);
  16614 + pos = vector(9);
  16615 + CImg<uptrT>::vector((uptrT)mp_rot3d,pos,arg1,arg2,arg3,arg4).move_to(code);
  16616 + } else { // 2d rotation
  16617 + _cimg_mp_check_type(arg1,1,1,0);
  16618 + pos = vector(4);
  16619 + CImg<uptrT>::vector((uptrT)mp_rot2d,pos,arg1).move_to(code);
  16620 + }
  16621 + _cimg_mp_return(pos);
  16622 + }
  16623 +
16305 16624 if (!std::strncmp(ss,"round(",6)) { // Value rounding
16306   - s_op = "Function 'round()'";
  16625 + _cimg_mp_op("Function 'round()'");
16307 16626 s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
16308   - arg1 = compile(ss6,s1==se2?++s1:s1,depth1,0);
  16627 + arg1 = compile(ss6,s1,depth1,0);
16309 16628 arg2 = 1;
16310 16629 arg3 = 0;
16311 16630 if (s1<se1) {
16312 16631 s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
16313   - arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
16314   - if (s2<se1) arg3 = compile(s2 + 1,se1,depth1,0);
  16632 + arg2 = compile(++s1,s2,depth1,0);
  16633 + arg3 = s2<se1?compile(++s2,se1,depth1,0):0;
16315 16634 }
16316   - _cimg_mp_check_type(arg2,2,s_op,1,0);
16317   - _cimg_mp_check_type(arg3,3,s_op,1,0);
  16635 + _cimg_mp_check_type(arg2,2,1,0);
  16636 + _cimg_mp_check_type(arg3,3,1,0);
16318 16637 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_round,arg1,arg2,arg3);
16319 16638 if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))
16320 16639 _cimg_mp_constant(cimg::round(mem[arg1],mem[arg2],(int)mem[arg3]));
... ... @@ -16324,6 +16643,7 @@ namespace cimg_library_suffixed {
16324 16643  
16325 16644 case 's' :
16326 16645 if (!std::strncmp(ss,"sign(",5)) { // Sign
  16646 + _cimg_mp_op("Function 'sign()'");
16327 16647 arg1 = compile(ss5,se1,depth1,0);
16328 16648 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sign,arg1);
16329 16649 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sign(mem[arg1]));
... ... @@ -16331,6 +16651,7 @@ namespace cimg_library_suffixed {
16331 16651 }
16332 16652  
16333 16653 if (!std::strncmp(ss,"sin(",4)) { // Sine
  16654 + _cimg_mp_op("Function 'sin()'");
16334 16655 arg1 = compile(ss4,se1,depth1,0);
16335 16656 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sin,arg1);
16336 16657 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sin(mem[arg1]));
... ... @@ -16338,13 +16659,23 @@ namespace cimg_library_suffixed {
16338 16659 }
16339 16660  
16340 16661 if (!std::strncmp(ss,"sinc(",5)) { // Sine cardinal
  16662 + _cimg_mp_op("Function 'sinc()'");
16341 16663 arg1 = compile(ss5,se1,depth1,0);
16342 16664 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinc,arg1);
16343 16665 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sinc(mem[arg1]));
16344 16666 _cimg_mp_scalar1(mp_sinc,arg1);
16345 16667 }
16346 16668  
  16669 + if (!std::strncmp(ss,"single(",7)) { // Force single thread execution
  16670 + _cimg_mp_op("Function 'single()'");
  16671 + p1 = code._width;
  16672 + arg1 = compile(ss7,se1,depth1,p_ref);
  16673 + CImg<uptrT>::vector((uptrT)mp_single,arg1,code._width - p1).move_to(code,p1);
  16674 + _cimg_mp_return(arg1);
  16675 + }
  16676 +
16347 16677 if (!std::strncmp(ss,"sinh(",5)) { // Hyperbolic sine
  16678 + _cimg_mp_op("Function 'sinh()'");
16348 16679 arg1 = compile(ss5,se1,depth1,0);
16349 16680 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinh,arg1);
16350 16681 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sinh(mem[arg1]));
... ... @@ -16352,24 +16683,76 @@ namespace cimg_library_suffixed {
16352 16683 }
16353 16684  
16354 16685 if (!std::strncmp(ss,"size(",5)) { // Vector size.
  16686 + _cimg_mp_op("Function 'size()'");
16355 16687 arg1 = compile(ss5,se1,depth1,0);
16356 16688 _cimg_mp_constant(_cimg_mp_is_scalar(arg1)?0:_cimg_mp_vector_size(arg1));
16357 16689 }
16358 16690  
  16691 + if (!std::strncmp(ss,"solve(",6)) { // Solve linear system
  16692 + _cimg_mp_op("Function 'solve()'");
  16693 + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16694 + arg1 = compile(ss6,s1,depth1,0);
  16695 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  16696 + arg2 = compile(++s1,s2,depth1,0);
  16697 + arg3 = s2<se1?compile(++s2,se1,depth1,0):1;
  16698 + _cimg_mp_check_type(arg1,1,2,0);
  16699 + _cimg_mp_check_type(arg2,2,2,0);
  16700 + _cimg_mp_check_constant(arg3,3,true);
  16701 + p1 = _cimg_mp_vector_size(arg1);
  16702 + p2 = _cimg_mp_vector_size(arg2);
  16703 + p3 = (unsigned int)mem[arg3];
  16704 + arg5 = p2/p3;
  16705 + arg4 = p1/arg5;
  16706 + if (arg4*arg5!=p1 || arg5*p3!=p2) {
  16707 + *se = saved_char; cimg::strellipsize(expr,64);
  16708 + throw CImgArgumentException("[_cimg_math_parser] "
  16709 + "CImg<%s>::%s: %s: Types of first and second arguments ('%s' and '%s') "
  16710 + "do not match for third argument 'nb_colsB=%u', "
  16711 + "in expression '%s%s%s'.",
  16712 + pixel_type(),_cimg_mp_calling_function,s_op,
  16713 + s_type(arg1)._data,s_type(arg2)._data,p3,
  16714 + (ss - 4)>expr._data?"...":"",
  16715 + (ss - 4)>expr._data?ss - 4:expr._data,
  16716 + se<&expr.back()?"...":"");
  16717 + }
  16718 + pos = vector(arg4*p3);
  16719 + CImg<uptrT>::vector((uptrT)mp_solve,pos,arg1,arg2,arg4,arg5,p3).move_to(code);
  16720 + _cimg_mp_return(pos);
  16721 + }
  16722 +
16359 16723 if (!std::strncmp(ss,"sort(",5)) { // Sort vector
16360   - s_op = "Function 'sort()'";
  16724 + _cimg_mp_op("Function 'sort()'");
16361 16725 s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
16362 16726 arg1 = compile(ss5,s1,depth1,0);
16363   - if (s1<se1) arg2 = compile(++s1,se1,depth1,0); else arg2 = 1;
16364   - _cimg_mp_check_type(arg1,1,s_op,2,0);
16365   - _cimg_mp_check_type(arg2,2,s_op,1,0);
  16727 + arg2 = arg3 = 1;
  16728 + if (s1<se1) {
  16729 + s0 = ++s1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  16730 + arg2 = compile(s1,s0,depth1,0);
  16731 + arg3 = s0<se1?compile(++s0,se1,depth1,0):1;
  16732 + }
  16733 + _cimg_mp_check_type(arg1,1,2,0);
  16734 + _cimg_mp_check_type(arg2,2,1,0);
  16735 + _cimg_mp_check_constant(arg3,3,true);
  16736 + arg3 = (unsigned int)mem[arg3];
16366 16737 p1 = _cimg_mp_vector_size(arg1);
  16738 + if (p1%arg3) {
  16739 + *se = saved_char; cimg::strellipsize(expr,64);
  16740 + throw CImgArgumentException("[_cimg_math_parser] "
  16741 + "CImg<%s>::%s: %s: Invalid specified chunk size (%u) for first argument "
  16742 + "('%s'), in expression '%s%s%s'.",
  16743 + pixel_type(),_cimg_mp_calling_function,s_op,
  16744 + arg3,s_type(arg1)._data,
  16745 + (ss - 4)>expr._data?"...":"",
  16746 + (ss - 4)>expr._data?ss - 4:expr._data,
  16747 + se<&expr.back()?"...":"");
  16748 + }
16367 16749 pos = vector(p1);
16368   - CImg<uptrT>::vector((uptrT)mp_vector_sort,pos,arg1,p1,arg2).move_to(code);
  16750 + CImg<uptrT>::vector((uptrT)mp_sort,pos,arg1,p1,arg2,arg3).move_to(code);
16369 16751 _cimg_mp_return(pos);
16370 16752 }
16371 16753  
16372 16754 if (!std::strncmp(ss,"sqr(",4)) { // Square
  16755 + _cimg_mp_op("Function 'sqr()'");
16373 16756 arg1 = compile(ss4,se1,depth1,0);
16374 16757 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqr,arg1);
16375 16758 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sqr(mem[arg1]));
... ... @@ -16377,6 +16760,7 @@ namespace cimg_library_suffixed {
16377 16760 }
16378 16761  
16379 16762 if (!std::strncmp(ss,"sqrt(",5)) { // Square root
  16763 + _cimg_mp_op("Function 'sqrt()'");
16380 16764 arg1 = compile(ss5,se1,depth1,0);
16381 16765 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqrt,arg1);
16382 16766 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sqrt(mem[arg1]));
... ... @@ -16386,6 +16770,7 @@ namespace cimg_library_suffixed {
16386 16770  
16387 16771 case 't' :
16388 16772 if (!std::strncmp(ss,"tan(",4)) { // Tangent
  16773 + _cimg_mp_op("Function 'tan()'");
16389 16774 arg1 = compile(ss4,se1,depth1,0);
16390 16775 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tan,arg1);
16391 16776 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tan(mem[arg1]));
... ... @@ -16393,20 +16778,57 @@ namespace cimg_library_suffixed {
16393 16778 }
16394 16779  
16395 16780 if (!std::strncmp(ss,"tanh(",5)) { // Hyperbolic tangent
  16781 + _cimg_mp_op("Function 'tanh()'");
16396 16782 arg1 = compile(ss5,se1,depth1,0);
16397 16783 if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tanh,arg1);
16398 16784 if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tanh(mem[arg1]));
16399 16785 _cimg_mp_scalar1(mp_tanh,arg1);
16400 16786 }
  16787 +
  16788 + if (!std::strncmp(ss,"trace(",6)) { // Matrix trace
  16789 + _cimg_mp_op("Function 'trace()'");
  16790 + arg1 = compile(ss6,se1,depth1,0);
  16791 + _cimg_mp_check_matrix_square(arg1,1);
  16792 + p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
  16793 + _cimg_mp_scalar2(mp_trace,arg1,p1);
  16794 + }
  16795 +
  16796 + if (!std::strncmp(ss,"transp(",7)) { // Matrix transpose
  16797 + _cimg_mp_op("Function 'transp()'");
  16798 + s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16799 + arg1 = compile(ss7,s1,depth1,0);
  16800 + arg2 = compile(++s1,se1,depth1,0);
  16801 + _cimg_mp_check_type(arg1,1,2,0);
  16802 + _cimg_mp_check_constant(arg2,2,true);
  16803 + p1 = _cimg_mp_vector_size(arg1);
  16804 + p2 = (unsigned int)mem[arg2];
  16805 + p3 = p1/p2;
  16806 + if (p2*p3!=p1) {
  16807 + *se = saved_char; cimg::strellipsize(expr,64);
  16808 + throw CImgArgumentException("[_cimg_math_parser] "
  16809 + "CImg<%s>::%s: %s: Size of first argument ('%s') does not match"
  16810 + "for second specified argument 'nb_cols=%u', "
  16811 + "in expression '%s%s%s'.",
  16812 + pixel_type(),_cimg_mp_calling_function,s_op,
  16813 + s_type(arg1)._data,p2,
  16814 + (ss - 4)>expr._data?"...":"",
  16815 + (ss - 4)>expr._data?ss - 4:expr._data,
  16816 + se<&expr.back()?"...":"");
  16817 + }
  16818 + pos = vector(p3*p2);
  16819 + CImg<uptrT>::vector((uptrT)mp_transp,pos,arg1,p2,p3).move_to(code);
  16820 + _cimg_mp_return(pos);
  16821 + }
16401 16822 break;
16402 16823  
16403 16824 case 'u' :
16404 16825 if (*ss1=='(') { // Random value with uniform distribution
  16826 + _cimg_mp_op("Function 'u()'");
16405 16827 if (*ss2==')') _cimg_mp_scalar2(mp_u,0,1);
16406 16828 s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
16407 16829 arg1 = compile(ss2,s1,depth1,0);
16408   - if (s1<se1) arg2 = compile(s1 + 1,se1,depth1,0); else { arg2 = arg1; arg1 = 0; }
16409   - _cimg_mp_check_type(arg2,2,"Function 'u()'",3,_cimg_mp_vector_size(arg1));
  16830 + if (s1<se1) arg2 = compile(++s1,se1,depth1,0); else { arg2 = arg1; arg1 = 0; }
  16831 + _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
16410 16832 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_u,arg1,arg2);
16411 16833 if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_u,arg1,arg2);
16412 16834 if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_u,arg1,arg2);
... ... @@ -16417,9 +16839,10 @@ namespace cimg_library_suffixed {
16417 16839 case 'v' :
16418 16840 if ((cimg_sscanf(ss,"vector%u%c",&(arg1=~0U),&sep)==2 && sep=='(' && arg1>0) ||
16419 16841 !std::strncmp(ss,"vector(",7)) { // Vector
  16842 + _cimg_mp_op("Function 'vector()'");
16420 16843 arg2 = 0; // Number of specified values.
16421 16844 s = std::strchr(ss6,'(') + 1;
16422   - if (*s!=')' || arg1==~0U) for (; s<se; ++s) {
  16845 + if (s<se1 || arg1==~0U) for (; s<se; ++s) {
16423 16846 ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
16424 16847 (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
16425 16848 arg3 = compile(s,ns,depth1,0);
... ... @@ -16431,7 +16854,7 @@ namespace cimg_library_suffixed {
16431 16854 s = ns;
16432 16855 }
16433 16856 if (arg1==~0U) arg1 = arg2;
16434   - _cimg_mp_check_vector0(arg1,"Function 'vector()'");
  16857 + _cimg_mp_check_vector0(arg1);
16435 16858 pos = vector(arg1);
16436 16859 _opcode.insert(CImg<uptrT>::vector((uptrT)mp_vector_init,pos,arg1),0);
16437 16860 (_opcode>'y').move_to(code);
... ... @@ -16441,13 +16864,14 @@ namespace cimg_library_suffixed {
16441 16864  
16442 16865 case 'w' :
16443 16866 if (!std::strncmp(ss,"whiledo",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // While...do
  16867 + _cimg_mp_op("Function 'whiledo()'");
16444 16868 if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace
16445 16869 s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
16446 16870 p1 = code._width;
16447 16871 arg1 = compile(ss8,s1,depth1,0);
16448 16872 p2 = code._width;
16449   - pos = compile(s1 + 1,se1,depth1,0);
16450   - _cimg_mp_check_type(arg1,1,"Function 'whiledo()'",1,0);
  16873 + pos = compile(++s1,se1,depth1,0);
  16874 + _cimg_mp_check_type(arg1,1,1,0);
16451 16875 arg2 = _cimg_mp_is_vector(pos)?_cimg_mp_vector_size(pos):0; // Output vector size (or 0 if scalar)
16452 16876 CImg<uptrT>::vector((uptrT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1);
16453 16877 _cimg_mp_return(pos);
... ... @@ -16457,15 +16881,31 @@ namespace cimg_library_suffixed {
16457 16881  
16458 16882 if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4) ||
16459 16883 !std::strncmp(ss,"med(",4) || !std::strncmp(ss,"kth(",4) ||
16460   - !std::strncmp(ss,"arg(",4) ||
  16884 + !std::strncmp(ss,"arg(",4) || !std::strncmp(ss,"sum(",4) ||
  16885 + !std::strncmp(ss,"std(",4) || !std::strncmp(ss,"var(",4) ||
  16886 + !std::strncmp(ss,"prod(",5) || !std::strncmp(ss,"mean(",5) ||
16461 16887 !std::strncmp(ss,"argmin(",7) || !std::strncmp(ss,"argmax(",7)) { // Multi-argument functions
  16888 + _cimg_mp_op(*ss=='a'?(ss[3]=='('?"Function 'arg()'":ss[4]=='i'?"Function 'argmin()'":
  16889 + "Function 'argmax()'"):
  16890 + *ss=='s'?(ss[1]=='u'?"Function 'sum()'":"Function 'std()'"):
  16891 + *ss=='k'?"Function 'kth()'":
  16892 + *ss=='p'?"Function 'prod()'":
  16893 + *ss=='v'?"Function 'var()'":
  16894 + ss[1]=='i'?"Function 'min()'":
  16895 + ss[1]=='a'?"Function 'max()'":
  16896 + ss[2]=='a'?"Function 'mean()'":"Function 'med()'");
16462 16897 pos = scalar();
16463   - is_sth = *ss=='a' && ss[3]!='(';
16464 16898 CImg<uptrT>::vector((uptrT)(*ss=='a'?(ss[3]=='('?mp_arg:ss[4]=='i'?mp_argmin:mp_argmax):
16465   - *ss=='k'?mp_kth:ss[1]=='i'?mp_min:
16466   - ss[1]=='a'?mp_max:mp_med),pos).
  16899 + *ss=='s'?(ss[1]=='u'?mp_sum:mp_std):
  16900 + *ss=='k'?mp_kth:
  16901 + *ss=='p'?mp_prod:
  16902 + *ss=='v'?mp_var:
  16903 + ss[1]=='i'?mp_min:
  16904 + ss[1]=='a'?mp_max:
  16905 + ss[2]=='a'?mp_mean:
  16906 + mp_med),pos).
16467 16907 move_to(_opcode);
16468   - for (s = is_sth?ss7:ss4; s<se; ++s) {
  16908 + for (s = std::strchr(ss,'(') + 1; s<se; ++s) {
16469 16909 ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
16470 16910 (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
16471 16911 arg2 = compile(s,ns,depth1,0);
... ... @@ -16480,7 +16920,7 @@ namespace cimg_library_suffixed {
16480 16920 _cimg_mp_return(pos);
16481 16921 }
16482 16922  
16483   - // No corresponding built-in function -> Look for a user-defined function.
  16923 + // No corresponding built-in function -> Look for a user-defined macro.
16484 16924 s0 = strchr(ss,'(');
16485 16925 if (s0) {
16486 16926 variable_name.assign(ss,s0 - ss + 1).back() = 0;
... ... @@ -16512,7 +16952,7 @@ namespace cimg_library_suffixed {
16512 16952 if (p1!=p2+1) { // Number of specified argument do not fit
16513 16953 *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
16514 16954 throw CImgArgumentException("[_cimg_math_parser] "
16515   - "CImg<%s>::%s: function '%s()': Number of specified arguments does not "
  16955 + "CImg<%s>::%s: Function '%s()': Number of specified arguments does not "
16516 16956 "match function declaration (%u argument%s required), "
16517 16957 "in expression '%s%s%s'.",
16518 16958 pixel_type(),_cimg_mp_calling_function,variable_name._data,
... ... @@ -16550,6 +16990,7 @@ namespace cimg_library_suffixed {
16550 16990  
16551 16991 // Vector specification using initializer '[ ... ]'.
16552 16992 if (*ss=='[' && *se1==']') {
  16993 + _cimg_mp_op("Operator '[]'");
16553 16994 arg1 = 0; // Number of specified values.
16554 16995 if (*ss1!=']') for (s = ss1; s<se; ++s) {
16555 16996 ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
... ... @@ -16562,7 +17003,7 @@ namespace cimg_library_suffixed {
16562 17003 } else { CImg<uptrT>::vector(arg2).move_to(_opcode); ++arg1; }
16563 17004 s = ns;
16564 17005 }
16565   - _cimg_mp_check_vector0(arg1,"operator '[]'");
  17006 + _cimg_mp_check_vector0(arg1);
16566 17007 pos = vector(arg1);
16567 17008 _opcode.insert(CImg<uptrT>::vector((uptrT)mp_vector_init,pos,arg1),0);
16568 17009 (_opcode>'y').move_to(code);
... ... @@ -16702,7 +17143,7 @@ namespace cimg_library_suffixed {
16702 17143 // Reached an unknown item -> error.
16703 17144 is_sth = true; // is_valid_variable_name
16704 17145 if (*variable_name>='0' && *variable_name<='9') is_sth = false;
16705   - else for (ns = variable_name._data + 1; *ns; ++ns)
  17146 + else for (ns = variable_name._data; *ns; ++ns)
16706 17147 if (!is_varchar(*ns)) { is_sth = false; break; }
16707 17148  
16708 17149 *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
... ... @@ -16883,7 +17324,7 @@ namespace cimg_library_suffixed {
16883 17324 while (siz-->0) *(ptr++) = -1;
16884 17325 }
16885 17326  
16886   - unsigned int vector(const unsigned int siz) { // Insert new vector of specified size in memory.
  17327 + unsigned int vector(const unsigned int siz) { // Insert new vector of specified size in memory
16887 17328 if (mempos + siz>=mem._width) {
16888 17329 mem.resize(2*mem._width + siz,1,1,1,0);
16889 17330 memtype.resize(mem._width,1,1,1,0);
... ... @@ -16895,7 +17336,14 @@ namespace cimg_library_suffixed {
16895 17336 return pos;
16896 17337 }
16897 17338  
16898   - unsigned int vector_copy(const unsigned int arg) { // Insert new copy of specified vector in memory.
  17339 + unsigned int vector(const unsigned int siz, const double value) { // Insert new initialized vector
  17340 + const unsigned int pos = vector(siz);
  17341 + double *ptr = &mem[pos] + 1;
  17342 + for (unsigned int i = 0; i<siz; ++i) *(ptr++) = value;
  17343 + return pos;
  17344 + }
  17345 +
  17346 + unsigned int vector_copy(const unsigned int arg) { // Insert new copy of specified vector in memory
16899 17347 const unsigned int
16900 17348 siz = _cimg_mp_vector_size(arg),
16901 17349 pos = vector(siz);
... ... @@ -16903,11 +17351,36 @@ namespace cimg_library_suffixed {
16903 17351 return pos;
16904 17352 }
16905 17353  
  17354 + void self_vector_s(const unsigned int pos, const mp_func op, const unsigned int arg1) {
  17355 + const unsigned int siz = _cimg_mp_vector_size(pos);
  17356 + if (siz>24) CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,pos,siz,(uptrT)op,arg1).move_to(code);
  17357 + else {
  17358 + code.insert(siz);
  17359 + for (unsigned int k = 1; k<=siz; ++k)
  17360 + CImg<uptrT>::vector((uptrT)op,pos + k,arg1).move_to(code[code._width - 1 - siz + k]);
  17361 + }
  17362 + }
  17363 +
  17364 + void self_vector_v(const unsigned int pos, const mp_func op, const unsigned int arg1) {
  17365 + const unsigned int siz = _cimg_mp_vector_size(pos);
  17366 + if (siz>24) CImg<uptrT>::vector((uptrT)mp_self_map_vector_v,pos,siz,(uptrT)op,arg1).move_to(code);
  17367 + else {
  17368 + code.insert(siz);
  17369 + for (unsigned int k = 1; k<=siz; ++k)
  17370 + CImg<uptrT>::vector((uptrT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]);
  17371 + }
  17372 + }
  17373 +
16906 17374 unsigned int vector1_v(const mp_func op, const unsigned int arg1) {
16907 17375 const unsigned int
16908 17376 siz = _cimg_mp_vector_size(arg1),
16909 17377 pos = is_tmp_vector(arg1)?arg1:vector(siz);
16910   - CImg<uptrT>::vector((uptrT)mp_vector_map_v,pos,siz,(uptrT)op,arg1).move_to(code);
  17378 + if (siz>24) CImg<uptrT>::vector((uptrT)mp_vector_map_v,pos,siz,(uptrT)op,arg1).move_to(code);
  17379 + else {
  17380 + code.insert(siz);
  17381 + for (unsigned int k = 1; k<=siz; ++k)
  17382 + CImg<uptrT>::vector((uptrT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]);
  17383 + }
16911 17384 return pos;
16912 17385 }
16913 17386  
... ... @@ -16915,7 +17388,12 @@ namespace cimg_library_suffixed {
16915 17388 const unsigned int
16916 17389 siz = _cimg_mp_vector_size(arg1),
16917 17390 pos = is_tmp_vector(arg1)?arg1:is_tmp_vector(arg2)?arg2:vector(siz);
16918   - CImg<uptrT>::vector((uptrT)mp_vector_map_vv,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  17391 + if (siz>24) CImg<uptrT>::vector((uptrT)mp_vector_map_vv,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  17392 + else {
  17393 + code.insert(siz);
  17394 + for (unsigned int k = 1; k<=siz; ++k)
  17395 + CImg<uptrT>::vector((uptrT)op,pos + k,arg1 + k,arg2 + k).move_to(code[code._width - 1 - siz + k]);
  17396 + }
16919 17397 return pos;
16920 17398 }
16921 17399  
... ... @@ -16923,7 +17401,12 @@ namespace cimg_library_suffixed {
16923 17401 const unsigned int
16924 17402 siz = _cimg_mp_vector_size(arg1),
16925 17403 pos = is_tmp_vector(arg1)?arg1:vector(siz);
16926   - CImg<uptrT>::vector((uptrT)mp_vector_map_vs,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  17404 + if (siz>24) CImg<uptrT>::vector((uptrT)mp_vector_map_vs,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  17405 + else {
  17406 + code.insert(siz);
  17407 + for (unsigned int k = 1; k<=siz; ++k)
  17408 + CImg<uptrT>::vector((uptrT)op,pos + k,arg1 + k,arg2).move_to(code[code._width - 1 - siz + k]);
  17409 + }
16927 17410 return pos;
16928 17411 }
16929 17412  
... ... @@ -16931,7 +17414,12 @@ namespace cimg_library_suffixed {
16931 17414 const unsigned int
16932 17415 siz = _cimg_mp_vector_size(arg2),
16933 17416 pos = is_tmp_vector(arg2)?arg2:vector(siz);
16934   - CImg<uptrT>::vector((uptrT)mp_vector_map_sv,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  17417 + if (siz>24) CImg<uptrT>::vector((uptrT)mp_vector_map_sv,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  17418 + else {
  17419 + code.insert(siz);
  17420 + for (unsigned int k = 1; k<=siz; ++k)
  17421 + CImg<uptrT>::vector((uptrT)op,pos + k,arg1,arg2 + k).move_to(code[code._width - 1 - siz + k]);
  17422 + }
16935 17423 return pos;
16936 17424 }
16937 17425  
... ... @@ -16940,22 +17428,29 @@ namespace cimg_library_suffixed {
16940 17428 const unsigned int
16941 17429 siz = _cimg_mp_vector_size(arg1),
16942 17430 pos = is_tmp_vector(arg1)?arg1:vector(siz);
16943   - CImg<uptrT>::vector((uptrT)mp_vector_map_vss,pos,siz,(uptrT)op,arg1,arg2,arg3).move_to(code);
  17431 + if (siz>24) CImg<uptrT>::vector((uptrT)mp_vector_map_vss,pos,siz,(uptrT)op,arg1,arg2,arg3).move_to(code);
  17432 + else {
  17433 + code.insert(siz);
  17434 + for (unsigned int k = 1; k<=siz; ++k)
  17435 + CImg<uptrT>::vector((uptrT)op,pos + k,arg1 + k,arg2,arg3).move_to(code[code._width - 1 - siz + k]);
  17436 + }
16944 17437 return pos;
16945 17438 }
16946 17439  
16947 17440 // Check if a memory slot is a positive integer constant scalar value.
16948   - void check_constant(const unsigned int arg, const unsigned int n_arg, const char *const s_op,
  17441 + void check_constant(const unsigned int arg, const unsigned int n_arg,
16949 17442 const bool is_strictly_positive,
16950 17443 const char *const ss, char *const se, const char saved_char) {
16951   - _cimg_mp_check_type(arg,n_arg,s_op,1,0);
  17444 + _cimg_mp_check_type(arg,n_arg,1,0);
16952 17445 if (!_cimg_mp_is_constant(arg) || mem[arg]<(is_strictly_positive?1:0) || (double)(int)mem[arg]!=mem[arg]) {
16953   - const char *s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One ";
  17446 + const char *s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":
  17447 + n_arg==4?"Fourth ":n_arg==5?"Fifth ":n_arg==6?"Sixth ":n_arg==7?"Seventh ":n_arg==8?"Eighth ":
  17448 + n_arg==9?"Ninth ":"One of the ";
16954 17449 *se = saved_char; cimg::strellipsize(expr,64);
16955 17450 throw CImgArgumentException("[_cimg_math_parser] "
16956   - "CImg<%s>::%s(): %s: %s%s (of type '%s') is not a %spositive integer constant, "
  17451 + "CImg<%s>::%s(): %s%s %s%s (of type '%s') is not a %spositive integer constant, "
16957 17452 "in expression '%s%s%s'.",
16958   - pixel_type(),_cimg_mp_calling_function,s_op,
  17453 + pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
16959 17454 s_arg,*s_arg?"argument":"Argument",s_type(arg)._data,
16960 17455 is_strictly_positive?"strictly ":"",
16961 17456 (ss - 4)>expr._data?"...":"",
... ... @@ -16965,9 +17460,9 @@ namespace cimg_library_suffixed {
16965 17460 }
16966 17461  
16967 17462 // Check a matrix is square.
16968   - void check_matrix_square(const unsigned int arg, const unsigned int n_arg, const char *const s_op,
  17463 + void check_matrix_square(const unsigned int arg, const unsigned int n_arg,
16969 17464 const char *const ss, char *const se, const char saved_char) {
16970   - _cimg_mp_check_type(arg,n_arg,s_op,2,0);
  17465 + _cimg_mp_check_type(arg,n_arg,2,0);
16971 17466 const unsigned int
16972 17467 siz = _cimg_mp_vector_size(arg),
16973 17468 n = (unsigned int)std::sqrt((float)siz);
... ... @@ -16977,9 +17472,9 @@ namespace cimg_library_suffixed {
16977 17472 else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One ";
16978 17473 *se = saved_char; cimg::strellipsize(expr,64);
16979 17474 throw CImgArgumentException("[_cimg_math_parser] "
16980   - "CImg<%s>::%s(): %s: %s%s (of type '%s') "
  17475 + "CImg<%s>::%s(): %s%s %s%s (of type '%s') "
16981 17476 "cannot be considered as a square matrix, in expression '%s%s%s'.",
16982   - pixel_type(),_cimg_mp_calling_function,s_op,
  17477 + pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
16983 17478 s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"),
16984 17479 s_type(arg)._data,
16985 17480 (ss - 4)>expr._data?"...":"",
... ... @@ -16992,7 +17487,7 @@ namespace cimg_library_suffixed {
16992 17487 // Bits of 'mode' tells what types are allowed:
16993 17488 // { 1 = scalar | 2 = vectorN }.
16994 17489 // If 'N' is not zero, it also restricts the vectors to be of size N only.
16995   - void check_type(const unsigned int arg, const unsigned int n_arg, const char *const s_op,
  17490 + void check_type(const unsigned int arg, const unsigned int n_arg,
16996 17491 const unsigned int mode, const unsigned int N,
16997 17492 const char *const ss, char *const se, const char saved_char) {
16998 17493 const bool
... ... @@ -17004,7 +17499,9 @@ namespace cimg_library_suffixed {
17004 17499 if (!cond) {
17005 17500 const char *s_arg;
17006 17501 if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand ";
17007   - else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One ";
  17502 + else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":
  17503 + n_arg==4?"Fourth ":n_arg==5?"Fifth ":n_arg==6?"Sixth ":n_arg==7?"Seventh ":n_arg==8?"Eighth":
  17504 + n_arg==9?"Ninth":"One of the ";
17008 17505 CImg<charT> sb_type(32);
17009 17506 if (mode==1) cimg_snprintf(sb_type,sb_type._width,"'scalar'");
17010 17507 else if (mode==2) {
... ... @@ -17016,9 +17513,9 @@ namespace cimg_library_suffixed {
17016 17513 }
17017 17514 *se = saved_char; cimg::strellipsize(expr,64);
17018 17515 throw CImgArgumentException("[_cimg_math_parser] "
17019   - "CImg<%s>::%s(): %s: %s%s has invalid type '%s' (should be %s), "
  17516 + "CImg<%s>::%s(): %s%s %s%s has invalid type '%s' (should be %s), "
17020 17517 "in expression '%s%s%s'.",
17021   - pixel_type(),_cimg_mp_calling_function,s_op,
  17518 + pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
17022 17519 s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"),
17023 17520 s_type(arg)._data,sb_type._data,
17024 17521 (ss - 4)>expr._data?"...":"",
... ... @@ -17027,24 +17524,39 @@ namespace cimg_library_suffixed {
17027 17524 }
17028 17525 }
17029 17526  
  17527 + // Check is listin is not empty.
  17528 + void check_list(const bool is_out,
  17529 + const char *const ss, char *const se, const char saved_char) {
  17530 + if ((!is_out && !listin) || (is_out && !listout)) {
  17531 + *se = saved_char; cimg::strellipsize(expr,64);
  17532 + throw CImgArgumentException("[_cimg_math_parser] "
  17533 + "CImg<%s>::%s(): %s%s Invalid call with an empty image list, "
  17534 + "in expression '%s%s%s'.",
  17535 + pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
  17536 + (ss - 4)>expr._data?"...":"",
  17537 + (ss - 4)>expr._data?ss - 4:expr._data,
  17538 + se<&expr.back()?"...":"");
  17539 + }
  17540 + }
  17541 +
17030 17542 // Check a vector is not 0-dimensional, or with unknown dimension at compile time.
17031   - void check_vector0(const unsigned int dim, const char *const s_op,
  17543 + void check_vector0(const unsigned int dim,
17032 17544 const char *const ss, char *const se, const char saved_char) {
17033 17545 if (!dim) {
17034 17546 *se = saved_char; cimg::strellipsize(expr,64);
17035 17547 throw CImgArgumentException("[_cimg_math_parser] "
17036   - "CImg<%s>::%s(): %s: Invalid construction of a 0-dimensional vector, "
  17548 + "CImg<%s>::%s(): %s%s Invalid construction of a 0-dimensional vector, "
17037 17549 "in expression '%s%s%s'.",
17038   - pixel_type(),_cimg_mp_calling_function,s_op,
  17550 + pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
17039 17551 (ss - 4)>expr._data?"...":"",
17040 17552 (ss - 4)>expr._data?ss - 4:expr._data,
17041 17553 se<&expr.back()?"...":"");
17042 17554 } else if (dim==~0U) {
17043 17555 *se = saved_char; cimg::strellipsize(expr,64);
17044 17556 throw CImgArgumentException("[_cimg_math_parser] "
17045   - "CImg<%s>::%s(): %s: Invalid construction of a vector with dynamic size, "
  17557 + "CImg<%s>::%s(): %s%s Invalid construction of a vector with dynamic size, "
17046 17558 "in expression '%s%s%s'.",
17047   - pixel_type(),_cimg_mp_calling_function,s_op,
  17559 + pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
17048 17560 (ss - 4)>expr._data?"...":"",
17049 17561 (ss - 4)>expr._data?ss - 4:expr._data,
17050 17562 se<&expr.back()?"...":"");
... ... @@ -17253,6 +17765,26 @@ namespace cimg_library_suffixed {
17253 17765 return std::cosh(_mp_arg(2));
17254 17766 }
17255 17767  
  17768 + static double mp_crop(_cimg_math_parser& mp) {
  17769 + double *ptrd = &_mp_arg(1) + 1;
  17770 + const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6);
  17771 + const unsigned int
  17772 + dx = (unsigned int)mp.opcode[7],
  17773 + dy = (unsigned int)mp.opcode[8],
  17774 + dz = (unsigned int)mp.opcode[9],
  17775 + dc = (unsigned int)mp.opcode[10];
  17776 + const bool boundary_conditions = (bool)_mp_arg(11);
  17777 + unsigned int ind = (unsigned int)mp.opcode[2];
  17778 + if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17779 + const CImg<T> &img = ind==~0U?mp.imgin:mp.listin[ind];
  17780 + if (!img) std::memset(ptrd,0,dx*dy*dz*dc*sizeof(double));
  17781 + else CImg<double>(ptrd,dx,dy,dz,dc,true) = img.get_crop(x,y,z,c,
  17782 + x + dx - 1,y + dy - 1,
  17783 + z + dz - 1,c + dc - 1,
  17784 + boundary_conditions);
  17785 + return cimg::type<double>::nan();
  17786 + }
  17787 +
17256 17788 static double mp_cross(_cimg_math_parser& mp) {
17257 17789 CImg<doubleT>
17258 17790 vout(&_mp_arg(1) + 1,1,3,1,1,true),
... ... @@ -17268,52 +17800,56 @@ namespace cimg_library_suffixed {
17268 17800 }
17269 17801  
17270 17802 static double mp_debug(_cimg_math_parser& mp) {
17271   -#ifdef cimg_use_openmp
17272   - const unsigned int n_thread = omp_get_thread_num();
17273   -#else
17274   - const unsigned int n_thread = 0;
17275   -#endif
17276 17803 CImg<charT> expr(mp.opcode._height - 3);
17277 17804 const uptrT *ptrs = mp.opcode._data + 3;
17278 17805 cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
17279 17806 cimg::strellipsize(expr);
17280 17807 const uptrT g_target = mp.opcode[1];
17281   - std::fprintf(cimg::output(),
17282   - "\n[_cimg_math_parser] %p[thread #%u]:%*c"
17283   - "Start debugging expression '%s', code length %u -> mem[%u] (memsize: %u)",
17284   - (void*)&mp,n_thread,mp.debug_indent,' ',
17285   - expr._data,(unsigned int)mp.opcode[2],(unsigned int)g_target,mp.mem._width);
17286   - std::fflush(cimg::output());
17287   - const CImg<uptrT> *const p_end = (++mp.p_code) + mp.opcode[2];
17288   - CImg<uptrT> _op;
17289   - mp.debug_indent+=3;
17290   - for ( ; mp.p_code<p_end; ++mp.p_code) {
17291   - const CImg<uptrT> &op = *mp.p_code;
17292   - mp.opcode._data = op._data; mp.opcode._height = op._height;
17293 17808  
17294   - _op.assign(1,op._height - 1);
17295   - const uptrT *ptrs = op._data + 1;
17296   - for (uptrT *ptrd = _op._data, *const ptrde = _op._data + _op._height; ptrd<ptrde; ++ptrd)
17297   - *ptrd = *(ptrs++);
  17809 +#ifndef cimg_use_openmp
  17810 + const unsigned int n_thread = 0;
  17811 +#else
  17812 + const unsigned int n_thread = omp_get_thread_num();
  17813 +#pragma omp critical
  17814 +#endif
  17815 + {
  17816 + std::fprintf(cimg::output(),
  17817 + "\n[_cimg_math_parser] %p[thread #%u]:%*c"
  17818 + "Start debugging expression '%s', code length %u -> mem[%u] (memsize: %u)",
  17819 + (void*)&mp,n_thread,mp.debug_indent,' ',
  17820 + expr._data,(unsigned int)mp.opcode[2],(unsigned int)g_target,mp.mem._width);
  17821 + std::fflush(cimg::output());
  17822 + const CImg<uptrT> *const p_end = (++mp.p_code) + mp.opcode[2];
  17823 + CImg<uptrT> _op;
  17824 + mp.debug_indent+=3;
  17825 + for ( ; mp.p_code<p_end; ++mp.p_code) {
  17826 + const CImg<uptrT> &op = *mp.p_code;
  17827 + mp.opcode._data = op._data; mp.opcode._height = op._height;
  17828 +
  17829 + _op.assign(1,op._height - 1);
  17830 + const uptrT *ptrs = op._data + 1;
  17831 + for (uptrT *ptrd = _op._data, *const ptrde = _op._data + _op._height; ptrd<ptrde; ++ptrd)
  17832 + *ptrd = *(ptrs++);
17298 17833  
17299   - const uptrT target = mp.opcode[1];
17300   - mp.mem[target] = _cimg_mp_defunc(mp);
  17834 + const uptrT target = mp.opcode[1];
  17835 + mp.mem[target] = _cimg_mp_defunc(mp);
  17836 + std::fprintf(cimg::output(),
  17837 + "\n[_cimg_math_parser] %p[thread #%u]:%*c"
  17838 + "Opcode %p = [ %p,%s ] -> mem[%u] = %g",
  17839 + (void*)&mp,n_thread,mp.debug_indent,' ',
  17840 + (void*)mp.opcode._data,(void*)*mp.opcode,_op.value_string().data(),
  17841 + (unsigned int)target,mp.mem[target]);
  17842 + std::fflush(cimg::output());
  17843 + }
  17844 + mp.debug_indent-=3;
17301 17845 std::fprintf(cimg::output(),
17302 17846 "\n[_cimg_math_parser] %p[thread #%u]:%*c"
17303   - "Opcode %p = [ %p,%s ] -> mem[%u] = %g",
  17847 + "End debugging expression '%s' -> mem[%u] = %g (memsize: %u)",
17304 17848 (void*)&mp,n_thread,mp.debug_indent,' ',
17305   - (void*)mp.opcode._data,(void*)*mp.opcode,_op.value_string().data(),
17306   - (unsigned int)target,mp.mem[target]);
  17849 + expr._data,(unsigned int)g_target,mp.mem[g_target],mp.mem._width);
17307 17850 std::fflush(cimg::output());
  17851 + --mp.p_code;
17308 17852 }
17309   - mp.debug_indent-=3;
17310   - std::fprintf(cimg::output(),
17311   - "\n[_cimg_math_parser] %p[thread #%u]:%*c"
17312   - "End debugging expression '%s' -> mem[%u] = %g (memsize: %u)",
17313   - (void*)&mp,n_thread,mp.debug_indent,' ',
17314   - expr._data,(unsigned int)g_target,mp.mem[g_target],mp.mem._width);
17315   - std::fflush(cimg::output());
17316   - --mp.p_code;
17317 17853 return mp.mem[g_target];
17318 17854 }
17319 17855  
... ... @@ -17321,6 +17857,24 @@ namespace cimg_library_suffixed {
17321 17857 return _mp_arg(2) - 1;
17322 17858 }
17323 17859  
  17860 + static double mp_det(_cimg_math_parser& mp) {
  17861 + const double *ptrs = &_mp_arg(2) + 1;
  17862 + const unsigned int k = (unsigned int)mp.opcode(3);
  17863 + return CImg<double>(ptrs,k,k,1,1,true).det();
  17864 + }
  17865 +
  17866 + static double mp_diag(_cimg_math_parser& mp) {
  17867 + double *ptrd = &_mp_arg(1) + 1;
  17868 + const double *ptrs = &_mp_arg(2) + 1;
  17869 + const unsigned int k = (unsigned int)mp.opcode(3);
  17870 + CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptrs,1,k,1,1,true).get_diagonal();
  17871 + return cimg::type<double>::nan();
  17872 + }
  17873 +
  17874 + static double mp_div(_cimg_math_parser& mp) {
  17875 + return _mp_arg(2)/_mp_arg(3);
  17876 + }
  17877 +
17324 17878 static double mp_dot(_cimg_math_parser& mp) {
17325 17879 const unsigned int siz = (unsigned int)mp.opcode[4];
17326 17880 return CImg<doubleT>(&_mp_arg(2) + 1,1,siz,1,1,true).
... ... @@ -17346,8 +17900,36 @@ namespace cimg_library_suffixed {
17346 17900 return mp.mem[mem_proc];
17347 17901 }
17348 17902  
17349   - static double mp_div(_cimg_math_parser& mp) {
17350   - return _mp_arg(2)/_mp_arg(3);
  17903 + static double mp_draw(_cimg_math_parser& mp) {
  17904 + const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6);
  17905 + const unsigned int
  17906 + dx = (unsigned int)mp.opcode[7],
  17907 + dy = (unsigned int)mp.opcode[8],
  17908 + dz = (unsigned int)mp.opcode[9],
  17909 + dc = (unsigned int)mp.opcode[10];
  17910 + const CImg<double> S(&_mp_arg(1) + 1,dx,dy,dz,dc,true);
  17911 + const float opacity = (float)_mp_arg(11);
  17912 + unsigned int ind = (unsigned int)mp.opcode[2];
  17913 + if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17914 + CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
  17915 + if (img) {
  17916 + if (mp.opcode[12]!=(uptrT)-1) {
  17917 + const CImg<double> M(&_mp_arg(12) + 1,dx,dy,dz,(unsigned int)mp.opcode[13],true);
  17918 + img.draw_image(x,y,z,c,S,M,opacity,(float)_mp_arg(14));
  17919 + } else img.draw_image(x,y,z,c,S,opacity);
  17920 + }
  17921 + return cimg::type<double>::nan();
  17922 + }
  17923 +
  17924 + static double mp_eig(_cimg_math_parser& mp) {
  17925 + double *ptrd = &_mp_arg(1) + 1;
  17926 + const double *ptr1 = &_mp_arg(2) + 1;
  17927 + const unsigned int k = (unsigned int)mp.opcode(3);
  17928 + CImg<double> val, vec;
  17929 + CImg<double>(ptr1,k,k,1,1,true).symmetric_eigen(val,vec);
  17930 + CImg<double>(ptrd,k,1,1,1,true) = val.unroll('x');
  17931 + CImg<double>(ptrd + k,k,k,1,1,true) = vec.get_transpose();
  17932 + return cimg::type<double>::nan();
17351 17933 }
17352 17934  
17353 17935 static double mp_eq(_cimg_math_parser& mp) {
... ... @@ -17358,6 +17940,13 @@ namespace cimg_library_suffixed {
17358 17940 return std::exp(_mp_arg(2));
17359 17941 }
17360 17942  
  17943 + static double mp_eye(_cimg_math_parser& mp) {
  17944 + double *ptrd = &_mp_arg(1) + 1;
  17945 + const unsigned int k = (unsigned int)mp.opcode(2);
  17946 + CImg<double>(ptrd,k,k,1,1,true).identity_matrix();
  17947 + return cimg::type<double>::nan();
  17948 + }
  17949 +
17361 17950 static double mp_g(_cimg_math_parser& mp) {
17362 17951 cimg::unused(mp);
17363 17952 return cimg::grand();
... ... @@ -17424,6 +18013,14 @@ namespace cimg_library_suffixed {
17424 18013 return (double)(long)_mp_arg(2);
17425 18014 }
17426 18015  
  18016 + static double mp_inv(_cimg_math_parser& mp) {
  18017 + double *ptrd = &_mp_arg(1) + 1;
  18018 + const double *ptr1 = &_mp_arg(2) + 1;
  18019 + const unsigned int k = (unsigned int)mp.opcode(3);
  18020 + CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptr1,k,k,1,1,true).get_invert();
  18021 + return cimg::type<double>::nan();
  18022 + }
  18023 +
17427 18024 static double mp_ioff(_cimg_math_parser& mp) {
17428 18025 const unsigned int
17429 18026 boundary_conditions = (unsigned int)_mp_arg(3);
... ... @@ -17713,9 +18310,8 @@ namespace cimg_library_suffixed {
17713 18310 z = (int)_mp_arg(5), c = (int)_mp_arg(6);
17714 18311 const double val = _mp_arg(1);
17715 18312 if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
17716   - z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) {
  18313 + z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
17717 18314 img(x,y,z,c) = (T)val;
17718   - }
17719 18315 return val;
17720 18316 }
17721 18317  
... ... @@ -17744,9 +18340,8 @@ namespace cimg_library_suffixed {
17744 18340 z = (int)(oz + _mp_arg(5)), c = (int)(oc + _mp_arg(6));
17745 18341 const double val = _mp_arg(1);
17746 18342 if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
17747   - z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) {
  18343 + z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
17748 18344 img(x,y,z,c) = (T)val;
17749   - }
17750 18345 return val;
17751 18346 }
17752 18347  
... ... @@ -18099,46 +18694,6 @@ namespace cimg_library_suffixed {
18099 18694 return (double)(_mp_arg(2)<=_mp_arg(3));
18100 18695 }
18101 18696  
18102   - static double mp_matrix_det(_cimg_math_parser& mp) {
18103   - const double *ptrs = &_mp_arg(2) + 1;
18104   - const unsigned int k = (unsigned int)mp.opcode(3);
18105   - return CImg<double>(ptrs,k,k,1,1,true).det();
18106   - }
18107   -
18108   - static double mp_matrix_diag(_cimg_math_parser& mp) {
18109   - double *ptrd = &_mp_arg(1) + 1;
18110   - const double *ptrs = &_mp_arg(2) + 1;
18111   - const unsigned int k = (unsigned int)mp.opcode(3);
18112   - CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptrs,1,k,1,1,true).get_diagonal();
18113   - return cimg::type<double>::nan();
18114   - }
18115   -
18116   - static double mp_matrix_eig(_cimg_math_parser& mp) {
18117   - double *ptrd = &_mp_arg(1) + 1;
18118   - const double *ptr1 = &_mp_arg(2) + 1;
18119   - const unsigned int k = (unsigned int)mp.opcode(3);
18120   - CImg<double> val, vec;
18121   - CImg<double>(ptr1,k,k,1,1,true).symmetric_eigen(val,vec);
18122   - CImg<double>(ptrd,k,1,1,1,true) = val.unroll('x');
18123   - CImg<double>(ptrd + k,k,k,1,1,true) = vec.get_transpose();
18124   - return cimg::type<double>::nan();
18125   - }
18126   -
18127   - static double mp_matrix_eye(_cimg_math_parser& mp) {
18128   - double *ptrd = &_mp_arg(1) + 1;
18129   - const unsigned int k = (unsigned int)mp.opcode(2);
18130   - CImg<double>(ptrd,k,k,1,1,true).identity_matrix();
18131   - return cimg::type<double>::nan();
18132   - }
18133   -
18134   - static double mp_matrix_inv(_cimg_math_parser& mp) {
18135   - double *ptrd = &_mp_arg(1) + 1;
18136   - const double *ptr1 = &_mp_arg(2) + 1;
18137   - const unsigned int k = (unsigned int)mp.opcode(3);
18138   - CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptr1,k,k,1,1,true).get_invert();
18139   - return cimg::type<double>::nan();
18140   - }
18141   -
18142 18697 static double mp_matrix_mul(_cimg_math_parser& mp) {
18143 18698 double *ptrd = &_mp_arg(1) + 1;
18144 18699 const double
... ... @@ -18152,48 +18707,110 @@ namespace cimg_library_suffixed {
18152 18707 return cimg::type<double>::nan();
18153 18708 }
18154 18709  
18155   - static double mp_matrix_rot(_cimg_math_parser& mp) {
18156   - double *ptrd = &_mp_arg(1) + 1;
18157   - const float x = (float)_mp_arg(2), y = (float)_mp_arg(3), z = (float)_mp_arg(4), theta = (float)_mp_arg(5);
18158   - CImg<double>(ptrd,3,3,1,1,true) = CImg<double>::rotation_matrix(x,y,z,theta);
18159   - return cimg::type<double>::nan();
18160   - }
18161   -
18162   - static double mp_matrix_solve(_cimg_math_parser& mp) {
18163   - double *ptrd = &_mp_arg(1) + 1;
18164   - const double
18165   - *ptr1 = &_mp_arg(2) + 1,
18166   - *ptr2 = &_mp_arg(3) + 1;
18167   - const unsigned int
18168   - k = (unsigned int)mp.opcode(4),
18169   - l = (unsigned int)mp.opcode(5),
18170   - m = (unsigned int)mp.opcode(6);
18171   - CImg<double>(ptrd,m,l,1,1,true) = CImg<double>(ptr2,m,k,1,1,true).get_solve(CImg<double>(ptr1,l,k,1,1,true));
18172   - return cimg::type<double>::nan();
18173   - }
18174   -
18175   - static double mp_matrix_trace(_cimg_math_parser& mp) {
18176   - const double *ptrs = &_mp_arg(2) + 1;
18177   - const unsigned int k = (unsigned int)mp.opcode(3);
18178   - return CImg<double>(ptrs,k,k,1,1,true).trace();
18179   - }
18180   -
18181   - static double mp_matrix_trans(_cimg_math_parser& mp) {
18182   - double *ptrd = &_mp_arg(1) + 1;
18183   - const double *ptr1 = &_mp_arg(2) + 1;
18184   - const unsigned int
18185   - k = (unsigned int)mp.opcode(3),
18186   - l = (unsigned int)mp.opcode(4);
18187   - CImg<double>(ptrd,l,k,1,1,true) = CImg<double>(ptr1,k,l,1,1,true).get_transpose();
18188   - return cimg::type<double>::nan();
18189   - }
18190   -
18191 18710 static double mp_max(_cimg_math_parser& mp) {
18192 18711 double val = _mp_arg(2);
18193 18712 for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::max(val,_mp_arg(i));
18194 18713 return val;
18195 18714 }
18196 18715  
  18716 + static double* _mp_memcopy_double(_cimg_math_parser& mp, const unsigned int ind, const uptrT *const p_ref,
  18717 + const long siz, const long inc) {
  18718 + const long
  18719 + off = *p_ref?p_ref[1] + (long)mp.mem[(long)p_ref[2]] + 1:ind,
  18720 + eoff = off + (siz - 1)*inc;
  18721 + if (off<0 || eoff>=mp.mem.width())
  18722 + throw CImgArgumentException("[_cimg_math_parser] CImg<%s>: 'copy()': "
  18723 + "Out-of-bounds variable pointer "
  18724 + "(length: %ld, increment: %ld, offset start: %ld, "
  18725 + "offset end: %ld, offset max: %u).",
  18726 + mp.imgin.pixel_type(),siz,inc,off,eoff,mp.mem._width - 1);
  18727 + return &mp.mem[off];
  18728 + }
  18729 +
  18730 + static float* _mp_memcopy_float(_cimg_math_parser& mp, const uptrT *const p_ref,
  18731 + const long siz, const long inc) {
  18732 + const unsigned ind = p_ref[1];
  18733 + const CImg<T> &img = ind==~0U?mp.imgin:mp.listin[cimg::mod((int)mp.mem[ind],mp.listin.width())];
  18734 + const bool is_relative = (bool)p_ref[2];
  18735 + int ox, oy, oz, oc;
  18736 + long off = 0;
  18737 + if (is_relative) {
  18738 + ox = (int)mp.mem[_cimg_mp_x];
  18739 + oy = (int)mp.mem[_cimg_mp_y];
  18740 + oz = (int)mp.mem[_cimg_mp_z];
  18741 + oc = (int)mp.mem[_cimg_mp_c];
  18742 + off = img.offset(ox,oy,oz,oc);
  18743 + }
  18744 + if ((*p_ref)%2) {
  18745 + const int
  18746 + x = (int)mp.mem[p_ref[3]],
  18747 + y = (int)mp.mem[p_ref[4]],
  18748 + z = (int)mp.mem[p_ref[5]],
  18749 + c = *p_ref==5?0:(int)mp.mem[p_ref[6]];
  18750 + off+=(long)img.offset(x,y,z,c);
  18751 + } else off+=(long)mp.mem[p_ref[3]];
  18752 + const long eoff = off + (siz - 1)*inc;
  18753 + if (off<0 || eoff>=(long)img.size())
  18754 + throw CImgArgumentException("[_cimg_math_parser] CImg<%s>: Function 'copy()': "
  18755 + "Out-of-bounds image pointer "
  18756 + "(length: %ld, increment: %ld, offset start: %ld, "
  18757 + "offset end: %ld, offset max: %lu).",
  18758 + mp.imgin.pixel_type(),siz,inc,off,eoff,img.size() - 1);
  18759 + return (float*)&img[off];
  18760 + }
  18761 +
  18762 + static double mp_memcopy(_cimg_math_parser& mp) {
  18763 + long siz = (long)_mp_arg(4);
  18764 + const long inc_d = (long)_mp_arg(5), inc_s = (long)_mp_arg(6);
  18765 + if (siz>0) {
  18766 + const bool
  18767 + is_doubled = mp.opcode[7]<=1,
  18768 + is_doubles = mp.opcode[14]<=1;
  18769 + if (is_doubled && is_doubles) { // (double*) <- (double*)
  18770 + double *ptrd = _mp_memcopy_double(mp,mp.opcode[2],&mp.opcode[7],siz,inc_d);
  18771 + const double *ptrs = _mp_memcopy_double(mp,mp.opcode[3],&mp.opcode[14],siz,inc_s);
  18772 + if (inc_d==1 && inc_s==1) {
  18773 + if (ptrs + siz - 1<ptrd || ptrs>ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(double));
  18774 + else std::memmove(ptrd,ptrs,siz*sizeof(double));
  18775 + } else {
  18776 + if (ptrs + (siz - 1)*inc_s<ptrd || ptrs>ptrd + (siz - 1)*inc_d)
  18777 + while (siz-->0) { *ptrd = (double)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }
  18778 + else { // Overlapping buffers
  18779 + CImg<double> buf(siz);
  18780 + cimg_for(buf,ptr,double) { *ptr = *ptrs; ptrs+=inc_s; }
  18781 + ptrs = buf;
  18782 + while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; }
  18783 + }
  18784 + }
  18785 + } else if (is_doubled && !is_doubles) { // (double*) <- (float*)
  18786 + double *ptrd = _mp_memcopy_double(mp,mp.opcode[2],&mp.opcode[7],siz,inc_d);
  18787 + const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[14],siz,inc_s);
  18788 + while (siz-->0) { *ptrd = (double)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }
  18789 + } else if (!is_doubled && is_doubles) { // (float*) <- (double*)
  18790 + float *ptrd = _mp_memcopy_float(mp,&mp.opcode[7],siz,inc_d);
  18791 + const double *ptrs = _mp_memcopy_double(mp,mp.opcode[3],&mp.opcode[14],siz,inc_s);
  18792 + while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }
  18793 + } else { // (float*) <- (float*)
  18794 + float *ptrd = _mp_memcopy_float(mp,&mp.opcode[7],siz,inc_d);
  18795 + const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[14],siz,inc_s);
  18796 + if (inc_d==1 && inc_s==1) {
  18797 + if (ptrs + siz - 1<ptrd || ptrs>ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(float));
  18798 + else std::memmove(ptrd,ptrs,siz*sizeof(float));
  18799 + } else {
  18800 + if (ptrs + (siz - 1)*inc_s<ptrd || ptrs>ptrd + (siz - 1)*inc_d)
  18801 + while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }
  18802 + else { // Overlapping buffers
  18803 + CImg<float> buf(siz);
  18804 + cimg_for(buf,ptr,float) { *ptr = *ptrs; ptrs+=inc_s; }
  18805 + ptrs = buf;
  18806 + while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; }
  18807 + }
  18808 + }
  18809 + }
  18810 + }
  18811 + return _mp_arg(1);
  18812 + }
  18813 +
18197 18814 static double mp_min(_cimg_math_parser& mp) {
18198 18815 double val = _mp_arg(2);
18199 18816 for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::min(val,_mp_arg(i));
... ... @@ -18204,6 +18821,12 @@ namespace cimg_library_suffixed {
18204 18821 return -_mp_arg(2);
18205 18822 }
18206 18823  
  18824 + static double mp_mean(_cimg_math_parser& mp) {
  18825 + double val = _mp_arg(2);
  18826 + for (unsigned int i = 3; i<mp.opcode._height; ++i) val+=_mp_arg(i);
  18827 + return val/(mp.opcode._height - 2);
  18828 + }
  18829 +
18207 18830 static double mp_med(_cimg_math_parser& mp) {
18208 18831 CImg<doubleT> vals(mp.opcode._height - 2);
18209 18832 double *p = vals.data();
... ... @@ -18278,13 +18901,26 @@ namespace cimg_library_suffixed {
18278 18901 }
18279 18902  
18280 18903 static double mp_print(_cimg_math_parser& mp) {
  18904 + cimg::mutex(6);
18281 18905 CImg<charT> expr(mp.opcode._height - 2);
18282 18906 const uptrT *ptrs = mp.opcode._data + 2;
18283 18907 cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
18284 18908 cimg::strellipsize(expr);
18285 18909 const double val = _mp_arg(1);
18286   - std::fprintf(cimg::output(),"\n[_cimg_math_parser] %s = %g",expr._data,val);
18287   - std::fflush(cimg::output());
  18910 +#ifdef cimg_use_openmp
  18911 +#pragma omp critical
  18912 +#endif
  18913 + {
  18914 + std::fprintf(cimg::output(),"\n[_cimg_math_parser] %s = %g",expr._data,val);
  18915 + std::fflush(cimg::output());
  18916 + }
  18917 + cimg::mutex(6,0);
  18918 + return val;
  18919 + }
  18920 +
  18921 + static double mp_prod(_cimg_math_parser& mp) {
  18922 + double val = _mp_arg(2);
  18923 + for (unsigned int i = 3; i<mp.opcode._height; ++i) val*=_mp_arg(i);
18288 18924 return val;
18289 18925 }
18290 18926  
... ... @@ -18300,6 +18936,26 @@ namespace cimg_library_suffixed {
18300 18936 return cimg::ror(_mp_arg(2),(unsigned int)_mp_arg(3));
18301 18937 }
18302 18938  
  18939 + static double mp_rot2d(_cimg_math_parser& mp) {
  18940 + double *ptrd = &_mp_arg(1) + 1;
  18941 + const float
  18942 + theta = (float)_mp_arg(2),
  18943 + ca = std::cos(theta),
  18944 + sa = std::sin(theta);
  18945 + *(ptrd++) = ca;
  18946 + *(ptrd++) = -sa;
  18947 + *(ptrd++) = sa;
  18948 + *ptrd = ca;
  18949 + return cimg::type<double>::nan();
  18950 + }
  18951 +
  18952 + static double mp_rot3d(_cimg_math_parser& mp) {
  18953 + double *ptrd = &_mp_arg(1) + 1;
  18954 + const float x = (float)_mp_arg(2), y = (float)_mp_arg(3), z = (float)_mp_arg(4), theta = (float)_mp_arg(5);
  18955 + CImg<double>(ptrd,3,3,1,1,true) = CImg<double>::rotation_matrix(x,y,z,theta);
  18956 + return cimg::type<double>::nan();
  18957 + }
  18958 +
18303 18959 static double mp_round(_cimg_math_parser& mp) {
18304 18960 return cimg::round(_mp_arg(2),_mp_arg(3),(int)_mp_arg(4));
18305 18961 }
... ... @@ -18403,9 +19059,8 @@ namespace cimg_library_suffixed {
18403 19059 z = (int)_mp_arg(4), c = (int)_mp_arg(5);
18404 19060 const double val = _mp_arg(1);
18405 19061 if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
18406   - z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) {
  19062 + z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
18407 19063 img(x,y,z,c) = (T)val;
18408   - }
18409 19064 return val;
18410 19065 }
18411 19066  
... ... @@ -18432,9 +19087,8 @@ namespace cimg_library_suffixed {
18432 19087 z = (int)(oz + _mp_arg(4)), c = (int)(oc + _mp_arg(5));
18433 19088 const double val = _mp_arg(1);
18434 19089 if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
18435   - z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) {
  19090 + z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
18436 19091 img(x,y,z,c) = (T)val;
18437   - }
18438 19092 return val;
18439 19093 }
18440 19094  
... ... @@ -18558,10 +19212,53 @@ namespace cimg_library_suffixed {
18558 19212 return cimg::sinc(_mp_arg(2));
18559 19213 }
18560 19214  
  19215 + static double mp_single(_cimg_math_parser& mp) {
  19216 + const double res = _mp_arg(1);
  19217 +#ifdef cimg_use_openmp
  19218 +#pragma omp critical
  19219 +#endif
  19220 + {
  19221 + for (const CImg<uptrT> *const p_end = ++mp.p_code + mp.opcode[2];
  19222 + mp.p_code<p_end; ++mp.p_code) { // Evaluate loop iteration + condition
  19223 + const CImg<uptrT> &op = *mp.p_code;
  19224 + mp.opcode._data = op._data; mp.opcode._height = op._height;
  19225 + const uptrT target = mp.opcode[1];
  19226 + mp.mem[target] = _cimg_mp_defunc(mp);
  19227 + }
  19228 + }
  19229 + --mp.p_code;
  19230 + return res;
  19231 + }
  19232 +
18561 19233 static double mp_sinh(_cimg_math_parser& mp) {
18562 19234 return std::sinh(_mp_arg(2));
18563 19235 }
18564 19236  
  19237 + static double mp_solve(_cimg_math_parser& mp) {
  19238 + double *ptrd = &_mp_arg(1) + 1;
  19239 + const double
  19240 + *ptr1 = &_mp_arg(2) + 1,
  19241 + *ptr2 = &_mp_arg(3) + 1;
  19242 + const unsigned int
  19243 + k = (unsigned int)mp.opcode(4),
  19244 + l = (unsigned int)mp.opcode(5),
  19245 + m = (unsigned int)mp.opcode(6);
  19246 + CImg<double>(ptrd,m,k,1,1,true) = CImg<double>(ptr2,m,l,1,1,true).get_solve(CImg<double>(ptr1,k,l,1,1,true));
  19247 + return cimg::type<double>::nan();
  19248 + }
  19249 +
  19250 + static double mp_sort(_cimg_math_parser& mp) {
  19251 + double *const ptrd = &_mp_arg(1) + 1;
  19252 + const double *const ptrs = &_mp_arg(2) + 1;
  19253 + const unsigned int
  19254 + siz = mp.opcode[3],
  19255 + chunk_siz = mp.opcode[5];
  19256 + const bool is_increasing = (bool)_mp_arg(4);
  19257 + CImg<doubleT>(ptrd,chunk_siz,siz/chunk_siz,1,1,true) = CImg<doubleT>(ptrs,chunk_siz,siz/chunk_siz,1,1,true).
  19258 + get_sort(is_increasing,chunk_siz>1?'y':0);
  19259 + return cimg::type<double>::nan();
  19260 + }
  19261 +
18565 19262 static double mp_sqr(_cimg_math_parser& mp) {
18566 19263 return cimg::sqr(_mp_arg(2));
18567 19264 }
... ... @@ -18570,10 +19267,23 @@ namespace cimg_library_suffixed {
18570 19267 return std::sqrt(_mp_arg(2));
18571 19268 }
18572 19269  
  19270 + static double mp_std(_cimg_math_parser& mp) {
  19271 + CImg<doubleT> vals(mp.opcode._height - 2);
  19272 + double *p = vals.data();
  19273 + for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i);
  19274 + return std::sqrt(vals.variance());
  19275 + }
  19276 +
18573 19277 static double mp_sub(_cimg_math_parser& mp) {
18574 19278 return _mp_arg(2) - _mp_arg(3);
18575 19279 }
18576 19280  
  19281 + static double mp_sum(_cimg_math_parser& mp) {
  19282 + double val = _mp_arg(2);
  19283 + for (unsigned int i = 3; i<mp.opcode._height; ++i) val+=_mp_arg(i);
  19284 + return val;
  19285 + }
  19286 +
18577 19287 static double mp_tan(_cimg_math_parser& mp) {
18578 19288 return std::tan(_mp_arg(2));
18579 19289 }
... ... @@ -18582,10 +19292,33 @@ namespace cimg_library_suffixed {
18582 19292 return std::tanh(_mp_arg(2));
18583 19293 }
18584 19294  
  19295 + static double mp_trace(_cimg_math_parser& mp) {
  19296 + const double *ptrs = &_mp_arg(2) + 1;
  19297 + const unsigned int k = (unsigned int)mp.opcode(3);
  19298 + return CImg<double>(ptrs,k,k,1,1,true).trace();
  19299 + }
  19300 +
  19301 + static double mp_transp(_cimg_math_parser& mp) {
  19302 + double *ptrd = &_mp_arg(1) + 1;
  19303 + const double *ptr1 = &_mp_arg(2) + 1;
  19304 + const unsigned int
  19305 + k = (unsigned int)mp.opcode(3),
  19306 + l = (unsigned int)mp.opcode(4);
  19307 + CImg<double>(ptrd,l,k,1,1,true) = CImg<double>(ptr1,k,l,1,1,true).get_transpose();
  19308 + return cimg::type<double>::nan();
  19309 + }
  19310 +
18585 19311 static double mp_u(_cimg_math_parser& mp) {
18586 19312 return cimg::rand(_mp_arg(2),_mp_arg(3));
18587 19313 }
18588 19314  
  19315 + static double mp_var(_cimg_math_parser& mp) {
  19316 + CImg<doubleT> vals(mp.opcode._height - 2);
  19317 + double *p = vals.data();
  19318 + for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i);
  19319 + return vals.variance();
  19320 + }
  19321 +
18589 19322 static double mp_vector_copy(_cimg_math_parser& mp) {
18590 19323 std::memcpy(&_mp_arg(1) + 1,&_mp_arg(2) + 1,sizeof(double)*mp.opcode[3]);
18591 19324 return cimg::type<double>::nan();
... ... @@ -18704,15 +19437,6 @@ namespace cimg_library_suffixed {
18704 19437 return _mp_arg(5);
18705 19438 }
18706 19439  
18707   - static double mp_vector_sort(_cimg_math_parser& mp) {
18708   - double *const ptrd = &_mp_arg(1) + 1;
18709   - const double *const ptrs = &_mp_arg(2) + 1;
18710   - const unsigned int siz = mp.opcode[3];
18711   - const bool is_increasing = (bool)_mp_arg(4);
18712   - CImg<doubleT>(ptrd,1,siz,1,1,true) = CImg<doubleT>(ptrs,1,siz,1,1,true).get_sort(is_increasing);
18713   - return cimg::type<double>::nan();
18714   - }
18715   -
18716 19440 static double mp_vector_print(_cimg_math_parser& mp) {
18717 19441 CImg<charT> expr(mp.opcode._height - 3);
18718 19442 const uptrT *ptrs = mp.opcode._data + 3;
... ... @@ -20185,7 +20909,8 @@ namespace cimg_library_suffixed {
20185 20909 case 's' : return (double)_spectrum;
20186 20910 case 'r' : return (double)_is_shared;
20187 20911 }
20188   - _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*'?1:0),"eval",
  20912 + _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||
  20913 + *expression=='*' || *expression==':'?1:0),"eval",
20189 20914 *this,img_output,list_inputs,list_outputs);
20190 20915 return mp(x,y,z,c);
20191 20916 }
... ... @@ -20229,7 +20954,8 @@ namespace cimg_library_suffixed {
20229 20954 case 's' : output.assign(1); *output = (t)_spectrum;
20230 20955 case 'r' : output.assign(1); *output = (t)_is_shared;
20231 20956 }
20232   - _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*'?1:0),"eval",
  20957 + _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||
  20958 + *expression=='*' || *expression==':'?1:0),"eval",
20233 20959 *this,img_output,list_inputs,list_outputs);
20234 20960 output.assign(1,cimg::max(1U,mp.result_dim));
20235 20961 mp(x,y,z,c,output._data);
... ... @@ -20823,13 +21549,13 @@ namespace cimg_library_suffixed {
20823 21549 "incompatible dimensions.",
20824 21550 cimg_instance,
20825 21551 A._width,A._height,A._depth,A._spectrum,A._data);
20826   - if (_width!=1) {
20827   - cimg_forX(*this,i) draw_image(i,get_column(i).solve(A));
20828   - return *this;
20829   - }
20830   -
20831 21552 typedef _cimg_Ttfloat Ttfloat;
20832   - if (A._width==A._height) {
  21553 + if (A._width==A._height) { // Classical linear system
  21554 + if (_width!=1) {
  21555 + CImg<T> res(_width,A._width);
  21556 + cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));
  21557 + return res.move_to(*this);
  21558 + }
20833 21559 #ifdef cimg_use_lapack
20834 21560 char TRANS = 'N';
20835 21561 int INFO, N = _height, LWORK = 4*N, *const IPIV = new int[N];
... ... @@ -20865,6 +21591,11 @@ namespace cimg_library_suffixed {
20865 21591 #endif
20866 21592 } else { // Least-square solution for non-square systems.
20867 21593 #ifdef cimg_use_lapack
  21594 + if (_width!=1) {
  21595 + CImg<T> res(_width,A._width);
  21596 + cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));
  21597 + return res.move_to(*this);
  21598 + }
20868 21599 char TRANS = 'N';
20869 21600 int INFO, N = A._width, M = A._height, LWORK = -1, LDA = M, LDB = M, NRHS = _width;
20870 21601 Ttfloat WORK_QUERY;
... ... @@ -22393,24 +23124,25 @@ namespace cimg_library_suffixed {
22393 23124  
22394 23125 CImg<T>& _fill(const char *const expression, const bool repeat_values, const bool allow_formula,
22395 23126 const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs,
22396   - const char *const calling_function, const CImg<T> *provide_base) {
  23127 + const char *const calling_function, const CImg<T> *provides_copy) {
22397 23128 if (is_empty() || !expression || !*expression) return *this;
22398 23129 const unsigned int omode = cimg::exception_mode();
22399 23130 cimg::exception_mode(0);
22400 23131 CImg<charT> is_error;
22401 23132  
22402 23133 if (allow_formula) try { // Try to fill values according to a formula
22403   - bool is_parallelizable = true;
22404   - const CImg<T>
22405   - _base = _cimg_math_parser::needs_input_copy(expression,is_parallelizable)?
22406   - (provide_base?*provide_base:+*this):CImg<T>(),
22407   - &base = provide_base?*provide_base:_base?_base:*this;
22408   - _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*'?1:0),
  23134 + CImg<T> base = provides_copy?provides_copy->get_shared():get_shared();
  23135 + _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||
  23136 + *expression=='*' || *expression==':'?1:0),
22409 23137 calling_function,base,this,list_inputs,list_outputs);
  23138 + if (!provides_copy && expression && *expression!='>' && *expression!='<' && *expression!=':' &&
  23139 + mp.need_input_copy)
  23140 + base.assign().assign(*this); // Needs input copy
  23141 +
22410 23142 bool do_in_parallel = false;
22411 23143 #ifdef cimg_use_openmp
22412   - cimg_openmp_if(*expression=='*' ||
22413   - (is_parallelizable && _width>=320 && _height*_depth*_spectrum>=2 &&
  23144 + cimg_openmp_if(*expression=='*' || *expression==':' ||
  23145 + (mp.is_parallelizable && _width>=320 && _height*_depth*_spectrum>=2 &&
22414 23146 std::strlen(expression)>=6))
22415 23147 do_in_parallel = true;
22416 23148 #endif
... ... @@ -26443,18 +27175,20 @@ namespace cimg_library_suffixed {
26443 27175 \param boundary Boundary conditions. Can be <tt>{ 0=dirichlet | 1=neumann | 2=periodic }</tt>.
26444 27176 \note Most of the time, size of the image is modified.
26445 27177 **/
26446   - CImg<T>& rotate(const float angle, const unsigned int interpolation=1, const unsigned int boundary=0) {
  27178 + CImg<T>& rotate(const float angle, const unsigned int interpolation=1,
  27179 + const unsigned int boundary_conditions=0) {
26447 27180 const float nangle = cimg::mod(angle,360.0f);
26448 27181 if (nangle==0.0f) return *this;
26449   - return get_rotate(angle,interpolation,boundary).move_to(*this);
  27182 + return get_rotate(angle,interpolation,boundary_conditions).move_to(*this);
26450 27183 }
26451 27184  
26452 27185 //! Rotate image with arbitrary angle \newinstance.
26453   - CImg<T> get_rotate(const float angle, const unsigned int interpolation=1, const unsigned int boundary=0) const {
  27186 + CImg<T> get_rotate(const float angle, const unsigned int interpolation=1,
  27187 + const unsigned int boundary_conditions=0) const {
26454 27188 if (is_empty()) return *this;
26455 27189 CImg<T> res;
26456 27190 const float nangle = cimg::mod(angle,360.0f);
26457   - if (boundary!=1 && cimg::mod(nangle,90.0f)==0) { // Optimized version for orthogonal angles.
  27191 + if (boundary_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // Optimized version for orthogonal angles.
26458 27192 const int wm1 = width() - 1, hm1 = height() - 1;
26459 27193 const int iangle = (int)nangle/90;
26460 27194 switch (iangle) {
... ... @@ -26487,7 +27221,7 @@ namespace cimg_library_suffixed {
26487 27221 w2 = 0.5f*_width, h2 = 0.5f*_height,
26488 27222 dw2 = 0.5f*(ux + vx), dh2 = 0.5f*(uy + vy);
26489 27223 res.assign((int)(ux + vx),(int)(uy + vy),_depth,_spectrum);
26490   - switch (boundary) {
  27224 + switch (boundary_conditions) {
26491 27225 case 0 : { // Dirichlet boundaries.
26492 27226 switch (interpolation) {
26493 27227 case 2 : { // Cubic interpolation.
... ... @@ -26577,7 +27311,7 @@ namespace cimg_library_suffixed {
26577 27311 "rotate(): Invalid specified border conditions %d "
26578 27312 "(should be { 0=dirichlet | 1=neumann | 2=periodic }).",
26579 27313 cimg_instance,
26580   - boundary);
  27314 + boundary_conditions);
26581 27315 }
26582 27316 }
26583 27317 return res;
... ... @@ -26593,13 +27327,13 @@ namespace cimg_library_suffixed {
26593 27327 \param interpolation_type Type of interpolation. Can be <tt>{ 0=nearest | 1=linear | 2=cubic }</tt>.
26594 27328 **/
26595 27329 CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom,
26596   - const unsigned int interpolation=1, const unsigned int boundary=3) {
26597   - return get_rotate(angle,cx,cy,zoom,interpolation,boundary).move_to(*this);
  27330 + const unsigned int interpolation=1, const unsigned int boundary_conditions=0) {
  27331 + return get_rotate(angle,cx,cy,zoom,interpolation,boundary_conditions).move_to(*this);
26598 27332 }
26599 27333  
26600 27334 //! Rotate image with arbitrary angle, around a center point \newinstance.
26601 27335 CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom,
26602   - const unsigned int interpolation=1, const unsigned int boundary=3) const {
  27336 + const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const {
26603 27337 if (interpolation>2)
26604 27338 throw CImgArgumentException(_cimg_instance
26605 27339 "rotate(): Invalid specified interpolation type %d "
... ... @@ -26613,7 +27347,7 @@ namespace cimg_library_suffixed {
26613 27347 rad = (float)((angle*cimg::PI)/180.0),
26614 27348 ca = (float)std::cos(rad)/zoom,
26615 27349 sa = (float)std::sin(rad)/zoom;
26616   - switch (boundary) {
  27350 + switch (boundary_conditions) {
26617 27351 case 0 : {
26618 27352 switch (interpolation) {
26619 27353 case 2 : {
... ... @@ -26703,7 +27437,7 @@ namespace cimg_library_suffixed {
26703 27437 "rotate(): Invalid specified border conditions %d "
26704 27438 "(should be { 0=dirichlet | 1=neumann | 2=periodic }).",
26705 27439 cimg_instance,
26706   - boundary);
  27440 + boundary_conditions);
26707 27441 }
26708 27442 return res;
26709 27443 }
... ... @@ -29523,12 +30257,25 @@ namespace cimg_library_suffixed {
29523 30257 //! Compute watershed transform.
29524 30258 /**
29525 30259 \param priority Priority map.
29526   - \param fill_lines Tells if watershed lines must be filled or not.
  30260 + \param is_high_connectivity Boolean that choose between 4(false)- or 8(true)-connectivity
  30261 + in 2d case, and between 6(false)- or 26(true)-connectivity in 3d case.
29527 30262 \note Non-zero values of the instance instance are propagated to zero-valued ones according to
29528   - specified the priority map.
  30263 + specified the priority map.
29529 30264 **/
29530 30265 template<typename t>
29531   - CImg<T>& watershed(const CImg<t>& priority, const bool fill_lines=true) {
  30266 + CImg<T>& watershed(const CImg<t>& priority, const bool is_high_connectivity=false) {
  30267 +#define _cimg_watershed_init(cond,X,Y,Z) \
  30268 + if (cond && !(*this)(X,Y,Z)) Q._priority_queue_insert(labels,sizeQ,priority(X,Y,Z),X,Y,Z,nb_seeds)
  30269 +
  30270 +#define _cimg_watershed_propagate(cond,X,Y,Z) \
  30271 + if (cond) { \
  30272 + if ((*this)(X,Y,Z)) { \
  30273 + ns = labels(X,Y,Z) - 1; xs = seeds(ns,0); ys = seeds(ns,1); zs = seeds(ns,2); \
  30274 + d = cimg::sqr((float)x - xs) + cimg::sqr((float)y - ys) + cimg::sqr((float)z - zs); \
  30275 + if (d<dmin) { dmin = d; nmin = ns; label = (*this)(xs,ys,zs); } \
  30276 + } else Q._priority_queue_insert(labels,sizeQ,priority(X,Y,Z),X,Y,Z,n); \
  30277 + }
  30278 +
29532 30279 if (is_empty()) return *this;
29533 30280 if (!is_sameXYZ(priority))
29534 30281 throw CImgArgumentException(_cimg_instance
... ... @@ -29538,29 +30285,62 @@ namespace cimg_library_suffixed {
29538 30285 priority._width,priority._height,priority._depth,priority._spectrum,priority._data);
29539 30286 if (_spectrum!=1) {
29540 30287 cimg_forC(*this,c)
29541   - get_shared_channel(c).watershed(priority.get_shared_channel(c%priority._spectrum),fill_lines);
  30288 + get_shared_channel(c).watershed(priority.get_shared_channel(c%priority._spectrum));
29542 30289 return *this;
29543 30290 }
29544 30291  
29545   - CImg<boolT> is_queued(_width,_height,_depth,1,0);
  30292 + CImg<uintT> labels(_width,_height,_depth,1,0), seeds(64,3);
29546 30293 CImg<typename cimg::superset2<T,t,int>::type> Q;
29547 30294 unsigned int sizeQ = 0;
  30295 + int px, nx, py, ny, pz, nz;
  30296 + bool is_px, is_nx, is_py, is_ny, is_pz, is_nz;
  30297 + const bool is_3d = _depth>1;
29548 30298  
29549 30299 // Find seed points and insert them in priority queue.
  30300 + unsigned int nb_seeds = 0;
29550 30301 const T *ptrs = _data;
29551   - cimg_forXYZ(*this,x,y,z) if (*(ptrs++)) {
29552   - if (x - 1>=0 && !(*this)(x - 1,y,z))
29553   - Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z);
29554   - if (x + 1<width() && !(*this)(x + 1,y,z))
29555   - Q._priority_queue_insert(is_queued,sizeQ,priority(x + 1,y,z),x + 1,y,z);
29556   - if (y - 1>=0 && !(*this)(x,y - 1,z))
29557   - Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z);
29558   - if (y + 1<height() && !(*this)(x,y + 1,z))
29559   - Q._priority_queue_insert(is_queued,sizeQ,priority(x,y + 1,z),x,y + 1,z);
29560   - if (z - 1>=0 && !(*this)(x,y,z - 1))
29561   - Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1);
29562   - if (z + 1<depth() && !(*this)(x,y,z + 1))
29563   - Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z + 1),x,y,z + 1);
  30302 + cimg_forXYZ(*this,x,y,z) if (*(ptrs++)) { // 3d version
  30303 + if (nb_seeds>=seeds._width) seeds.resize(2*seeds._width,3,1,1,0);
  30304 + seeds(nb_seeds,0) = x; seeds(nb_seeds,1) = y; seeds(nb_seeds++,2) = z;
  30305 + px = x - 1; nx = x + 1;
  30306 + py = y - 1; ny = y + 1;
  30307 + pz = z - 1; nz = z + 1;
  30308 + is_px = px>=0; is_nx = nx<width();
  30309 + is_py = py>=0; is_ny = ny<height();
  30310 + is_pz = pz>=0; is_nz = nz<depth();
  30311 + _cimg_watershed_init(is_px,px,y,z);
  30312 + _cimg_watershed_init(is_nx,nx,y,z);
  30313 + _cimg_watershed_init(is_py,x,py,z);
  30314 + _cimg_watershed_init(is_ny,x,ny,z);
  30315 + if (is_3d) {
  30316 + _cimg_watershed_init(is_pz,x,y,pz);
  30317 + _cimg_watershed_init(is_nz,x,y,nz);
  30318 + }
  30319 + if (is_high_connectivity) {
  30320 + _cimg_watershed_init(is_px && is_py,px,py,z);
  30321 + _cimg_watershed_init(is_nx && is_py,nx,py,z);
  30322 + _cimg_watershed_init(is_px && is_ny,px,ny,z);
  30323 + _cimg_watershed_init(is_nx && is_ny,nx,ny,z);
  30324 + if (is_3d) {
  30325 + _cimg_watershed_init(is_px && is_pz,px,y,pz);
  30326 + _cimg_watershed_init(is_nx && is_pz,nx,y,pz);
  30327 + _cimg_watershed_init(is_px && is_nz,px,y,nz);
  30328 + _cimg_watershed_init(is_nx && is_nz,nx,y,nz);
  30329 + _cimg_watershed_init(is_py && is_pz,x,py,pz);
  30330 + _cimg_watershed_init(is_ny && is_pz,x,ny,pz);
  30331 + _cimg_watershed_init(is_py && is_nz,x,py,nz);
  30332 + _cimg_watershed_init(is_ny && is_nz,x,ny,nz);
  30333 + _cimg_watershed_init(is_px && is_py && is_pz,px,py,pz);
  30334 + _cimg_watershed_init(is_nx && is_py && is_pz,nx,py,pz);
  30335 + _cimg_watershed_init(is_px && is_ny && is_pz,px,ny,pz);
  30336 + _cimg_watershed_init(is_nx && is_ny && is_pz,nx,ny,pz);
  30337 + _cimg_watershed_init(is_px && is_py && is_nz,px,py,nz);
  30338 + _cimg_watershed_init(is_nx && is_py && is_nz,nx,py,nz);
  30339 + _cimg_watershed_init(is_px && is_ny && is_nz,px,ny,nz);
  30340 + _cimg_watershed_init(is_nx && is_ny && is_nz,nx,ny,nz);
  30341 + }
  30342 + }
  30343 + labels(x,y,z) = nb_seeds;
29564 30344 }
29565 30345  
29566 30346 // Start watershed computation.
... ... @@ -29568,145 +30348,113 @@ namespace cimg_library_suffixed {
29568 30348  
29569 30349 // Get and remove point with maximal priority from the queue.
29570 30350 const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3);
29571   - Q._priority_queue_remove(sizeQ);
  30351 + const unsigned int n = labels(x,y,z);
  30352 + px = x - 1; nx = x + 1;
  30353 + py = y - 1; ny = y + 1;
  30354 + pz = z - 1; nz = z + 1;
  30355 + is_px = px>=0; is_nx = nx<width();
  30356 + is_py = py>=0; is_ny = ny<height();
  30357 + is_pz = pz>=0; is_nz = nz<depth();
29572 30358  
29573 30359 // Check labels of the neighbors.
29574   - bool is_same_label = true;
29575   - T label = 0;
29576   - if (x - 1>=0) {
29577   - if ((*this)(x - 1,y,z)) {
29578   - if (!label) label = (*this)(x - 1,y,z);
29579   - else if (label!=(*this)(x - 1,y,z)) is_same_label = false;
29580   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z);
29581   - }
29582   - if (x + 1<width()) {
29583   - if ((*this)(x + 1,y,z)) {
29584   - if (!label) label = (*this)(x + 1,y,z);
29585   - else if (label!=(*this)(x + 1,y,z)) is_same_label = false;
29586   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x + 1,y,z),x + 1,y,z);
29587   - }
29588   - if (y - 1>=0) {
29589   - if ((*this)(x,y - 1,z)) {
29590   - if (!label) label = (*this)(x,y - 1,z);
29591   - else if (label!=(*this)(x,y - 1,z)) is_same_label = false;
29592   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z);
29593   - }
29594   - if (y + 1<height()) {
29595   - if ((*this)(x,y + 1,z)) {
29596   - if (!label) label = (*this)(x,y + 1,z);
29597   - else if (label!=(*this)(x,y + 1,z)) is_same_label = false;
29598   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y + 1,z),x,y + 1,z);
29599   - }
29600   - if (z - 1>=0) {
29601   - if ((*this)(x,y,z - 1)) {
29602   - if (!label) label = (*this)(x,y,z - 1);
29603   - else if (label!=(*this)(x,y,z - 1)) is_same_label = false;
29604   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1);
29605   - }
29606   - if (z + 1<depth()) {
29607   - if ((*this)(x,y,z + 1)) {
29608   - if (!label) label = (*this)(x,y,z + 1);
29609   - else if (label!=(*this)(x,y,z + 1)) is_same_label = false;
29610   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z + 1),x,y,z + 1);
29611   - }
29612   - if (is_same_label) (*this)(x,y,z) = label;
29613   - }
29614   -
29615   - // Fill lines.
29616   - if (fill_lines) {
29617   -
29618   - // Sort all non-labeled pixels with labeled neighbors.
29619   - is_queued = false;
29620   - const T *ptrs = _data;
29621   - cimg_forXYZ(*this,x,y,z) if (!*(ptrs++) &&
29622   - ((x - 1>=0 && (*this)(x - 1,y,z)) || (x + 1<width() && (*this)(x + 1,y,z)) ||
29623   - (y - 1>=0 && (*this)(x,y - 1,z)) || (y + 1<height() && (*this)(x,y + 1,z)) ||
29624   - (z - 1>=0 && (*this)(x,y,z - 1)) || (z + 1>depth() && (*this)(x,y,z + 1))))
29625   - Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z),x,y,z);
  30360 + Q._priority_queue_remove(sizeQ);
29626 30361  
29627   - // Start line filling process.
29628   - while (sizeQ) {
29629   - const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3);
29630   - Q._priority_queue_remove(sizeQ);
29631   - t pmax = cimg::type<t>::min();
29632   - int xmax = 0, ymax = 0, zmax = 0;
29633   - if (x - 1>=0) {
29634   - if ((*this)(x - 1,y,z)) {
29635   - if (priority(x - 1,y,z)>pmax) { pmax = priority(x - 1,y,z); xmax = x - 1; ymax = y; zmax = z; }
29636   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z);
29637   - }
29638   - if (x + 1<width()) {
29639   - if ((*this)(x + 1,y,z)) {
29640   - if (priority(x + 1,y,z)>pmax) { pmax = priority(x + 1,y,z); xmax = x + 1; ymax = y; zmax = z; }
29641   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x + 1,y,z),x + 1,y,z);
29642   - }
29643   - if (y - 1>=0) {
29644   - if ((*this)(x,y - 1,z)) {
29645   - if (priority(x,y - 1,z)>pmax) { pmax = priority(x,y - 1,z); xmax = x; ymax = y - 1; zmax = z; }
29646   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z);
29647   - }
29648   - if (y + 1<height()) {
29649   - if ((*this)(x,y + 1,z)) {
29650   - if (priority(x,y + 1,z)>pmax) { pmax = priority(x,y + 1,z); xmax = x; ymax = y + 1; zmax = z; }
29651   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y + 1,z),x,y + 1,z);
29652   - }
29653   - if (z - 1>=0) {
29654   - if ((*this)(x,y,z - 1)) {
29655   - if (priority(x,y,z - 1)>pmax) { pmax = priority(x,y,z - 1); xmax = x; ymax = y; zmax = z - 1; }
29656   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1);
29657   - }
29658   - if (z + 1<depth()) {
29659   - if ((*this)(x,y,z + 1)) {
29660   - if (priority(x,y,z + 1)>pmax) { pmax = priority(x,y,z + 1); xmax = x; ymax = y; zmax = z + 1; }
29661   - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z + 1),x,y,z + 1);
29662   - }
29663   - (*this)(x,y,z) = (*this)(xmax,ymax,zmax);
  30362 + unsigned int xs, ys, zs, ns, nmin = 0;
  30363 + float d, dmin = cimg::type<float>::inf();
  30364 + T label = 0;
  30365 + _cimg_watershed_propagate(is_px,px,y,z);
  30366 + _cimg_watershed_propagate(is_nx,nx,y,z);
  30367 + _cimg_watershed_propagate(is_py,x,py,z);
  30368 + _cimg_watershed_propagate(is_ny,x,ny,z);
  30369 + if (is_3d) {
  30370 + _cimg_watershed_propagate(is_pz,x,y,pz);
  30371 + _cimg_watershed_propagate(is_nz,x,y,nz);
29664 30372 }
  30373 + if (is_high_connectivity) {
  30374 + _cimg_watershed_propagate(is_px && is_py,px,py,z);
  30375 + _cimg_watershed_propagate(is_nx && is_py,nx,py,z);
  30376 + _cimg_watershed_propagate(is_px && is_ny,px,ny,z);
  30377 + _cimg_watershed_propagate(is_nx && is_ny,nx,ny,z);
  30378 + if (is_3d) {
  30379 + _cimg_watershed_propagate(is_px && is_pz,px,y,pz);
  30380 + _cimg_watershed_propagate(is_nx && is_pz,nx,y,pz);
  30381 + _cimg_watershed_propagate(is_px && is_nz,px,y,nz);
  30382 + _cimg_watershed_propagate(is_nx && is_nz,nx,y,nz);
  30383 + _cimg_watershed_propagate(is_py && is_pz,x,py,pz);
  30384 + _cimg_watershed_propagate(is_ny && is_pz,x,ny,pz);
  30385 + _cimg_watershed_propagate(is_py && is_nz,x,py,nz);
  30386 + _cimg_watershed_propagate(is_ny && is_nz,x,ny,nz);
  30387 + _cimg_watershed_propagate(is_px && is_py && is_pz,px,py,pz);
  30388 + _cimg_watershed_propagate(is_nx && is_py && is_pz,nx,py,pz);
  30389 + _cimg_watershed_propagate(is_px && is_ny && is_pz,px,ny,pz);
  30390 + _cimg_watershed_propagate(is_nx && is_ny && is_pz,nx,ny,pz);
  30391 + _cimg_watershed_propagate(is_px && is_py && is_nz,px,py,nz);
  30392 + _cimg_watershed_propagate(is_nx && is_py && is_nz,nx,py,nz);
  30393 + _cimg_watershed_propagate(is_px && is_ny && is_nz,px,ny,nz);
  30394 + _cimg_watershed_propagate(is_nx && is_ny && is_nz,nx,ny,nz);
  30395 + }
  30396 + }
  30397 + (*this)(x,y,z) = label;
  30398 + labels(x,y,z) = ++nmin;
29665 30399 }
29666 30400 return *this;
29667 30401 }
29668 30402  
29669 30403 //! Compute watershed transform \newinstance.
29670 30404 template<typename t>
29671   - CImg<T> get_watershed(const CImg<t>& priority, const bool fill_lines=true) const {
29672   - return (+*this).watershed(priority,fill_lines);
  30405 + CImg<T> get_watershed(const CImg<t>& priority, const bool is_high_connectivity=false) const {
  30406 + return (+*this).watershed(priority,is_high_connectivity);
29673 30407 }
29674 30408  
29675 30409 // [internal] Insert/Remove items in priority queue, for watershed/distance transforms.
29676   - template<typename t>
29677   - bool _priority_queue_insert(CImg<boolT>& is_queued, unsigned int& siz, const t value,
29678   - const unsigned int x, const unsigned int y, const unsigned int z) {
  30410 + template<typename tq, typename tv>
  30411 + bool _priority_queue_insert(CImg<tq>& is_queued, unsigned int& siz, const tv value,
  30412 + const unsigned int x, const unsigned int y, const unsigned int z,
  30413 + const unsigned int n=1) {
29679 30414 if (is_queued(x,y,z)) return false;
29680   - is_queued(x,y,z) = true;
  30415 + is_queued(x,y,z) = (tq)n;
29681 30416 if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); }
29682   - (*this)(siz - 1,0) = (T)value; (*this)(siz - 1,1) = (T)x; (*this)(siz - 1,2) = (T)y; (*this)(siz - 1,3) = (T)z;
  30417 + (*this)(siz - 1,0) = (T)value;
  30418 + (*this)(siz - 1,1) = (T)x;
  30419 + (*this)(siz - 1,2) = (T)y;
  30420 + (*this)(siz - 1,3) = (T)z;
29683 30421 for (unsigned int pos = siz - 1, par = 0; pos && value>(*this)(par=(pos + 1)/2 - 1,0); pos = par) {
29684   - cimg::swap((*this)(pos,0),(*this)(par,0)); cimg::swap((*this)(pos,1),(*this)(par,1));
29685   - cimg::swap((*this)(pos,2),(*this)(par,2)); cimg::swap((*this)(pos,3),(*this)(par,3));
  30422 + cimg::swap((*this)(pos,0),(*this)(par,0));
  30423 + cimg::swap((*this)(pos,1),(*this)(par,1));
  30424 + cimg::swap((*this)(pos,2),(*this)(par,2));
  30425 + cimg::swap((*this)(pos,3),(*this)(par,3));
29686 30426 }
29687 30427 return true;
29688 30428 }
29689 30429  
29690 30430 CImg<T>& _priority_queue_remove(unsigned int& siz) {
29691   - (*this)(0,0) = (*this)(--siz,0); (*this)(0,1) = (*this)(siz,1);
29692   - (*this)(0,2) = (*this)(siz,2); (*this)(0,3) = (*this)(siz,3);
  30431 + (*this)(0,0) = (*this)(--siz,0);
  30432 + (*this)(0,1) = (*this)(siz,1);
  30433 + (*this)(0,2) = (*this)(siz,2);
  30434 + (*this)(0,3) = (*this)(siz,3);
29693 30435 const float value = (*this)(0,0);
29694 30436 for (unsigned int pos = 0, left = 0, right = 0;
29695 30437 ((right=2*(pos + 1),(left=right - 1))<siz && value<(*this)(left,0)) ||
29696 30438 (right<siz && value<(*this)(right,0));) {
29697 30439 if (right<siz) {
29698 30440 if ((*this)(left,0)>(*this)(right,0)) {
29699   - cimg::swap((*this)(pos,0),(*this)(left,0)); cimg::swap((*this)(pos,1),(*this)(left,1));
29700   - cimg::swap((*this)(pos,2),(*this)(left,2)); cimg::swap((*this)(pos,3),(*this)(left,3));
  30441 + cimg::swap((*this)(pos,0),(*this)(left,0));
  30442 + cimg::swap((*this)(pos,1),(*this)(left,1));
  30443 + cimg::swap((*this)(pos,2),(*this)(left,2));
  30444 + cimg::swap((*this)(pos,3),(*this)(left,3));
29701 30445 pos = left;
29702 30446 } else {
29703   - cimg::swap((*this)(pos,0),(*this)(right,0)); cimg::swap((*this)(pos,1),(*this)(right,1));
29704   - cimg::swap((*this)(pos,2),(*this)(right,2)); cimg::swap((*this)(pos,3),(*this)(right,3));
  30447 + cimg::swap((*this)(pos,0),(*this)(right,0));
  30448 + cimg::swap((*this)(pos,1),(*this)(right,1));
  30449 + cimg::swap((*this)(pos,2),(*this)(right,2));
  30450 + cimg::swap((*this)(pos,3),(*this)(right,3));
29705 30451 pos = right;
29706 30452 }
29707 30453 } else {
29708   - cimg::swap((*this)(pos,0),(*this)(left,0)); cimg::swap((*this)(pos,1),(*this)(left,1));
29709   - cimg::swap((*this)(pos,2),(*this)(left,2)); cimg::swap((*this)(pos,3),(*this)(left,3));
  30454 + cimg::swap((*this)(pos,0),(*this)(left,0));
  30455 + cimg::swap((*this)(pos,1),(*this)(left,1));
  30456 + cimg::swap((*this)(pos,2),(*this)(left,2));
  30457 + cimg::swap((*this)(pos,3),(*this)(left,3));
29710 30458 pos = left;
29711 30459 }
29712 30460 }
... ... @@ -39484,11 +40232,11 @@ namespace cimg_library_suffixed {
39484 40232 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),
39485 40233 lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);
39486 40234 const t
39487   - *ptrs = sprite._data -
39488   - (bx?x0:0) -
39489   - (by?y0*(uptrT)sprite.width():0) -
39490   - (bz?z0*(uptrT)sprite.width()*sprite.height():0) -
39491   - (bc?c0*(uptrT)sprite.width()*sprite.height()*sprite.depth():0);
  40235 + *ptrs = sprite._data +
  40236 + (bx?-x0:0) +
  40237 + (by?-y0*(uptrT)sprite.width():0) +
  40238 + (bz?-z0*(uptrT)sprite.width()*sprite.height():0) +
  40239 + (bc?-c0*(uptrT)sprite.width()*sprite.height()*sprite.depth():0);
39492 40240 const uptrT
39493 40241 offX = (unsigned long)_width - lX,
39494 40242 soffX = (unsigned long)sprite._width - lX,
... ... @@ -39528,11 +40276,11 @@ namespace cimg_library_suffixed {
39528 40276 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),
39529 40277 lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);
39530 40278 const T
39531   - *ptrs = sprite._data -
39532   - (bx?x0:0) -
39533   - (by?y0*(uptrT)sprite.width():0) -
39534   - (bz?z0*(uptrT)sprite.width()*sprite.height():0) -
39535   - (bc?c0*(uptrT)sprite.width()*sprite.height()*sprite.depth():0);
  40279 + *ptrs = sprite._data +
  40280 + (bx?-x0:0) +
  40281 + (by?-y0*(uptrT)sprite.width():0) +
  40282 + (bz?-z0*(uptrT)sprite.width()*sprite.height():0) +
  40283 + (bc?-c0*(uptrT)sprite.width()*sprite.height()*sprite.depth():0);
39536 40284 const unsigned long
39537 40285 offX = (unsigned long)_width - lX,
39538 40286 soffX = (unsigned long)sprite._width - lX,
... ... @@ -39623,10 +40371,10 @@ namespace cimg_library_suffixed {
39623 40371 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),
39624 40372 lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);
39625 40373 const uptrT
39626   - coff = -(bx?x0:0) -
39627   - (by?y0*(uptrT)mask.width():0) -
39628   - (bz?z0*(uptrT)mask.width()*mask.height():0) -
39629   - (bc?c0*(uptrT)mask.width()*mask.height()*mask.depth():0),
  40374 + coff = (bx?-x0:0) +
  40375 + (by?-y0*(uptrT)mask.width():0) +
  40376 + (bz?-z0*(uptrT)mask.width()*mask.height():0) +
  40377 + (bc?-c0*(uptrT)mask.width()*mask.height()*mask.depth():0),
39630 40378 ssize = (uptrT)mask.width()*mask.height()*mask.depth()*mask.spectrum();
39631 40379 const ti *ptrs = sprite._data + coff;
39632 40380 const tm *ptrm = mask._data + coff;
... ... @@ -43423,7 +44171,7 @@ namespace cimg_library_suffixed {
43423 44171 unsigned int cdx = 0, dx = 0, dy = 0;
43424 44172 int err = 0;
43425 44173 double val;
43426   - assign(256,256);
  44174 + assign(256,256,1,1,0);
43427 44175 while ((err = std::fscanf(nfile,"%lf%255[^0-9eEinfa.+-]",&val,delimiter._data))>0) {
43428 44176 if (err>0) (*this)(cdx++,dy) = (T)val;
43429 44177 if (cdx>=_width) resize(3*_width/2,_height,1,1,0);
... ... @@ -48536,7 +49284,7 @@ namespace cimg_library_suffixed {
48536 49284 **/
48537 49285 const CImg<T>& save_tiff(const char *const filename, const unsigned int compression_type=0,
48538 49286 const float *const voxel_size=0, const char *const description=0,
48539   - const bool is_bigtiff=true) const {
  49287 + const bool use_bigtiff=true) const {
48540 49288 if (!filename)
48541 49289 throw CImgArgumentException(_cimg_instance
48542 49290 "save_tiff(): Specified filename is (null).",
... ... @@ -48544,7 +49292,9 @@ namespace cimg_library_suffixed {
48544 49292 if (is_empty()) { cimg::fempty(0,filename); return *this; }
48545 49293  
48546 49294 #ifdef cimg_use_tiff
48547   - TIFF *tif = TIFFOpen(filename,is_bigtiff?"w8":"w4");
  49295 + const bool
  49296 + _use_bigtiff = use_bigtiff && sizeof(uptrT)>=8 && size()*sizeof(T)>=1UL<<31; // No bigtiff for small images.
  49297 + TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4");
48548 49298 if (tif) {
48549 49299 cimg_forZ(*this,z) _save_tiff(tif,z,z,compression_type,voxel_size,description);
48550 49300 TIFFClose(tif);
... ... @@ -48554,7 +49304,7 @@ namespace cimg_library_suffixed {
48554 49304 filename);
48555 49305 return *this;
48556 49306 #else
48557   - cimg::unused(compression_type,voxel_size,description,is_bigtiff);
  49307 + cimg::unused(compression_type,voxel_size,description,use_bigtiff);
48558 49308 return save_other(filename);
48559 49309 #endif
48560 49310 }
... ... @@ -49078,9 +49828,9 @@ namespace cimg_library_suffixed {
49078 49828 if (is_empty()) { cimg::fempty(file,filename); return *this; }
49079 49829  
49080 49830 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
49081   - static const unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
49082   - 0,0,0,0,'C','I','m','g',0,0,0,0,0,
49083   - 'N','o',' ','d','a','t','e',0,0,0,0 };
  49831 + unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
  49832 + 0,0,0,0,'C','I','m','g',0,0,0,0,0,
  49833 + 'N','o',' ','d','a','t','e',0,0,0,0 };
49084 49834 unsigned int nbdims, dims[5] = { 0 };
49085 49835 bool saved = false;
49086 49836 _cimg_save_pandore_case(1,1,1,"unsigned char",2);
... ... @@ -52584,7 +53334,7 @@ namespace cimg_library_suffixed {
52584 53334 *tmp = *str_pixeltype = *str_endian = 0;
52585 53335 unsigned int j, N, W, H, D, C;
52586 53336 int i, err;
52587   - j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
  53337 + j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
52588 53338 err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",
52589 53339 &N,str_pixeltype._data,str_endian._data);
52590 53340 if (err<2) {
... ... @@ -53773,7 +54523,7 @@ namespace cimg_library_suffixed {
53773 54523 #define _cimg_save_cimg_case(Ts,Tss) \
53774 54524 if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
53775 54525 for (unsigned int l = 0; l<lmax; ++l) { \
53776   - j = 0; while((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j] = 0; \
  54526 + j = 0; while ((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j] = 0; \
53777 54527 W = H = D = C = 0; \
53778 54528 if (cimg_sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \
53779 54529 throw CImgIOException(_cimglist_instance \
... ... @@ -53843,7 +54593,7 @@ namespace cimg_library_suffixed {
53843 54593 *tmp = *str_pixeltype = *str_endian = 0;
53844 54594 unsigned int j, N, W, H, D, C;
53845 54595 int i, err;
53846   - j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
  54596 + j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
53847 54597 err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype._data,str_endian._data);
53848 54598 if (err<2) {
53849 54599 if (!file) cimg::fclose(nfile);
... ... @@ -53966,7 +54716,7 @@ namespace cimg_library_suffixed {
53966 54716 **/
53967 54717 const CImgList<T>& save_tiff(const char *const filename, const unsigned int compression_type=0,
53968 54718 const float *const voxel_size=0, const char *const description=0,
53969   - const bool is_bigtiff=true) const {
  54719 + const bool use_bigtiff=true) const {
53970 54720 if (!filename)
53971 54721 throw CImgArgumentException(_cimglist_instance
53972 54722 "save_tiff(): Specified filename is (null).",
... ... @@ -53974,14 +54724,17 @@ namespace cimg_library_suffixed {
53974 54724 if (is_empty()) { cimg::fempty(0,filename); return *this; }
53975 54725  
53976 54726 #ifndef cimg_use_tiff
53977   - if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description,is_bigtiff);
  54727 + if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description,use_bigtiff);
53978 54728 else cimglist_for(*this,l) {
53979 54729 CImg<charT> nfilename(1024);
53980 54730 cimg::number_filename(filename,l,6,nfilename);
53981   - _data[l].save_tiff(nfilename,compression_type,voxel_size,description,is_bigtiff);
  54731 + _data[l].save_tiff(nfilename,compression_type,voxel_size,description,use_bigtiff);
53982 54732 }
53983 54733 #else
53984   - TIFF *tif = TIFFOpen(filename,is_bigtiff?"w8":"w4");
  54734 + typename CImg<T>::uptrT siz = 0;
  54735 + cimglist_for(*this,l) siz+=_data[l].size();
  54736 + const bool _use_bigtiff = use_bigtiff && sizeof(siz)>=8 && siz*sizeof(T)>=1UL<<31; // No bigtiff for small images.
  54737 + TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4");
53985 54738 if (tif) {
53986 54739 for (unsigned int dir = 0, l = 0; l<_width; ++l) {
53987 54740 const CImg<T>& img = (*this)[l];
... ...
stim/image/image.h
... ... @@ -35,7 +35,7 @@ public:
35 35 img = cimg_library::CImg<T>(x, y, z);
36 36 }*/
37 37  
38   - image(unsigned int x, unsigned int y = 1, unsigned int z = 1, unsigned int c = 1){
  38 + image(size_t x, size_t y = 1, size_t z = 1, size_t c = 1){
39 39 img = cimg_library::CImg<T>(x, y, z, c);
40 40 }
41 41  
... ... @@ -50,13 +50,13 @@ public:
50 50 }
51 51  
52 52 //create an image from an interleaved buffer
53   - void set_interleaved(T* buffer, unsigned int width, unsigned int height, unsigned int channels = 1){
  53 + void set_interleaved(T* buffer, size_t width, size_t height, size_t channels = 1){
54 54  
55 55 T* non_interleaved = (T*)malloc(width * height * 3 * sizeof(T));
56   - unsigned int S = width * height;
  56 + size_t S = width * height;
57 57  
58   - for(unsigned int i = 0; i < S; i++){
59   - for(unsigned int c = 0; c < channels; c++){
  58 + for(size_t i = 0; i < S; i++){
  59 + for(size_t c = 0; c < channels; c++){
60 60 non_interleaved[i + c * S] = buffer[i * channels + c];
61 61 }
62 62 }
... ... @@ -71,19 +71,19 @@ public:
71 71  
72 72 void data_interleaved(T* data){
73 73  
74   - unsigned int C = channels();
75   - unsigned int X = width() * height();
  74 + size_t C = channels();
  75 + size_t X = width() * height();
76 76  
77 77 T* ptr = img.data();
78 78  
79 79 //for each channel
80   - for(unsigned int c = 0; c < C; c++)
  80 + for(size_t c = 0; c < C; c++)
81 81 //convert each pixel
82   - for(unsigned int x = 0; x < X; x++)
  82 + for(size_t x = 0; x < X; x++)
83 83 data[x * C + c] = ptr[c * X + x];
84 84 }
85 85  
86   - image<T> channel(unsigned int c){
  86 + image<T> channel(size_t c){
87 87  
88 88 //create a new image
89 89 image<T> single;
... ... @@ -94,7 +94,7 @@ public:
94 94  
95 95 }
96 96  
97   - T& operator()(unsigned x, unsigned y, unsigned z = 0, unsigned c = 0){
  97 + T& operator()(size_t x, size_t y, size_t z = 0, size_t c = 0){
98 98 return img(x, y, z, c);
99 99 }
100 100  
... ... @@ -103,9 +103,9 @@ public:
103 103 /// @param v is the value used to set all values in the image
104 104 image<T> operator=(T v){
105 105  
106   - unsigned int X = width() * height() * depth() * channels();
  106 + size_t X = width() * height() * depth() * channels();
107 107  
108   - for(unsigned x = 0; x < X; x++)
  108 + for(size_t x = 0; x < X; x++)
109 109 img.data()[x] = v;
110 110  
111 111 return *this;
... ... @@ -117,10 +117,10 @@ public:
117 117 /// @param c is the channel number that the data will be copied to
118 118 /// @param buffer is a pointer to the image to be copied to channel c
119 119  
120   - void set_channel(unsigned int c, T* buffer){
  120 + void set_channel(size_t c, T* buffer){
121 121  
122 122 //calculate the number of pixels in a channel
123   - unsigned int channel_size = width() * height();
  123 + size_t channel_size = width() * height();
124 124  
125 125 //retreive a pointer to the raw image data
126 126 T* ptr = img.data() + channel_size * c;
... ... @@ -129,7 +129,7 @@ public:
129 129 memcpy(ptr, buffer, sizeof(T) * channel_size);
130 130 }
131 131  
132   - image<T> getslice(unsigned int c){
  132 + image<T> getslice(size_t c){
133 133  
134 134 //create a new image
135 135 image<T> slice;
... ... @@ -140,19 +140,19 @@ public:
140 140  
141 141 }
142 142  
143   - unsigned int channels(){
144   - return (unsigned int)img.spectrum();
  143 + size_t channels(){
  144 + return (size_t)img.spectrum();
145 145 }
146 146  
147   - unsigned int width(){
  147 + size_t width(){
148 148 return img.width();
149 149 }
150 150  
151   - unsigned int height(){
  151 + size_t height(){
152 152 return img.height();
153 153 }
154 154  
155   - unsigned int depth(){
  155 + size_t depth(){
156 156 return img.depth();
157 157 }
158 158  
... ... @@ -162,22 +162,22 @@ public:
162 162 }
163 163  
164 164 //returns the size (number of values) of the image
165   - unsigned long size(){
  165 + size_t size(){
166 166 return img.size();
167 167 }
168 168  
169 169 /// Returns the number of nonzero values
170   - unsigned int nnz(){
  170 + size_t nnz(){
171 171  
172   - unsigned long P = width() * height();
173   - unsigned long C = channels();
  172 + size_t P = width() * height();
  173 + size_t C = channels();
174 174  
175 175 T* ptr = img.data();
176 176  
177   - unsigned long n = 0;
  177 + size_t n = 0;
178 178  
179   - for(unsigned long p = 0; p < P; p++){
180   - for(unsigned long c = 0; c < C; c++){
  179 + for(size_t p = 0; p < P; p++){
  180 + for(size_t c = 0; c < C; c++){
181 181  
182 182 if(ptr[c * P + p] > 0){
183 183 n++;
... ... @@ -191,19 +191,19 @@ public:
191 191 }
192 192  
193 193 //this function returns indices of pixels that have nonzero values
194   - std::vector<unsigned long> sparse_idx(){
  194 + std::vector<size_t> sparse_idx(){
195 195  
196   - std::vector<unsigned long> s; //allocate an array
  196 + std::vector<size_t> s; //allocate an array
197 197 s.resize(nnz()); //allocate space in the array
198 198  
199   - unsigned long P = width() * height();
200   - unsigned long C = channels();
  199 + size_t P = width() * height();
  200 + size_t C = channels();
201 201  
202 202 T* ptr = img.data(); //get a pointer to the image data
203 203  
204   - unsigned long i = 0;
205   - for(unsigned long p = 0; p < P; p++){
206   - for(unsigned long c = 0; c < C; c++){
  204 + size_t i = 0;
  205 + for(size_t p = 0; p < P; p++){
  206 + for(size_t c = 0; c < C; c++){
207 207  
208 208 if(ptr[c * P + p] > 0){
209 209 s[i] = p;
... ... @@ -220,9 +220,9 @@ public:
220 220 /// Returns the maximum pixel value in the image
221 221 T maxv(){
222 222 float max = 0;
223   - unsigned long N = width() * height(); //get the number of pixels
  223 + size_t N = width() * height(); //get the number of pixels
224 224  
225   - for (unsigned long i=0; i<N; i++){
  225 + for (size_t i=0; i<N; i++){
226 226  
227 227 if (img.data()[i] > max)
228 228 {
... ... @@ -236,9 +236,9 @@ public:
236 236 /// Returns the minimum pixel value in the image
237 237 T minv(){
238 238 float min = 0;
239   - unsigned long N = width() * height(); //get the number of pixels
  239 + size_t N = width() * height(); //get the number of pixels
240 240  
241   - for (unsigned long i=0; i<N; i++){
  241 + for (size_t i=0; i<N; i++){
242 242  
243 243 if (img.data()[i] < min)
244 244 {
... ... @@ -276,8 +276,8 @@ public:
276 276  
277 277 image<T> result;
278 278 float zoom = 1;
279   - unsigned int interpolation = 1;
280   - unsigned int boundary = 1;
  279 + size_t interpolation = 1;
  280 + size_t boundary = 1;
281 281 result.img = img.get_rotate (angle, cx, cy, zoom, interpolation, boundary);
282 282 //result.save("data_output/test_rotate_neum.bmp");
283 283  
... ... @@ -286,13 +286,13 @@ public:
286 286  
287 287 // leila's code for non_interleaving data in 3D
288 288 //create an data set from an interleaved buffer
289   - void set_interleaved3(T* buffer, unsigned int width, unsigned int height, unsigned int depth, unsigned int channels = 3){
  289 + void set_interleaved3(T* buffer, size_t width, size_t height, size_t depth, size_t channels = 3){
290 290  
291 291 T* non_interleaved3 = (T*)malloc(width * height * depth * 3 * sizeof(T));
292   - unsigned int p = width * height * depth;
  292 + size_t p = width * height * depth;
293 293  
294   - for(unsigned int i = 0; i < p; i++){
295   - for(unsigned int c = 0; c < channels; c++){
  294 + for(size_t i = 0; i < p; i++){
  295 + for(size_t c = 0; c < channels; c++){
296 296 non_interleaved3[i + c * p] = buffer[i * channels + c];
297 297 }
298 298 }
... ...
stim/parser/arguments.h
... ... @@ -76,7 +76,7 @@ namespace stim{
76 76  
77 77 }
78 78  
79   - int nargs()
  79 + size_t nargs()
80 80 {
81 81 return vals.size();
82 82 }
... ... @@ -135,9 +135,9 @@ namespace stim{
135 135 }
136 136  
137 137 //get the width of the left column
138   - int col_width()
  138 + size_t col_width()
139 139 {
140   - int n = 3;
  140 + size_t n = 3;
141 141 //add the length of the option name
142 142 n += name.size();
143 143  
... ... @@ -148,7 +148,7 @@ namespace stim{
148 148 n += 6;
149 149  
150 150 //for each default option value
151   - for(unsigned int v=0; v<vals.size(); v++)
  151 + for(size_t v=0; v<vals.size(); v++)
152 152 n += vals[v].size() + 1;
153 153 }
154 154  
... ... @@ -160,7 +160,7 @@ namespace stim{
160 160  
161 161  
162 162 //string output
163   - std::string toStr(int width = 0)
  163 + std::string toStr(size_t width = 0)
164 164 {
165 165 std::stringstream ss;
166 166  
... ... @@ -174,7 +174,7 @@ namespace stim{
174 174 if(ansi)
175 175 left_part += "\033[1;32m";
176 176 left_part += " ( = ";
177   - for(unsigned int v=0; v<vals.size(); v++)
  177 + for(size_t v=0; v<vals.size(); v++)
178 178 left_part += vals[v] + std::string(" ");
179 179 left_part += ")";
180 180 if(ansi)
... ... @@ -191,7 +191,7 @@ namespace stim{
191 191 ss<<std::left<<std::setw(width + color_size)<<left_part;
192 192  
193 193 //output right column
194   - for(unsigned int d=0; d<desc.size(); d++)
  194 + for(size_t d=0; d<desc.size(); d++)
195 195 {
196 196 if(d == 0)
197 197 ss<<desc[0];
... ... @@ -234,7 +234,7 @@ namespace stim{
234 234 struct argsection
235 235 {
236 236 std::string name;
237   - unsigned int index;
  237 + size_t index;
238 238 };
239 239  
240 240 /**The arglist class implements command line arguments.
... ... @@ -285,7 +285,7 @@ namespace stim{
285 285 std::vector<std::string> args;
286 286  
287 287 //column width of the longest option
288   - int col_width;
  288 + size_t col_width;
289 289  
290 290 //list of sections
291 291 std::vector<argsection> sections;
... ... @@ -327,7 +327,7 @@ namespace stim{
327 327 opt.set_ansi(ansi);
328 328 opts.push_back(opt);
329 329  
330   - col_width = std::max<int>(col_width, opt.col_width());
  330 + col_width = std::max<size_t>(col_width, opt.col_width());
331 331 }
332 332  
333 333 ///Specifies a section name that can be used to organize parameters in the output.
... ... @@ -373,32 +373,28 @@ namespace stim{
373 373 ///Retrieves the index for a supported argument, given that argument's name.
374 374  
375 375 /// @param _name is the name of the requested argument
376   - int index(std::string _name)
  376 + size_t index(std::string _name)
377 377 {
378   - unsigned int i = find(opts.begin(), opts.end(), _name) - opts.begin();
  378 + size_t i = find(opts.begin(), opts.end(), _name) - opts.begin();
379 379  
380   - if(i >= opts.size())
381   - return -1;
  380 + if(i >= opts.size()){
  381 + std::cout<<"ERROR stim::arglist: option name '"<<_name<<"' not found"<<std::endl;
  382 + exit(1);
  383 + }
382 384  
383   - return (int)i;
  385 + return i;
384 386 }
385 387  
386 388 ///Sets an argument to a specified value
387 389  
388 390 /// @param _name is the name of the argument to be set
389 391 /// @param _value is the value that it is given
390   - void set(std::string _name, std::string _value)
391   - {
392   - int i = index(_name);
  392 + void set(std::string _name, std::string _value){
  393 + size_t i = index(_name);
393 394  
394   - if(i != -1)
395   - {
396   - opts[i].set(_value);
397   - //adjust the column width if necessary
398   - col_width = (std::max)(col_width, opts[i].col_width());
399   - }
400   - else
401   - std::cout<<"ERROR - option not recognized: "<<_name<<std::endl;
  395 + opts[i].set(_value);
  396 + //adjust the column width if necessary
  397 + col_width = (std::max)(col_width, opts[i].col_width());
402 398 }
403 399  
404 400 ///Parses the command line
... ... @@ -449,10 +445,9 @@ namespace stim{
449 445 /// @param _name is the name of the argument
450 446 bool operator()(std::string _name)
451 447 {
452   - int i = find(opts.begin(), opts.end(), _name) - opts.begin();
  448 + size_t i = find(opts.begin(), opts.end(), _name) - opts.begin();
453 449  
454   - if(i < 0)
455   - {
  450 + if(i < 0){
456 451 std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl;
457 452 exit(1);
458 453 }
... ... @@ -463,12 +458,11 @@ namespace stim{
463 458 ///Returns the number of parameters for a specified argument
464 459  
465 460 /// @param _name is the name of the argument whose parameter number will be returned
466   - unsigned int nargs(std::string _name)
  461 + size_t nargs(std::string _name)
467 462 {
468   - int i = find(opts.begin(), opts.end(), _name) - opts.begin();
  463 + size_t i = find(opts.begin(), opts.end(), _name) - opts.begin();
469 464  
470   - if(i < 0)
471   - {
  465 + if(i < 0){
472 466 std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl;
473 467 exit(1);
474 468 }
... ... @@ -477,14 +471,14 @@ namespace stim{
477 471 }
478 472  
479 473 ///Returns the number of arguments that have been set
480   - unsigned int nargs(){
  474 + size_t nargs(){
481 475 return args.size();
482 476 }
483 477  
484 478 /// Returns the number of options that are set
485   - unsigned int nopts(){
486   - unsigned int n = 0; //initialize the counter for the number of options
487   - for(unsigned int i = 0; i < opts.size(); i++) //go through each option
  479 + size_t nopts(){
  480 + size_t n = 0; //initialize the counter for the number of options
  481 + for(size_t i = 0; i < opts.size(); i++) //go through each option
488 482 if(opts[i].is_set()) n++; //if a value is specified, increment the counter
489 483 return n;
490 484 }
... ... @@ -492,7 +486,7 @@ namespace stim{
492 486 ///Returns the name of an argument, given its index
493 487  
494 488 /// @param a is the index of the requested argument
495   - std::string arg(unsigned int a){
  489 + std::string arg(size_t a){
496 490 return args[a];
497 491 }
498 492  
... ... @@ -501,7 +495,7 @@ namespace stim{
501 495 /// @param _name is the name of the requested argument
502 496 cmd_option operator[](std::string _name)
503 497 {
504   - int i = find(opts.begin(), opts.end(), _name) - opts.begin();
  498 + size_t i = find(opts.begin(), opts.end(), _name) - opts.begin();
505 499  
506 500 if(i < 0 || i >= opts.size())
507 501 {
... ...
stim/parser/filename.h
... ... @@ -305,7 +305,7 @@ public:
305 305 return result; //return the result
306 306 }
307 307  
308   - stim::filename insert(unsigned i, unsigned int n = 2){
  308 + stim::filename insert(size_t i, size_t n = 2){
309 309  
310 310 std::stringstream ss;
311 311 ss << std::setw(n) << std::setfill('0') << i;
... ...
stim/visualization/colormap.h
... ... @@ -36,7 +36,7 @@ namespace stim{
36 36  
37 37 enum colormapType {cmBrewer, cmGrayscale, cmRainbow};
38 38  
39   -static void buffer2image(unsigned char* buffer, std::string filename, unsigned int width, unsigned int height)
  39 +static void buffer2image(unsigned char* buffer, std::string filename, size_t width, size_t height)
40 40 {
41 41 /*unsigned char* non_interleaved = (unsigned char*)malloc(x_size * y_size * 3);
42 42 unsigned int S = x_size * y_size;
... ... @@ -216,9 +216,9 @@ static void gpu2image(T* gpuSource, std::string fileDest, unsigned int x_size, u
216 216 #endif
217 217  
218 218 template<class T>
219   -static void cpuApplyBrewer(T* cpuSource, unsigned char* cpuDest, unsigned int N, T minVal = 0, T maxVal = 1)
  219 +static void cpuApplyBrewer(T* cpuSource, unsigned char* cpuDest, size_t N, T minVal = 0, T maxVal = 1)
220 220 {
221   - for(int i=0; i<N; i++)
  221 + for(size_t i=0; i<N; i++)
222 222 {
223 223 //compute the normalized value on [minVal maxVal]
224 224 float a;
... ... @@ -249,15 +249,15 @@ static void cpuApplyBrewer(T* cpuSource, unsigned char* cpuDest, unsigned int N,
249 249 }
250 250  
251 251  
252   - cpuDest[i * 3 + 0] = 255 * r;
253   - cpuDest[i * 3 + 1] = 255 * g;
254   - cpuDest[i * 3 + 2] = 255 * b;
  252 + cpuDest[i * 3 + 0] = (unsigned char)(255 * r);
  253 + cpuDest[i * 3 + 1] = (unsigned char)(255 * g);
  254 + cpuDest[i * 3 + 2] = (unsigned char)(255 * b);
255 255  
256 256 }
257 257 }
258 258  
259 259 template<class T>
260   -static void cpu2cpu(T* cpuSource, unsigned char* cpuDest, unsigned int nVals, T valMin, T valMax, colormapType cm = cmGrayscale)
  260 +static void cpu2cpu(T* cpuSource, unsigned char* cpuDest, size_t nVals, T valMin, T valMax, colormapType cm = cmGrayscale)
261 261 {
262 262  
263 263 if(cm == cmBrewer)
... ... @@ -279,15 +279,15 @@ static void cpu2cpu(T* cpuSource, unsigned char* cpuDest, unsigned int nVals, T
279 279 if(a < 0) a = 0;
280 280 if(a > 1) a = 1;
281 281  
282   - cpuDest[i * 3 + 0] = 255 * a;
283   - cpuDest[i * 3 + 1] = 255 * a;
284   - cpuDest[i * 3 + 2] = 255 * a;
  282 + cpuDest[i * 3 + 0] = (unsigned char)(255 * a);
  283 + cpuDest[i * 3 + 1] = (unsigned char)(255 * a);
  284 + cpuDest[i * 3 + 2] = (unsigned char)(255 * a);
285 285 }
286 286 }
287 287 }
288 288  
289 289 template<class T>
290   -static void cpu2cpu(T* cpuSource, unsigned char* cpuDest, unsigned int nVals, colormapType cm = cmGrayscale)
  290 +static void cpu2cpu(T* cpuSource, unsigned char* cpuDest, unsigned long long nVals, colormapType cm = cmGrayscale)
291 291 {
292 292 //computes the max and min range automatically
293 293  
... ... @@ -313,7 +313,7 @@ static void cpu2cpu(T* cpuSource, unsigned char* cpuDest, unsigned int nVals, co
313 313  
314 314  
315 315 template<typename T>
316   -static void cpu2image(T* cpuSource, std::string fileDest, unsigned int x_size, unsigned int y_size, T valMin, T valMax, colormapType cm = cmGrayscale)
  316 +static void cpu2image(T* cpuSource, std::string fileDest, size_t x_size, size_t y_size, T valMin, T valMax, colormapType cm = cmGrayscale)
317 317 {
318 318 //allocate a color buffer
319 319 unsigned char* cpuBuffer = (unsigned char*) malloc(sizeof(unsigned char) * 3 * x_size * y_size);
... ... @@ -329,7 +329,7 @@ static void cpu2image(T* cpuSource, std::string fileDest, unsigned int x_size, u
329 329 }
330 330  
331 331 template<typename T>
332   -static void cpu2image(T* cpuSource, std::string fileDest, unsigned int x_size, unsigned int y_size, colormapType cm = cmGrayscale)
  332 +static void cpu2image(T* cpuSource, std::string fileDest, size_t x_size, size_t y_size, colormapType cm = cmGrayscale)
333 333 {
334 334 //allocate a color buffer
335 335 unsigned char* cpuBuffer = (unsigned char*) malloc(sizeof(unsigned char) * 3 * x_size * y_size);
... ...