Commit 43dec7889fc305d2dab2e19da474e33c27774061
1 parent
b3a38641
added code for sifting BSQ files in memory, updated CImg
Showing
4 changed files
with
6908 additions
and
2339 deletions
Show diff stats
stim/envi/bsq.h
... | ... | @@ -26,7 +26,7 @@ class bsq: public binary<T> { |
26 | 26 | |
27 | 27 | |
28 | 28 | protected: |
29 | - | |
29 | + | |
30 | 30 | std::vector<double> w; //band wavelengths |
31 | 31 | unsigned int offset; |
32 | 32 | |
... | ... | @@ -51,7 +51,7 @@ public: |
51 | 51 | using binary<T>::read_line_01; |
52 | 52 | using binary<T>::read_plane_2; |
53 | 53 | //using binary<T>::getSlice; |
54 | - | |
54 | + | |
55 | 55 | |
56 | 56 | /// Open a data file for reading using the class interface. |
57 | 57 | |
... | ... | @@ -60,7 +60,7 @@ public: |
60 | 60 | /// @param Y is the number of samples (lines) along dimension 2 |
61 | 61 | /// @param B is the number of samples (bands) along dimension 3 |
62 | 62 | /// @param header_offset is the number of bytes (if any) in the binary header |
63 | - /// @param wavelengths is an optional STL vector of size B specifying a numerical label for each band | |
63 | + /// @param wavelengths is an STL vector of size B specifying a numerical label for each band | |
64 | 64 | bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int B, unsigned int header_offset, std::vector<double> wavelengths){ |
65 | 65 | |
66 | 66 | //copy the wavelengths to the BSQ file structure |
... | ... | @@ -69,7 +69,6 @@ public: |
69 | 69 | offset = header_offset; |
70 | 70 | |
71 | 71 | return open(filename, vec<unsigned int>(X, Y, B), header_offset); |
72 | - | |
73 | 72 | } |
74 | 73 | |
75 | 74 | /// Retrieve a single band (based on index) and stores it in pre-allocated memory. |
... | ... | @@ -91,7 +90,7 @@ public: |
91 | 90 | return band_index(p, (unsigned int)wavelength); |
92 | 91 | |
93 | 92 | unsigned int XY = X() * Y(); //calculate the number of pixels in a band |
94 | - unsigned page = 0; | |
93 | + unsigned page = 0; | |
95 | 94 | |
96 | 95 | |
97 | 96 | //get the two neighboring bands (above and below 'wavelength') |
... | ... | @@ -165,13 +164,13 @@ public: |
165 | 164 | file.seekg((bandnum - 1) * sizeof(T), std::ios::cur); //go to the next band |
166 | 165 | } |
167 | 166 | |
168 | - return true; | |
167 | + return true; | |
169 | 168 | } |
170 | 169 | |
171 | 170 | /// Perform baseline correction given a list of baseline points and stores the result in a new BSQ file. |
172 | 171 | |
173 | 172 | /// @param outname is the name of the output file used to store the resulting baseline-corrected data. |
174 | - /// @param wls is the list of baseline points based on band labels. | |
173 | + /// @param wls is the list of baseline points based on band labels. | |
175 | 174 | bool baseline(std::string outname, std::vector<double> wls ) |
176 | 175 | { |
177 | 176 | unsigned N = wls.size(); //get the number of baseline points |
... | ... | @@ -194,8 +193,8 @@ public: |
194 | 193 | T * c; //pointer to the current image |
195 | 194 | |
196 | 195 | a = (T*)malloc( S ); //memory allocation |
197 | - b = (T*)malloc( S ); | |
198 | - c = (T*)malloc( S ); | |
196 | + b = (T*)malloc( S ); | |
197 | + c = (T*)malloc( S ); | |
199 | 198 | |
200 | 199 | if (a == NULL || b == NULL || c == NULL){ |
201 | 200 | std::cout<<"ERROR: error allocating memory"; |
... | ... | @@ -203,13 +202,13 @@ public: |
203 | 202 | } |
204 | 203 | |
205 | 204 | |
206 | - //initialize lownum, highnum, low, high | |
205 | + //initialize lownum, highnum, low, high | |
207 | 206 | ai=w[0]; |
208 | 207 | |
209 | 208 | //if no baseline point is specified at band 0, |
210 | 209 | //set the baseline point at band 0 to 0 |
211 | 210 | if(wls[0] != w[0]){ |
212 | - bi = wls[control]; | |
211 | + bi = wls[control]; | |
213 | 212 | memset(a, (char)0, S); |
214 | 213 | } |
215 | 214 | //else get the low band |
... | ... | @@ -221,7 +220,7 @@ public: |
221 | 220 | //get the high band |
222 | 221 | band(b, bi); |
223 | 222 | |
224 | - //correct every band | |
223 | + //correct every band | |
225 | 224 | for(unsigned cii = 0; cii < B; cii++){ |
226 | 225 | |
227 | 226 | //update baseline points, if necessary |
... | ... | @@ -253,21 +252,21 @@ public: |
253 | 252 | //get the current band |
254 | 253 | band_index(c, cii); |
255 | 254 | ci = w[cii]; |
256 | - | |
255 | + | |
257 | 256 | //perform the baseline correction |
258 | 257 | for(unsigned i=0; i < XY; i++){ |
259 | 258 | double r = (double) (ci - ai) / (double) (bi - ai); |
260 | 259 | c[i] =(T) ( c[i] - (b[i] - a[i]) * r - a[i] ); |
261 | 260 | } |
262 | - | |
261 | + | |
263 | 262 | target.write(reinterpret_cast<const char*>(c), S); //write the corrected data into destination |
264 | 263 | |
265 | 264 | thread_data = (double)cii / B * 100; |
266 | - | |
267 | - } | |
265 | + | |
266 | + } | |
268 | 267 | |
269 | 268 | //header.save(headername); //save the new header file |
270 | - | |
269 | + | |
271 | 270 | free(a); |
272 | 271 | free(b); |
273 | 272 | free(c); |
... | ... | @@ -295,7 +294,7 @@ public: |
295 | 294 | T * c; //pointer to the current image |
296 | 295 | |
297 | 296 | b = (T*)malloc( S ); //memory allocation |
298 | - c = (T*)malloc( S ); | |
297 | + c = (T*)malloc( S ); | |
299 | 298 | |
300 | 299 | band(b, w); //get the certain band into memory |
301 | 300 | |
... | ... | @@ -314,17 +313,17 @@ public: |
314 | 313 | thread_data = (double)j / B * 100; |
315 | 314 | } |
316 | 315 | |
317 | - | |
316 | + | |
318 | 317 | |
319 | 318 | //header.save(headername); //save the new header file |
320 | - | |
319 | + | |
321 | 320 | free(b); |
322 | 321 | free(c); |
323 | 322 | target.close(); |
324 | 323 | thread_data = 100; //make sure that the progress bar is full |
325 | 324 | return true; |
326 | 325 | } |
327 | - | |
326 | + | |
328 | 327 | /// Convert the current BSQ file to a BIP file with the specified file name. |
329 | 328 | |
330 | 329 | /// @param outname is the name of the output BIP file to be saved to disk. |
... | ... | @@ -356,10 +355,10 @@ public: |
356 | 355 | //simplify image resolution |
357 | 356 | unsigned int L = X() * Z() * sizeof(T); //calculate the number of bytes of a ZX slice |
358 | 357 | unsigned int jump = (Y() - 1) * X() * sizeof(T); |
359 | - | |
358 | + | |
360 | 359 | std::ofstream target(outname.c_str(), std::ios::binary); |
361 | 360 | std::string headername = outname + ".hdr"; |
362 | - | |
361 | + | |
363 | 362 | unsigned int xz_bytes = X() * Z() * sizeof(T); |
364 | 363 | T * xz_slice; //pointer to the current spectrum |
365 | 364 | xz_slice = (T*)malloc(xz_bytes); |
... | ... | @@ -372,16 +371,16 @@ public: |
372 | 371 | file.read((char *)(xz_slice + z * X()), sizeof(T) * X()); //read a line |
373 | 372 | file.seekg(jump, std::ios::cur); //seek to the next band |
374 | 373 | |
375 | - | |
374 | + | |
376 | 375 | thread_data = (double)(y * Z() + z) / (Z() * Y()) * 100; //update the progress counter |
377 | - } | |
378 | - target.write(reinterpret_cast<const char*>(xz_slice), xz_bytes); //write the generated XZ slice to the target file | |
376 | + } | |
377 | + target.write(reinterpret_cast<const char*>(xz_slice), xz_bytes); //write the generated XZ slice to the target file | |
379 | 378 | } |
380 | 379 | |
381 | 380 | |
382 | - | |
381 | + | |
383 | 382 | thread_data = 100; |
384 | - | |
383 | + | |
385 | 384 | free(xz_slice); |
386 | 385 | target.close(); |
387 | 386 | |
... | ... | @@ -425,7 +424,7 @@ public: |
425 | 424 | rp = (T*) malloc(S); |
426 | 425 | |
427 | 426 | band(lp, lb); |
428 | - band(rp, rb); | |
427 | + band(rp, rb); | |
429 | 428 | |
430 | 429 | baseline_band(lb, rb, lp, rp, bandwavelength, result); |
431 | 430 | |
... | ... | @@ -496,7 +495,7 @@ public: |
496 | 495 | } |
497 | 496 | baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part |
498 | 497 | baseline_band(lb, rb, lp, rp, w[ai], cur); |
499 | - for(unsigned j = 0; j < XY; j++){ | |
498 | + for(unsigned j = 0; j < XY; j++){ | |
500 | 499 | result[j] += (w[ai] - lab) * (cur[j] + cur2[j]) / 2.0; |
501 | 500 | } |
502 | 501 | |
... | ... | @@ -507,7 +506,7 @@ public: |
507 | 506 | baseline_band(lb, rb, lp, rp, w[ai], cur2); |
508 | 507 | for(unsigned j = 0; j < XY; j++) |
509 | 508 | { |
510 | - result[j] += (w[ai] - w[ai-1]) * (cur[j] + cur2[j]) / 2.0; | |
509 | + result[j] += (w[ai] - w[ai-1]) * (cur[j] + cur2[j]) / 2.0; | |
511 | 510 | } |
512 | 511 | std::swap(cur,cur2); //swap the band pointers |
513 | 512 | } |
... | ... | @@ -530,9 +529,9 @@ public: |
530 | 529 | /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size |
531 | 530 | bool ph_to_ph(double lb1, double rb1, double pos1, double lb2, double rb2, double pos2, T * result){ |
532 | 531 | |
533 | - T* p1 = (T*)malloc(X() * Y() * sizeof(T)); | |
534 | - T* p2 = (T*)malloc(X() * Y() * sizeof(T)); | |
535 | - | |
532 | + T* p1 = (T*)malloc(X() * Y() * sizeof(T)); | |
533 | + T* p2 = (T*)malloc(X() * Y() * sizeof(T)); | |
534 | + | |
536 | 535 | //get the two peak band |
537 | 536 | height(lb1, rb1, pos1, p1); |
538 | 537 | height(lb2, rb2, pos2, p2); |
... | ... | @@ -546,9 +545,9 @@ public: |
546 | 545 | |
547 | 546 | free(p1); |
548 | 547 | free(p2); |
549 | - return true; | |
548 | + return true; | |
550 | 549 | } |
551 | - | |
550 | + | |
552 | 551 | /// Compute the ratio between a peak area and peak height. |
553 | 552 | |
554 | 553 | /// @param lb1 is the label value for the left baseline point for the first peak (numerator) |
... | ... | @@ -560,10 +559,10 @@ public: |
560 | 559 | /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size |
561 | 560 | bool pa_to_ph(double lb1, double rb1, double lab1, double rab1, |
562 | 561 | double lb2, double rb2, double pos, T* result){ |
563 | - | |
564 | - T* p1 = (T*)malloc(X() * Y() * sizeof(T)); | |
565 | - T* p2 = (T*)malloc(X() * Y() * sizeof(T)); | |
566 | - | |
562 | + | |
563 | + T* p1 = (T*)malloc(X() * Y() * sizeof(T)); | |
564 | + T* p2 = (T*)malloc(X() * Y() * sizeof(T)); | |
565 | + | |
567 | 566 | //get the area and the peak band |
568 | 567 | area(lb1, rb1, lab1, rab1, p1); |
569 | 568 | height(lb2, rb2, pos, p2); |
... | ... | @@ -577,9 +576,9 @@ public: |
577 | 576 | |
578 | 577 | free(p1); |
579 | 578 | free(p2); |
580 | - return true; | |
581 | - } | |
582 | - | |
579 | + return true; | |
580 | + } | |
581 | + | |
583 | 582 | /// Compute the ratio between two peak areas. |
584 | 583 | |
585 | 584 | /// @param lb1 is the label value for the left baseline point for the first peak (numerator) |
... | ... | @@ -589,14 +588,14 @@ public: |
589 | 588 | /// @param lb2 is the label value for the left baseline point for the second peak (denominator) |
590 | 589 | /// @param rb2 is the label value for the right baseline point for the second peak (denominator) |
591 | 590 | /// @param lab2 is the label value for the left bound (start of the integration) of the second peak (denominator) |
592 | - /// @param rab2 is the label value for the right bound (end of the integration) of the second peak (denominator) | |
591 | + /// @param rab2 is the label value for the right bound (end of the integration) of the second peak (denominator) | |
593 | 592 | /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size |
594 | 593 | bool pa_to_pa(double lb1, double rb1, double lab1, double rab1, |
595 | 594 | double lb2, double rb2, double lab2, double rab2, T* result){ |
596 | - | |
597 | - T* p1 = (T*)malloc(X() * Y() * sizeof(T)); | |
598 | - T* p2 = (T*)malloc(X() * Y() * sizeof(T)); | |
599 | - | |
595 | + | |
596 | + T* p1 = (T*)malloc(X() * Y() * sizeof(T)); | |
597 | + T* p2 = (T*)malloc(X() * Y() * sizeof(T)); | |
598 | + | |
600 | 599 | //get the area and the peak band |
601 | 600 | area(lb1, rb1, lab1, rab1, p1); |
602 | 601 | area(lb2, rb2, lab2, rab2, p2); |
... | ... | @@ -610,8 +609,8 @@ public: |
610 | 609 | |
611 | 610 | free(p1); |
612 | 611 | free(p2); |
613 | - return true; | |
614 | - } | |
612 | + return true; | |
613 | + } | |
615 | 614 | |
616 | 615 | /// Compute the definite integral of a baseline corrected peak. |
617 | 616 | |
... | ... | @@ -671,7 +670,7 @@ public: |
671 | 670 | } |
672 | 671 | baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part |
673 | 672 | baseline_band(lb, rb, lp, rp, w[ai], cur); |
674 | - for(unsigned j = 0; j < XY; j++){ | |
673 | + for(unsigned j = 0; j < XY; j++){ | |
675 | 674 | result[j] += (w[ai] - lab) * (w[ai] + lab) * (cur[j] + cur2[j]) / 4.0; |
676 | 675 | } |
677 | 676 | |
... | ... | @@ -682,7 +681,7 @@ public: |
682 | 681 | baseline_band(lb, rb, lp, rp, w[ai], cur2); |
683 | 682 | for(unsigned j = 0; j < XY; j++) |
684 | 683 | { |
685 | - result[j] += (w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * (cur[j] + cur2[j]) / 4.0; | |
684 | + result[j] += (w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * (cur[j] + cur2[j]) / 4.0; | |
686 | 685 | } |
687 | 686 | std::swap(cur,cur2); //swap the band pointers |
688 | 687 | } |
... | ... | @@ -702,9 +701,9 @@ public: |
702 | 701 | /// @param rab is the label for the end of the peak |
703 | 702 | /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size |
704 | 703 | bool cpoint(double lb, double rb, double lab, double rab, T* result){ |
705 | - T* p1 = (T*)malloc(X() * Y() * sizeof(T)); | |
706 | - T* p2 = (T*)malloc(X() * Y() * sizeof(T)); | |
707 | - | |
704 | + T* p1 = (T*)malloc(X() * Y() * sizeof(T)); | |
705 | + T* p2 = (T*)malloc(X() * Y() * sizeof(T)); | |
706 | + | |
708 | 707 | //get the area and the peak band |
709 | 708 | x_area(lb, rb, lab, rab, p1); |
710 | 709 | area(lb, rb, lab, rab, p2); |
... | ... | @@ -718,7 +717,7 @@ public: |
718 | 717 | |
719 | 718 | free(p1); |
720 | 719 | free(p2); |
721 | - return true; | |
720 | + return true; | |
722 | 721 | } |
723 | 722 | |
724 | 723 | /// Create a mask based on a given band and threshold value. |
... | ... | @@ -777,7 +776,80 @@ public: |
777 | 776 | return true; |
778 | 777 | } |
779 | 778 | |
779 | + /// Saves only those pixels in a band corresponding to the mask value != 0 | |
780 | + /// @param array is a pointer to the destination array used to store the data | |
781 | + /// @param i is the band index | |
782 | + /// @p is a pointer to the mask data | |
783 | + bool sift_band(T* values, unsigned long b, unsigned char* p){ | |
784 | + unsigned long long XY = X() * Y(); //Number of XY pixels | |
785 | + unsigned long long L = XY * sizeof(T); //size of XY plane (in bytes) | |
786 | + | |
787 | + unsigned long long vi = 0; //create an index into the values array | |
788 | + | |
789 | + unsigned long long start, end; //start and end indices of a block of masked pixels in the band | |
790 | + bool reading = false; | |
791 | + unsigned long long l, i; //length of the masked region | |
792 | + | |
793 | + for(unsigned long long xy = 0; xy < XY; xy++){ //for each pixel in the band | |
794 | + | |
795 | + if(reading){ //if we are currently iterating through a block of masked pixels | |
796 | + if(p[xy]) end++; //if the current pixel is part of that block, increment the end index | |
797 | + else{ //otherwise, terminate the block | |
798 | + reading = false; //stop reading | |
799 | + i = b * XY + start; | |
800 | + file.seekg( i * sizeof(T) + header); //skip all of the unmasked pixels up to this point | |
801 | + l = (end - start); | |
802 | + file.read((char *)&values[vi], l * sizeof(T)); //write the values between start and end to the values array | |
803 | + vi += l; //increment the pointer into the values array | |
804 | + } | |
805 | + } | |
806 | + else{ //if we are currently iterating through a block of empty pixels | |
807 | + if(p[xy]){ //if the next pixel is masked, start a new block for reading | |
808 | + reading = true; | |
809 | + start = xy; //set the start and end indices to the beginning of this new block | |
810 | + end = start + 1; | |
811 | + } | |
812 | + } | |
813 | + } | |
814 | + | |
815 | + return true; | |
816 | + } | |
817 | + | |
818 | + /// Saves only those spectra corresponding to mask value != 0 to pre-allocated memory | |
819 | + /// @param matrix is the destination for the sifted pixels | |
820 | + /// @param p is the mask file used for sifting | |
821 | + bool sift(T* matrix, unsigned char* p){ | |
822 | + | |
823 | + // open a band (XY plane) | |
824 | + unsigned long XY = X() * Y(); //Number of XY pixels | |
825 | + unsigned long L = XY * sizeof(T); //size of XY pixels | |
826 | + | |
827 | + //count the number of masked pixels | |
828 | + unsigned long P = 0; //allocate space for the number of pixels | |
829 | + for(unsigned long xy = 0; xy < XY; xy++){ //count the number of pixels | |
830 | + if(p[xy] != 0) P++; | |
831 | + } | |
832 | + | |
833 | + T* bandvals = (T*) malloc(sizeof(T) * P); //allocate a temporary array to store the pixels for a single band | |
834 | + memset(matrix, 0, sizeof(T) * P * Z()); | |
835 | + for (unsigned long z = 0; z < Z(); z++){ //for each band | |
836 | + | |
837 | + if(!sift_band(bandvals, z, p)){ | |
838 | + std::cout<<"ERROR sifting band index "<<z<<std::endl; | |
839 | + exit(1); | |
840 | + } | |
841 | + | |
842 | + for(unsigned long p = 0; p < P; p++) //for each pixel in the array representing a single band | |
843 | + matrix[p * Z() + z] = bandvals[p]; //copy it to the appropriate location in the matrix | |
844 | + } | |
845 | + | |
846 | + free(bandvals); //clean up temporary memory | |
847 | + return true; | |
848 | + } | |
849 | + | |
780 | 850 | /// Saves to disk only those spectra corresponding to mask values != 0 |
851 | + /// @param outfile is the name of the sifted ENVI file to be written to disk | |
852 | + /// @param unsigned char* p is the mask file used for sifting | |
781 | 853 | bool sift(std::string outfile, unsigned char* p){ |
782 | 854 | std::ofstream target(outfile.c_str(), std::ios::binary); |
783 | 855 | // open a band (XY plane) |
... | ... | @@ -912,7 +984,7 @@ public: |
912 | 984 | for (unsigned j = 0; j < XY; j++){ //loop through temp, averaging valid pixels |
913 | 985 | if (mask[j] != 0){ |
914 | 986 | p[i] += temp[j] / (T)count; |
915 | - } | |
987 | + } | |
916 | 988 | } |
917 | 989 | } |
918 | 990 | free(temp); |
... | ... | @@ -930,7 +1002,7 @@ public: |
930 | 1002 | unsigned int B = Z(); |
931 | 1003 | T* bandi = (T*)malloc(sizeof(T) * xy); |
932 | 1004 | T* bandj = (T*)malloc(sizeof(T) * xy); |
933 | - | |
1005 | + | |
934 | 1006 | //count vaild pixels in a band |
935 | 1007 | unsigned count = 0; |
936 | 1008 | for (unsigned j = 0; j < xy; j++){ |
... | ... | @@ -1004,11 +1076,11 @@ public: |
1004 | 1076 | for (unsigned y = 0; y < lines; y++) |
1005 | 1077 | { |
1006 | 1078 | file.read((char *)(temp + y * samples), sizeof(T) * samples); |
1007 | - file.seekg(jumpl, std::ios::cur); //go to the next band | |
1079 | + file.seekg(jumpl, std::ios::cur); //go to the next band | |
1008 | 1080 | |
1009 | 1081 | thread_data = (double)(z * lines + y) / (Z() * lines) * 100; |
1010 | 1082 | } |
1011 | - out.write(reinterpret_cast<const char*>(temp), L); //write slice data into target file | |
1083 | + out.write(reinterpret_cast<const char*>(temp), L); //write slice data into target file | |
1012 | 1084 | file.seekg(jumpb, std::ios::cur); |
1013 | 1085 | } |
1014 | 1086 | free(temp); |
... | ... | @@ -1030,4 +1102,4 @@ public: |
1030 | 1102 | |
1031 | 1103 | #endif |
1032 | 1104 | |
1033 | - | |
1105 | + | ... | ... |
stim/envi/envi.h
... | ... | @@ -465,7 +465,26 @@ public: |
465 | 465 | return false; |
466 | 466 | } |
467 | 467 | |
468 | + /// sift copies all spectra corresponding to nonzero values of a mask into a pre-allocated matrix | |
469 | + /// @param matrix is the destination for the pixel data | |
470 | + /// @param p is the mask | |
471 | + bool sift(void* matrix, unsigned char* p){ | |
472 | + | |
473 | + if (header.interleave == envi_header::BSQ){ //if the infile is bsq file | |
474 | + if (header.data_type == envi_header::float32) | |
475 | + return ((bsq<float>*)file)->sift((float*)matrix, p); | |
476 | + else if (header.data_type == envi_header::float64) | |
477 | + return ((bsq<double>*)file)->sift((double*)matrix, p); | |
478 | + else | |
479 | + std::cout << "ERROR: unidentified data type" << std::endl; | |
480 | + } | |
481 | + return false; | |
482 | + | |
483 | + } | |
484 | + | |
468 | 485 | /// sift-mask saves in an array only those spectra corresponding to nonzero values of the mask. |
486 | + /// @param outfile is the name of the sifted output file | |
487 | + /// @param p is the mask | |
469 | 488 | bool sift(std::string outfile, unsigned char* p) |
470 | 489 | { |
471 | 490 | ... | ... |
stim/image/CImg.h
Changes suppressed. Click to show
... | ... | @@ -54,7 +54,7 @@ |
54 | 54 | |
55 | 55 | // Set version number of the library. |
56 | 56 | #ifndef cimg_version |
57 | -#define cimg_version 165 | |
57 | +#define cimg_version 169 | |
58 | 58 | |
59 | 59 | /*----------------------------------------------------------- |
60 | 60 | # |
... | ... | @@ -75,6 +75,7 @@ |
75 | 75 | #include <cstdarg> |
76 | 76 | #include <cstring> |
77 | 77 | #include <cmath> |
78 | +#include <cfloat> | |
78 | 79 | #include <climits> |
79 | 80 | #include <ctime> |
80 | 81 | #include <exception> |
... | ... | @@ -122,16 +123,30 @@ |
122 | 123 | #pragma warning(disable:4820) |
123 | 124 | #pragma warning(disable:4996) |
124 | 125 | #define _CRT_SECURE_NO_DEPRECATE 1 |
126 | +#define _CRT_SECURE_NO_WARNINGS 1 | |
125 | 127 | #define _CRT_NONSTDC_NO_DEPRECATE 1 |
126 | -#define cimg_snprintf cimg::c99_snprintf | |
127 | -#define cimg_vsnprintf cimg::c99_vsnprintf | |
128 | 128 | #endif |
129 | 129 | |
130 | -#ifndef cimg_snprintf | |
130 | +// Define correct string functions for each compiler and OS. | |
131 | +#if cimg_OS==2 && defined(_MSC_VER) | |
132 | +#define cimg_sscanf std::sscanf | |
133 | +#define cimg_sprintf std::sprintf | |
134 | +#define cimg_snprintf cimg::_snprintf | |
135 | +#define cimg_vsnprintf cimg::_vsnprintf | |
136 | +#else | |
131 | 137 | #include <stdio.h> |
138 | +#if defined(__MACOSX__) || defined(__APPLE__) | |
139 | +#define cimg_sscanf cimg::_sscanf | |
140 | +#define cimg_sprintf cimg::_sprintf | |
141 | +#define cimg_snprintf cimg::_snprintf | |
142 | +#define cimg_vsnprintf cimg::_vsnprintf | |
143 | +#else | |
144 | +#define cimg_sscanf std::sscanf | |
145 | +#define cimg_sprintf std::sprintf | |
132 | 146 | #define cimg_snprintf snprintf |
133 | 147 | #define cimg_vsnprintf vsnprintf |
134 | 148 | #endif |
149 | +#endif | |
135 | 150 | |
136 | 151 | // Include OS-specific headers. |
137 | 152 | #if cimg_OS==1 |
... | ... | @@ -145,6 +160,9 @@ |
145 | 160 | #ifndef NOMINMAX |
146 | 161 | #define NOMINMAX |
147 | 162 | #endif |
163 | +#ifndef WIN32_LEAN_AND_MEAN | |
164 | +#define WIN32_LEAN_AND_MEAN | |
165 | +#endif | |
148 | 166 | #include <windows.h> |
149 | 167 | #ifndef _WIN32_IE |
150 | 168 | #define _WIN32_IE 0x0400 |
... | ... | @@ -154,15 +172,28 @@ |
154 | 172 | #include <io.h> |
155 | 173 | #endif |
156 | 174 | |
157 | -// Look for C++11 features | |
175 | +// Look for C++11 features. | |
158 | 176 | #if !defined(cimg_use_cpp11) && __cplusplus>201100 |
159 | -#define cimg_use_cpp11 | |
177 | +#define cimg_use_cpp11 1 | |
160 | 178 | #endif |
161 | -#ifdef cimg_use_cpp11 | |
179 | +#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0 | |
162 | 180 | #include <initializer_list> |
163 | 181 | #include <utility> |
164 | 182 | #endif |
165 | 183 | |
184 | +// Configure the 'abort' signal handler (does nothing by default). | |
185 | +// A typical signal handler can be defined in your own source like this: | |
186 | +// Without OpenMP support: #define cimg_test_abort() if (is_abort) throw CImgAbortException("") | |
187 | +// | |
188 | +// or | |
189 | +// | |
190 | +// With OpenMP support: #define cimg_test_abort() if (!omp_get_thread_num() && is_abort) throw CImgAbortException("") | |
191 | +// | |
192 | +// where 'is_abort' is a boolean variable. | |
193 | +#ifndef cimg_test_abort | |
194 | +#define cimg_test_abort() | |
195 | +#endif | |
196 | + | |
166 | 197 | // Configure filename separator. |
167 | 198 | // |
168 | 199 | // Filename separator is set by default to '/', except for Windows where it is '\'. |
... | ... | @@ -186,7 +217,11 @@ |
186 | 217 | // |
187 | 218 | // Define 'cimg_use_vt100' to allow output of color messages on VT100-compatible terminals. |
188 | 219 | #ifndef cimg_verbosity |
220 | +#if cimg_OS==2 | |
189 | 221 | #define cimg_verbosity 2 |
222 | +#else | |
223 | +#define cimg_verbosity 1 | |
224 | +#endif | |
190 | 225 | #elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4) |
191 | 226 | #error CImg Library: Configuration variable 'cimg_verbosity' is badly defined. |
192 | 227 | #error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }). |
... | ... | @@ -201,11 +236,7 @@ |
201 | 236 | #if cimg_OS==0 |
202 | 237 | #define cimg_display 0 |
203 | 238 | #elif cimg_OS==1 |
204 | -#if defined(__MACOSX__) || defined(__APPLE__) | |
205 | -#define cimg_display 1 | |
206 | -#else | |
207 | 239 | #define cimg_display 1 |
208 | -#endif | |
209 | 240 | #elif cimg_OS==2 |
210 | 241 | #define cimg_display 2 |
211 | 242 | #endif |
... | ... | @@ -471,26 +502,6 @@ extern "C" { |
471 | 502 | #define cimg_usage(usage) cimg_library_suffixed::cimg::option((char*)0,argc,argv,(char*)0,usage,false) |
472 | 503 | #define cimg_help(str) cimg_library_suffixed::cimg::option((char*)0,argc,argv,str,(char*)0) |
473 | 504 | #define cimg_option(name,defaut,usage) cimg_library_suffixed::cimg::option(name,argc,argv,defaut,usage) |
474 | -#define cimg_argument(pos) \ | |
475 | - cimg_library_suffixed::cimg::argument(pos,argc,argv) | |
476 | -#define cimg_argument1(pos,s0) \ | |
477 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,1,s0) | |
478 | -#define cimg_argument2(pos,s0,s1) \ | |
479 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,2,s0,s1) | |
480 | -#define cimg_argument3(pos,s0,s1,s2) \ | |
481 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,3,s0,s1,s2) | |
482 | -#define cimg_argument4(pos,s0,s1,s2,s3) \ | |
483 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3) | |
484 | -#define cimg_argument5(pos,s0,s1,s2,s3,s4) \ | |
485 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4) | |
486 | -#define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) \ | |
487 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5) | |
488 | -#define cimg_argument7(pos,s0,s1,s2,s3,s4,s5,s6) \ | |
489 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,7,s0,s1,s2,s3,s4,s5,s6) | |
490 | -#define cimg_argument8(pos,s0,s1,s2,s3,s4,s5,s6,s7) \ | |
491 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,8,s0,s1,s2,s3,s4,s5,s6,s7) | |
492 | -#define cimg_argument9(pos,s0,s1,s2,s3,s4,s5,s6,s7,s8) \ | |
493 | - cimg_library_suffixed::cimg::argument(pos,argc,argv,9,s0,s1,s2,s3,s4,s5,s6,s7,s8) | |
494 | 505 | |
495 | 506 | // Macros to define and manipulate local neighborhoods. |
496 | 507 | #define CImg_2x2(I,T) T I[4]; \ |
... | ... | @@ -2069,26 +2080,26 @@ namespace cimg_library_suffixed { |
2069 | 2080 | |
2070 | 2081 | // Declare cimg:: namespace. |
2071 | 2082 | // This is an uncomplete namespace definition here. It only contains some |
2072 | - // necessary stuffs to ensure a correct declaration order of the classes and functions | |
2083 | + // necessary stuff to ensure a correct declaration order of the classes and functions | |
2073 | 2084 | // defined afterwards. |
2074 | 2085 | namespace cimg { |
2075 | 2086 | |
2076 | 2087 | // Define ascii sequences for colored terminal output. |
2077 | 2088 | #ifdef cimg_use_vt100 |
2078 | - const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 }; | |
2079 | - const char t_black[] = { 0x1b, '[', '0', ';', '3', '0', ';', '5', '9', 'm', 0 }; | |
2080 | - const char t_red[] = { 0x1b, '[', '0', ';', '3', '1', ';', '5', '9', 'm', 0 }; | |
2081 | - const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 }; | |
2082 | - const char t_yellow[] = { 0x1b, '[', '0', ';', '3', '3', ';', '5', '9', 'm', 0 }; | |
2083 | - const char t_blue[] = { 0x1b, '[', '0', ';', '3', '4', ';', '5', '9', 'm', 0 }; | |
2084 | - const char t_magenta[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 }; | |
2085 | - const char t_cyan[] = { 0x1b, '[', '0', ';', '3', '6', ';', '5', '9', 'm', 0 }; | |
2086 | - const char t_white[] = { 0x1b, '[', '0', ';', '3', '7', ';', '5', '9', 'm', 0 }; | |
2087 | - const char t_bold[] = { 0x1b, '[', '1', 'm', 0 }; | |
2088 | - const char t_underscore[] = { 0x1b, '[', '4', 'm', 0 }; | |
2089 | + static const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 }; | |
2090 | + static const char t_black[] = { 0x1b, '[', '0', ';', '3', '0', ';', '5', '9', 'm', 0 }; | |
2091 | + static const char t_red[] = { 0x1b, '[', '0', ';', '3', '1', ';', '5', '9', 'm', 0 }; | |
2092 | + static const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 }; | |
2093 | + static const char t_yellow[] = { 0x1b, '[', '0', ';', '3', '3', ';', '5', '9', 'm', 0 }; | |
2094 | + static const char t_blue[] = { 0x1b, '[', '0', ';', '3', '4', ';', '5', '9', 'm', 0 }; | |
2095 | + static const char t_magenta[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 }; | |
2096 | + static const char t_cyan[] = { 0x1b, '[', '0', ';', '3', '6', ';', '5', '9', 'm', 0 }; | |
2097 | + static const char t_white[] = { 0x1b, '[', '0', ';', '3', '7', ';', '5', '9', 'm', 0 }; | |
2098 | + static const char t_bold[] = { 0x1b, '[', '1', 'm', 0 }; | |
2099 | + static const char t_underscore[] = { 0x1b, '[', '4', 'm', 0 }; | |
2089 | 2100 | #else |
2090 | - const char t_normal[] = { 0 }; | |
2091 | - const char *const t_black = cimg::t_normal, | |
2101 | + static const char t_normal[] = { 0 }; | |
2102 | + static const char *const t_black = cimg::t_normal, | |
2092 | 2103 | *const t_red = cimg::t_normal, |
2093 | 2104 | *const t_green = cimg::t_normal, |
2094 | 2105 | *const t_yellow = cimg::t_normal, |
... | ... | @@ -2114,30 +2125,68 @@ namespace cimg_library_suffixed { |
2114 | 2125 | |
2115 | 2126 | inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) { |
2116 | 2127 | static unsigned int mode = cimg_verbosity; |
2117 | - cimg::mutex(0); | |
2118 | - if (is_set) mode = value; | |
2119 | - cimg::mutex(0,0); | |
2128 | + if (is_set) { cimg::mutex(0); mode = value<4?value:4; cimg::mutex(0,0); } | |
2120 | 2129 | return mode; |
2121 | 2130 | } |
2122 | 2131 | |
2123 | 2132 | // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\0' character |
2124 | 2133 | // at the end of the string. |
2125 | 2134 | #if cimg_OS==2 && defined(_MSC_VER) |
2126 | - inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) { | |
2127 | - int count = -1; | |
2135 | + inline int _snprintf(char *const s, const size_t size, const char *const format, ...) { | |
2136 | + va_list ap; | |
2137 | + va_start(ap,format); | |
2138 | + const int result = _vsnprintf(s,size,format,ap); | |
2139 | + va_end(ap); | |
2140 | + return result; | |
2141 | + } | |
2142 | + | |
2143 | + inline int _vsnprintf(char *const s, const size_t size, const char *const format, va_list ap) { | |
2144 | + int result = -1; | |
2128 | 2145 | cimg::mutex(6); |
2129 | - if (size) count = _vsnprintf_s(str,size,_TRUNCATE,format,ap); | |
2130 | - if (count==-1) count = _vscprintf(format,ap); | |
2146 | + if (size) result = _vsnprintf_s(s,size,_TRUNCATE,format,ap); | |
2147 | + if (result==-1) result = _vscprintf(format,ap); | |
2131 | 2148 | cimg::mutex(6,0); |
2132 | - return count; | |
2149 | + return result; | |
2133 | 2150 | } |
2134 | - inline int c99_snprintf(char* str, size_t size, const char* format, ...) { | |
2135 | - int count; | |
2136 | - va_list ap; | |
2137 | - va_start(ap, format); | |
2138 | - count = c99_vsnprintf(str,size,format,ap); | |
2139 | - va_end(ap); | |
2140 | - return count; | |
2151 | + | |
2152 | + // Mutex-protected version of sscanf, sprintf and snprintf. | |
2153 | + // Used only MacOSX, as it seems those functions are not re-entrant on MacOSX. | |
2154 | +#elif defined(__MACOSX__) || defined(__APPLE__) | |
2155 | + inline int _sscanf(const char *const s, const char *const format, ...) { | |
2156 | + cimg::mutex(6); | |
2157 | + va_list args; | |
2158 | + va_start(args,format); | |
2159 | + const int result = std::vsscanf(s,format,args); | |
2160 | + va_end(args); | |
2161 | + cimg::mutex(6,0); | |
2162 | + return result; | |
2163 | + } | |
2164 | + | |
2165 | + inline int _sprintf(char *const s, const char *const format, ...) { | |
2166 | + cimg::mutex(6); | |
2167 | + va_list args; | |
2168 | + va_start(args,format); | |
2169 | + const int result = std::vsprintf(s,format,args); | |
2170 | + va_end(args); | |
2171 | + cimg::mutex(6,0); | |
2172 | + return result; | |
2173 | + } | |
2174 | + | |
2175 | + inline int _snprintf(char *const s, const size_t n, const char *const format, ...) { | |
2176 | + cimg::mutex(6); | |
2177 | + va_list args; | |
2178 | + va_start(args,format); | |
2179 | + const int result = std::vsnprintf(s,n,format,args); | |
2180 | + va_end(args); | |
2181 | + cimg::mutex(6,0); | |
2182 | + return result; | |
2183 | + } | |
2184 | + | |
2185 | + inline int _vsnprintf(char *const s, const size_t size, const char* format, va_list ap) { | |
2186 | + cimg::mutex(6); | |
2187 | + const int result = std::vsnprintf(s,size,format,ap); | |
2188 | + cimg::mutex(6,0); | |
2189 | + return result; | |
2141 | 2190 | } |
2142 | 2191 | #endif |
2143 | 2192 | |
... | ... | @@ -2163,6 +2212,31 @@ namespace cimg_library_suffixed { |
2163 | 2212 | return _exception_mode(0,false); |
2164 | 2213 | } |
2165 | 2214 | |
2215 | + //! Set current \CImg openmp mode. | |
2216 | + /** | |
2217 | + The way openmp-based methods are handled by \CImg can be changed dynamically, using this function. | |
2218 | + \param mode Desired openmp mode. Possible values are: | |
2219 | + - \c 0: Never parallelize (quiet mode). | |
2220 | + - \c 1: Always parallelize. | |
2221 | + - \c 2: Adaptive parallelization mode (default behavior). | |
2222 | + **/ | |
2223 | + inline unsigned int& _openmp_mode(const unsigned int value, const bool is_set) { | |
2224 | + static unsigned int mode = 2; | |
2225 | + if (is_set) { cimg::mutex(0); mode = value<2?value:2; cimg::mutex(0,0); } | |
2226 | + return mode; | |
2227 | + } | |
2228 | + | |
2229 | + inline unsigned int& openmp_mode(const unsigned int mode) { | |
2230 | + return _openmp_mode(mode,true); | |
2231 | + } | |
2232 | + | |
2233 | + //! Return current \CImg openmp mode. | |
2234 | + inline unsigned int& openmp_mode() { | |
2235 | + return _openmp_mode(0,false); | |
2236 | + } | |
2237 | + | |
2238 | +#define cimg_openmp_if(cond) if (cimg::openmp_mode()==1 || (cimg::openmp_mode()>1 && (cond))) | |
2239 | + | |
2166 | 2240 | // Display a simple dialog box, and wait for the user's response. |
2167 | 2241 | inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK", |
2168 | 2242 | const char *const button2_label=0, const char *const button3_label=0, |
... | ... | @@ -2172,6 +2246,7 @@ namespace cimg_library_suffixed { |
2172 | 2246 | // Evaluate math expression. |
2173 | 2247 | inline double eval(const char *const expression, |
2174 | 2248 | const double x=0, const double y=0, const double z=0, const double c=0); |
2249 | + | |
2175 | 2250 | } |
2176 | 2251 | |
2177 | 2252 | /*--------------------------------------- |
... | ... | @@ -2183,9 +2258,12 @@ namespace cimg_library_suffixed { |
2183 | 2258 | /** |
2184 | 2259 | \par Overview |
2185 | 2260 | |
2186 | - CImgException is the base class of all exceptions thrown by \CImg. | |
2261 | + CImgException is the base class of all exceptions thrown by \CImg (except \b CImgAbortException). | |
2187 | 2262 | CImgException is never thrown itself. Derived classes that specify the type of errord are thrown instead. |
2188 | - These derived classes can be: | |
2263 | + These classes can be: | |
2264 | + | |
2265 | + - \b CImgAbortException: Thrown when a computationally-intensive function is aborted by an external signal. | |
2266 | + This is the only \c non-derived exception class. | |
2189 | 2267 | |
2190 | 2268 | - \b CImgArgumentException: Thrown when one argument of a called \CImg function is invalid. |
2191 | 2269 | This is probably one of the most thrown exception by \CImg. |
... | ... | @@ -2243,28 +2321,65 @@ namespace cimg_library_suffixed { |
2243 | 2321 | **/ |
2244 | 2322 | struct CImgException : public std::exception { |
2245 | 2323 | #define _cimg_exception_err(etype,disp_flag) \ |
2246 | - std::va_list ap; va_start(ap,format); cimg_vsnprintf(_message,16384,format,ap); va_end(ap); \ | |
2247 | - if (cimg::exception_mode()) { \ | |
2248 | - std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \ | |
2249 | - if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } \ | |
2250 | - catch (CImgException&) {} \ | |
2251 | - if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \ | |
2252 | - } | |
2324 | + std::va_list ap, ap2; \ | |
2325 | + va_start(ap,format); va_start(ap2,format); \ | |
2326 | + int size = cimg_vsnprintf(0,0,format,ap2); \ | |
2327 | + if (size++>=0) { \ | |
2328 | + delete[] _message; \ | |
2329 | + _message = new char[size]; \ | |
2330 | + cimg_vsnprintf(_message,size,format,ap); \ | |
2331 | + if (cimg::exception_mode()) { \ | |
2332 | + std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \ | |
2333 | + if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } \ | |
2334 | + catch (CImgException&) {} \ | |
2335 | + if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \ | |
2336 | + } \ | |
2337 | + } \ | |
2338 | + va_end(ap); va_end(ap2); \ | |
2253 | 2339 | |
2254 | 2340 | char *_message; |
2255 | - CImgException() { _message = new char[16384]; *_message = 0; } | |
2256 | - CImgException(const char *const format, ...) { | |
2257 | - _message = new char[16384]; *_message = 0; _cimg_exception_err("CImgException",true); | |
2341 | + CImgException() { _message = new char[1]; *_message = 0; } | |
2342 | + CImgException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgException",true); } | |
2343 | + CImgException(const CImgException& e) { | |
2344 | + const int size = std::strlen(e._message); | |
2345 | + _message = new char[size + 1]; | |
2346 | + std::strncpy(_message,e._message,size); | |
2347 | + _message[size] = 0; | |
2258 | 2348 | } |
2259 | 2349 | ~CImgException() throw() { delete[] _message; } |
2350 | + CImgException& operator=(const CImgException& e) { | |
2351 | + const int size = std::strlen(e._message); | |
2352 | + _message = new char[size + 1]; | |
2353 | + std::strncpy(_message,e._message,size); | |
2354 | + _message[size] = 0; | |
2355 | + return *this; | |
2356 | + } | |
2260 | 2357 | //! Return a C-string containing the error message associated to the thrown exception. |
2261 | 2358 | const char *what() const throw() { return _message; } |
2262 | 2359 | }; |
2263 | 2360 | |
2264 | - // The CImgInstanceException class is used to throw an exception related | |
2265 | - // to an invalid instance encountered in a library function call. | |
2266 | - struct CImgInstanceException : public CImgException { | |
2267 | - CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); } | |
2361 | + // The CImgAbortException class is used to throw an exception when | |
2362 | + // a computationally-intensive function has been aborted by an external signal. | |
2363 | + struct CImgAbortException : public std::exception { | |
2364 | + char *_message; | |
2365 | + CImgAbortException() { _message = new char[1]; *_message = 0; } | |
2366 | + CImgAbortException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgAbortException",true); } | |
2367 | + CImgAbortException(const CImgAbortException& e) { | |
2368 | + const int size = std::strlen(e._message); | |
2369 | + _message = new char[size + 1]; | |
2370 | + std::strncpy(_message,e._message,size); | |
2371 | + _message[size] = 0; | |
2372 | + } | |
2373 | + ~CImgAbortException() throw() { delete[] _message; } | |
2374 | + CImgAbortException& operator=(const CImgAbortException& e) { | |
2375 | + const int size = std::strlen(e._message); | |
2376 | + _message = new char[size + 1]; | |
2377 | + std::strncpy(_message,e._message,size); | |
2378 | + _message[size] = 0; | |
2379 | + return *this; | |
2380 | + } | |
2381 | + //! Return a C-string containing the error message associated to the thrown exception. | |
2382 | + const char *what() const throw() { return _message; } | |
2268 | 2383 | }; |
2269 | 2384 | |
2270 | 2385 | // The CImgArgumentException class is used to throw an exception related |
... | ... | @@ -2273,18 +2388,24 @@ namespace cimg_library_suffixed { |
2273 | 2388 | CImgArgumentException(const char *const format, ...) { _cimg_exception_err("CImgArgumentException",true); } |
2274 | 2389 | }; |
2275 | 2390 | |
2276 | - // The CImgIOException class is used to throw an exception related | |
2277 | - // to input/output file problems encountered in a library function call. | |
2278 | - struct CImgIOException : public CImgException { | |
2279 | - CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); } | |
2280 | - }; | |
2281 | - | |
2282 | 2391 | // The CImgDisplayException class is used to throw an exception related |
2283 | 2392 | // to display problems encountered in a library function call. |
2284 | 2393 | struct CImgDisplayException : public CImgException { |
2285 | 2394 | CImgDisplayException(const char *const format, ...) { _cimg_exception_err("CImgDisplayException",false); } |
2286 | 2395 | }; |
2287 | 2396 | |
2397 | + // The CImgInstanceException class is used to throw an exception related | |
2398 | + // to an invalid instance encountered in a library function call. | |
2399 | + struct CImgInstanceException : public CImgException { | |
2400 | + CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); } | |
2401 | + }; | |
2402 | + | |
2403 | + // The CImgIOException class is used to throw an exception related | |
2404 | + // to input/output file problems encountered in a library function call. | |
2405 | + struct CImgIOException : public CImgException { | |
2406 | + CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); } | |
2407 | + }; | |
2408 | + | |
2288 | 2409 | // The CImgWarningException class is used to throw an exception for warnings |
2289 | 2410 | // encountered in a library function call. |
2290 | 2411 | struct CImgWarningException : public CImgException { |
... | ... | @@ -2497,10 +2618,22 @@ namespace cimg_library_suffixed { |
2497 | 2618 | return !(val==val); |
2498 | 2619 | #endif |
2499 | 2620 | } |
2500 | - static double min() { return -1.7E308; } | |
2501 | - static double max() { return 1.7E308; } | |
2502 | - static double inf() { return max()*max(); } | |
2503 | - static double nan() { const double val_nan = -std::sqrt(-1.0); return val_nan; } | |
2621 | + static double min() { return -DBL_MAX; } | |
2622 | + static double max() { return DBL_MAX; } | |
2623 | + static double inf() { | |
2624 | +#ifdef INFINITY | |
2625 | + return (double)INFINITY; | |
2626 | +#else | |
2627 | + return max()*max(); | |
2628 | +#endif | |
2629 | + } | |
2630 | + static double nan() { | |
2631 | +#ifdef NAN | |
2632 | + return (double)NAN; | |
2633 | +#else | |
2634 | + const double val_nan = -std::sqrt(-1.0); return val_nan; | |
2635 | +#endif | |
2636 | + } | |
2504 | 2637 | static double cut(const double val) { return val<min()?min():val>max()?max():val; } |
2505 | 2638 | static const char* format() { return "%.16g"; } |
2506 | 2639 | static double format(const double val) { return val; } |
... | ... | @@ -2523,8 +2656,8 @@ namespace cimg_library_suffixed { |
2523 | 2656 | return !(val==val); |
2524 | 2657 | #endif |
2525 | 2658 | } |
2526 | - static float min() { return -3.4E38f; } | |
2527 | - static float max() { return 3.4E38f; } | |
2659 | + static float min() { return -FLT_MAX; } | |
2660 | + static float max() { return FLT_MAX; } | |
2528 | 2661 | static float inf() { return (float)cimg::type<double>::inf(); } |
2529 | 2662 | static float nan() { return (float)cimg::type<double>::nan(); } |
2530 | 2663 | static float cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(float)val; } |
... | ... | @@ -2532,6 +2665,32 @@ namespace cimg_library_suffixed { |
2532 | 2665 | static double format(const float val) { return (double)val; } |
2533 | 2666 | }; |
2534 | 2667 | |
2668 | + template<> struct type<long double> { | |
2669 | + static const char* string() { static const char *const s = "long double"; return s; } | |
2670 | + static bool is_float() { return true; } | |
2671 | + static bool is_inf(const long double val) { | |
2672 | +#ifdef isinf | |
2673 | + return (bool)isinf(val); | |
2674 | +#else | |
2675 | + return !is_nan(val) && (val<cimg::type<long double>::min() || val>cimg::type<long double>::max()); | |
2676 | +#endif | |
2677 | + } | |
2678 | + static bool is_nan(const long double val) { | |
2679 | +#ifdef isnan | |
2680 | + return (bool)isnan(val); | |
2681 | +#else | |
2682 | + return !(val==val); | |
2683 | +#endif | |
2684 | + } | |
2685 | + static long double min() { return -LDBL_MAX; } | |
2686 | + static long double max() { return LDBL_MAX; } | |
2687 | + static long double inf() { return max()*max(); } | |
2688 | + static long double nan() { const long double val_nan = -std::sqrt(-1.0L); return val_nan; } | |
2689 | + static long double cut(const long double val) { return val<min()?min():val>max()?max():val; } | |
2690 | + static const char* format() { return "%.16g"; } | |
2691 | + static double format(const long double val) { return (double)val; } | |
2692 | + }; | |
2693 | + | |
2535 | 2694 | template<typename T, typename t> struct superset { typedef T type; }; |
2536 | 2695 | template<> struct superset<bool,unsigned char> { typedef unsigned char type; }; |
2537 | 2696 | template<> struct superset<bool,char> { typedef char type; }; |
... | ... | @@ -3015,7 +3174,7 @@ namespace cimg_library_suffixed { |
3015 | 3174 | const double PI = 3.14159265358979323846; //!< Value of the mathematical constant PI |
3016 | 3175 | |
3017 | 3176 | // Define a 12x13 font (small size). |
3018 | - const char *const data_font12x13 = | |
3177 | + static const char *const data_font12x13 = | |
3019 | 3178 | " .wjwlwmyuw>wjwkwbwjwkwRxuwmwjwkwmyuwJwjwlx`w Fw mwlwlwuwnwuynwuwmyTwlwkwuwmwuwnwlwkwuwmwuw_wuxl" |
3020 | 3179 | "wlwkwuwnwuynwuwTwlwlwtwnwtwnw my Qw +wlw b{ \\w Wx`xTw_w[wbxawSwkw nynwky<x1w `y ,w Xwuw CxlwiwlwmyuwbwuwUwiwlwbwiwrwqw^wuwmxuwnwiwlwmy" |
3021 | 3180 | "uwJwiwlw^wnwEymymymymy1w^wkxnxtxnw<| gybwkwuwjwtwowmxswnxnwkxlxkw:wlymxlymykwn{myo{nymy2ykwqwqwm{myozn{o{mzpwrwpwkwkwswowkwqwqxswnyozlyozmzp}pwrwqwqwq" |
... | ... | @@ -3055,7 +3214,7 @@ namespace cimg_library_suffixed { |
3055 | 3214 | "wlxm"; |
3056 | 3215 | |
3057 | 3216 | // Define a 20x23 font (normal size). |
3058 | - const char *const data_font20x23 = | |
3217 | + static const char *const data_font20x23 = | |
3059 | 3218 | " 9q\\q^r_rnp`qnq`plp7q\\q^q_qmqbq\\q^q_qmqHqmp_q\\q^r_rnp`qnq7q\\q^q_qmq_q \"r " |
3060 | 3219 | " Mq^q^qnq`pnr`qnq`plp6q^q^pmp`qmqaq^q^pmp`qmqIpmq]q^q^qnq`pnr`qnq6q^q^pmp`qmq`q \"plp 'q 5qmq Vq " |
3061 | 3220 | " Xq [plp 3qYq_p^rnpLplp8qYq_qNqYq_q4rmpaqYq_q_rmp%qYq^pGq Irc|!pKp]raqjq`p HtNq_qmq\\plqbp_shpdscq[q^q[p [q]s_r`uau]rbv`tcxbua" |
... | ... | @@ -3123,7 +3282,7 @@ namespace cimg_library_suffixed { |
3123 | 3282 | "r^q *q kr i"; |
3124 | 3283 | |
3125 | 3284 | // Define a 47x53 font (extra-large size). |
3126 | - const char *const data_font47x53 = | |
3285 | + static const char *const data_font47x53 = | |
3127 | 3286 | " " |
3128 | 3287 | " 9])]2_2]T\\8^U^3] E])]2`4^U^>])]2_4^U^ 6^T\\5])]1_2]T\\8^U^ K])]2`4^V^3] " |
3129 | 3288 | " U]*\\2a4`V\\8^U^5a F]*\\1\\X\\4^U^=]*\\" |
... | ... | @@ -3316,7 +3475,7 @@ namespace cimg_library_suffixed { |
3316 | 3475 | " F]']2] +]']2^ D]']3_ E]']1] \"]']2^ 8] H"; |
3317 | 3476 | |
3318 | 3477 | // Define a 90x103 font (huge size). |
3319 | - const char *const _data_font90x103[] = { // Defined as an array to avoid MS compiler limit about constant string (65Kb). | |
3478 | + static const char *const _data_font90x103[] = { // Defined as an array to avoid MS compiler limit about constant string (65Kb). | |
3320 | 3479 | // Start of first string. |
3321 | 3480 | " " |
3322 | 3481 | " " |
... | ... | @@ -3856,7 +4015,7 @@ namespace cimg_library_suffixed { |
3856 | 4015 | " D" }; |
3857 | 4016 | |
3858 | 4017 | // Define a 40x38 'danger' color logo (used by cimg::dialog()). |
3859 | - const unsigned char logo40x38[4576] = { | |
4018 | + static const unsigned char logo40x38[4576] = { | |
3860 | 4019 | 177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200, |
3861 | 4020 | 1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0, |
3862 | 4021 | 0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200, |
... | ... | @@ -3882,23 +4041,6 @@ namespace cimg_library_suffixed { |
3882 | 4041 | 0,4,123,123,123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25, |
3883 | 4042 | 123,123,123,86,200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0 }; |
3884 | 4043 | |
3885 | - // Mutex-protected version of sscanf. | |
3886 | - // Used only MacOSX, as it seems std::sscanf() is not re-entrant on MacOSX. | |
3887 | -#if (__MACOSX__) || defined(__APPLE__) | |
3888 | -#define cimg_sscanf cimg::_sscanf | |
3889 | - inline int _sscanf(const char *s, const char *format, ...) { | |
3890 | - cimg::mutex(13); | |
3891 | - va_list args; | |
3892 | - va_start(args, format); | |
3893 | - const int result = std::vsscanf(s,format,args); | |
3894 | - va_end(args); | |
3895 | - cimg::mutex(13,0); | |
3896 | - return result; | |
3897 | - } | |
3898 | -#else | |
3899 | -#define cimg_sscanf std::sscanf | |
3900 | -#endif | |
3901 | - | |
3902 | 4044 | //! Get/set default output stream for the \CImg library messages. |
3903 | 4045 | /** |
3904 | 4046 | \param file Desired output stream. Set to \c 0 to get the currently used output stream only. |
... | ... | @@ -3980,7 +4122,7 @@ namespace cimg_library_suffixed { |
3980 | 4122 | return -1; |
3981 | 4123 | #else |
3982 | 4124 | #if cimg_OS==1 |
3983 | - const unsigned int l = std::strlen(command); | |
4125 | + const unsigned int l = (unsigned int)std::strlen(command); | |
3984 | 4126 | if (l) { |
3985 | 4127 | char *const ncommand = new char[l + 16]; |
3986 | 4128 | std::strncpy(ncommand,command,l); |
... | ... | @@ -4243,8 +4385,9 @@ namespace cimg_library_suffixed { |
4243 | 4385 | _rand(seed,true); |
4244 | 4386 | } |
4245 | 4387 | |
4246 | - inline double rand() { | |
4247 | - return cimg::_rand()/16777215.; | |
4388 | + inline double rand(const double val_min, const double val_max) { | |
4389 | + const double val = cimg::_rand()/16777215.; | |
4390 | + return val_min + (val_max - val_min)*val; | |
4248 | 4391 | } |
4249 | 4392 | |
4250 | 4393 | #else |
... | ... | @@ -4265,19 +4408,20 @@ namespace cimg_library_suffixed { |
4265 | 4408 | std::srand(seed); |
4266 | 4409 | } |
4267 | 4410 | |
4268 | - //! Return a random variable between [0,1] with respect to an uniform distribution. | |
4411 | + //! Return a random variable uniformely distributed between [val_min,val_max]. | |
4269 | 4412 | /** |
4270 | 4413 | **/ |
4271 | - inline double rand() { | |
4272 | - return (double)std::rand()/RAND_MAX; | |
4414 | + inline double rand(const double val_min, const double val_max) { | |
4415 | + const double val = (double)std::rand()/RAND_MAX; | |
4416 | + return val_min + (val_max - val_min)*val; | |
4273 | 4417 | } |
4274 | 4418 | #endif |
4275 | 4419 | |
4276 | - //! Return a random variable between [-1,1] with respect to an uniform distribution. | |
4420 | + //! Return a random variable uniformely distributed between [0,val_max]. | |
4277 | 4421 | /** |
4278 | - **/ | |
4279 | - inline double crand() { | |
4280 | - return 1 - 2*cimg::rand(); | |
4422 | + **/ | |
4423 | + inline double rand(const double val_max=1) { | |
4424 | + return cimg::rand(0,val_max); | |
4281 | 4425 | } |
4282 | 4426 | |
4283 | 4427 | //! Return a random variable following a gaussian distribution and a standard deviation of 1. |
... | ... | @@ -4286,8 +4430,8 @@ namespace cimg_library_suffixed { |
4286 | 4430 | inline double grand() { |
4287 | 4431 | double x1, w; |
4288 | 4432 | do { |
4289 | - const double x2 = 2*cimg::rand() - 1.0; | |
4290 | - x1 = 2*cimg::rand() - 1.0; | |
4433 | + const double x2 = cimg::rand(-1,1); | |
4434 | + x1 = cimg::rand(-1,1); | |
4291 | 4435 | w = x1*x1 + x2*x2; |
4292 | 4436 | } while (w<=0 || w>=1.0); |
4293 | 4437 | return x1*std::sqrt((-2*std::log(w))/w); |
... | ... | @@ -4319,6 +4463,10 @@ namespace cimg_library_suffixed { |
4319 | 4463 | return (double)rol((long)a,n); |
4320 | 4464 | } |
4321 | 4465 | |
4466 | + inline double rol(const long double a, const unsigned int n=1) { | |
4467 | + return (double)rol((long)a,n); | |
4468 | + } | |
4469 | + | |
4322 | 4470 | //! Bitwise-rotate value on the right. |
4323 | 4471 | template<typename T> |
4324 | 4472 | inline T ror(const T& a, const unsigned int n=1) { |
... | ... | @@ -4333,6 +4481,10 @@ namespace cimg_library_suffixed { |
4333 | 4481 | return (double)ror((long)a,n); |
4334 | 4482 | } |
4335 | 4483 | |
4484 | + inline double ror(const long double a, const unsigned int n=1) { | |
4485 | + return (double)ror((long)a,n); | |
4486 | + } | |
4487 | + | |
4336 | 4488 | //! Return absolute value of a value. |
4337 | 4489 | template<typename T> |
4338 | 4490 | inline T abs(const T& a) { |
... | ... | @@ -4515,11 +4667,12 @@ namespace cimg_library_suffixed { |
4515 | 4667 | else { const double tmp = absa/absb; return absb==0?0:absb*std::sqrt(1.0 + tmp*tmp); } |
4516 | 4668 | } |
4517 | 4669 | |
4518 | - inline bool _is_self_expr(const char *expression) { | |
4519 | - if (!expression || *expression=='>' || *expression=='<') return false; | |
4520 | - for (const char *s = expression; *s; ++s) | |
4521 | - if ((*s=='i' || *s=='j') && (s[1]=='(' || s[1]=='[')) return true; | |
4522 | - return false; | |
4670 | + //! Return sqrt(x^2 + y^2). | |
4671 | + inline double hypot(const double x, const double y) { | |
4672 | + double nx = cimg::abs(x), ny = cimg::abs(y), t; | |
4673 | + if (nx<ny) { t = nx; nx = ny; } else t = ny; | |
4674 | + if (nx>0) { t/=nx; return nx*std::sqrt(1+t*t); } | |
4675 | + return 0; | |
4523 | 4676 | } |
4524 | 4677 | |
4525 | 4678 | //! Convert ascii character to lower case. |
... | ... | @@ -4575,6 +4728,51 @@ namespace cimg_library_suffixed { |
4575 | 4728 | return cimg::strncasecmp(str1,str2,1 + (l1<l2?l1:l2)); |
4576 | 4729 | } |
4577 | 4730 | |
4731 | + //! Ellipsize a string. | |
4732 | + /** | |
4733 | + \param str C-string. | |
4734 | + \param l Max number of characters. | |
4735 | + \param is_ending Tell if the dots are placed at the end or at the center of the ellipsized string. | |
4736 | + **/ | |
4737 | + inline char *strellipsize(char *const str, const unsigned int l=64, | |
4738 | + const bool is_ending=true) { | |
4739 | + if (!str) return str; | |
4740 | + const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str); | |
4741 | + if (ls<=nl) return str; | |
4742 | + if (is_ending) std::strcpy(str + nl - 5,"(...)"); | |
4743 | + else { | |
4744 | + const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5; | |
4745 | + std::strcpy(str + ll,"(...)"); | |
4746 | + std::memmove(str + ll + 5,str + ls - lr,lr); | |
4747 | + } | |
4748 | + str[nl] = 0; | |
4749 | + return str; | |
4750 | + } | |
4751 | + | |
4752 | + //! Ellipsize a string. | |
4753 | + /** | |
4754 | + \param str C-string. | |
4755 | + \param res output C-string. | |
4756 | + \param l Max number of characters. | |
4757 | + \param is_ending Tell if the dots are placed at the end or at the center of the ellipsized string. | |
4758 | + **/ | |
4759 | + inline char *strellipsize(const char *const str, char *const res, const unsigned int l=64, | |
4760 | + const bool is_ending=true) { | |
4761 | + const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str); | |
4762 | + if (ls<=nl) { std::strcpy(res,str); return res; } | |
4763 | + if (is_ending) { | |
4764 | + std::strncpy(res,str,nl - 5); | |
4765 | + std::strcpy(res + nl -5,"(...)"); | |
4766 | + } else { | |
4767 | + const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5; | |
4768 | + std::strncpy(res,str,ll); | |
4769 | + std::strcpy(res + ll,"(...)"); | |
4770 | + std::strncpy(res + ll + 5,str + ls - lr,lr); | |
4771 | + } | |
4772 | + res[nl] = 0; | |
4773 | + return res; | |
4774 | + } | |
4775 | + | |
4578 | 4776 | //! Remove delimiters on the start and/or end of a C-string. |
4579 | 4777 | /** |
4580 | 4778 | \param[in,out] str C-string to work with (modified at output). |
... | ... | @@ -4638,7 +4836,7 @@ namespace cimg_library_suffixed { |
4638 | 4836 | *nd = (char)val; break; |
4639 | 4837 | case 'x' : |
4640 | 4838 | cimg_sscanf(++ns,"%x",&val); |
4641 | - while ((*ns>='0' && *ns<='7') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns; | |
4839 | + while ((*ns>='0' && *ns<='9') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns; | |
4642 | 4840 | *nd = (char)val; break; |
4643 | 4841 | default : *nd = *(ns++); |
4644 | 4842 | } else *nd = *(ns++); |
... | ... | @@ -4650,20 +4848,20 @@ namespace cimg_library_suffixed { |
4650 | 4848 | // Return string that identifies the running OS. |
4651 | 4849 | inline const char *stros() { |
4652 | 4850 | #if defined(linux) || defined(__linux) || defined(__linux__) |
4653 | - const char *const str = "Linux"; | |
4851 | + static const char *const str = "Linux"; | |
4654 | 4852 | #elif defined(sun) || defined(__sun) |
4655 | - const char *const str = "Sun OS"; | |
4853 | + static const char *const str = "Sun OS"; | |
4656 | 4854 | #elif defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined (__DragonFly__) |
4657 | - const char *const str = "BSD"; | |
4855 | + static const char *const str = "BSD"; | |
4658 | 4856 | #elif defined(sgi) || defined(__sgi) |
4659 | - const char *const str = "Irix"; | |
4857 | + static const char *const str = "Irix"; | |
4660 | 4858 | #elif defined(__MACOSX__) || defined(__APPLE__) |
4661 | - const char *const str = "Mac OS"; | |
4859 | + static const char *const str = "Mac OS"; | |
4662 | 4860 | #elif defined(unix) || defined(__unix) || defined(__unix__) |
4663 | - const char *const str = "Generic Unix"; | |
4861 | + static const char *const str = "Generic Unix"; | |
4664 | 4862 | #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \ |
4665 | 4863 | defined(WIN64) || defined(_WIN64) || defined(__WIN64__) |
4666 | - const char *const str = "Windows"; | |
4864 | + static const char *const str = "Windows"; | |
4667 | 4865 | #else |
4668 | 4866 | const char |
4669 | 4867 | *const _str1 = std::getenv("OSTYPE"), |
... | ... | @@ -4683,11 +4881,12 @@ namespace cimg_library_suffixed { |
4683 | 4881 | // Return a random filename. |
4684 | 4882 | inline const char* filenamerand() { |
4685 | 4883 | cimg::mutex(6); |
4686 | - static char randomid[9] = { 0 }; | |
4884 | + static char randomid[9]; | |
4687 | 4885 | cimg::srand(); |
4688 | 4886 | for (unsigned int k = 0; k<8; ++k) { |
4689 | - const int v = (int)std::rand()%3; | |
4690 | - randomid[k] = (char)(v==0?('0' + (std::rand()%10)):(v==1?('a' + (std::rand()%26)):('A' + (std::rand()%26)))); | |
4887 | + const int v = (int)cimg::rand(65535)%3; | |
4888 | + randomid[k] = (char)(v==0?('0' + ((int)cimg::rand(65535)%10)): | |
4889 | + (v==1?('a' + ((int)cimg::rand(65535)%26)):('A' + ((int)cimg::rand(65535)%26)))); | |
4691 | 4890 | } |
4692 | 4891 | cimg::mutex(6,0); |
4693 | 4892 | return randomid; |
... | ... | @@ -4815,7 +5014,7 @@ namespace cimg_library_suffixed { |
4815 | 5014 | Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second } |
4816 | 5015 | **/ |
4817 | 5016 | inline int date(const unsigned int attr) { |
4818 | - int res = -1; | |
5017 | + int res; | |
4819 | 5018 | cimg::mutex(6); |
4820 | 5019 | #if cimg_OS==2 |
4821 | 5020 | SYSTEMTIME st; |
... | ... | @@ -4892,7 +5091,7 @@ namespace cimg_library_suffixed { |
4892 | 5091 | const char *const ext = cimg::split_filename(filename,body); |
4893 | 5092 | if (*ext) cimg_snprintf(format,1024,"%%s_%%.%ud.%%s",digits); |
4894 | 5093 | else cimg_snprintf(format,1024,"%%s_%%.%ud",digits); |
4895 | - std::sprintf(str,format,body,number,ext); | |
5094 | + cimg_sprintf(str,format,body,number,ext); | |
4896 | 5095 | delete[] format; delete[] body; |
4897 | 5096 | return str; |
4898 | 5097 | } |
... | ... | @@ -4970,7 +5169,8 @@ namespace cimg_library_suffixed { |
4970 | 5169 | |
4971 | 5170 | // Load file from network as a local temporary file. |
4972 | 5171 | inline char *load_network(const char *const url, char *const filename_local, |
4973 | - const unsigned int timeout=0, const bool try_fallback=false); | |
5172 | + const unsigned int timeout=0, const bool try_fallback=false, | |
5173 | + const char *const referer=0); | |
4974 | 5174 | |
4975 | 5175 | //! Return options specified on the command line. |
4976 | 5176 | inline const char* option(const char *const name, const int argc, const char *const *const argv, |
... | ... | @@ -5033,8 +5233,8 @@ namespace cimg_library_suffixed { |
5033 | 5233 | const char defaut, const char *const usage=0) { |
5034 | 5234 | const char *const s = cimg::option(name,argc,argv,(char*)0); |
5035 | 5235 | const char res = s?*s:defaut; |
5036 | - char tmp[8] = { 0 }; | |
5037 | - *tmp = res; | |
5236 | + char tmp[8]; | |
5237 | + *tmp = res; tmp[1] = 0; | |
5038 | 5238 | cimg::option(name,0,0,tmp,usage); |
5039 | 5239 | return res; |
5040 | 5240 | } |
... | ... | @@ -5061,25 +5261,6 @@ namespace cimg_library_suffixed { |
5061 | 5261 | return res; |
5062 | 5262 | } |
5063 | 5263 | |
5064 | - inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, | |
5065 | - const unsigned int nb_singles=0, ...) { | |
5066 | - for (int k = 1, pos = 0; k<argc;) { | |
5067 | - const char *const item = argv[k]; | |
5068 | - bool option = (*item=='-'), single_option = false; | |
5069 | - if (option) { | |
5070 | - va_list ap; | |
5071 | - va_start(ap,nb_singles); | |
5072 | - for (unsigned int i = 0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { | |
5073 | - single_option = true; break; | |
5074 | - } | |
5075 | - va_end(ap); | |
5076 | - } | |
5077 | - if (option) { ++k; if (!single_option) ++k; } | |
5078 | - else { if (pos++==(int)nb) return item; else ++k; } | |
5079 | - } | |
5080 | - return 0; | |
5081 | - } | |
5082 | - | |
5083 | 5264 | //! Print information about \CImg environement variables. |
5084 | 5265 | /** |
5085 | 5266 | \note Output is done on the default output stream. |
... | ... | @@ -5372,6 +5553,7 @@ namespace cimg_library_suffixed { |
5372 | 5553 | _cimg_create_ext_operators(long) |
5373 | 5554 | _cimg_create_ext_operators(float) |
5374 | 5555 | _cimg_create_ext_operators(double) |
5556 | + _cimg_create_ext_operators(long double) | |
5375 | 5557 | |
5376 | 5558 | template<typename T> |
5377 | 5559 | inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) { |
... | ... | @@ -5380,7 +5562,7 @@ namespace cimg_library_suffixed { |
5380 | 5562 | |
5381 | 5563 | template<typename T> |
5382 | 5564 | inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) { |
5383 | - return CImg<_cimg_Tfloat>(img._width,img._height,img._depth,img._spectrum,expression,true)-=img; | |
5565 | + return CImg<_cimg_Tfloat>(img,false).fill(expression,true)-=img; | |
5384 | 5566 | } |
5385 | 5567 | |
5386 | 5568 | template<typename T> |
... | ... | @@ -5410,12 +5592,12 @@ namespace cimg_library_suffixed { |
5410 | 5592 | |
5411 | 5593 | template<typename T> |
5412 | 5594 | inline bool operator==(const char *const expression, const CImg<T>& img) { |
5413 | - return img == expression; | |
5595 | + return img==expression; | |
5414 | 5596 | } |
5415 | 5597 | |
5416 | 5598 | template<typename T> |
5417 | 5599 | inline bool operator!=(const char *const expression, const CImg<T>& img) { |
5418 | - return img != expression; | |
5600 | + return img!=expression; | |
5419 | 5601 | } |
5420 | 5602 | |
5421 | 5603 | template<typename T> |
... | ... | @@ -5528,7 +5710,7 @@ namespace cimg_library_suffixed { |
5528 | 5710 | # Define the CImgDisplay structure |
5529 | 5711 | # |
5530 | 5712 | ----------------------------------*/ |
5531 | - //! Allow to create windows, display images on them and manage user events (keyboard, mouse and windows events). | |
5713 | + //! Allow the creation of windows, display images on them and manage user events (keyboard, mouse and windows events). | |
5532 | 5714 | /** |
5533 | 5715 | CImgDisplay methods rely on a low-level graphic library to perform: it can be either \b X-Window |
5534 | 5716 | (X11, for Unix-based systems) or \b GDI32 (for Windows-based systems). |
... | ... | @@ -5802,6 +5984,12 @@ namespace cimg_library_suffixed { |
5802 | 5984 | return _empty.assign(); |
5803 | 5985 | } |
5804 | 5986 | |
5987 | + //! Return a reference to an empty display \const. | |
5988 | + static const CImgDisplay& const_empty() { | |
5989 | + static const CImgDisplay _empty; | |
5990 | + return _empty; | |
5991 | + } | |
5992 | + | |
5805 | 5993 | #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false), \ |
5806 | 5994 | CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true) |
5807 | 5995 | static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz, |
... | ... | @@ -6191,7 +6379,7 @@ namespace cimg_library_suffixed { |
6191 | 6379 | in fullscreen mode. |
6192 | 6380 | **/ |
6193 | 6381 | const char *title() const { |
6194 | - return _title; | |
6382 | + return _title?_title:""; | |
6195 | 6383 | } |
6196 | 6384 | |
6197 | 6385 | //! Return width of the associated window. |
... | ... | @@ -7136,7 +7324,7 @@ namespace cimg_library_suffixed { |
7136 | 7324 | XEvent event; |
7137 | 7325 | pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0); |
7138 | 7326 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0); |
7139 | - if (!arg) for (;;) { | |
7327 | + if (!arg) for ( ; ; ) { | |
7140 | 7328 | cimg_lock_display(); |
7141 | 7329 | bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event); |
7142 | 7330 | if (!event_flag) event_flag = XCheckMaskEvent(dpy, |
... | ... | @@ -7397,7 +7585,7 @@ namespace cimg_library_suffixed { |
7397 | 7585 | |
7398 | 7586 | // Allocate space for window title |
7399 | 7587 | const char *const nptitle = ptitle?ptitle:""; |
7400 | - const unsigned int s = std::strlen(nptitle) + 1; | |
7588 | + const unsigned int s = (unsigned int)std::strlen(nptitle) + 1; | |
7401 | 7589 | char *const tmp_title = s?new char[s]:0; |
7402 | 7590 | if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char)); |
7403 | 7591 | |
... | ... | @@ -7535,7 +7723,7 @@ namespace cimg_library_suffixed { |
7535 | 7723 | // Remove display window from event thread list. |
7536 | 7724 | unsigned int i; |
7537 | 7725 | for (i = 0; i<cimg::X11_attr().nb_wins && cimg::X11_attr().wins[i]!=this; ++i) {} |
7538 | - for (; i<cimg::X11_attr().nb_wins - 1; ++i) cimg::X11_attr().wins[i] = cimg::X11_attr().wins[i + 1]; | |
7726 | + for ( ; i<cimg::X11_attr().nb_wins - 1; ++i) cimg::X11_attr().wins[i] = cimg::X11_attr().wins[i + 1]; | |
7539 | 7727 | --cimg::X11_attr().nb_wins; |
7540 | 7728 | |
7541 | 7729 | // Destroy window, image, colormap and title. |
... | ... | @@ -7630,24 +7818,27 @@ namespace cimg_library_suffixed { |
7630 | 7818 | tmpdimy = (nheight>0)?nheight:(-nheight*height()/100), |
7631 | 7819 | dimx = tmpdimx?tmpdimx:1, |
7632 | 7820 | dimy = tmpdimy?tmpdimy:1; |
7633 | - cimg_lock_display(); | |
7634 | - if (_window_width!=dimx || _window_height!=dimy) { | |
7635 | - XWindowAttributes attr; | |
7636 | - for (unsigned int i = 0; i<10; ++i) { | |
7637 | - XResizeWindow(dpy,_window,dimx,dimy); | |
7638 | - XGetWindowAttributes(dpy,_window,&attr); | |
7639 | - if (attr.width==(int)dimx && attr.height==(int)dimy) break; | |
7640 | - cimg::wait(5); | |
7821 | + if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) { | |
7822 | + show(); | |
7823 | + cimg_lock_display(); | |
7824 | + if (_window_width!=dimx || _window_height!=dimy) { | |
7825 | + XWindowAttributes attr; | |
7826 | + for (unsigned int i = 0; i<10; ++i) { | |
7827 | + XResizeWindow(dpy,_window,dimx,dimy); | |
7828 | + XGetWindowAttributes(dpy,_window,&attr); | |
7829 | + if (attr.width==(int)dimx && attr.height==(int)dimy) break; | |
7830 | + cimg::wait(5); | |
7831 | + } | |
7641 | 7832 | } |
7833 | + if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) { | |
7834 | + case 8 : { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break; | |
7835 | + case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break; | |
7836 | + default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } | |
7837 | + } | |
7838 | + _window_width = _width = dimx; _window_height = _height = dimy; | |
7839 | + cimg_unlock_display(); | |
7642 | 7840 | } |
7643 | - if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) { | |
7644 | - case 8 : { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break; | |
7645 | - case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break; | |
7646 | - default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } | |
7647 | - } | |
7648 | - _window_width = _width = dimx; _window_height = _height = dimy; | |
7649 | 7841 | _is_resized = false; |
7650 | - cimg_unlock_display(); | |
7651 | 7842 | if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2); |
7652 | 7843 | if (force_redraw) return paint(); |
7653 | 7844 | return *this; |
... | ... | @@ -7692,13 +7883,15 @@ namespace cimg_library_suffixed { |
7692 | 7883 | |
7693 | 7884 | CImgDisplay& move(const int posx, const int posy) { |
7694 | 7885 | if (is_empty()) return *this; |
7695 | - show(); | |
7696 | - Display *const dpy = cimg::X11_attr().display; | |
7697 | - cimg_lock_display(); | |
7698 | - XMoveWindow(dpy,_window,posx,posy); | |
7699 | - _window_x = posx; _window_y = posy; | |
7886 | + if (_window_x!=posx || _window_y!=posy) { | |
7887 | + show(); | |
7888 | + Display *const dpy = cimg::X11_attr().display; | |
7889 | + cimg_lock_display(); | |
7890 | + XMoveWindow(dpy,_window,posx,posy); | |
7891 | + _window_x = posx; _window_y = posy; | |
7892 | + cimg_unlock_display(); | |
7893 | + } | |
7700 | 7894 | _is_moved = false; |
7701 | - cimg_unlock_display(); | |
7702 | 7895 | return paint(); |
7703 | 7896 | } |
7704 | 7897 | |
... | ... | @@ -7715,7 +7908,7 @@ namespace cimg_library_suffixed { |
7715 | 7908 | if (is_empty()) return *this; |
7716 | 7909 | Display *const dpy = cimg::X11_attr().display; |
7717 | 7910 | cimg_lock_display(); |
7718 | - const char pix_data[8] = { 0 }; | |
7911 | + static const char pix_data[8] = { 0 }; | |
7719 | 7912 | XColor col; |
7720 | 7913 | col.red = col.green = col.blue = 0; |
7721 | 7914 | Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8); |
... | ... | @@ -7747,7 +7940,7 @@ namespace cimg_library_suffixed { |
7747 | 7940 | va_end(ap); |
7748 | 7941 | if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; } |
7749 | 7942 | delete[] _title; |
7750 | - const unsigned int s = std::strlen(tmp) + 1; | |
7943 | + const unsigned int s = (unsigned int)std::strlen(tmp) + 1; | |
7751 | 7944 | _title = new char[s]; |
7752 | 7945 | std::memcpy(_title,tmp,s*sizeof(char)); |
7753 | 7946 | Display *const dpy = cimg::X11_attr().display; |
... | ... | @@ -8269,7 +8462,9 @@ namespace cimg_library_suffixed { |
8269 | 8462 | } break; |
8270 | 8463 | case WM_PAINT : |
8271 | 8464 | disp->paint(); |
8465 | + cimg::mutex(15); | |
8272 | 8466 | if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); |
8467 | + cimg::mutex(15,0); | |
8273 | 8468 | break; |
8274 | 8469 | case WM_ERASEBKGND : |
8275 | 8470 | // return 0; |
... | ... | @@ -8299,12 +8494,16 @@ namespace cimg_library_suffixed { |
8299 | 8494 | disp->_mouse_x = disp->_mouse_y = -1; |
8300 | 8495 | disp->_is_event = true; |
8301 | 8496 | SetEvent(cimg::Win32_attr().wait_event); |
8497 | + cimg::mutex(15); | |
8302 | 8498 | if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); |
8499 | + cimg::mutex(15,0); | |
8303 | 8500 | } break; |
8304 | 8501 | case WM_MOUSELEAVE : { |
8305 | 8502 | disp->_mouse_x = disp->_mouse_y = -1; |
8306 | 8503 | disp->_is_mouse_tracked = false; |
8504 | + cimg::mutex(15); | |
8307 | 8505 | while (ShowCursor(TRUE)<0); |
8506 | + cimg::mutex(15,0); | |
8308 | 8507 | } break; |
8309 | 8508 | case WM_LBUTTONDOWN : |
8310 | 8509 | disp->set_button(1); |
... | ... | @@ -8563,24 +8762,27 @@ namespace cimg_library_suffixed { |
8563 | 8762 | tmpdimy = (nheight>0)?nheight:(-nheight*_height/100), |
8564 | 8763 | dimx = tmpdimx?tmpdimx:1, |
8565 | 8764 | dimy = tmpdimy?tmpdimy:1; |
8566 | - if (_window_width!=dimx || _window_height!=dimy) { | |
8567 | - RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1; | |
8568 | - AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); | |
8569 | - const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1; | |
8570 | - SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS); | |
8571 | - } | |
8572 | - if (_width!=dimx || _height!=dimy) { | |
8573 | - unsigned int *const ndata = new unsigned int[dimx*dimy]; | |
8574 | - if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy); | |
8575 | - else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy); | |
8576 | - delete[] _data; | |
8577 | - _data = ndata; | |
8578 | - _bmi.bmiHeader.biWidth = (LONG)dimx; | |
8579 | - _bmi.bmiHeader.biHeight = -(int)dimy; | |
8580 | - _width = dimx; | |
8581 | - _height = dimy; | |
8765 | + if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) { | |
8766 | + if (_window_width!=dimx || _window_height!=dimy) { | |
8767 | + RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1; | |
8768 | + AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); | |
8769 | + const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1; | |
8770 | + SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS); | |
8771 | + } | |
8772 | + if (_width!=dimx || _height!=dimy) { | |
8773 | + unsigned int *const ndata = new unsigned int[dimx*dimy]; | |
8774 | + if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy); | |
8775 | + else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy); | |
8776 | + delete[] _data; | |
8777 | + _data = ndata; | |
8778 | + _bmi.bmiHeader.biWidth = (LONG)dimx; | |
8779 | + _bmi.bmiHeader.biHeight = -(int)dimy; | |
8780 | + _width = dimx; | |
8781 | + _height = dimy; | |
8782 | + } | |
8783 | + _window_width = dimx; _window_height = dimy; | |
8784 | + show(); | |
8582 | 8785 | } |
8583 | - _window_width = dimx; _window_height = dimy; | |
8584 | 8786 | _is_resized = false; |
8585 | 8787 | if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2); |
8586 | 8788 | if (force_redraw) return paint(); |
... | ... | @@ -8623,19 +8825,22 @@ namespace cimg_library_suffixed { |
8623 | 8825 | |
8624 | 8826 | CImgDisplay& move(const int posx, const int posy) { |
8625 | 8827 | if (is_empty()) return *this; |
8626 | - if (!_is_fullscreen) { | |
8627 | - RECT rect; | |
8628 | - rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_height - 1; | |
8629 | - AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); | |
8630 | - const int | |
8631 | - border1 = (int)((rect.right - rect.left + 1 -_width)/2), | |
8632 | - border2 = (int)(rect.bottom - rect.top + 1 - _height - border1); | |
8633 | - SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER); | |
8634 | - } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER); | |
8635 | - _window_x = posx; | |
8636 | - _window_y = posy; | |
8828 | + if (_window_x!=posx || _window_y!=posy) { | |
8829 | + if (!_is_fullscreen) { | |
8830 | + RECT rect; | |
8831 | + rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_height - 1; | |
8832 | + AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); | |
8833 | + const int | |
8834 | + border1 = (int)((rect.right - rect.left + 1 -_width)/2), | |
8835 | + border2 = (int)(rect.bottom - rect.top + 1 - _height - border1); | |
8836 | + SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER); | |
8837 | + } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER); | |
8838 | + _window_x = posx; | |
8839 | + _window_y = posy; | |
8840 | + show(); | |
8841 | + } | |
8637 | 8842 | _is_moved = false; |
8638 | - return show(); | |
8843 | + return *this; | |
8639 | 8844 | } |
8640 | 8845 | |
8641 | 8846 | CImgDisplay& show_mouse() { |
... | ... | @@ -8651,7 +8856,7 @@ namespace cimg_library_suffixed { |
8651 | 8856 | } |
8652 | 8857 | |
8653 | 8858 | CImgDisplay& set_mouse(const int posx, const int posy) { |
8654 | - if (_is_closed || posx<0 || posy<0) return *this; | |
8859 | + if (is_empty() || _is_closed || posx<0 || posy<0) return *this; | |
8655 | 8860 | _update_window_pos(); |
8656 | 8861 | const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy); |
8657 | 8862 | if (res) { _mouse_x = posx; _mouse_y = posy; } |
... | ... | @@ -8891,10 +9096,8 @@ namespace cimg_library_suffixed { |
8891 | 9096 | - Construct images from C-style arrays: |
8892 | 9097 | - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer |
8893 | 9098 | \c data_buffer (of size 256x256=65536). |
8894 | - - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image | |
9099 | + - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3);</tt> constructs a 256x256 color image | |
8895 | 9100 | from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others). |
8896 | - - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image | |
8897 | - from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed). | |
8898 | 9101 | |
8899 | 9102 | The complete list of constructors can be found <a href="#constructors">here</a>. |
8900 | 9103 | |
... | ... | @@ -8903,7 +9106,7 @@ namespace cimg_library_suffixed { |
8903 | 9106 | The \c CImg<T> class contains a lot of functions that operates on images. |
8904 | 9107 | Some of the most useful are: |
8905 | 9108 | |
8906 | - - operator()(): allows to access or write pixel values. | |
9109 | + - operator()(): Read or write pixel values. | |
8907 | 9110 | - display(): displays the image in a new window. |
8908 | 9111 | **/ |
8909 | 9112 | template<typename T> |
... | ... | @@ -8977,6 +9180,13 @@ namespace cimg_library_suffixed { |
8977 | 9180 | typedef typename cimg::last<T,long>::type longT; |
8978 | 9181 | typedef typename cimg::last<T,float>::type floatT; |
8979 | 9182 | typedef typename cimg::last<T,double>::type doubleT; |
9183 | +#if cimg_OS==2 | |
9184 | + typedef typename cimg::last<T,UINT_PTR>::type uptrT; // Unsigned integer type that can store a pointer. | |
9185 | + typedef typename cimg::last<T,INT_PTR>::type ptrT; // Signed integer type that can store a pointer. | |
9186 | +#else | |
9187 | + typedef typename cimg::last<T,unsigned long>::type uptrT; | |
9188 | + typedef typename cimg::last<T,long>::type ptrT; | |
9189 | +#endif | |
8980 | 9190 | |
8981 | 9191 | //@} |
8982 | 9192 | //--------------------------- |
... | ... | @@ -9165,7 +9375,7 @@ namespace cimg_library_suffixed { |
9165 | 9375 | *(ptrd++) = (T)a0; \ |
9166 | 9376 | if (_siz--) { \ |
9167 | 9377 | *(ptrd++) = (T)a1; \ |
9168 | - for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \ | |
9378 | + for ( ; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \ | |
9169 | 9379 | } \ |
9170 | 9380 | va_end(ap); \ |
9171 | 9381 | } \ |
... | ... | @@ -9174,7 +9384,7 @@ namespace cimg_library_suffixed { |
9174 | 9384 | _CImg_stdarg(*this,value0,value1,(unsigned long)size_x*size_y*size_z*size_c,int); |
9175 | 9385 | } |
9176 | 9386 | |
9177 | -#ifdef cimg_use_cpp11 | |
9387 | +#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0 | |
9178 | 9388 | //! Construct image with specified size and initialize pixel values from an initializer list of integers. |
9179 | 9389 | /** |
9180 | 9390 | Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, |
... | ... | @@ -9423,7 +9633,8 @@ namespace cimg_library_suffixed { |
9423 | 9633 | cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), |
9424 | 9634 | size_x,size_y,size_z,size_c); |
9425 | 9635 | } |
9426 | - std::memcpy(_data,values,siz*sizeof(T)); } | |
9636 | + std::memcpy(_data,values,siz*sizeof(T)); | |
9637 | + } | |
9427 | 9638 | } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } |
9428 | 9639 | } |
9429 | 9640 | |
... | ... | @@ -9629,7 +9840,7 @@ namespace cimg_library_suffixed { |
9629 | 9840 | |
9630 | 9841 | // Constructor and assignment operator for rvalue references (c++11). |
9631 | 9842 | // This avoids an additional image copy for methods returning new images. Can save RAM for big images ! |
9632 | -#ifdef cimg_use_cpp11 | |
9843 | +#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0 | |
9633 | 9844 | CImg(CImg<T>&& img):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { |
9634 | 9845 | swap(img); |
9635 | 9846 | } |
... | ... | @@ -9954,10 +10165,7 @@ namespace cimg_library_suffixed { |
9954 | 10165 | \endcode |
9955 | 10166 | **/ |
9956 | 10167 | CImg<T>& swap(CImg<T>& img) { |
9957 | - cimg::swap(_width,img._width); | |
9958 | - cimg::swap(_height,img._height); | |
9959 | - cimg::swap(_depth,img._depth); | |
9960 | - cimg::swap(_spectrum,img._spectrum); | |
10168 | + cimg::swap(_width,img._width,_height,img._height,_depth,img._depth,_spectrum,img._spectrum); | |
9961 | 10169 | cimg::swap(_data,img._data); |
9962 | 10170 | cimg::swap(_is_shared,img._is_shared); |
9963 | 10171 | return img; |
... | ... | @@ -9977,6 +10185,12 @@ namespace cimg_library_suffixed { |
9977 | 10185 | return _empty.assign(); |
9978 | 10186 | } |
9979 | 10187 | |
10188 | + //! Return a reference to an empty image \const. | |
10189 | + static const CImg<T>& const_empty() { | |
10190 | + static const CImg<T> _empty; | |
10191 | + return _empty; | |
10192 | + } | |
10193 | + | |
9980 | 10194 | //@} |
9981 | 10195 | //------------------------------------------ |
9982 | 10196 | // |
... | ... | @@ -10023,9 +10237,9 @@ namespace cimg_library_suffixed { |
10023 | 10237 | const unsigned long off = (unsigned long)offset(x,y,z,c); |
10024 | 10238 | if (!_data || off>=size()) { |
10025 | 10239 | cimg::warn(_cimg_instance |
10026 | - "operator(): Invalid pixel request, at coordinates (%u,%u,%u,%u) [offset=%u].", | |
10240 | + "operator(): Invalid pixel request, at coordinates (%d,%d,%d,%d) [offset=%u].", | |
10027 | 10241 | cimg_instance, |
10028 | - x,y,z,c,off); | |
10242 | + (int)x,(int)y,(int)z,(int)c,off); | |
10029 | 10243 | return *_data; |
10030 | 10244 | } |
10031 | 10245 | else return _data[off]; |
... | ... | @@ -10191,7 +10405,7 @@ namespace cimg_library_suffixed { |
10191 | 10405 | const unsigned int omode = cimg::exception_mode(); |
10192 | 10406 | cimg::exception_mode(0); |
10193 | 10407 | try { |
10194 | - fill(expression,true); | |
10408 | + _fill(expression,true,true,0,0,"operator=",0); | |
10195 | 10409 | } catch (CImgException&) { |
10196 | 10410 | cimg::exception_mode(omode); |
10197 | 10411 | load(expression); |
... | ... | @@ -10254,7 +10468,7 @@ namespace cimg_library_suffixed { |
10254 | 10468 | CImg<T>& operator+=(const t value) { |
10255 | 10469 | if (is_empty()) return *this; |
10256 | 10470 | #ifdef cimg_use_openmp |
10257 | -#pragma omp parallel for if (size()>=524288) | |
10471 | +#pragma omp parallel for cimg_openmp_if(size()>=524288) | |
10258 | 10472 | #endif |
10259 | 10473 | cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd + value); |
10260 | 10474 | return *this; |
... | ... | @@ -10269,37 +10483,7 @@ namespace cimg_library_suffixed { |
10269 | 10483 | instead of assigning them. |
10270 | 10484 | **/ |
10271 | 10485 | CImg<T>& operator+=(const char *const expression) { |
10272 | - if (is_empty()) return *this; | |
10273 | - const unsigned int omode = cimg::exception_mode(); | |
10274 | - cimg::exception_mode(0); | |
10275 | - try { | |
10276 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
10277 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator+="); | |
10278 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
10279 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); --ptrd; } | |
10280 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); ++ptrd; } | |
10281 | - else { | |
10282 | -#ifdef cimg_use_openmp | |
10283 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
10284 | -#pragma omp parallel | |
10285 | - { | |
10286 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
10287 | -#pragma omp for collapse(3) | |
10288 | - cimg_forYZC(*this,y,z,c) { | |
10289 | - T *ptrd = data(0,y,z,c); | |
10290 | - cimg_forX(*this,x) { *ptrd = (T)(*ptrd + lmp(x,y,z,c)); ++ptrd; } | |
10291 | - } | |
10292 | - } | |
10293 | - else | |
10294 | -#endif | |
10295 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); ++ptrd; } | |
10296 | - } | |
10297 | - } catch (CImgException&) { | |
10298 | - cimg::exception_mode(omode); | |
10299 | - *this+=CImg<T>(_width,_height,_depth,_spectrum,expression,true); | |
10300 | - } | |
10301 | - cimg::exception_mode(omode); | |
10302 | - return *this; | |
10486 | + return *this+=(+*this)._fill(expression,true,true,0,0,"operator+=",this); | |
10303 | 10487 | } |
10304 | 10488 | |
10305 | 10489 | //! In-place addition operator. |
... | ... | @@ -10345,7 +10529,7 @@ namespace cimg_library_suffixed { |
10345 | 10529 | CImg<T>& operator++() { |
10346 | 10530 | if (is_empty()) return *this; |
10347 | 10531 | #ifdef cimg_use_openmp |
10348 | -#pragma omp parallel for if (size()>=524288) | |
10532 | +#pragma omp parallel for cimg_openmp_if(size()>=524288) | |
10349 | 10533 | #endif |
10350 | 10534 | cimg_rof(*this,ptrd,T) ++*ptrd; |
10351 | 10535 | return *this; |
... | ... | @@ -10414,7 +10598,7 @@ namespace cimg_library_suffixed { |
10414 | 10598 | CImg<T>& operator-=(const t value) { |
10415 | 10599 | if (is_empty()) return *this; |
10416 | 10600 | #ifdef cimg_use_openmp |
10417 | -#pragma omp parallel for if (size()>=524288) | |
10601 | +#pragma omp parallel for cimg_openmp_if(size()>=524288) | |
10418 | 10602 | #endif |
10419 | 10603 | cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd - value); |
10420 | 10604 | return *this; |
... | ... | @@ -10425,37 +10609,7 @@ namespace cimg_library_suffixed { |
10425 | 10609 | Similar to operator+=(const char*), except that it performs a substraction instead of an addition. |
10426 | 10610 | **/ |
10427 | 10611 | CImg<T>& operator-=(const char *const expression) { |
10428 | - if (is_empty()) return *this; | |
10429 | - const unsigned int omode = cimg::exception_mode(); | |
10430 | - cimg::exception_mode(0); | |
10431 | - try { | |
10432 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
10433 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator-="); | |
10434 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
10435 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); --ptrd; } | |
10436 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); ++ptrd; } | |
10437 | - else { | |
10438 | -#ifdef cimg_use_openmp | |
10439 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
10440 | -#pragma omp parallel | |
10441 | - { | |
10442 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
10443 | -#pragma omp for collapse(3) | |
10444 | - cimg_forYZC(*this,y,z,c) { | |
10445 | - T *ptrd = data(0,y,z,c); | |
10446 | - cimg_forX(*this,x) { *ptrd = (T)(*ptrd - lmp(x,y,z,c)); ++ptrd; } | |
10447 | - } | |
10448 | - } | |
10449 | - else | |
10450 | -#endif | |
10451 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); ++ptrd; } | |
10452 | - } | |
10453 | - } catch (CImgException&) { | |
10454 | - cimg::exception_mode(omode); | |
10455 | - *this-=CImg<T>(_width,_height,_depth,_spectrum,expression,true); | |
10456 | - } | |
10457 | - cimg::exception_mode(omode); | |
10458 | - return *this; | |
10612 | + return *this-=(+*this)._fill(expression,true,true,0,0,"operator-=",this); | |
10459 | 10613 | } |
10460 | 10614 | |
10461 | 10615 | //! In-place substraction operator. |
... | ... | @@ -10483,7 +10637,7 @@ namespace cimg_library_suffixed { |
10483 | 10637 | CImg<T>& operator--() { |
10484 | 10638 | if (is_empty()) return *this; |
10485 | 10639 | #ifdef cimg_use_openmp |
10486 | -#pragma omp parallel for if (size()>=524288) | |
10640 | +#pragma omp parallel for cimg_openmp_if(size()>=524288) | |
10487 | 10641 | #endif |
10488 | 10642 | cimg_rof(*this,ptrd,T) *ptrd = *ptrd - (T)1; |
10489 | 10643 | return *this; |
... | ... | @@ -10554,7 +10708,7 @@ namespace cimg_library_suffixed { |
10554 | 10708 | CImg<T>& operator*=(const t value) { |
10555 | 10709 | if (is_empty()) return *this; |
10556 | 10710 | #ifdef cimg_use_openmp |
10557 | -#pragma omp parallel for if (size()>=262144) | |
10711 | +#pragma omp parallel for cimg_openmp_if(size()>=262144) | |
10558 | 10712 | #endif |
10559 | 10713 | cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd * value); |
10560 | 10714 | return *this; |
... | ... | @@ -10565,37 +10719,7 @@ namespace cimg_library_suffixed { |
10565 | 10719 | Similar to operator+=(const char*), except that it performs a multiplication instead of an addition. |
10566 | 10720 | **/ |
10567 | 10721 | CImg<T>& operator*=(const char *const expression) { |
10568 | - if (is_empty()) return *this; | |
10569 | - const unsigned int omode = cimg::exception_mode(); | |
10570 | - cimg::exception_mode(0); | |
10571 | - try { | |
10572 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
10573 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator*="); | |
10574 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
10575 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); --ptrd; } | |
10576 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); ++ptrd; } | |
10577 | - else { | |
10578 | -#ifdef cimg_use_openmp | |
10579 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
10580 | -#pragma omp parallel | |
10581 | - { | |
10582 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
10583 | -#pragma omp for collapse(3) | |
10584 | - cimg_forYZC(*this,y,z,c) { | |
10585 | - T *ptrd = data(0,y,z,c); | |
10586 | - cimg_forX(*this,x) { *ptrd = (T)(*ptrd * lmp(x,y,z,c)); ++ptrd; } | |
10587 | - } | |
10588 | - } | |
10589 | - else | |
10590 | -#endif | |
10591 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); ++ptrd; } | |
10592 | - } | |
10593 | - } catch (CImgException&) { | |
10594 | - cimg::exception_mode(omode); | |
10595 | - mul(CImg<T>(_width,_height,_depth,_spectrum,expression,true)); | |
10596 | - } | |
10597 | - cimg::exception_mode(omode); | |
10598 | - return *this; | |
10722 | + return mul((+*this)._fill(expression,true,true,0,0,"operator*=",this)); | |
10599 | 10723 | } |
10600 | 10724 | |
10601 | 10725 | //! In-place multiplication operator. |
... | ... | @@ -10654,7 +10778,7 @@ namespace cimg_library_suffixed { |
10654 | 10778 | img._width,img._height,img._depth,img._spectrum,img._data); |
10655 | 10779 | CImg<_cimg_Tt> res(img._width,_height); |
10656 | 10780 | #ifdef cimg_use_openmp |
10657 | -#pragma omp parallel for if (size()>1024 && img.size()>1024) collapse(2) | |
10781 | +#pragma omp parallel for collapse(2) cimg_openmp_if(size()>1024 && img.size()>1024) | |
10658 | 10782 | cimg_forXY(res,i,j) { |
10659 | 10783 | _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); res(i,j) = (_cimg_Tt)value; |
10660 | 10784 | } |
... | ... | @@ -10675,7 +10799,7 @@ namespace cimg_library_suffixed { |
10675 | 10799 | CImg<T>& operator/=(const t value) { |
10676 | 10800 | if (is_empty()) return *this; |
10677 | 10801 | #ifdef cimg_use_openmp |
10678 | -#pragma omp parallel for if (size()>=32768) | |
10802 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
10679 | 10803 | #endif |
10680 | 10804 | cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd / value); |
10681 | 10805 | return *this; |
... | ... | @@ -10686,37 +10810,7 @@ namespace cimg_library_suffixed { |
10686 | 10810 | Similar to operator+=(const char*), except that it performs a division instead of an addition. |
10687 | 10811 | **/ |
10688 | 10812 | CImg<T>& operator/=(const char *const expression) { |
10689 | - if (is_empty()) return *this; | |
10690 | - const unsigned int omode = cimg::exception_mode(); | |
10691 | - cimg::exception_mode(0); | |
10692 | - try { | |
10693 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
10694 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator/="); | |
10695 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
10696 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); --ptrd; } | |
10697 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); ++ptrd; } | |
10698 | - else { | |
10699 | -#ifdef cimg_use_openmp | |
10700 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
10701 | -#pragma omp parallel | |
10702 | - { | |
10703 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
10704 | -#pragma omp for collapse(3) | |
10705 | - cimg_forYZC(*this,y,z,c) { | |
10706 | - T *ptrd = data(0,y,z,c); | |
10707 | - cimg_forX(*this,x) { *ptrd = (T)(*ptrd / lmp(x,y,z,c)); ++ptrd; } | |
10708 | - } | |
10709 | - } | |
10710 | - else | |
10711 | -#endif | |
10712 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); ++ptrd; } | |
10713 | - } | |
10714 | - } catch (CImgException&) { | |
10715 | - cimg::exception_mode(omode); | |
10716 | - div(CImg<T>(_width,_height,_depth,_spectrum,expression,true)); | |
10717 | - } | |
10718 | - cimg::exception_mode(omode); | |
10719 | - return *this; | |
10813 | + return div((+*this)._fill(expression,true,true,0,0,"operator/=",this)); | |
10720 | 10814 | } |
10721 | 10815 | |
10722 | 10816 | //! In-place division operator. |
... | ... | @@ -10772,7 +10866,7 @@ namespace cimg_library_suffixed { |
10772 | 10866 | CImg<T>& operator%=(const t value) { |
10773 | 10867 | if (is_empty()) return *this; |
10774 | 10868 | #ifdef cimg_use_openmp |
10775 | -#pragma omp parallel for if (size()>=16384) | |
10869 | +#pragma omp parallel for cimg_openmp_if(size()>=16384) | |
10776 | 10870 | #endif |
10777 | 10871 | cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value); |
10778 | 10872 | return *this; |
... | ... | @@ -10783,37 +10877,7 @@ namespace cimg_library_suffixed { |
10783 | 10877 | Similar to operator+=(const char*), except that it performs a modulo operation instead of an addition. |
10784 | 10878 | **/ |
10785 | 10879 | CImg<T>& operator%=(const char *const expression) { |
10786 | - if (is_empty()) return *this; | |
10787 | - const unsigned int omode = cimg::exception_mode(); | |
10788 | - cimg::exception_mode(0); | |
10789 | - try { | |
10790 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
10791 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator%="); | |
10792 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
10793 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); --ptrd; } | |
10794 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } | |
10795 | - else { | |
10796 | -#ifdef cimg_use_openmp | |
10797 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
10798 | -#pragma omp parallel | |
10799 | - { | |
10800 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
10801 | -#pragma omp for collapse(3) | |
10802 | - cimg_forYZC(*this,y,z,c) { | |
10803 | - T *ptrd = data(0,y,z,c); | |
10804 | - cimg_forX(*this,x) { *ptrd = (T)cimg::mod(*ptrd,(T)lmp(x,y,z,c)); ++ptrd; } | |
10805 | - } | |
10806 | - } | |
10807 | - else | |
10808 | -#endif | |
10809 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } | |
10810 | - } | |
10811 | - } catch (CImgException&) { | |
10812 | - cimg::exception_mode(omode); | |
10813 | - *this%=CImg<T>(_width,_height,_depth,_spectrum,expression,true); | |
10814 | - } | |
10815 | - cimg::exception_mode(omode); | |
10816 | - return *this; | |
10880 | + return *this%=(+*this)._fill(expression,true,true,0,0,"operator%=",this); | |
10817 | 10881 | } |
10818 | 10882 | |
10819 | 10883 | //! In-place modulo operator. |
... | ... | @@ -10871,7 +10935,7 @@ namespace cimg_library_suffixed { |
10871 | 10935 | CImg<T>& operator&=(const t value) { |
10872 | 10936 | if (is_empty()) return *this; |
10873 | 10937 | #ifdef cimg_use_openmp |
10874 | -#pragma omp parallel for if (size()>=32768) | |
10938 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
10875 | 10939 | #endif |
10876 | 10940 | cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)value); |
10877 | 10941 | return *this; |
... | ... | @@ -10882,39 +10946,7 @@ namespace cimg_library_suffixed { |
10882 | 10946 | Similar to operator+=(const char*), except that it performs a bitwise AND operation instead of an addition. |
10883 | 10947 | **/ |
10884 | 10948 | CImg<T>& operator&=(const char *const expression) { |
10885 | - if (is_empty()) return *this; | |
10886 | - const unsigned int omode = cimg::exception_mode(); | |
10887 | - cimg::exception_mode(0); | |
10888 | - try { | |
10889 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
10890 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator&="); | |
10891 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
10892 | - if (*expression=='<') | |
10893 | - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp(x,y,z,c)); --ptrd; } | |
10894 | - else if (*expression=='>') | |
10895 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp(x,y,z,c)); ++ptrd; } | |
10896 | - else { | |
10897 | -#ifdef cimg_use_openmp | |
10898 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
10899 | -#pragma omp parallel | |
10900 | - { | |
10901 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
10902 | -#pragma omp for collapse(3) | |
10903 | - cimg_forYZC(*this,y,z,c) { | |
10904 | - T *ptrd = data(0,y,z,c); | |
10905 | - cimg_forX(*this,x) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)lmp(x,y,z,c)); ++ptrd; } | |
10906 | - } | |
10907 | - } | |
10908 | - else | |
10909 | -#endif | |
10910 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp(x,y,z,c)); ++ptrd; } | |
10911 | - } | |
10912 | - } catch (CImgException&) { | |
10913 | - cimg::exception_mode(omode); | |
10914 | - *this&=CImg<T>(_width,_height,_depth,_spectrum,expression,true); | |
10915 | - } | |
10916 | - cimg::exception_mode(omode); | |
10917 | - return *this; | |
10949 | + return *this&=(+*this)._fill(expression,true,true,0,0,"operator&=",this); | |
10918 | 10950 | } |
10919 | 10951 | |
10920 | 10952 | //! In-place bitwise AND operator. |
... | ... | @@ -10972,7 +11004,7 @@ namespace cimg_library_suffixed { |
10972 | 11004 | CImg<T>& operator|=(const t value) { |
10973 | 11005 | if (is_empty()) return *this; |
10974 | 11006 | #ifdef cimg_use_openmp |
10975 | -#pragma omp parallel for if (size()>=32768) | |
11007 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
10976 | 11008 | #endif |
10977 | 11009 | cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)value); |
10978 | 11010 | return *this; |
... | ... | @@ -10983,39 +11015,7 @@ namespace cimg_library_suffixed { |
10983 | 11015 | Similar to operator+=(const char*), except that it performs a bitwise OR operation instead of an addition. |
10984 | 11016 | **/ |
10985 | 11017 | CImg<T>& operator|=(const char *const expression) { |
10986 | - if (is_empty()) return *this; | |
10987 | - const unsigned int omode = cimg::exception_mode(); | |
10988 | - cimg::exception_mode(0); | |
10989 | - try { | |
10990 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
10991 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator|="); | |
10992 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
10993 | - if (*expression=='<') | |
10994 | - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp(x,y,z,c)); --ptrd; } | |
10995 | - else if (*expression=='>') | |
10996 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp(x,y,z,c)); ++ptrd; } | |
10997 | - else { | |
10998 | -#ifdef cimg_use_openmp | |
10999 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
11000 | -#pragma omp parallel | |
11001 | - { | |
11002 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
11003 | -#pragma omp for collapse(3) | |
11004 | - cimg_forYZC(*this,y,z,c) { | |
11005 | - T *ptrd = data(0,y,z,c); | |
11006 | - cimg_forX(*this,x) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)lmp(x,y,z,c)); ++ptrd; } | |
11007 | - } | |
11008 | - } | |
11009 | - else | |
11010 | -#endif | |
11011 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp(x,y,z,c)); ++ptrd; } | |
11012 | - } | |
11013 | - } catch (CImgException&) { | |
11014 | - cimg::exception_mode(omode); | |
11015 | - *this|=CImg<T>(_width,_height,_depth,_spectrum,expression,true); | |
11016 | - } | |
11017 | - cimg::exception_mode(omode); | |
11018 | - return *this; | |
11018 | + return *this|=(+*this)._fill(expression,true,true,0,0,"operator|=",this); | |
11019 | 11019 | } |
11020 | 11020 | |
11021 | 11021 | //! In-place bitwise OR operator. |
... | ... | @@ -11075,7 +11075,7 @@ namespace cimg_library_suffixed { |
11075 | 11075 | CImg<T>& operator^=(const t value) { |
11076 | 11076 | if (is_empty()) return *this; |
11077 | 11077 | #ifdef cimg_use_openmp |
11078 | -#pragma omp parallel for if (size()>=32768) | |
11078 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
11079 | 11079 | #endif |
11080 | 11080 | cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)value); |
11081 | 11081 | return *this; |
... | ... | @@ -11088,39 +11088,7 @@ namespace cimg_library_suffixed { |
11088 | 11088 | - It does \e not compute the \e power of pixel values. For this purpose, use pow(const char*) instead. |
11089 | 11089 | **/ |
11090 | 11090 | CImg<T>& operator^=(const char *const expression) { |
11091 | - if (is_empty()) return *this; | |
11092 | - const unsigned int omode = cimg::exception_mode(); | |
11093 | - cimg::exception_mode(0); | |
11094 | - try { | |
11095 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
11096 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator^="); | |
11097 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
11098 | - if (*expression=='<') | |
11099 | - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp(x,y,z,c)); --ptrd; } | |
11100 | - else if (*expression=='>') | |
11101 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp(x,y,z,c)); ++ptrd; } | |
11102 | - else { | |
11103 | -#ifdef cimg_use_openmp | |
11104 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
11105 | -#pragma omp parallel | |
11106 | - { | |
11107 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
11108 | -#pragma omp for collapse(3) | |
11109 | - cimg_forYZC(*this,y,z,c) { | |
11110 | - T *ptrd = data(0,y,z,c); | |
11111 | - cimg_forX(*this,x) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)lmp(x,y,z,c)); ++ptrd; } | |
11112 | - } | |
11113 | - } | |
11114 | - else | |
11115 | -#endif | |
11116 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp(x,y,z,c)); ++ptrd; } | |
11117 | - } | |
11118 | - } catch (CImgException&) { | |
11119 | - cimg::exception_mode(omode); | |
11120 | - *this^=CImg<T>(_width,_height,_depth,_spectrum,expression,true); | |
11121 | - } | |
11122 | - cimg::exception_mode(omode); | |
11123 | - return *this; | |
11091 | + return *this^=(+*this)._fill(expression,true,true,0,0,"operator^=",this); | |
11124 | 11092 | } |
11125 | 11093 | |
11126 | 11094 | //! In-place bitwise XOR operator. |
... | ... | @@ -11180,7 +11148,7 @@ namespace cimg_library_suffixed { |
11180 | 11148 | CImg<T>& operator<<=(const t value) { |
11181 | 11149 | if (is_empty()) return *this; |
11182 | 11150 | #ifdef cimg_use_openmp |
11183 | -#pragma omp parallel for if (size()>=65536) | |
11151 | +#pragma omp parallel for cimg_openmp_if(size()>=65536) | |
11184 | 11152 | #endif |
11185 | 11153 | cimg_rof(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) << (int)value); |
11186 | 11154 | return *this; |
... | ... | @@ -11191,37 +11159,7 @@ namespace cimg_library_suffixed { |
11191 | 11159 | Similar to operator+=(const char*), except that it performs a bitwise left shift instead of an addition. |
11192 | 11160 | **/ |
11193 | 11161 | CImg<T>& operator<<=(const char *const expression) { |
11194 | - if (is_empty()) return *this; | |
11195 | - const unsigned int omode = cimg::exception_mode(); | |
11196 | - cimg::exception_mode(0); | |
11197 | - try { | |
11198 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
11199 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<="); | |
11200 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
11201 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); --ptrd; } | |
11202 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); ++ptrd; } | |
11203 | - else { | |
11204 | -#ifdef cimg_use_openmp | |
11205 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
11206 | -#pragma omp parallel | |
11207 | - { | |
11208 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
11209 | -#pragma omp for collapse(3) | |
11210 | - cimg_forYZC(*this,y,z,c) { | |
11211 | - T *ptrd = data(0,y,z,c); | |
11212 | - cimg_forX(*this,x) { *ptrd = (T)((long)*ptrd << (int)lmp(x,y,z,c)); ++ptrd; } | |
11213 | - } | |
11214 | - } | |
11215 | - else | |
11216 | -#endif | |
11217 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); ++ptrd; } | |
11218 | - } | |
11219 | - } catch (CImgException&) { | |
11220 | - cimg::exception_mode(omode); | |
11221 | - *this<<=CImg<T>(_width,_height,_depth,_spectrum,expression,true); | |
11222 | - } | |
11223 | - cimg::exception_mode(omode); | |
11224 | - return *this; | |
11162 | + return *this<<=(+*this)._fill(expression,true,true,0,0,"operator<<=",this); | |
11225 | 11163 | } |
11226 | 11164 | |
11227 | 11165 | //! In-place bitwise left shift operator. |
... | ... | @@ -11280,7 +11218,7 @@ namespace cimg_library_suffixed { |
11280 | 11218 | CImg<T>& operator>>=(const t value) { |
11281 | 11219 | if (is_empty()) return *this; |
11282 | 11220 | #ifdef cimg_use_openmp |
11283 | -#pragma omp parallel for if (size()>=65536) | |
11221 | +#pragma omp parallel for cimg_openmp_if(size()>=65536) | |
11284 | 11222 | #endif |
11285 | 11223 | cimg_rof(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) >> (int)value); |
11286 | 11224 | return *this; |
... | ... | @@ -11291,37 +11229,7 @@ namespace cimg_library_suffixed { |
11291 | 11229 | Similar to operator+=(const char*), except that it performs a bitwise right shift instead of an addition. |
11292 | 11230 | **/ |
11293 | 11231 | CImg<T>& operator>>=(const char *const expression) { |
11294 | - if (is_empty()) return *this; | |
11295 | - const unsigned int omode = cimg::exception_mode(); | |
11296 | - cimg::exception_mode(0); | |
11297 | - try { | |
11298 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
11299 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<="); | |
11300 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
11301 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); --ptrd; } | |
11302 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); ++ptrd; } | |
11303 | - else { | |
11304 | -#ifdef cimg_use_openmp | |
11305 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
11306 | -#pragma omp parallel | |
11307 | - { | |
11308 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
11309 | -#pragma omp for collapse(3) | |
11310 | - cimg_forYZC(*this,y,z,c) { | |
11311 | - T *ptrd = data(0,y,z,c); | |
11312 | - cimg_forX(*this,x) { *ptrd = (T)((long)*ptrd >> (int)lmp(x,y,z,c)); ++ptrd; } | |
11313 | - } | |
11314 | - } | |
11315 | - else | |
11316 | -#endif | |
11317 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); ++ptrd; } | |
11318 | - } | |
11319 | - } catch (CImgException&) { | |
11320 | - cimg::exception_mode(omode); | |
11321 | - *this>>=CImg<T>(_width,_height,_depth,_spectrum,expression,true); | |
11322 | - } | |
11323 | - cimg::exception_mode(omode); | |
11324 | - return *this; | |
11232 | + return *this>>=(+*this)._fill(expression,true,true,0,0,"operator>>=",this); | |
11325 | 11233 | } |
11326 | 11234 | |
11327 | 11235 | //! In-place bitwise right shift operator. |
... | ... | @@ -11403,25 +11311,7 @@ namespace cimg_library_suffixed { |
11403 | 11311 | \param expression Value string describing the way pixel values are compared. |
11404 | 11312 | **/ |
11405 | 11313 | bool operator==(const char *const expression) const { |
11406 | - if (is_empty()) return !*expression; | |
11407 | - const unsigned int omode = cimg::exception_mode(); | |
11408 | - cimg::exception_mode(0); | |
11409 | - bool is_equal = true; | |
11410 | - try { | |
11411 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
11412 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<="); | |
11413 | - const T *ptrs = *expression=='<'?end() - 1:_data; | |
11414 | - if (*expression=='<') | |
11415 | - cimg_rofXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs--)==mp(x,y,z,c)); } | |
11416 | - else if (*expression=='>') | |
11417 | - cimg_forXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs++)==mp(x,y,z,c)); } | |
11418 | - else cimg_forXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs++)==mp(x,y,z,c)); } | |
11419 | - } catch (CImgException&) { | |
11420 | - cimg::exception_mode(omode); | |
11421 | - is_equal = (*this==CImg<T>(_width,_height,_depth,_spectrum,expression,true)); | |
11422 | - } | |
11423 | - cimg::exception_mode(omode); | |
11424 | - return is_equal; | |
11314 | + return *this==(+*this)._fill(expression,true,true,0,0,"operator==",this); | |
11425 | 11315 | } |
11426 | 11316 | |
11427 | 11317 | //! Test if two images have the same size and values. |
... | ... | @@ -12946,6 +12836,8 @@ namespace cimg_library_suffixed { |
12946 | 12836 | of the image instance (written in base 10), separated by specified \c separator character. |
12947 | 12837 | \param separator A \c char character which specifies the separator between values in the returned C-string. |
12948 | 12838 | \param max_size Maximum size of the returned image. |
12839 | + \param format For float-values, tell the printf format used to generate the ascii representation of the numbers. | |
12840 | + (or \c 0 for default representation). | |
12949 | 12841 | \note |
12950 | 12842 | - The returned image is never empty. |
12951 | 12843 | - For an empty image instance, the returned string is <tt>""</tt>. |
... | ... | @@ -12953,15 +12845,18 @@ namespace cimg_library_suffixed { |
12953 | 12845 | - Otherwise, if the maximum number of string characters is exceeded, the value string is cut off |
12954 | 12846 | and terminated by character \c '\0'. In that case, the returned image size is <tt>max_size + 1</tt>. |
12955 | 12847 | **/ |
12956 | - CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const { | |
12848 | + CImg<charT> value_string(const char separator=',', const unsigned int max_size=0, | |
12849 | + const char *const format=0) const { | |
12957 | 12850 | if (is_empty()) return CImg<charT>::string(""); |
12958 | 12851 | CImgList<charT> items; |
12959 | 12852 | CImg<charT> s_item(256); *s_item = 0; |
12960 | 12853 | const T *ptrs = _data; |
12961 | 12854 | unsigned int string_size = 0; |
12855 | + const char *const _format = format?format:cimg::type<T>::format(); | |
12856 | + | |
12962 | 12857 | for (unsigned long off = 0, siz = (unsigned int)size(); off<siz && string_size<=max_size; ++off) { |
12963 | - const unsigned int printed_size = 1U + cimg_snprintf(s_item,s_item._width, | |
12964 | - cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++))); | |
12858 | + const unsigned int printed_size = 1U + cimg_snprintf(s_item,s_item._width,_format, | |
12859 | + cimg::type<T>::format(*(ptrs++))); | |
12965 | 12860 | CImg<charT> item(s_item._data,printed_size); |
12966 | 12861 | item[printed_size - 1] = separator; |
12967 | 12862 | item.move_to(items); |
... | ... | @@ -13011,9 +12906,9 @@ namespace cimg_library_suffixed { |
13011 | 12906 | return false; |
13012 | 12907 | } |
13013 | 12908 | |
13014 | - //! Test if image instance contains a 'nan' value. | |
12909 | + //! Test if image instance contains a NaN value. | |
13015 | 12910 | /** |
13016 | - Return \c true, if image instance contains a 'nan' value, and \c false otherwise. | |
12911 | + Return \c true, if image instance contains a NaN value, and \c false otherwise. | |
13017 | 12912 | **/ |
13018 | 12913 | bool is_nan() const { |
13019 | 12914 | if (cimg::type<T>::is_float()) cimg_for(*this,p,T) if (cimg::type<T>::is_nan((float)*p)) return true; |
... | ... | @@ -13430,7 +13325,7 @@ namespace cimg_library_suffixed { |
13430 | 13325 | // Check consistency for the particular case of an empty 3d object. |
13431 | 13326 | if (is_empty()) { |
13432 | 13327 | if (primitives || colors || opacities) { |
13433 | - if (error_message) std::sprintf(error_message, | |
13328 | + if (error_message) cimg_sprintf(error_message, | |
13434 | 13329 | "3d object (%u,%u) defines no vertices but %u primitives, " |
13435 | 13330 | "%u colors and %lu opacities", |
13436 | 13331 | _width,primitives._width,primitives._width, |
... | ... | @@ -13442,19 +13337,19 @@ namespace cimg_library_suffixed { |
13442 | 13337 | |
13443 | 13338 | // Check consistency of vertices. |
13444 | 13339 | if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions. |
13445 | - if (error_message) std::sprintf(error_message, | |
13340 | + if (error_message) cimg_sprintf(error_message, | |
13446 | 13341 | "3d object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)", |
13447 | 13342 | _width,primitives._width,_width,_height,_depth,_spectrum); |
13448 | 13343 | return false; |
13449 | 13344 | } |
13450 | 13345 | if (colors._width>primitives._width + 1) { |
13451 | - if (error_message) std::sprintf(error_message, | |
13346 | + if (error_message) cimg_sprintf(error_message, | |
13452 | 13347 | "3d object (%u,%u) defines %u colors", |
13453 | 13348 | _width,primitives._width,colors._width); |
13454 | 13349 | return false; |
13455 | 13350 | } |
13456 | 13351 | if (opacities.size()>primitives._width) { |
13457 | - if (error_message) std::sprintf(error_message, | |
13352 | + if (error_message) cimg_sprintf(error_message, | |
13458 | 13353 | "3d object (%u,%u) defines %lu opacities", |
13459 | 13354 | _width,primitives._width,(unsigned long)opacities.size()); |
13460 | 13355 | return false; |
... | ... | @@ -13469,7 +13364,7 @@ namespace cimg_library_suffixed { |
13469 | 13364 | case 1 : { // Point. |
13470 | 13365 | const unsigned int i0 = (unsigned int)primitive(0); |
13471 | 13366 | if (i0>=_width) { |
13472 | - if (error_message) std::sprintf(error_message, | |
13367 | + if (error_message) cimg_sprintf(error_message, | |
13473 | 13368 | "3d object (%u,%u) refers to invalid vertex indice %u in " |
13474 | 13369 | "point primitive [%u]", |
13475 | 13370 | _width,primitives._width,i0,l); |
... | ... | @@ -13481,7 +13376,7 @@ namespace cimg_library_suffixed { |
13481 | 13376 | i0 = (unsigned int)primitive(0), |
13482 | 13377 | i1 = (unsigned int)primitive(1); |
13483 | 13378 | if (i0>=_width || i1>=_width) { |
13484 | - if (error_message) std::sprintf(error_message, | |
13379 | + if (error_message) cimg_sprintf(error_message, | |
13485 | 13380 | "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in " |
13486 | 13381 | "sphere primitive [%u]", |
13487 | 13382 | _width,primitives._width,i0,i1,l); |
... | ... | @@ -13494,7 +13389,7 @@ namespace cimg_library_suffixed { |
13494 | 13389 | i0 = (unsigned int)primitive(0), |
13495 | 13390 | i1 = (unsigned int)primitive(1); |
13496 | 13391 | if (i0>=_width || i1>=_width) { |
13497 | - if (error_message) std::sprintf(error_message, | |
13392 | + if (error_message) cimg_sprintf(error_message, | |
13498 | 13393 | "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in " |
13499 | 13394 | "segment primitive [%u]", |
13500 | 13395 | _width,primitives._width,i0,i1,l); |
... | ... | @@ -13508,7 +13403,7 @@ namespace cimg_library_suffixed { |
13508 | 13403 | i1 = (unsigned int)primitive(1), |
13509 | 13404 | i2 = (unsigned int)primitive(2); |
13510 | 13405 | if (i0>=_width || i1>=_width || i2>=_width) { |
13511 | - if (error_message) std::sprintf(error_message, | |
13406 | + if (error_message) cimg_sprintf(error_message, | |
13512 | 13407 | "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in " |
13513 | 13408 | "triangle primitive [%u]", |
13514 | 13409 | _width,primitives._width,i0,i1,i2,l); |
... | ... | @@ -13523,7 +13418,7 @@ namespace cimg_library_suffixed { |
13523 | 13418 | i2 = (unsigned int)primitive(2), |
13524 | 13419 | i3 = (unsigned int)primitive(3); |
13525 | 13420 | if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) { |
13526 | - if (error_message) std::sprintf(error_message, | |
13421 | + if (error_message) cimg_sprintf(error_message, | |
13527 | 13422 | "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in " |
13528 | 13423 | "quadrangle primitive [%u]", |
13529 | 13424 | _width,primitives._width,i0,i1,i2,i3,l); |
... | ... | @@ -13531,7 +13426,7 @@ namespace cimg_library_suffixed { |
13531 | 13426 | } |
13532 | 13427 | } break; |
13533 | 13428 | default : |
13534 | - if (error_message) std::sprintf(error_message, | |
13429 | + if (error_message) cimg_sprintf(error_message, | |
13535 | 13430 | "3d object (%u,%u) defines an invalid primitive [%u] of size %u", |
13536 | 13431 | _width,primitives._width,l,(unsigned int)psiz); |
13537 | 13432 | return false; |
... | ... | @@ -13542,7 +13437,7 @@ namespace cimg_library_suffixed { |
13542 | 13437 | cimglist_for(colors,c) { |
13543 | 13438 | const CImg<tc>& color = colors[c]; |
13544 | 13439 | if (!color) { |
13545 | - if (error_message) std::sprintf(error_message, | |
13440 | + if (error_message) cimg_sprintf(error_message, | |
13546 | 13441 | "3d object (%u,%u) defines no color for primitive [%u]", |
13547 | 13442 | _width,primitives._width,c); |
13548 | 13443 | return false; |
... | ... | @@ -13553,7 +13448,7 @@ namespace cimg_library_suffixed { |
13553 | 13448 | if (colors._width>primitives._width) { |
13554 | 13449 | const CImg<tc> &light = colors.back(); |
13555 | 13450 | if (!light || light._depth>1) { |
13556 | - if (error_message) std::sprintf(error_message, | |
13451 | + if (error_message) cimg_sprintf(error_message, | |
13557 | 13452 | "3d object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)", |
13558 | 13453 | _width,primitives._width,light._width, |
13559 | 13454 | light._height,light._depth,light._spectrum); |
... | ... | @@ -13579,7 +13474,7 @@ namespace cimg_library_suffixed { |
13579 | 13474 | |
13580 | 13475 | // Check instance dimension and header. |
13581 | 13476 | if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) { |
13582 | - if (error_message) std::sprintf(error_message, | |
13477 | + if (error_message) cimg_sprintf(error_message, | |
13583 | 13478 | "CImg3d has invalid dimensions (%u,%u,%u,%u)", |
13584 | 13479 | _width,_height,_depth,_spectrum); |
13585 | 13480 | return false; |
... | ... | @@ -13587,7 +13482,7 @@ namespace cimg_library_suffixed { |
13587 | 13482 | const T *ptrs = _data, *const ptre = end(); |
13588 | 13483 | if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') || |
13589 | 13484 | !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) { |
13590 | - if (error_message) std::sprintf(error_message, | |
13485 | + if (error_message) cimg_sprintf(error_message, | |
13591 | 13486 | "CImg3d header not found"); |
13592 | 13487 | return false; |
13593 | 13488 | } |
... | ... | @@ -13599,7 +13494,7 @@ namespace cimg_library_suffixed { |
13599 | 13494 | if (!full_check) { |
13600 | 13495 | const unsigned long minimal_size = 8UL + 3*nb_points + 6*nb_primitives; |
13601 | 13496 | if (_data + minimal_size>ptre) { |
13602 | - if (error_message) std::sprintf(error_message, | |
13497 | + if (error_message) cimg_sprintf(error_message, | |
13603 | 13498 | "CImg3d (%u,%u) has only %lu values, while at least %lu values were expected", |
13604 | 13499 | nb_points,nb_primitives,size(),minimal_size); |
13605 | 13500 | return false; |
... | ... | @@ -13609,13 +13504,13 @@ namespace cimg_library_suffixed { |
13609 | 13504 | // Check consistency of vertex data. |
13610 | 13505 | if (!nb_points) { |
13611 | 13506 | if (nb_primitives) { |
13612 | - if (error_message) std::sprintf(error_message, | |
13507 | + if (error_message) cimg_sprintf(error_message, | |
13613 | 13508 | "CImg3d (%u,%u) defines no vertices but %u primitives", |
13614 | 13509 | nb_points,nb_primitives,nb_primitives); |
13615 | 13510 | return false; |
13616 | 13511 | } |
13617 | 13512 | if (ptrs!=ptre) { |
13618 | - if (error_message) std::sprintf(error_message, | |
13513 | + if (error_message) cimg_sprintf(error_message, | |
13619 | 13514 | "CImg3d (%u,%u) is an empty object but contains %u value%s " |
13620 | 13515 | "more than expected", |
13621 | 13516 | nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":""); |
... | ... | @@ -13624,7 +13519,7 @@ namespace cimg_library_suffixed { |
13624 | 13519 | return true; |
13625 | 13520 | } |
13626 | 13521 | if (ptrs + 3*nb_points>ptre) { |
13627 | - if (error_message) std::sprintf(error_message, | |
13522 | + if (error_message) cimg_sprintf(error_message, | |
13628 | 13523 | "CImg3d (%u,%u) defines only %u vertices data", |
13629 | 13524 | nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3); |
13630 | 13525 | return false; |
... | ... | @@ -13633,7 +13528,7 @@ namespace cimg_library_suffixed { |
13633 | 13528 | |
13634 | 13529 | // Check consistency of primitive data. |
13635 | 13530 | if (ptrs==ptre) { |
13636 | - if (error_message) std::sprintf(error_message, | |
13531 | + if (error_message) cimg_sprintf(error_message, | |
13637 | 13532 | "CImg3d (%u,%u) defines %u vertices but no primitive", |
13638 | 13533 | nb_points,nb_primitives,nb_points); |
13639 | 13534 | return false; |
... | ... | @@ -13647,7 +13542,7 @@ namespace cimg_library_suffixed { |
13647 | 13542 | case 1 : { // Point. |
13648 | 13543 | const unsigned int i0 = cimg::float2uint((float)*(ptrs++)); |
13649 | 13544 | if (i0>=nb_points) { |
13650 | - if (error_message) std::sprintf(error_message, | |
13545 | + if (error_message) cimg_sprintf(error_message, | |
13651 | 13546 | "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive [%u]", |
13652 | 13547 | nb_points,nb_primitives,i0,p); |
13653 | 13548 | return false; |
... | ... | @@ -13659,7 +13554,7 @@ namespace cimg_library_suffixed { |
13659 | 13554 | i1 = cimg::float2uint((float)*(ptrs++)); |
13660 | 13555 | ptrs+=3; |
13661 | 13556 | if (i0>=nb_points || i1>=nb_points) { |
13662 | - if (error_message) std::sprintf(error_message, | |
13557 | + if (error_message) cimg_sprintf(error_message, | |
13663 | 13558 | "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in " |
13664 | 13559 | "sphere primitive [%u]", |
13665 | 13560 | nb_points,nb_primitives,i0,i1,p); |
... | ... | @@ -13672,7 +13567,7 @@ namespace cimg_library_suffixed { |
13672 | 13567 | i1 = cimg::float2uint((float)*(ptrs++)); |
13673 | 13568 | if (nb_inds==6) ptrs+=4; |
13674 | 13569 | if (i0>=nb_points || i1>=nb_points) { |
13675 | - if (error_message) std::sprintf(error_message, | |
13570 | + if (error_message) cimg_sprintf(error_message, | |
13676 | 13571 | "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in " |
13677 | 13572 | "segment primitive [%u]", |
13678 | 13573 | nb_points,nb_primitives,i0,i1,p); |
... | ... | @@ -13686,7 +13581,7 @@ namespace cimg_library_suffixed { |
13686 | 13581 | i2 = cimg::float2uint((float)*(ptrs++)); |
13687 | 13582 | if (nb_inds==9) ptrs+=6; |
13688 | 13583 | if (i0>=nb_points || i1>=nb_points || i2>=nb_points) { |
13689 | - if (error_message) std::sprintf(error_message, | |
13584 | + if (error_message) cimg_sprintf(error_message, | |
13690 | 13585 | "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in " |
13691 | 13586 | "triangle primitive [%u]", |
13692 | 13587 | nb_points,nb_primitives,i0,i1,i2,p); |
... | ... | @@ -13701,7 +13596,7 @@ namespace cimg_library_suffixed { |
13701 | 13596 | i3 = cimg::float2uint((float)*(ptrs++)); |
13702 | 13597 | if (nb_inds==12) ptrs+=8; |
13703 | 13598 | if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) { |
13704 | - if (error_message) std::sprintf(error_message, | |
13599 | + if (error_message) cimg_sprintf(error_message, | |
13705 | 13600 | "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in " |
13706 | 13601 | "quadrangle primitive [%u]", |
13707 | 13602 | nb_points,nb_primitives,i0,i1,i2,i3,p); |
... | ... | @@ -13709,13 +13604,13 @@ namespace cimg_library_suffixed { |
13709 | 13604 | } |
13710 | 13605 | } break; |
13711 | 13606 | default : |
13712 | - if (error_message) std::sprintf(error_message, | |
13607 | + if (error_message) cimg_sprintf(error_message, | |
13713 | 13608 | "CImg3d (%u,%u) defines an invalid primitive [%u] of size %u", |
13714 | 13609 | nb_points,nb_primitives,p,nb_inds); |
13715 | 13610 | return false; |
13716 | 13611 | } |
13717 | 13612 | if (ptrs>ptre) { |
13718 | - if (error_message) std::sprintf(error_message, | |
13613 | + if (error_message) cimg_sprintf(error_message, | |
13719 | 13614 | "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], " |
13720 | 13615 | "%u values missing", |
13721 | 13616 | nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre)); |
... | ... | @@ -13725,7 +13620,7 @@ namespace cimg_library_suffixed { |
13725 | 13620 | |
13726 | 13621 | // Check consistency of color data. |
13727 | 13622 | if (ptrs==ptre) { |
13728 | - if (error_message) std::sprintf(error_message, | |
13623 | + if (error_message) cimg_sprintf(error_message, | |
13729 | 13624 | "CImg3d (%u,%u) defines no color/texture data", |
13730 | 13625 | nb_points,nb_primitives); |
13731 | 13626 | return false; |
... | ... | @@ -13739,7 +13634,7 @@ namespace cimg_library_suffixed { |
13739 | 13634 | s = (unsigned int)*(ptrs - 1); |
13740 | 13635 | if (!h && !s) { |
13741 | 13636 | if (w>=c) { |
13742 | - if (error_message) std::sprintf(error_message, | |
13637 | + if (error_message) cimg_sprintf(error_message, | |
13743 | 13638 | "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u " |
13744 | 13639 | "for primitive [%u]", |
13745 | 13640 | nb_points,nb_primitives,w,c); |
... | ... | @@ -13748,7 +13643,7 @@ namespace cimg_library_suffixed { |
13748 | 13643 | } else ptrs+=w*h*s; |
13749 | 13644 | } |
13750 | 13645 | if (ptrs>ptre) { |
13751 | - if (error_message) std::sprintf(error_message, | |
13646 | + if (error_message) cimg_sprintf(error_message, | |
13752 | 13647 | "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], " |
13753 | 13648 | "%u values missing", |
13754 | 13649 | nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre)); |
... | ... | @@ -13758,7 +13653,7 @@ namespace cimg_library_suffixed { |
13758 | 13653 | |
13759 | 13654 | // Check consistency of opacity data. |
13760 | 13655 | if (ptrs==ptre) { |
13761 | - if (error_message) std::sprintf(error_message, | |
13656 | + if (error_message) cimg_sprintf(error_message, | |
13762 | 13657 | "CImg3d (%u,%u) defines no opacity data", |
13763 | 13658 | nb_points,nb_primitives); |
13764 | 13659 | return false; |
... | ... | @@ -13771,7 +13666,7 @@ namespace cimg_library_suffixed { |
13771 | 13666 | s = (unsigned int)*(ptrs - 1); |
13772 | 13667 | if (!h && !s) { |
13773 | 13668 | if (w>=o) { |
13774 | - if (error_message) std::sprintf(error_message, | |
13669 | + if (error_message) cimg_sprintf(error_message, | |
13775 | 13670 | "CImg3d (%u,%u) refers to invalid shared opacity indice %u " |
13776 | 13671 | "for primitive [%u]", |
13777 | 13672 | nb_points,nb_primitives,w,o); |
... | ... | @@ -13780,7 +13675,7 @@ namespace cimg_library_suffixed { |
13780 | 13675 | } else ptrs+=w*h*s; |
13781 | 13676 | } |
13782 | 13677 | if (ptrs>ptre) { |
13783 | - if (error_message) std::sprintf(error_message, | |
13678 | + if (error_message) cimg_sprintf(error_message, | |
13784 | 13679 | "CImg3d (%u,%u) has incomplete opacity data for primitive [%u]", |
13785 | 13680 | nb_points,nb_primitives,o); |
13786 | 13681 | return false; |
... | ... | @@ -13789,7 +13684,7 @@ namespace cimg_library_suffixed { |
13789 | 13684 | |
13790 | 13685 | // Check end of data. |
13791 | 13686 | if (ptrs<ptre) { |
13792 | - if (error_message) std::sprintf(error_message, | |
13687 | + if (error_message) cimg_sprintf(error_message, | |
13793 | 13688 | "CImg3d (%u,%u) contains %u value%s more than expected", |
13794 | 13689 | nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":""); |
13795 | 13690 | return false; |
... | ... | @@ -13808,1106 +13703,5206 @@ namespace cimg_library_suffixed { |
13808 | 13703 | //@{ |
13809 | 13704 | //------------------------------------- |
13810 | 13705 | |
13811 | - // Define the math formula parser/compiler and evaluator. | |
13706 | + // Define the math formula parser/compiler and expression evaluator. | |
13812 | 13707 | struct _cimg_math_parser { |
13813 | - CImgList<longT> code; | |
13814 | - CImg<longT> opcode; | |
13815 | - const CImg<longT>* p_code; | |
13816 | - CImgList<charT> labelM; | |
13817 | - CImg<uintT> level, labelMpos, reserved_label; | |
13818 | 13708 | CImg<doubleT> mem; |
13819 | - CImg<charT> expr; | |
13820 | - const CImg<T>& reference; | |
13821 | - CImg<Tdouble> reference_stats; | |
13822 | - double median_value; | |
13823 | - bool is_median_value; | |
13824 | - unsigned int mempos, result; | |
13709 | + CImg<intT> memtype; | |
13710 | + CImgList<uptrT> _code, &code; | |
13711 | + CImg<uptrT> opcode; | |
13712 | + const CImg<uptrT> *p_code_begin, *p_code_end, *p_code; | |
13713 | + | |
13714 | + CImg<charT> expr, pexpr; | |
13715 | + const CImg<T>& imgin; | |
13716 | + const CImgList<T>& listin; | |
13717 | + CImg<T> &imgout; | |
13718 | + CImgList<T>& listout; | |
13719 | + | |
13720 | + CImg<doubleT> _img_stats, &img_stats; | |
13721 | + CImgList<doubleT> _list_stats, &list_stats, _list_median, &list_median; | |
13722 | + CImg<uintT> mem_img_stats; | |
13723 | + | |
13724 | + CImg<uintT> level, variable_pos, reserved_label; | |
13725 | + CImgList<charT> variable_def, function_def, function_body; | |
13726 | + char *user_function; | |
13727 | + | |
13728 | + unsigned int mempos, mem_img_median, debug_indent, init_size, result_dim; | |
13729 | + double *result; | |
13825 | 13730 | const char *const calling_function; |
13826 | 13731 | typedef double (*mp_func)(_cimg_math_parser&); |
13827 | 13732 | |
13733 | +#define _cimg_mp_is_constant(arg) (memtype[arg]==1) // Is constant? | |
13734 | +#define _cimg_mp_is_scalar(arg) (memtype[arg]<2) // Is scalar? | |
13735 | +#define _cimg_mp_is_temp(arg) (!memtype[arg]) // Is temporary scalar? | |
13736 | +#define _cimg_mp_is_variable(arg) (memtype[arg]==-1) // Is scalar variable? | |
13737 | +#define _cimg_mp_is_vector(arg) (memtype[arg]>1) // Is vector? | |
13738 | +#define _cimg_mp_vector_size(arg) (_cimg_mp_is_scalar(arg)?0U:(unsigned int)memtype[arg] - 1) // Vector size | |
13739 | +#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) | |
13744 | +#define _cimg_mp_defunc(mp) (*(mp_func)(*(mp).opcode))(mp) | |
13828 | 13745 | #define _cimg_mp_return(x) { *se = saved_char; return x; } |
13829 | -#define _cimg_mp_opcode0(op) _cimg_mp_return(opcode0(op)); | |
13830 | -#define _cimg_mp_opcode1(op,i1) _cimg_mp_return(opcode1(op,i1)); | |
13831 | -#define _cimg_mp_opcode2(op,i1,i2) { const unsigned int _i1 = i1, _i2 = i2; _cimg_mp_return(opcode2(op,_i1,_i2)); } | |
13832 | -#define _cimg_mp_opcode3(op,i1,i2,i3) \ | |
13833 | - { const unsigned int _i1 = i1, _i2 = i2, _i3 = i3; _cimg_mp_return(opcode3(op,_i1,_i2,_i3)); } | |
13834 | -#define _cimg_mp_opcode6(op,i1,i2,i3,i4,i5,i6) \ | |
13835 | - { const unsigned int _i1 = i1, _i2 = i2, _i3 = i3, _i4 = i4, _i5 = i5, _i6 = i6; \ | |
13836 | - _cimg_mp_return(opcode6(op,_i1,_i2,_i3,_i4,_i5,_i6)); } | |
13837 | - | |
13838 | -#if defined(_WIN64) | |
13839 | - // On Win64 and gcc 4.7, sizeof(long)!=sizeof(pointer), so a workaround is needed.. | |
13840 | -#define _cimg_mp_enfunc(op) (long)((char*)(op) - (char*)mp_u) | |
13841 | -#define _cimg_mp_defunc(mp) (*(mp_func)((char*)mp_u + (mp).opcode[0]))(mp) | |
13842 | -#else | |
13843 | -#define _cimg_mp_enfunc(op) (long)(op) | |
13844 | -#define _cimg_mp_defunc(mp) (*(mp_func)((mp).opcode[0]))(mp) | |
13845 | -#endif | |
13746 | +#define _cimg_mp_constant(val) _cimg_mp_return(constant(val)) | |
13747 | +#define _cimg_mp_scalar0(op) _cimg_mp_return(scalar0(op)) | |
13748 | +#define _cimg_mp_scalar1(op,i1) _cimg_mp_return(scalar1(op,i1)) | |
13749 | +#define _cimg_mp_scalar2(op,i1,i2) _cimg_mp_return(scalar2(op,i1,i2)) | |
13750 | +#define _cimg_mp_scalar3(op,i1,i2,i3) _cimg_mp_return(scalar3(op,i1,i2,i3)) | |
13751 | +#define _cimg_mp_scalar6(op,i1,i2,i3,i4,i5,i6) _cimg_mp_return(scalar6(op,i1,i2,i3,i4,i5,i6)) | |
13752 | +#define _cimg_mp_scalar7(op,i1,i2,i3,i4,i5,i6,i7) _cimg_mp_return(scalar7(op,i1,i2,i3,i4,i5,i6,i7)) | |
13753 | +#define _cimg_mp_vector1_v(op,i1) _cimg_mp_return(vector1_v(op,i1)) | |
13754 | +#define _cimg_mp_vector2_sv(op,i1,i2) _cimg_mp_return(vector2_sv(op,i1,i2)) | |
13755 | +#define _cimg_mp_vector2_vs(op,i1,i2) _cimg_mp_return(vector2_vs(op,i1,i2)) | |
13756 | +#define _cimg_mp_vector2_vv(op,i1,i2) _cimg_mp_return(vector2_vv(op,i1,i2)) | |
13757 | +#define _cimg_mp_vector3_vss(op,i1,i2,i3) _cimg_mp_return(vector3_vss(op,i1,i2,i3)) | |
13846 | 13758 | |
13847 | 13759 | // Constructors. |
13848 | - _cimg_math_parser():reference(CImg<T>::empty()),median_value(0),is_median_value(false),calling_function(0) {} | |
13849 | - | |
13850 | - _cimg_math_parser(const CImg<T>& img, const char *const expression, const char *const funcname=0): | |
13851 | - reference(img),median_value(0),is_median_value(false),calling_function(funcname?funcname:"cimg_math_parser") { | |
13760 | + _cimg_math_parser(const char *const expression, const char *const funcname=0, | |
13761 | + const CImg<T>& img_input=CImg<T>::const_empty(), CImg<T> *const img_output=0, | |
13762 | + const CImgList<T> *const list_input=0, CImgList<T> *const list_output=0): | |
13763 | + code(_code),imgin(img_input),listin(list_input?*list_input:CImgList<T>::const_empty()), | |
13764 | + imgout(img_output?*img_output:CImg<T>::empty()),listout(list_output?*list_output:CImgList<T>::empty()), | |
13765 | + 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") { | |
13852 | 13768 | if (!expression || !*expression) |
13853 | 13769 | throw CImgArgumentException("[_cimg_math_parser] " |
13854 | - "CImg<%s>::%s(): Empty specified expression.", | |
13855 | - pixel_type(),calling_function); | |
13856 | - CImg<charT>::string(expression).move_to(expr); | |
13770 | + "CImg<%s>::%s: Empty expression.", | |
13771 | + pixel_type(),_cimg_mp_calling_function); | |
13772 | + const char *_expression = expression; | |
13773 | + while (*_expression && *_expression<=' ') ++_expression; | |
13774 | + CImg<charT>::string(_expression).move_to(expr); | |
13775 | + | |
13776 | + // Ease the retrieval of previous non-space characters afterwards. | |
13777 | + pexpr.assign(expr._width); | |
13778 | + const char *ps; | |
13779 | + char c, *pe = pexpr._data; | |
13780 | + for (ps = expr._data, c = ' '; *ps; ++ps) { | |
13781 | + if (*ps!=' ') c = *ps; | |
13782 | + *(pe++) = c; | |
13783 | + } | |
13784 | + *pe = 0; | |
13785 | + | |
13786 | + // Count parentheses/brackets level of expression. | |
13857 | 13787 | level.assign(expr._width - 1); |
13858 | - int lv = 0; // Count parentheses/brackets level of expression. | |
13788 | + int lv = 0; | |
13859 | 13789 | unsigned int *pd = level._data; |
13860 | - for (const char *ps = expr._data; *ps && lv>=0; ++ps) | |
13790 | + for (ps = expr._data; *ps && lv>=0; ++ps) | |
13861 | 13791 | *(pd++) = (unsigned int)(*ps=='('||*ps=='['?lv++:*ps==')'||*ps==']'?--lv:lv); |
13862 | 13792 | if (lv!=0) { |
13793 | + cimg::strellipsize(expr,64); | |
13863 | 13794 | throw CImgArgumentException("[_cimg_math_parser] " |
13864 | - "CImg<%s>::%s(): Unbalanced parentheses/brackets in specified expression '%s'.", | |
13865 | - pixel_type(),calling_function, | |
13795 | + "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.", | |
13796 | + pixel_type(),_cimg_mp_calling_function, | |
13866 | 13797 | expr._data); |
13867 | 13798 | } |
13868 | 13799 | |
13869 | 13800 | // Init constant values. |
13870 | - mem.assign(512); | |
13871 | - mem[0] = 0.0; | |
13872 | - mem[1] = 1.0; | |
13873 | - mem[2] = 2.0; | |
13874 | - mem[3] = 3.0; | |
13875 | - mem[4] = 4.0; | |
13876 | - mem[5] = 5.0; | |
13877 | - mem[6] = (double)reference._width; | |
13878 | - mem[7] = (double)reference._height; | |
13879 | - mem[8] = (double)reference._depth; | |
13880 | - mem[9] = (double)reference._spectrum; | |
13881 | - mem[10] = (double)reference._is_shared; | |
13882 | - mem[11] = (double)reference._width*reference._height; | |
13883 | - mem[12] = (double)reference._width*reference._height*reference._depth; | |
13884 | - mem[13] = (double)reference._width*reference._height*reference._depth*reference._spectrum; | |
13885 | - mem[14] = cimg::PI; | |
13886 | - mem[15] = std::exp(1.0); // Then [16] = x, [17] = y, [18] = z and [19] = c. | |
13887 | - mempos = 20; | |
13888 | - labelMpos.assign(8); | |
13801 | + mem.assign(96); | |
13802 | + memtype.assign(96); | |
13803 | + double *p_mem = mem._data; | |
13804 | + for (unsigned int i = 0; i<=10; ++i) *(p_mem++) = (double)i; // mem[0-10] | |
13805 | + for (unsigned int i = 1; i<=5; ++i) *(p_mem++) = -(double)i; // mem[11-15] | |
13806 | + *(p_mem++) = 0.5; // mem[16] | |
13807 | + *(p_mem++) = 0; // mem[17] = thread_id | |
13808 | + *(p_mem++) = (double)imgin._width; // mem[18] | |
13809 | + *(p_mem++) = (double)imgin._height; // mem[19] | |
13810 | + *(p_mem++) = (double)imgin._depth; // mem[20] | |
13811 | + *(p_mem++) = (double)imgin._spectrum; // mem[21] | |
13812 | + *(p_mem++) = (double)imgin._is_shared; // mem[22] | |
13813 | + *(p_mem++) = (double)imgin._width*imgin._height; // mem[23] | |
13814 | + *(p_mem++) = (double)imgin._width*imgin._height*imgin._depth; // mem[24] | |
13815 | + *(p_mem++) = (double)imgin._width*imgin._height*imgin._depth*imgin._spectrum; // mem[25] | |
13816 | + *(p_mem++) = cimg::PI; // mem[26] | |
13817 | + *(p_mem++) = std::exp(1.0); // mem[27] | |
13818 | + *(p_mem++) = cimg::type<double>::nan(); // mem[28] | |
13819 | + | |
13820 | + // Then, [29] = x, [30] = y, [31] = z and [32] = c. | |
13821 | +#define _cimg_mp_x 29 | |
13822 | +#define _cimg_mp_y 30 | |
13823 | +#define _cimg_mp_z 31 | |
13824 | +#define _cimg_mp_c 32 | |
13825 | + | |
13826 | + // Set value property : | |
13827 | + // { -1 = variable | 0 = regular value | 1 = compile time constant | N>1 = constant ptr to vector[N-1] }. | |
13828 | + std::memset(memtype._data,0,sizeof(int)*memtype._width); | |
13829 | + int *p_memtype = memtype._data; for (unsigned int i = 0; i<_cimg_mp_x; ++i) *(p_memtype++) = 1; | |
13830 | + memtype[17] = 0; | |
13831 | + | |
13832 | + mempos = _cimg_mp_c + 1; | |
13833 | + variable_pos.assign(8); | |
13889 | 13834 | reserved_label.assign(128,1,1,1,~0U); |
13890 | - reserved_label['w'] = 6; | |
13891 | - reserved_label['h'] = 7; | |
13892 | - reserved_label['d'] = 8; | |
13893 | - reserved_label['s'] = 9; | |
13894 | - reserved_label['r'] = 10; | |
13895 | - reserved_label[0] = 11; // wh | |
13896 | - reserved_label[1] = 12; // whd | |
13897 | - reserved_label[2] = 13; // whds | |
13898 | - reserved_label[3] = 14; // pi | |
13899 | - reserved_label['e'] = 15; | |
13900 | - reserved_label['x'] = 16; | |
13901 | - reserved_label['y'] = 17; | |
13902 | - reserved_label['z'] = 18; | |
13903 | - reserved_label['c'] = 19; | |
13904 | - result = compile(expr._data,expr._data + expr._width - 1); // Compile formula into a serie of opcodes. | |
13905 | - } | |
13906 | - | |
13907 | - // Insert code instructions. | |
13908 | - unsigned int opcode0(const mp_func op) { | |
13909 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
13910 | - const unsigned int pos = mempos++; | |
13911 | - CImg<longT>::vector(_cimg_mp_enfunc(op),pos).move_to(code); | |
13912 | - return pos; | |
13913 | - } | |
13914 | - | |
13915 | - unsigned int opcode1(const mp_func op, const unsigned int arg1) { | |
13916 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
13917 | - const unsigned int pos = mempos++; | |
13918 | - CImg<longT>::vector(_cimg_mp_enfunc(op),pos,arg1).move_to(code); | |
13919 | - return pos; | |
13920 | - } | |
13921 | - | |
13922 | - unsigned int opcode2(const mp_func op, const unsigned int arg1, const unsigned int arg2) { | |
13923 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
13924 | - const unsigned int pos = mempos++; | |
13925 | - CImg<longT>::vector(_cimg_mp_enfunc(op),pos,arg1,arg2).move_to(code); | |
13926 | - return pos; | |
13835 | + reserved_label['t'] = 17; | |
13836 | + reserved_label['w'] = 18; | |
13837 | + reserved_label['h'] = 19; | |
13838 | + reserved_label['d'] = 20; | |
13839 | + reserved_label['s'] = 21; | |
13840 | + reserved_label['r'] = 22; | |
13841 | + reserved_label[0] = 23; // wh | |
13842 | + reserved_label[1] = 24; // whd | |
13843 | + reserved_label[2] = 25; // whds | |
13844 | + reserved_label[3] = 26; // pi | |
13845 | + reserved_label['e'] = 27; | |
13846 | + reserved_label[29] = 0; // interpolation | |
13847 | + reserved_label[30] = 0; // boundary | |
13848 | + reserved_label['x'] = _cimg_mp_x; | |
13849 | + reserved_label['y'] = _cimg_mp_y; | |
13850 | + reserved_label['z'] = _cimg_mp_z; | |
13851 | + reserved_label['c'] = _cimg_mp_c; | |
13852 | + // reserved_label[4-28] store also two-char variables: | |
13853 | + // [4] = im, [5] = iM, [6] = ia, [7] = iv, [8] = is, [9] = ip, [10] = ic, | |
13854 | + // [11] = xm, [12] = ym, [13] = zm, [14] = cm, [15] = xM, [16] = yM, [17] = zM, [18]=cM, [19]=i0...[28]=i9, | |
13855 | + | |
13856 | + // Compile expression into a serie of opcodes. | |
13857 | + const unsigned int ind_result = compile(expr._data,expr._data + expr._width - 1,0,0); | |
13858 | + p_code_end = code.end(); | |
13859 | + | |
13860 | + // Free resources used for parsing and prepare for evaluation. | |
13861 | + if (_cimg_mp_is_vector(ind_result)) result_dim = _cimg_mp_vector_size(ind_result); | |
13862 | + mem.resize(mempos,1,1,1,-1); | |
13863 | + result = mem._data + ind_result; | |
13864 | + memtype.assign(); | |
13865 | + level.assign(); | |
13866 | + variable_pos.assign(); | |
13867 | + reserved_label.assign(); | |
13868 | + expr.assign(); | |
13869 | + pexpr.assign(); | |
13870 | + opcode._width = opcode._depth = opcode._spectrum = 1; | |
13871 | + opcode._is_shared = true; | |
13872 | + | |
13873 | + // Execute init() function if any specified. | |
13874 | + p_code_begin = code._data + init_size; | |
13875 | + if (init_size) { | |
13876 | + mem[_cimg_mp_x] = mem[_cimg_mp_y] = mem[_cimg_mp_z] = mem[_cimg_mp_c] = 0; | |
13877 | + for (p_code = code._data; p_code<p_code_begin; ++p_code) { | |
13878 | + const CImg<uptrT> &op = *p_code; | |
13879 | + opcode._data = op._data; opcode._height = op._height; | |
13880 | + const uptrT target = opcode[1]; | |
13881 | + mem[target] = _cimg_mp_defunc(*this); | |
13882 | + } | |
13883 | + } | |
13884 | + } | |
13885 | + | |
13886 | + _cimg_math_parser(): | |
13887 | + code(_code),p_code_begin(0),p_code_end(0), | |
13888 | + imgin(CImg<T>::const_empty()),listin(CImgList<T>::const_empty()), | |
13889 | + imgout(CImg<T>::empty()),listout(CImgList<T>::empty()), | |
13890 | + img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),debug_indent(0), | |
13891 | + result_dim(0),calling_function(0) { | |
13892 | + mem.assign(1 + _cimg_mp_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()() | |
13893 | + result = mem._data; | |
13894 | + } | |
13895 | + | |
13896 | + _cimg_math_parser(const _cimg_math_parser& mp): | |
13897 | + mem(mp.mem),code(mp.code),p_code_begin(mp.p_code_begin),p_code_end(mp.p_code_end), | |
13898 | + 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) { | |
13901 | +#ifdef cimg_use_openmp | |
13902 | + mem[17] = omp_get_thread_num(); | |
13903 | +#endif | |
13904 | + opcode._width = opcode._depth = opcode._spectrum = 1; | |
13905 | + opcode._is_shared = true; | |
13906 | + } | |
13907 | + | |
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; | |
13927 | 13928 | } |
13928 | 13929 | |
13929 | - unsigned int opcode3(const mp_func op, | |
13930 | - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) { | |
13931 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
13932 | - const unsigned int pos = mempos++; | |
13933 | - CImg<longT>::vector(_cimg_mp_enfunc(op),pos,arg1,arg2,arg3).move_to(code); | |
13934 | - return pos; | |
13935 | - } | |
13930 | + // Compilation procedure. | |
13931 | + unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *p_ref) { | |
13932 | + if (depth>256) { | |
13933 | + cimg::strellipsize(expr,64); | |
13934 | + throw CImgArgumentException("[_cimg_math_parser] " | |
13935 | + "CImg<%s>::%s: Call stack overflow (infinite recursion?), " | |
13936 | + "in expression '%s%s%s'.", | |
13937 | + pixel_type(),_cimg_mp_calling_function, | |
13938 | + (ss - 4)>expr._data?"...":"", | |
13939 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
13940 | + se<&expr.back()?"...":""); | |
13941 | + } | |
13936 | 13942 | |
13937 | - unsigned int opcode6(const mp_func op, | |
13938 | - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, | |
13939 | - const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) { | |
13940 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
13941 | - const unsigned int pos = mempos++; | |
13942 | - CImg<longT>::vector(_cimg_mp_enfunc(op),pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code); | |
13943 | - return pos; | |
13944 | - } | |
13943 | + const char *const ss0 = ss; | |
13944 | + char c1, c2, c3, c4; | |
13945 | 13945 | |
13946 | - // Compilation procedure. | |
13947 | - unsigned int compile(char *ss, char *se) { | |
13948 | - while (*ss==' ') ++ss; | |
13949 | - while (se>ss && *(se-1)==' ') --se; | |
13946 | + if (ss<se) { | |
13947 | + while (*ss && (*ss<=' ' || *ss==';')) ++ss; | |
13948 | + while (se>ss && (c1=*(se - 1))>0 && (c1<=' ' || c1==';')) --se; | |
13949 | + } | |
13950 | + if (se>ss && *(se - 1)==';') --se; | |
13951 | + while (*ss=='(' && *(se - 1)==')' && std::strchr(ss,')')==se - 1) { // Detect simple content around parentheses. | |
13952 | + ++ss; --se; | |
13953 | + } | |
13950 | 13954 | if (se<=ss || !*ss) { |
13955 | + cimg::strellipsize(expr,64); | |
13951 | 13956 | throw CImgArgumentException("[_cimg_math_parser] " |
13952 | - "CImg<%s>::%s(): Missing item in specified expression '%s'.", | |
13953 | - pixel_type(),calling_function, | |
13957 | + "CImg<%s>::%s: Missing item, in expression '%s'.", | |
13958 | + pixel_type(),_cimg_mp_calling_function, | |
13954 | 13959 | expr._data); |
13955 | 13960 | } |
13961 | + const unsigned int depth1 = depth + 1; | |
13962 | + unsigned int pos, p1, p2, p3, arg1, arg2, arg3, arg4, arg5, arg6; | |
13956 | 13963 | char |
13957 | - *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3, *const se4 = se - 4, | |
13964 | + *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3, | |
13958 | 13965 | *const ss1 = ss + 1, *const ss2 = ss + 2, *const ss3 = ss + 3, *const ss4 = ss + 4, |
13959 | - *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7; | |
13966 | + *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7, *const ss8 = ss + 8, | |
13967 | + *s, *ps, *ns, *s0, *s1, *s2, *s3, sep = 0, end = 0; | |
13968 | + double val, val1, val2; | |
13969 | + const char *s_op; | |
13970 | + mp_func op; | |
13971 | + | |
13972 | + // 'p_ref' is a 'unsigned int[7]' used to return a reference to an image or vector value | |
13973 | + // linked to the returned memory slot (reference that cannot be determined at compile time). | |
13974 | + // p_ref[0] can be { 0 = scalar (unlinked) | 1 = vector value | 2 = image value (offset) | | |
13975 | + // 3 = image value (coordinates) | 4 = image value as a vector (offsets) | | |
13976 | + // 5 = image value as a vector (coordinates) }. | |
13977 | + // Depending on p_ref[0], the remaining p_ref[k] have the following meaning: | |
13978 | + // When p_ref[0]==0, p_ref is actually unlinked. | |
13979 | + // When p_ref[0]==1, p_ref = [ 1, vector_ind, offset ]. | |
13980 | + // When p_ref[0]==2, p_ref = [ 2, image_ind (or ~0U), is_relative, offset ]. | |
13981 | + // When p_ref[0]==3, p_ref = [ 3, image_ind (or ~0U), is_relative, x, y, z, c ]. | |
13982 | + // When p_ref[0]==4, p_ref = [ 4, image_ind (or ~0U), is_relative, offset ]. | |
13983 | + // When p_ref[0]==5, p_ref = [ 5, image_ind (or ~0U), is_relative, x, y, z ]. | |
13984 | + if (p_ref) { *p_ref = 0; p_ref[1] = p_ref[2] = p_ref[3] = p_ref[4] = p_ref[5] = p_ref[6] = ~0U; } | |
13985 | + | |
13960 | 13986 | const char saved_char = *se; *se = 0; |
13961 | 13987 | const unsigned int clevel = level[ss - expr._data], clevel1 = clevel + 1; |
13962 | - if (*se1==';') return compile(ss,se1); | |
13988 | + bool is_sth, is_relative; | |
13989 | + CImg<uintT> ref; | |
13990 | + CImgList<uptrT> _opcode; | |
13991 | + CImg<charT> variable_name; | |
13963 | 13992 | |
13964 | - // Look for a single value, variable or variable assignment. | |
13965 | - char end = 0, sep = 0; double val = 0; | |
13966 | - int nb = cimg_sscanf(ss,"%lf%c%c",&val,&sep,&end); | |
13993 | + // Look for a single value or a pre-defined variable. | |
13994 | + int nb = cimg_sscanf(ss,"%lf%c%c",&val,&(sep=0),&(end=0)); | |
13967 | 13995 | |
13968 | 13996 | #if cimg_OS==2 |
13969 | 13997 | // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able |
13970 | 13998 | // to read those particular values. |
13971 | 13999 | if (!nb && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) { |
13972 | - bool is_positive = true; | |
13973 | - const char *_ss = ss; | |
13974 | - if (*_ss=='+') ++_ss; else if (*_ss=='-') { ++_ss; is_positive = false; } | |
13975 | - if (!cimg::strcasecmp(_ss,"inf")) { val = cimg::type<double>::inf(); nb = 1; } | |
13976 | - else if (!cimg::strcasecmp(_ss,"nan")) { val = cimg::type<double>::nan(); nb = 1; } | |
13977 | - if (nb==1 && !is_positive) val = -val; | |
13978 | - } | |
13979 | -#endif | |
13980 | - | |
13981 | - if (nb==1) { | |
13982 | - if (val==0 || val==1 || val==2 || val==3 || val==4 || val==5) | |
13983 | - _cimg_mp_return((unsigned int)val); | |
13984 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
13985 | - const unsigned int pos = mempos++; | |
13986 | - mem[pos] = val; | |
13987 | - _cimg_mp_return(pos); | |
13988 | - } | |
13989 | - if (nb==2 && sep=='%') { | |
13990 | - if (val==0 || val==100 || val==200 || val==300 || val==400 || val==500) | |
13991 | - _cimg_mp_return((unsigned int)val/100); | |
13992 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
13993 | - const unsigned int pos = mempos++; | |
13994 | - mem[pos] = val/100; | |
13995 | - _cimg_mp_return(pos); | |
13996 | - } | |
13997 | - if (ss1==se) switch (*ss) { // One-char variable. | |
13998 | - case 'w' : case 'h' : case 'd' : case 's' : case 'r' : | |
13999 | - case 'x' : case 'y' : case 'z' : case 'c' : case 'e' : _cimg_mp_return(reserved_label[*ss]); | |
14000 | - case 'u' : if (reserved_label['u']!=~0U) _cimg_mp_return(reserved_label['u']); _cimg_mp_opcode2(mp_u,0,1); | |
14001 | - case 'g' : if (reserved_label['g']!=~0U) _cimg_mp_return(reserved_label['g']); _cimg_mp_opcode0(mp_g); | |
14002 | - case 'i' : if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']); _cimg_mp_opcode0(mp_i); | |
14003 | - case '?' : _cimg_mp_opcode2(mp_u,0,1); | |
14004 | - } | |
14005 | - else if (ss2==se) { // Two-chars variable. | |
14000 | + is_sth = true; | |
14001 | + s = ss; | |
14002 | + if (*s=='+') ++s; else if (*s=='-') { ++s; is_sth = false; } | |
14003 | + if (!cimg::strcasecmp(s,"inf")) { val = cimg::type<double>::inf(); nb = 1; } | |
14004 | + else if (!cimg::strcasecmp(s,"nan")) { val = cimg::type<double>::nan(); nb = 1; } | |
14005 | + if (nb==1 && !is_sth) val = -val; | |
14006 | + } | |
14007 | +#endif | |
14008 | + if (nb==1) _cimg_mp_constant(val); | |
14009 | + if (nb==2 && sep=='%') _cimg_mp_constant(val/100); | |
14010 | + | |
14011 | + if (ss1==se) switch (*ss) { // One-char variable | |
14012 | + case 't' : case 'w' : case 'h' : case 'd' : case 's' : case 'r' : | |
14013 | + case 'x' : case 'y' : case 'z' : case 'c' : case 'e' : | |
14014 | + _cimg_mp_return(reserved_label[*ss]); | |
14015 | + case 'u' : | |
14016 | + if (reserved_label['u']!=~0U) _cimg_mp_return(reserved_label['u']); | |
14017 | + _cimg_mp_scalar2(mp_u,0,1); | |
14018 | + case 'g' : | |
14019 | + if (reserved_label['g']!=~0U) _cimg_mp_return(reserved_label['g']); | |
14020 | + _cimg_mp_scalar0(mp_g); | |
14021 | + case 'i' : | |
14022 | + if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']); | |
14023 | + _cimg_mp_scalar0(mp_i); | |
14024 | + case 'I' : | |
14025 | + if (reserved_label['I']!=~0U) _cimg_mp_return(reserved_label['I']); | |
14026 | + _cimg_mp_check_vector0(imgin._spectrum,"variable 'I'"); | |
14027 | + pos = vector(imgin._spectrum); | |
14028 | + CImg<uptrT>::vector((uptrT)mp_Joff,pos,0,0).move_to(code); | |
14029 | + _cimg_mp_return(pos); | |
14030 | + case 'R' : | |
14031 | + if (reserved_label['R']!=~0U) _cimg_mp_return(reserved_label['R']); | |
14032 | + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,0,0,0); | |
14033 | + case 'G' : | |
14034 | + if (reserved_label['G']!=~0U) _cimg_mp_return(reserved_label['G']); | |
14035 | + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,1,0,0); | |
14036 | + case 'B' : | |
14037 | + if (reserved_label['B']!=~0U) _cimg_mp_return(reserved_label['B']); | |
14038 | + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,2,0,0); | |
14039 | + case 'A' : | |
14040 | + if (reserved_label['A']!=~0U) _cimg_mp_return(reserved_label['A']); | |
14041 | + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,3,0,0); | |
14042 | + } | |
14043 | + else if (ss2==se) { // Two-chars variable | |
14044 | + arg1 = arg2 = ~0U; | |
14006 | 14045 | if (*ss=='w' && *ss1=='h') _cimg_mp_return(reserved_label[0]); // wh |
14007 | 14046 | if (*ss=='p' && *ss1=='i') _cimg_mp_return(reserved_label[3]); // pi |
14008 | - if (*ss=='i') { // im | |
14009 | - if (*ss1=='m') { | |
14010 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14011 | - if (reserved_label[4]!=~0U) _cimg_mp_return(reserved_label[4]); _cimg_mp_opcode0(mp_im); | |
14047 | + if (*ss=='i') { | |
14048 | + if (*ss1>='0' && *ss1<='9') { // i0...i9 | |
14049 | + pos = 19 + *ss1 - '0'; | |
14050 | + if (reserved_label[pos]!=~0U) _cimg_mp_return(reserved_label[pos]); | |
14051 | + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,pos - 19,0,0); | |
14052 | + } | |
14053 | + switch (*ss1) { | |
14054 | + case 'm' : arg1 = 4; arg2 = 0; break; // im | |
14055 | + case 'M' : arg1 = 5; arg2 = 1; break; // iM | |
14056 | + case 'a' : arg1 = 6; arg2 = 2; break; // ia | |
14057 | + case 'v' : arg1 = 7; arg2 = 3; break; // iv | |
14058 | + case 's' : arg1 = 8; arg2 = 12; break; // is | |
14059 | + case 'p' : arg1 = 9; arg2 = 13; break; // is | |
14060 | + case 'c' : // ic | |
14061 | + if (reserved_label[10]!=~0U) _cimg_mp_return(reserved_label[10]); | |
14062 | + if (mem_img_median==~0U) mem_img_median = imgin?constant(imgin.median()):0; | |
14063 | + _cimg_mp_return(mem_img_median); | |
14064 | + break; | |
14012 | 14065 | } |
14013 | - if (*ss1=='M') { // iM | |
14014 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14015 | - if (reserved_label[5]!=~0U) _cimg_mp_return(reserved_label[5]); _cimg_mp_opcode0(mp_iM); | |
14066 | + } | |
14067 | + else if (*ss1=='m') switch (*ss) { | |
14068 | + case 'x' : arg1 = 11; arg2 = 4; break; // xm | |
14069 | + case 'y' : arg1 = 12; arg2 = 5; break; // ym | |
14070 | + case 'z' : arg1 = 13; arg2 = 6; break; // zm | |
14071 | + case 'c' : arg1 = 14; arg2 = 7; break; // cm | |
14072 | + } | |
14073 | + else if (*ss1=='M') switch (*ss) { | |
14074 | + case 'x' : arg1 = 15; arg2 = 8; break; // xM | |
14075 | + case 'y' : arg1 = 16; arg2 = 9; break; // yM | |
14076 | + case 'z' : arg1 = 17; arg2 = 10; break; // zM | |
14077 | + case 'c' : arg1 = 18; arg2 = 11; break; // cM | |
14016 | 14078 | } |
14017 | - if (*ss1=='a') { // ia | |
14018 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14019 | - if (reserved_label[6]!=~0U) _cimg_mp_return(reserved_label[6]); _cimg_mp_opcode0(mp_ia); | |
14079 | + if (arg1!=~0U) { | |
14080 | + if (reserved_label[arg1]!=~0U) _cimg_mp_return(reserved_label[arg1]); | |
14081 | + if (!img_stats) { | |
14082 | + img_stats.assign(1,14,1,1,0).fill(imgin.get_stats(),false); | |
14083 | + mem_img_stats.assign(1,14,1,1,~0U); | |
14084 | + } | |
14085 | + if (mem_img_stats[arg2]==~0U) mem_img_stats[arg2] = constant(img_stats[arg2]); | |
14086 | + _cimg_mp_return(mem_img_stats[arg2]); | |
14087 | + } | |
14088 | + } else if (ss3==se) { // Three-chars variable | |
14089 | + if (*ss=='w' && *ss1=='h' && *ss2=='d') _cimg_mp_return(reserved_label[1]); // whd | |
14090 | + } else if (ss4==se) { // Four-chars variable | |
14091 | + if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') _cimg_mp_return(reserved_label[2]); // whds | |
14092 | + } | |
14093 | + | |
14094 | + pos = ~0U; | |
14095 | + for (s0 = ss, s = ss1; s<se1; ++s) | |
14096 | + if (*s==';' && level[s - expr._data]==clevel) { // Separator ';' | |
14097 | + pos = compile(s0,s,depth,0); | |
14098 | + s0 = s + 1; | |
14099 | + } | |
14100 | + if (pos!=~0U) _cimg_mp_return(compile(s0,se,depth,p_ref)); | |
14101 | + | |
14102 | + // Declare / assign variable, vector value or image value. | |
14103 | + for (s = ss1, ps = ss, ns = ss2; s<se1; ++s, ++ps, ++ns) | |
14104 | + if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' && | |
14105 | + *ps!='+' && *ps!='-' && *ps!='*' && *ps!='/' && *ps!='%' && | |
14106 | + *ps!='>' && *ps!='<' && *ps!='&' && *ps!='|' && *ps!='^' && | |
14107 | + level[s - expr._data]==clevel) { | |
14108 | + variable_name.assign(ss,(unsigned int)(s + 1 - ss)).back() = 0; | |
14109 | + cimg::strpare(variable_name); | |
14110 | + const unsigned int l_variable_name = (unsigned int)std::strlen(variable_name); | |
14111 | + char *const ve1 = ss + l_variable_name - 1; | |
14112 | + s_op = "Operator '='"; | |
14113 | + | |
14114 | + // Assign image value (direct). | |
14115 | + if (l_variable_name>2 && (*ss=='i' || *ss=='j' || *ss=='I' || *ss=='J') && (*ss1=='(' || *ss1=='[') && | |
14116 | + (reserved_label[*ss]==~0U || *ss1=='(' || !_cimg_mp_is_vector(reserved_label[*ss]))) { | |
14117 | + is_relative = *ss=='j' || *ss=='J'; | |
14118 | + | |
14119 | + if (*ss1=='[' && *ve1==']') { // i/j/I/J[_#ind,offset] = value | |
14120 | + if (*ss2=='#') { // Index specified | |
14121 | + s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0; | |
14122 | + p1 = compile(ss3,s0++,depth1,0); | |
14123 | + } else { p1 = ~0U; s0 = ss2; } | |
14124 | + arg1 = compile(s0,ve1,depth1,0); // Offset | |
14125 | + arg2 = compile(s + 1,se,depth1,0); // Value to assign | |
14126 | + if (_cimg_mp_is_vector(arg2)) { | |
14127 | + p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any | |
14128 | + if (p1==~0U) p2 = imgin._spectrum; | |
14129 | + else if (_cimg_mp_is_constant(p1)) { | |
14130 | + p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width()); | |
14131 | + p2 = listin[p3]._spectrum; | |
14132 | + } | |
14133 | + _cimg_mp_check_vector0(p2,s_op); | |
14134 | + } else p2 = 0; | |
14135 | + _cimg_mp_check_type(arg2,2,s_op,*ss>='i'?1:3,p2); | |
14136 | + | |
14137 | + if (p_ref) { | |
14138 | + *p_ref = _cimg_mp_is_vector(arg2)?4:2; | |
14139 | + p_ref[1] = p1; | |
14140 | + p_ref[2] = (unsigned int)is_relative; | |
14141 | + p_ref[3] = arg1; | |
14142 | + if (_cimg_mp_is_vector(arg2)) | |
14143 | + set_variable_vector(arg2); // Prevent from being used in further optimization | |
14144 | + else if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; | |
14145 | + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; | |
14146 | + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1; | |
14147 | + } | |
14148 | + if (p1!=~0U) { | |
14149 | + if (!listout) _cimg_mp_return(arg2); | |
14150 | + if (*ss>='i') | |
14151 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_joff:mp_list_set_ioff), | |
14152 | + arg2,p1,arg1).move_to(code); | |
14153 | + else if (_cimg_mp_is_scalar(arg2)) | |
14154 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s), | |
14155 | + arg2,p1,arg1).move_to(code); | |
14156 | + else | |
14157 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), | |
14158 | + arg2,p1,arg1).move_to(code); | |
14159 | + } else { | |
14160 | + if (!imgout) _cimg_mp_return(arg2); | |
14161 | + if (*ss>='i') | |
14162 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_joff:mp_set_ioff), | |
14163 | + arg2,arg1).move_to(code); | |
14164 | + if (_cimg_mp_is_scalar(arg2)) | |
14165 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s), | |
14166 | + arg2,arg1).move_to(code); | |
14167 | + else | |
14168 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), | |
14169 | + arg2,arg1).move_to(code); | |
14170 | + } | |
14171 | + _cimg_mp_return(arg2); | |
14172 | + } | |
14173 | + | |
14174 | + if (*ss1=='(' && *ve1==')') { // i/j/I/J(_#ind,_x,_y,_z,_c) = value | |
14175 | + if (*ss2=='#') { // Index specified | |
14176 | + s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0; | |
14177 | + p1 = compile(ss3,s0++,depth1,0); | |
14178 | + } else { p1 = ~0U; s0 = ss2; } | |
14179 | + arg1 = is_relative?0U:(unsigned int)_cimg_mp_x; | |
14180 | + arg2 = is_relative?0U:(unsigned int)_cimg_mp_y; | |
14181 | + arg3 = is_relative?0U:(unsigned int)_cimg_mp_z; | |
14182 | + arg4 = is_relative?0U:(unsigned int)_cimg_mp_c; | |
14183 | + arg5 = compile(s + 1,se,depth1,0); // Value to assign | |
14184 | + if (s0<ve1) { // X or [ X,_Y,_Z,_C ] | |
14185 | + s1 = s0; while (s1<ve1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14186 | + arg1 = compile(s0,s1,depth1,0); | |
14187 | + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z,C] | |
14188 | + p2 = _cimg_mp_vector_size(arg1); // Vector size | |
14189 | + arg1 = arg1 + 1; | |
14190 | + if (p2>1) { | |
14191 | + arg2 = arg1 + 1; | |
14192 | + if (p2>2) { | |
14193 | + arg3 = arg2 + 1; | |
14194 | + if (p2>3) arg4 = arg3 + 1; | |
14195 | + } | |
14196 | + } | |
14197 | + } else if (s1<ve1) { // Y | |
14198 | + s2 = ++s1; while (s2<ve1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
14199 | + arg2 = compile(s1,s2,depth1,0); | |
14200 | + if (s2<ve1) { // Z | |
14201 | + s3 = ++s2; while (s3<ve1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3; | |
14202 | + arg3 = compile(s2,s3,depth1,0); | |
14203 | + if (s3<ve1) arg4 = compile(++s3,ve1,depth1,0); // C | |
14204 | + } | |
14205 | + } | |
14206 | + } | |
14207 | + | |
14208 | + if (_cimg_mp_is_vector(arg5)) { | |
14209 | + p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any | |
14210 | + if (p1==~0U) p2 = imgin._spectrum; | |
14211 | + else if (_cimg_mp_is_constant(p1)) { | |
14212 | + p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width()); | |
14213 | + p2 = listin[p3]._spectrum; | |
14214 | + } | |
14215 | + _cimg_mp_check_vector0(p2,s_op); | |
14216 | + } else p2 = 0; | |
14217 | + _cimg_mp_check_type(arg5,2,s_op,*ss>='i'?1:3,p2); | |
14218 | + | |
14219 | + if (p_ref) { | |
14220 | + *p_ref = _cimg_mp_is_vector(arg5)?5:3; | |
14221 | + p_ref[1] = p1; | |
14222 | + p_ref[2] = (unsigned int)is_relative; | |
14223 | + p_ref[3] = arg1; | |
14224 | + p_ref[4] = arg2; | |
14225 | + p_ref[5] = arg3; | |
14226 | + p_ref[6] = arg4; | |
14227 | + if (_cimg_mp_is_vector(arg5)) | |
14228 | + set_variable_vector(arg5); // Prevent from being used in further optimization | |
14229 | + else if (_cimg_mp_is_temp(arg5)) memtype[arg5] = -1; | |
14230 | + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; | |
14231 | + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1; | |
14232 | + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; | |
14233 | + if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1; | |
14234 | + if (_cimg_mp_is_temp(arg4)) memtype[arg4] = -1; | |
14235 | + } | |
14236 | + if (p1!=~0U) { | |
14237 | + if (!listout) _cimg_mp_return(arg5); | |
14238 | + if (*ss>='i') | |
14239 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), | |
14240 | + arg5,p1,arg1,arg2,arg3,arg4).move_to(code); | |
14241 | + else if (_cimg_mp_is_scalar(arg5)) | |
14242 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s), | |
14243 | + arg5,p1,arg1,arg2,arg3).move_to(code); | |
14244 | + else | |
14245 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), | |
14246 | + arg5,p1,arg1,arg2,arg3).move_to(code); | |
14247 | + } else { | |
14248 | + if (!imgout) _cimg_mp_return(arg5); | |
14249 | + if (*ss>='i') | |
14250 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), | |
14251 | + arg5,arg1,arg2,arg3,arg4).move_to(code); | |
14252 | + else if (_cimg_mp_is_scalar(arg5)) | |
14253 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s), | |
14254 | + arg5,arg1,arg2,arg3).move_to(code); | |
14255 | + else | |
14256 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), | |
14257 | + arg5,arg1,arg2,arg3).move_to(code); | |
14258 | + } | |
14259 | + _cimg_mp_return(arg5); | |
14260 | + } | |
14020 | 14261 | } |
14021 | - if (*ss1=='v') { // iv | |
14022 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14023 | - if (reserved_label[7]!=~0U) _cimg_mp_return(reserved_label[7]); _cimg_mp_opcode0(mp_iv); | |
14262 | + | |
14263 | + // Assign vector value (direct). | |
14264 | + if (l_variable_name>3 && *ve1==']' && *ss!='[') { | |
14265 | + s0 = ve1; while (s0>ss && *s0!='[') --s0; | |
14266 | + is_sth = true; // is_valid_variable_name? | |
14267 | + if (*ss>='0' && *ss<='9') is_sth = false; | |
14268 | + else for (ns = ss; ns<s0; ++ns) | |
14269 | + if (!is_varchar(*ns)) { is_sth = false; break; } | |
14270 | + if (is_sth && s0>ss) { | |
14271 | + variable_name[s0 - ss] = 0; // Remove brackets in variable name | |
14272 | + arg1 = ~0U; // Vector slot | |
14273 | + arg2 = compile(++s0,ve1,depth1,0); // Index | |
14274 | + arg3 = compile(s + 1,se,depth1,0); // Value to assign | |
14275 | + _cimg_mp_check_type(arg3,2,s_op,1,0); | |
14276 | + | |
14277 | + if (variable_name[1]) { // Multi-char variable | |
14278 | + cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i])) { | |
14279 | + arg1 = variable_pos[i]; break; | |
14280 | + } | |
14281 | + } else arg1 = reserved_label[*variable_name]; // Single-char variable | |
14282 | + if (arg1==~0U) compile(ss,s0 - 1,depth1,0); // Variable does not exist -> error | |
14283 | + else { // Variable already exists | |
14284 | + if (_cimg_mp_is_scalar(arg1)) compile(ss,s,depth1,0); // Variable is not a vector -> error | |
14285 | + if (_cimg_mp_is_constant(arg2)) { // Constant index -> return corresponding variable slot directly | |
14286 | + nb = (int)mem[arg2]; | |
14287 | + if (nb>=0 && nb<(int)_cimg_mp_vector_size(arg1)) { | |
14288 | + arg1+=nb + 1; | |
14289 | + CImg<uptrT>::vector((uptrT)mp_copy,arg1,arg3).move_to(code); | |
14290 | + _cimg_mp_return(arg1); | |
14291 | + } | |
14292 | + compile(ss,s,depth1,0); // Out-of-bounds reference -> error | |
14293 | + } | |
14294 | + | |
14295 | + // Case of non-constant index -> return assigned value + linked reference | |
14296 | + if (p_ref) { | |
14297 | + *p_ref = 1; | |
14298 | + p_ref[1] = arg1; | |
14299 | + p_ref[2] = arg2; | |
14300 | + if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1; // Prevent from being used in further optimization | |
14301 | + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; | |
14302 | + } | |
14303 | + CImg<uptrT>::vector((uptrT)mp_vector_set_off,arg3,arg1,(uptrT)_cimg_mp_vector_size(arg1),arg2,arg3). | |
14304 | + move_to(code); | |
14305 | + _cimg_mp_return(arg3); | |
14306 | + } | |
14307 | + } | |
14024 | 14308 | } |
14025 | - if (*ss1=='s') { // is | |
14026 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14027 | - if (reserved_label[8]!=~0U) _cimg_mp_return(reserved_label[8]); _cimg_mp_opcode0(mp_is); | |
14309 | + | |
14310 | + // Assign user-defined function. | |
14311 | + if (l_variable_name>3 && *ve1==')' && *ss!='(') { | |
14312 | + s0 = ve1; while (s0>ss && *s0!='(') --s0; | |
14313 | + is_sth = std::strncmp(variable_name,"debug(",6) && | |
14314 | + std::strncmp(variable_name,"print(",6); // is_valid_function_name? | |
14315 | + if (*ss>='0' && *ss<='9') is_sth = false; | |
14316 | + else for (ns = ss; ns<s0; ++ns) | |
14317 | + if (!is_varchar(*ns)) { is_sth = false; break; } | |
14318 | + | |
14319 | + if (is_sth && s0>ss) { // Looks like a valid function declaration | |
14320 | + s0 = variable_name._data + (s0 - ss); | |
14321 | + *s0 = 0; | |
14322 | + s1 = variable_name._data + l_variable_name - 1; // Pointer to closing parenthesis | |
14323 | + CImg<charT>(variable_name._data,s0 - variable_name._data + 1).move_to(function_def,0); | |
14324 | + ++s; while (*s && *s<=' ') ++s; | |
14325 | + CImg<charT>(s,se - s + 1).move_to(function_body,0); | |
14326 | + | |
14327 | + p1 = 1; // Indice of current parsed argument | |
14328 | + for (s = s0 + 1; s<=s1; ++p1, s = ns + 1) { // Parse function arguments | |
14329 | + if (p1>24) { | |
14330 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
14331 | + throw CImgArgumentException("[_cimg_math_parser] " | |
14332 | + "CImg<%s>::%s: %s: Too much specified arguments (>24) when defining " | |
14333 | + "function '%s()', in expression '%s%s%s'.", | |
14334 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
14335 | + variable_name._data, | |
14336 | + (ss - 4)>expr._data?"...":"", | |
14337 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
14338 | + se<&expr.back()?"...":""); | |
14339 | + } | |
14340 | + while (*s && *s<=' ') ++s; | |
14341 | + if (*s==')' && p1==1) break; // Function has no arguments | |
14342 | + | |
14343 | + s2 = s; // Start of the argument name | |
14344 | + is_sth = true; // is_valid_argument_name? | |
14345 | + if (*s>='0' && *s<='9') is_sth = false; | |
14346 | + else for (ns = s; ns<s1 && *ns!=',' && *ns>' '; ++ns) | |
14347 | + if (!is_varchar(*ns)) { is_sth = false; break; } | |
14348 | + s3 = ns; // End of the argument name | |
14349 | + while (*ns && *ns<=' ') ++ns; | |
14350 | + if (!is_sth || s2==s3 || (*ns!=',' && ns!=s1)) { | |
14351 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
14352 | + throw CImgArgumentException("[_cimg_math_parser] " | |
14353 | + "CImg<%s>::%s: %s: %s name specified for argument %u when defining " | |
14354 | + "function '%s()', in expression '%s%s%s'.", | |
14355 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
14356 | + is_sth?"Empty":"Invalid",p1, | |
14357 | + variable_name._data, | |
14358 | + (ss - 4)>expr._data?"...":"", | |
14359 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
14360 | + se<&expr.back()?"...":""); | |
14361 | + } | |
14362 | + if (ns==s1 || *ns==',') { // New argument found | |
14363 | + *s3 = 0; | |
14364 | + p2 = s3 - s2; // Argument length | |
14365 | + p3 = function_body[0]._width - p2 + 1; // Related to copy length | |
14366 | + for (ps = std::strstr(function_body[0],s2); ps; ps = std::strstr(ps,s2)) { // Replace by arg number | |
14367 | + if (!((ps>function_body[0]._data && is_varchar(*(ps - 1))) || | |
14368 | + (ps + p2<function_body[0].end() && is_varchar(*(ps + p2))))) { | |
14369 | + *(ps++) = (char)p1; | |
14370 | + if (p2>1) { | |
14371 | + std::memmove(ps,ps + p2 - 1,function_body[0]._data + p3 - ps); | |
14372 | + function_body[0]._width-=p2 - 1; | |
14373 | + } | |
14374 | + } else ++ps; | |
14375 | + } | |
14376 | + } | |
14377 | + } | |
14378 | + // Store number of arguments | |
14379 | + function_def[0].resize(function_def[0]._width + 1,1,1,1,0).back() = (char)(p1 - 1); | |
14380 | + _cimg_mp_return(28); | |
14381 | + } | |
14028 | 14382 | } |
14029 | - if (*ss1=='p') { // ip | |
14030 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14031 | - if (reserved_label[9]!=~0U) _cimg_mp_return(reserved_label[9]); _cimg_mp_opcode0(mp_ip); | |
14383 | + | |
14384 | + // Check if the variable name could be valid. If not, this is probably an lvalue assignment. | |
14385 | + is_sth = true; // is_valid_variable_name? | |
14386 | + if (*variable_name>='0' && *variable_name<='9') is_sth = false; | |
14387 | + else for (ns = variable_name._data; *ns; ++ns) | |
14388 | + if (!is_varchar(*ns)) { is_sth = false; break; } | |
14389 | + | |
14390 | + // Assign variable (direct). | |
14391 | + if (is_sth) { | |
14392 | + if (variable_name[1] && !variable_name[2]) { // Two-chars variable | |
14393 | + c1 = variable_name[0]; | |
14394 | + c2 = variable_name[1]; | |
14395 | + if (c1=='w' && c2=='h') variable_name.fill((char)0,(char)0); // wh | |
14396 | + else if (c1=='p' && c2=='i') variable_name.fill(3,0); // pi | |
14397 | + else if (c1=='i') { | |
14398 | + if (c2>='0' && c2<='9') variable_name.fill(19 + c2 - '0',0); // i0...i9 | |
14399 | + else if (c2=='m') variable_name.fill(4,0); // im | |
14400 | + else if (c2=='M') variable_name.fill(5,0); // iM | |
14401 | + else if (c2=='a') variable_name.fill(6,0); // ia | |
14402 | + else if (c2=='v') variable_name.fill(7,0); // iv | |
14403 | + else if (c2=='s') variable_name.fill(8,0); // is | |
14404 | + else if (c2=='p') variable_name.fill(9,0); // ip | |
14405 | + else if (c2=='c') variable_name.fill(10,0); // ic | |
14406 | + } else if (c2=='m') { | |
14407 | + if (c1=='x') variable_name.fill(11,0); // xm | |
14408 | + else if (c1=='y') variable_name.fill(12,0); // ym | |
14409 | + else if (c1=='z') variable_name.fill(13,0); // zm | |
14410 | + else if (c1=='c') variable_name.fill(14,0); // cm | |
14411 | + } else if (c2=='M') { | |
14412 | + if (c1=='x') variable_name.fill(15,0); // xM | |
14413 | + else if (c1=='y') variable_name.fill(16,0); // yM | |
14414 | + else if (c1=='z') variable_name.fill(17,0); // zM | |
14415 | + else if (c1=='c') variable_name.fill(18,0); // cM | |
14416 | + } | |
14417 | + } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable | |
14418 | + c1 = variable_name[0]; | |
14419 | + c2 = variable_name[1]; | |
14420 | + c3 = variable_name[2]; | |
14421 | + if (c1=='w' && c2=='h' && c3=='d') variable_name.fill(1,0); // whd | |
14422 | + } else if (variable_name[1] && variable_name[2] && variable_name[3] && | |
14423 | + !variable_name[4]) { // Four-chars variable | |
14424 | + c1 = variable_name[0]; | |
14425 | + c2 = variable_name[1]; | |
14426 | + c3 = variable_name[2]; | |
14427 | + c4 = variable_name[3]; | |
14428 | + if (c1=='w' && c2=='h' && c3=='d' && c4=='s') variable_name.fill(2,0); // whds | |
14429 | + } else if (!std::strcmp(variable_name,"interpolation")) variable_name.fill(29,0); | |
14430 | + else if (!std::strcmp(variable_name,"boundary")) variable_name.fill(30,0); | |
14431 | + | |
14432 | + arg1 = ~0U; | |
14433 | + arg2 = compile(s + 1,se,depth1,0); | |
14434 | + if (!variable_name[1]) // One-char variable, or variable in reserved_labels | |
14435 | + arg1 = reserved_label[*variable_name]; | |
14436 | + else // Multi-char variable name : check for existing variable with same name | |
14437 | + cimglist_for(variable_def,i) | |
14438 | + if (!std::strcmp(variable_name,variable_def[i])) { arg1 = variable_pos[i]; break; } | |
14439 | + | |
14440 | + if (arg1==~0U || arg1<=_cimg_mp_c) { // Create new variable | |
14441 | + if (_cimg_mp_is_vector(arg2)) { // Vector variable | |
14442 | + arg1 = vector_copy(arg2); | |
14443 | + set_variable_vector(arg1); | |
14444 | + } else { // Scalar variable | |
14445 | + arg1 = scalar1(mp_copy,arg2); | |
14446 | + memtype[arg1] = -1; | |
14447 | + } | |
14448 | + | |
14449 | + if (!variable_name[1]) reserved_label[*variable_name] = arg1; | |
14450 | + else { | |
14451 | + if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0); | |
14452 | + variable_pos[variable_def._width] = arg1; | |
14453 | + variable_name.move_to(variable_def); | |
14454 | + } | |
14455 | + | |
14456 | + } 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); | |
14458 | + if (_cimg_mp_is_vector(arg1)) { // Vector | |
14459 | + if (_cimg_mp_is_vector(arg2)) // From vector | |
14460 | + CImg<uptrT>::vector((uptrT)mp_vector_copy,arg1,arg2,(uptrT)_cimg_mp_vector_size(arg1)). | |
14461 | + move_to(code); | |
14462 | + else // From scalar | |
14463 | + CImg<uptrT>::vector((uptrT)mp_vector_init,arg1,(uptrT)_cimg_mp_vector_size(arg1),arg2). | |
14464 | + move_to(code); | |
14465 | + } else // Scalar | |
14466 | + CImg<uptrT>::vector((uptrT)mp_copy,arg1,arg2).move_to(code); | |
14467 | + } | |
14468 | + _cimg_mp_return(arg1); | |
14469 | + } | |
14470 | + | |
14471 | + // Assign lvalue (variable name was not valid). | |
14472 | + is_sth = (bool)std::strchr(variable_name,'?'); // Contains_ternary_operator? | |
14473 | + if (is_sth) break; // Do nothing and make ternary operator prioritary over assignment | |
14474 | + | |
14475 | + if (l_variable_name>2 && (std::strchr(variable_name,'(') || std::strchr(variable_name,'['))) { | |
14476 | + ref.assign(7); | |
14477 | + arg1 = compile(ss,s,depth1,ref); // Lvalue slot | |
14478 | + arg2 = compile(s + 1,se,depth1,0); // Value to assign | |
14479 | + | |
14480 | + if (*ref==1) { // Vector value (scalar): V[k] = scalar | |
14481 | + _cimg_mp_check_type(arg2,2,s_op,1,0); | |
14482 | + arg3 = ref[1]; // Vector slot | |
14483 | + arg4 = ref[2]; // Index | |
14484 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14485 | + CImg<uptrT>::vector((uptrT)mp_vector_set_off,arg2,arg3,(uptrT)_cimg_mp_vector_size(arg3),arg4,arg2). | |
14486 | + move_to(code); | |
14487 | + _cimg_mp_return(arg2); | |
14488 | + } | |
14489 | + | |
14490 | + if (*ref==2) { // Image value (scalar): i/j[_#ind,off] = scalar | |
14491 | + _cimg_mp_check_type(arg2,2,s_op,1,0); | |
14492 | + p1 = ref[1]; // Index | |
14493 | + is_relative = (bool)ref[2]; | |
14494 | + arg3 = ref[3]; // Offset | |
14495 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14496 | + if (p1!=~0U) { | |
14497 | + if (!listout) _cimg_mp_return(arg2); | |
14498 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_joff:mp_list_set_ioff), | |
14499 | + arg2,p1,arg3).move_to(code); | |
14500 | + } else { | |
14501 | + if (!imgout) _cimg_mp_return(arg2); | |
14502 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_joff:mp_set_ioff), | |
14503 | + arg2,arg3).move_to(code); | |
14504 | + } | |
14505 | + _cimg_mp_return(arg2); | |
14506 | + } | |
14507 | + | |
14508 | + 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); | |
14510 | + p1 = ref[1]; // Index | |
14511 | + is_relative = (bool)ref[2]; | |
14512 | + arg3 = ref[3]; // X | |
14513 | + arg4 = ref[4]; // Y | |
14514 | + arg5 = ref[5]; // Z | |
14515 | + arg6 = ref[6]; // C | |
14516 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14517 | + if (p1!=~0U) { | |
14518 | + if (!listout) _cimg_mp_return(arg2); | |
14519 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), | |
14520 | + arg2,p1,arg3,arg4,arg5,arg6).move_to(code); | |
14521 | + } else { | |
14522 | + if (!imgout) _cimg_mp_return(arg2); | |
14523 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), | |
14524 | + arg2,arg3,arg4,arg5,arg6).move_to(code); | |
14525 | + } | |
14526 | + _cimg_mp_return(arg2); | |
14527 | + } | |
14528 | + | |
14529 | + 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)); | |
14531 | + p1 = ref[1]; // Index | |
14532 | + is_relative = (bool)ref[2]; | |
14533 | + arg3 = ref[3]; // Offset | |
14534 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14535 | + if (p1!=~0U) { | |
14536 | + if (!listout) _cimg_mp_return(arg2); | |
14537 | + if (_cimg_mp_is_scalar(arg2)) | |
14538 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s), | |
14539 | + arg2,p1,arg3).move_to(code); | |
14540 | + else | |
14541 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), | |
14542 | + arg2,p1,arg3).move_to(code); | |
14543 | + } else { | |
14544 | + if (!imgout) _cimg_mp_return(arg2); | |
14545 | + if (_cimg_mp_is_scalar(arg2)) | |
14546 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s), | |
14547 | + arg2,arg3).move_to(code); | |
14548 | + else | |
14549 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), | |
14550 | + arg2,arg3).move_to(code); | |
14551 | + } | |
14552 | + _cimg_mp_return(arg2); | |
14553 | + } | |
14554 | + | |
14555 | + 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)); | |
14557 | + p1 = ref[1]; // Index | |
14558 | + is_relative = (bool)ref[2]; | |
14559 | + arg3 = ref[3]; // X | |
14560 | + arg4 = ref[4]; // Y | |
14561 | + arg5 = ref[5]; // Z | |
14562 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14563 | + if (p1!=~0U) { | |
14564 | + if (!listout) _cimg_mp_return(arg2); | |
14565 | + if (_cimg_mp_is_scalar(arg2)) | |
14566 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s), | |
14567 | + arg2,p1,arg3,arg4,arg5).move_to(code); | |
14568 | + else | |
14569 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), | |
14570 | + arg2,p1,arg3,arg4,arg5).move_to(code); | |
14571 | + } else { | |
14572 | + if (!imgout) _cimg_mp_return(arg2); | |
14573 | + if (_cimg_mp_is_scalar(arg2)) | |
14574 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s), | |
14575 | + arg2,arg3,arg4,arg5).move_to(code); | |
14576 | + else | |
14577 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), | |
14578 | + arg2,arg3,arg4,arg5).move_to(code); | |
14579 | + } | |
14580 | + _cimg_mp_return(arg2); | |
14581 | + } | |
14582 | + | |
14583 | + if (_cimg_mp_is_vector(arg1)) { // Vector variable: V = value | |
14584 | + _cimg_mp_check_type(arg2,2,s_op,1,0); | |
14585 | + if (_cimg_mp_is_vector(arg2)) // From vector | |
14586 | + CImg<uptrT>::vector((uptrT)mp_vector_copy,arg1,arg2,(uptrT)_cimg_mp_vector_size(arg1)). | |
14587 | + move_to(code); | |
14588 | + else // From scalar | |
14589 | + CImg<uptrT>::vector((uptrT)mp_vector_init,arg1,(uptrT)_cimg_mp_vector_size(arg1),arg2). | |
14590 | + move_to(code); | |
14591 | + _cimg_mp_return(arg1); | |
14592 | + } | |
14593 | + | |
14594 | + if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s = scalar | |
14595 | + _cimg_mp_check_type(arg2,2,s_op,1,0); | |
14596 | + CImg<uptrT>::vector((uptrT)mp_copy,arg1,arg2).move_to(code); | |
14597 | + _cimg_mp_return(arg1); | |
14598 | + | |
14599 | + } | |
14032 | 14600 | } |
14033 | - if (*ss1=='c') { // ic | |
14034 | - if (!is_median_value && reference) { median_value = reference.median(); is_median_value = true; } | |
14035 | - if (reserved_label[10]!=~0U) _cimg_mp_return(reserved_label[10]); _cimg_mp_opcode0(mp_ic); | |
14601 | + | |
14602 | + // No assignment expressions match -> error | |
14603 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
14604 | + throw CImgArgumentException("[_cimg_math_parser] " | |
14605 | + "CImg<%s>::%s: %s: Invalid left-hand operand '%s', " | |
14606 | + "in expression '%s%s%s'.", | |
14607 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
14608 | + variable_name._data, | |
14609 | + (ss - 4)>expr._data?"...":"", | |
14610 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
14611 | + se<&expr.back()?"...":""); | |
14612 | + } | |
14613 | + | |
14614 | + // Apply unary/binary/ternary operators. The operator precedences should be roughly the same as in C++. | |
14615 | + for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1 | |
14616 | + if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps && | |
14617 | + level[s - expr._data]==clevel) { // Self-operators for complex numbers only (**=,//=,^^=) | |
14618 | + s_op = *ps=='*'?"Operator '**='":*ps=='/'?"Operator '//='":"Operator '^^='"; | |
14619 | + | |
14620 | + ref.assign(7); | |
14621 | + arg1 = compile(ss,ns,depth1,ref); // Vector slot | |
14622 | + arg2 = compile(s + 1,se,depth1,0); // Right operand | |
14623 | + if (*ps!='*') { | |
14624 | + _cimg_mp_check_type(arg1,2,s_op,2,2); | |
14625 | + _cimg_mp_check_type(arg2,2,s_op,2,2); | |
14626 | + } | |
14627 | + if (_cimg_mp_is_vector(arg2)) { // Complex **= complex or Matrix **= matrix | |
14628 | + if (*ps=='*') { | |
14629 | + if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2) | |
14630 | + CImg<uptrT>::vector((uptrT)mp_complex_mul,arg1,arg1,arg2).move_to(code); | |
14631 | + else { | |
14632 | + _cimg_mp_check_matrix_square(arg2,2,s_op); | |
14633 | + p3 = _cimg_mp_vector_size(arg1); | |
14634 | + p2 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg2)); | |
14635 | + p1 = p3/p2; | |
14636 | + if (p1*p2!=p3) { | |
14637 | + *se = saved_char; cimg::strellipsize(expr,64); | |
14638 | + throw CImgArgumentException("[_cimg_math_parser] " | |
14639 | + "CImg<%s>::%s: %s: Sizes of left-hand and right-hand operands " | |
14640 | + "('%s' and '%s') do not match, in expression '%s%s%s'.", | |
14641 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
14642 | + s_type(arg1)._data,s_type(arg2)._data, | |
14643 | + (ss - 4)>expr._data?"...":"", | |
14644 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
14645 | + se<&expr.back()?"...":""); | |
14646 | + } | |
14647 | + CImg<uptrT>::vector((uptrT)mp_matrix_mul,arg1,arg1,arg2,p1,p2,p2).move_to(code); | |
14648 | + } | |
14649 | + } else if (*ps=='/') | |
14650 | + CImg<uptrT>::vector((uptrT)mp_complex_div_vv,arg1,arg1,arg2).move_to(code); | |
14651 | + else | |
14652 | + CImg<uptrT>::vector((uptrT)mp_complex_pow_vv,arg1,arg1,arg2).move_to(code); | |
14653 | + } 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 | + } | |
14661 | + | |
14662 | + // Write computed value back in image if necessary. | |
14663 | + if (*ref==4) { // Image value (vector): I/J[_#ind,off] **= value | |
14664 | + p1 = ref[1]; // Index | |
14665 | + is_relative = (bool)ref[2]; | |
14666 | + arg3 = ref[3]; // Offset | |
14667 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14668 | + if (p1!=~0U) { | |
14669 | + if (!listout) _cimg_mp_return(arg1); | |
14670 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), | |
14671 | + arg1,p1,arg3).move_to(code); | |
14672 | + } else { | |
14673 | + if (!imgout) _cimg_mp_return(arg1); | |
14674 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), | |
14675 | + arg1,arg3).move_to(code); | |
14676 | + } | |
14677 | + | |
14678 | + } else if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) **= value | |
14679 | + p1 = ref[1]; // Index | |
14680 | + is_relative = (bool)ref[2]; | |
14681 | + arg3 = ref[3]; // X | |
14682 | + arg4 = ref[4]; // Y | |
14683 | + arg5 = ref[5]; // Z | |
14684 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14685 | + if (p1!=~0U) { | |
14686 | + if (!listout) _cimg_mp_return(arg1); | |
14687 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), | |
14688 | + arg1,p1,arg3,arg4,arg5).move_to(code); | |
14689 | + } else { | |
14690 | + if (!imgout) _cimg_mp_return(arg1); | |
14691 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), | |
14692 | + arg1,arg3,arg4,arg5).move_to(code); | |
14693 | + } | |
14036 | 14694 | } |
14695 | + | |
14696 | + _cimg_mp_return(arg1); | |
14697 | + } | |
14698 | + | |
14699 | + for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1 | |
14700 | + if (*s=='=' && (*ps=='+' || *ps=='-' || *ps=='*' || *ps=='/' || *ps=='%' || | |
14701 | + *ps=='&' || *ps=='^' || *ps=='|' || | |
14702 | + (*ps=='>' && *ns=='>') || (*ps=='<' && *ns=='<')) && | |
14703 | + level[s - expr._data]==clevel) { // Self-operators (+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=) | |
14704 | + 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; | |
14715 | + } | |
14716 | + s1 = *ps=='>' || *ps=='<'?ns:ps; | |
14717 | + | |
14718 | + ref.assign(7); | |
14719 | + arg1 = compile(ss,s1,depth1,ref); // Variable slot | |
14720 | + arg2 = compile(s + 1,se,depth1,0); // Value to apply | |
14721 | + | |
14722 | + if (*ref>0 && !_cimg_mp_is_temp(arg1)) { // Apply operator on a copy if necessary. | |
14723 | + if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1); | |
14724 | + else arg1 = scalar1(mp_copy,arg1); | |
14725 | + } | |
14726 | + | |
14727 | + if (*ref==1) { // Vector value (scalar): V[k] += scalar | |
14728 | + _cimg_mp_check_type(arg2,2,s_op,1,0); | |
14729 | + arg3 = ref[1]; // Vector slot | |
14730 | + arg4 = ref[2]; // Index | |
14731 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14732 | + CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code); | |
14733 | + CImg<uptrT>::vector((uptrT)mp_vector_set_off,arg1,arg3,(uptrT)_cimg_mp_vector_size(arg3),arg4,arg1). | |
14734 | + move_to(code); | |
14735 | + _cimg_mp_return(arg1); | |
14736 | + } | |
14737 | + | |
14738 | + if (*ref==2) { // Image value (scalar): i/j[_#ind,off] += scalar | |
14739 | + _cimg_mp_check_type(arg2,2,s_op,1,0); | |
14740 | + p1 = ref[1]; // Index | |
14741 | + is_relative = (bool)ref[2]; | |
14742 | + arg3 = ref[3]; // Offset | |
14743 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14744 | + CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code); | |
14745 | + if (p1!=~0U) { | |
14746 | + if (!listout) _cimg_mp_return(arg1); | |
14747 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_joff:mp_list_set_ioff), | |
14748 | + arg1,p1,arg3).move_to(code); | |
14749 | + } else { | |
14750 | + if (!imgout) _cimg_mp_return(arg1); | |
14751 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_joff:mp_set_ioff), | |
14752 | + arg1,arg3).move_to(code); | |
14753 | + } | |
14754 | + _cimg_mp_return(arg1); | |
14755 | + } | |
14756 | + | |
14757 | + 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); | |
14759 | + p1 = ref[1]; // Index | |
14760 | + is_relative = (bool)ref[2]; | |
14761 | + arg3 = ref[3]; // X | |
14762 | + arg4 = ref[4]; // Y | |
14763 | + arg5 = ref[5]; // Z | |
14764 | + arg6 = ref[6]; // C | |
14765 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
14766 | + CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code); | |
14767 | + if (p1!=~0U) { | |
14768 | + if (!listout) _cimg_mp_return(arg1); | |
14769 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), | |
14770 | + arg1,p1,arg3,arg4,arg5,arg6).move_to(code); | |
14771 | + } else { | |
14772 | + if (!imgout) _cimg_mp_return(arg1); | |
14773 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), | |
14774 | + arg1,arg3,arg4,arg5,arg6).move_to(code); | |
14775 | + } | |
14776 | + _cimg_mp_return(arg1); | |
14777 | + } | |
14778 | + | |
14779 | + 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)); | |
14781 | + p1 = ref[1]; // Index | |
14782 | + is_relative = (bool)ref[2]; | |
14783 | + arg3 = ref[3]; // Offset | |
14784 | + 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); | |
14791 | + if (p1!=~0U) { | |
14792 | + if (!listout) _cimg_mp_return(arg1); | |
14793 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), | |
14794 | + arg1,p1,arg3).move_to(code); | |
14795 | + } else { | |
14796 | + if (!imgout) _cimg_mp_return(arg1); | |
14797 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), | |
14798 | + arg1,arg3).move_to(code); | |
14799 | + } | |
14800 | + _cimg_mp_return(arg1); | |
14801 | + } | |
14802 | + | |
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)); | |
14805 | + p1 = ref[1]; // Index | |
14806 | + is_relative = (bool)ref[2]; | |
14807 | + arg3 = ref[3]; // X | |
14808 | + arg4 = ref[4]; // Y | |
14809 | + arg5 = ref[5]; // Z | |
14810 | + 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); | |
14817 | + if (p1!=~0U) { | |
14818 | + if (!listout) _cimg_mp_return(arg1); | |
14819 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), | |
14820 | + arg1,p1,arg3,arg4,arg5).move_to(code); | |
14821 | + } else { | |
14822 | + if (!imgout) _cimg_mp_return(arg1); | |
14823 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), | |
14824 | + arg1,arg3,arg4,arg5).move_to(code); | |
14825 | + } | |
14826 | + _cimg_mp_return(arg1); | |
14827 | + } | |
14828 | + | |
14829 | + 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); | |
14837 | + _cimg_mp_return(arg1); | |
14838 | + } | |
14839 | + | |
14840 | + if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s += scalar | |
14841 | + _cimg_mp_check_type(arg2,2,s_op,1,0); | |
14842 | + CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code); | |
14843 | + _cimg_mp_return(arg1); | |
14844 | + } | |
14845 | + | |
14846 | + variable_name.assign(ss,(unsigned int)(s - ss)).back() = 0; | |
14847 | + *se = saved_char; cimg::strellipsize(expr,64); | |
14848 | + throw CImgArgumentException("[_cimg_math_parser] " | |
14849 | + "CImg<%s>::%s: %s: Invalid left-hand operand '%s', " | |
14850 | + "in expression '%s%s%s'.", | |
14851 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
14852 | + variable_name._data, | |
14853 | + (ss - 4)>expr._data?"...":"", | |
14854 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
14855 | + se<&expr.back()?"...":""); | |
14856 | + } | |
14857 | + | |
14858 | + for (s = ss1; s<se1; ++s) | |
14859 | + if (*s=='?' && level[s - expr._data]==clevel) { // Ternary operator 'cond?expr1:expr2' | |
14860 | + s_op = "Operator '?:'"; | |
14861 | + s1 = s + 1; while (s1<se1 && (*s1!=':' || level[s1 - expr._data]!=clevel)) ++s1; | |
14862 | + arg1 = compile(ss,s,depth1,0); | |
14863 | + p2 = code._width; | |
14864 | + arg2 = compile(s + 1,*s1!=':'?se:s1,depth1,0); | |
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]); | |
14871 | + arg4 = _cimg_mp_is_vector(arg2)?_cimg_mp_vector_size(arg2):0; // Output vector size (or 0 if scalar) | |
14872 | + if (arg4) pos = vector(arg4); else pos = scalar(); | |
14873 | + CImg<uptrT>::vector((uptrT)mp_if,pos,arg1,arg2,arg3, | |
14874 | + p3 - p2,code._width - p3,arg4).move_to(code,p2); | |
14875 | + _cimg_mp_return(pos); | |
14876 | + } | |
14877 | + | |
14878 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
14879 | + if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { // Logical or ('||') | |
14880 | + s_op = "Operator '||'"; | |
14881 | + arg1 = compile(ss,s,depth1,0); | |
14882 | + p2 = code._width; | |
14883 | + 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); | |
14886 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
14887 | + _cimg_mp_constant(mem[arg1] || mem[arg2]); | |
14888 | + pos = scalar(); | |
14889 | + CImg<uptrT>::vector((uptrT)mp_logical_or,pos,arg1,arg2,code._width - p2). | |
14890 | + move_to(code,p2); | |
14891 | + _cimg_mp_return(pos); | |
14892 | + } | |
14893 | + | |
14894 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
14895 | + if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { // Logical and ('&&') | |
14896 | + s_op = "Operator '&&'"; | |
14897 | + arg1 = compile(ss,s,depth1,0); | |
14898 | + p2 = code._width; | |
14899 | + 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); | |
14902 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
14903 | + _cimg_mp_constant(mem[arg1] && mem[arg2]); | |
14904 | + pos = scalar(); | |
14905 | + CImg<uptrT>::vector((uptrT)mp_logical_and,pos,arg1,arg2,code._width - p2). | |
14906 | + move_to(code,p2); | |
14907 | + _cimg_mp_return(pos); | |
14037 | 14908 | } |
14038 | - if (*ss1=='m') { | |
14039 | - if (*ss=='x') { // xm | |
14040 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14041 | - if (reserved_label[11]!=~0U) _cimg_mp_return(reserved_label[11]); _cimg_mp_opcode0(mp_xm); | |
14909 | + | |
14910 | + for (s = se2; s>ss; --s) | |
14911 | + if (*s=='|' && level[s - expr._data]==clevel) { // Bitwise or ('|') | |
14912 | + arg1 = compile(ss,s,depth1,0); | |
14913 | + arg2 = compile(s + 1,se,depth1,0); | |
14914 | + _cimg_mp_check_type(arg2,2,"operator '|'",3,_cimg_mp_vector_size(arg1)); | |
14915 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_or,arg1,arg2); | |
14916 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_or,arg1,arg2); | |
14917 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_or,arg1,arg2); | |
14918 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
14919 | + _cimg_mp_constant((unsigned long)mem[arg1] | (unsigned long)mem[arg2]); | |
14920 | + _cimg_mp_scalar2(mp_bitwise_or,arg1,arg2); | |
14921 | + } | |
14922 | + | |
14923 | + for (s = se2; s>ss; --s) | |
14924 | + if (*s=='&' && level[s - expr._data]==clevel) { // Bitwise and ('&') | |
14925 | + arg1 = compile(ss,s,depth1,0); | |
14926 | + arg2 = compile(s + 1,se,depth1,0); | |
14927 | + _cimg_mp_check_type(arg2,2,"operator '&'",3,_cimg_mp_vector_size(arg1)); | |
14928 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_and,arg1,arg2); | |
14929 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_and,arg1,arg2); | |
14930 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_and,arg1,arg2); | |
14931 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
14932 | + _cimg_mp_constant((unsigned long)mem[arg1] & (unsigned long)mem[arg2]); | |
14933 | + _cimg_mp_scalar2(mp_bitwise_and,arg1,arg2); | |
14934 | + } | |
14935 | + | |
14936 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
14937 | + if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) { // Not equal to ('!=') | |
14938 | + arg1 = compile(ss,s,depth1,0); | |
14939 | + arg2 = compile(s + 2,se,depth1,0); | |
14940 | + _cimg_mp_check_type(arg2,2,"operator '!='",3,_cimg_mp_vector_size(arg1)); | |
14941 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_neq,arg1,arg2); | |
14942 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_neq,arg1,arg2); | |
14943 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_neq,arg1,arg2); | |
14944 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]!=mem[arg2]); | |
14945 | + _cimg_mp_scalar2(mp_neq,arg1,arg2); | |
14946 | + } | |
14947 | + | |
14948 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
14949 | + if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) { // Equal to ('==') | |
14950 | + arg1 = compile(ss,s,depth1,0); | |
14951 | + arg2 = compile(s + 2,se,depth1,0); | |
14952 | + _cimg_mp_check_type(arg2,2,"operator '=='",3,_cimg_mp_vector_size(arg1)); | |
14953 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_eq,arg1,arg2); | |
14954 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_eq,arg1,arg2); | |
14955 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_eq,arg1,arg2); | |
14956 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]==mem[arg2]); | |
14957 | + _cimg_mp_scalar2(mp_eq,arg1,arg2); | |
14958 | + } | |
14959 | + | |
14960 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
14961 | + if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) { // Less or equal than ('<=') | |
14962 | + arg1 = compile(ss,s,depth1,0); | |
14963 | + arg2 = compile(s + 2,se,depth1,0); | |
14964 | + _cimg_mp_check_type(arg2,2,"operator '<='",3,_cimg_mp_vector_size(arg1)); | |
14965 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lte,arg1,arg2); | |
14966 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lte,arg1,arg2); | |
14967 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lte,arg1,arg2); | |
14968 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<=mem[arg2]); | |
14969 | + _cimg_mp_scalar2(mp_lte,arg1,arg2); | |
14970 | + } | |
14971 | + | |
14972 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
14973 | + if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) { // Greater or equal than ('>=') | |
14974 | + arg1 = compile(ss,s,depth1,0); | |
14975 | + arg2 = compile(s + 2,se,depth1,0); | |
14976 | + _cimg_mp_check_type(arg2,2,"operator '>='",3,_cimg_mp_vector_size(arg1)); | |
14977 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gte,arg1,arg2); | |
14978 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gte,arg1,arg2); | |
14979 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gte,arg1,arg2); | |
14980 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>=mem[arg2]); | |
14981 | + _cimg_mp_scalar2(mp_gte,arg1,arg2); | |
14982 | + } | |
14983 | + | |
14984 | + for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps) | |
14985 | + if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) { // Less than ('<') | |
14986 | + arg1 = compile(ss,s,depth1,0); | |
14987 | + arg2 = compile(s + 1,se,depth1,0); | |
14988 | + _cimg_mp_check_type(arg2,2,"operator '<'",3,_cimg_mp_vector_size(arg1)); | |
14989 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lt,arg1,arg2); | |
14990 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lt,arg1,arg2); | |
14991 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lt,arg1,arg2); | |
14992 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<mem[arg2]); | |
14993 | + _cimg_mp_scalar2(mp_lt,arg1,arg2); | |
14994 | + } | |
14995 | + | |
14996 | + for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps) | |
14997 | + if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) { // Greather than ('>') | |
14998 | + arg1 = compile(ss,s,depth1,0); | |
14999 | + arg2 = compile(s + 1,se,depth1,0); | |
15000 | + _cimg_mp_check_type(arg2,2,"operator '>'",3,_cimg_mp_vector_size(arg1)); | |
15001 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gt,arg1,arg2); | |
15002 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gt,arg1,arg2); | |
15003 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gt,arg1,arg2); | |
15004 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>mem[arg2]); | |
15005 | + _cimg_mp_scalar2(mp_gt,arg1,arg2); | |
15006 | + } | |
15007 | + | |
15008 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
15009 | + if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) { // Left bit shift ('<<') | |
15010 | + arg1 = compile(ss,s,depth1,0); | |
15011 | + arg2 = compile(s + 2,se,depth1,0); | |
15012 | + _cimg_mp_check_type(arg2,2,"operator '<<'",3,_cimg_mp_vector_size(arg1)); | |
15013 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) | |
15014 | + _cimg_mp_vector2_vv(mp_bitwise_left_shift,arg1,arg2); | |
15015 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) | |
15016 | + _cimg_mp_vector2_vs(mp_bitwise_left_shift,arg1,arg2); | |
15017 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) | |
15018 | + _cimg_mp_vector2_sv(mp_bitwise_left_shift,arg1,arg2); | |
15019 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
15020 | + _cimg_mp_constant((long)mem[arg1]<<(unsigned int)mem[arg2]); | |
15021 | + _cimg_mp_scalar2(mp_bitwise_left_shift,arg1,arg2); | |
15022 | + } | |
15023 | + | |
15024 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
15025 | + if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) { // Right bit shift ('>>') | |
15026 | + arg1 = compile(ss,s,depth1,0); | |
15027 | + arg2 = compile(s + 2,se,depth1,0); | |
15028 | + _cimg_mp_check_type(arg2,2,"operator '>>'",3,_cimg_mp_vector_size(arg1)); | |
15029 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) | |
15030 | + _cimg_mp_vector2_vv(mp_bitwise_right_shift,arg1,arg2); | |
15031 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) | |
15032 | + _cimg_mp_vector2_vs(mp_bitwise_right_shift,arg1,arg2); | |
15033 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) | |
15034 | + _cimg_mp_vector2_sv(mp_bitwise_right_shift,arg1,arg2); | |
15035 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
15036 | + _cimg_mp_constant((long)mem[arg1]>>(unsigned int)mem[arg2]); | |
15037 | + _cimg_mp_scalar2(mp_bitwise_right_shift,arg1,arg2); | |
15038 | + } | |
15039 | + | |
15040 | + for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps) | |
15041 | + if (*s=='+' && (*ns!='+' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && | |
15042 | + *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' && | |
15043 | + (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' && | |
15044 | + *(ps - 1)<='9')))) && | |
15045 | + level[s - expr._data]==clevel) { // Addition ('+') | |
15046 | + arg1 = compile(ss,s,depth1,0); | |
15047 | + arg2 = compile(s + 1,se,depth1,0); | |
15048 | + _cimg_mp_check_type(arg2,2,"operator '+'",3,_cimg_mp_vector_size(arg1)); | |
15049 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_add,arg1,arg2); | |
15050 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_add,arg1,arg2); | |
15051 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_add,arg1,arg2); | |
15052 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] + mem[arg2]); | |
15053 | + if (arg2==1) _cimg_mp_scalar1(mp_increment,arg1); | |
15054 | + if (arg1==1) _cimg_mp_scalar1(mp_increment,arg2); | |
15055 | + _cimg_mp_scalar2(mp_add,arg1,arg2); | |
15056 | + } | |
15057 | + | |
15058 | + for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps) | |
15059 | + if (*s=='-' && (*ns!='-' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && | |
15060 | + *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' && | |
15061 | + (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' && | |
15062 | + *(ps - 1)<='9')))) && | |
15063 | + level[s - expr._data]==clevel) { // Subtraction ('-') | |
15064 | + arg1 = compile(ss,s,depth1,0); | |
15065 | + arg2 = compile(s + 1,se,depth1,0); | |
15066 | + _cimg_mp_check_type(arg2,2,"operator '-'",3,_cimg_mp_vector_size(arg1)); | |
15067 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_sub,arg1,arg2); | |
15068 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_sub,arg1,arg2); | |
15069 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_sub,arg1,arg2); | |
15070 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] - mem[arg2]); | |
15071 | + if (arg2==1) _cimg_mp_scalar1(mp_decrement,arg1); | |
15072 | + _cimg_mp_scalar2(mp_sub,arg1,arg2); | |
15073 | + } | |
15074 | + | |
15075 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
15076 | + if (*s=='*' && *ns=='*' && level[s - expr._data]==clevel) { // Complex/matrix multiplication ('**') | |
15077 | + s_op = "Operator '**'"; | |
15078 | + arg1 = compile(ss,s,depth1,0); | |
15079 | + arg2 = compile(s + 2,se,depth1,0); | |
15080 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) { | |
15081 | + if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2) { // Complex multiplication | |
15082 | + pos = vector(2); | |
15083 | + CImg<uptrT>::vector((uptrT)mp_complex_mul,pos,arg1,arg2).move_to(code); | |
15084 | + _cimg_mp_return(pos); | |
15085 | + } else { // Matrix multiplication | |
15086 | + p1 = _cimg_mp_vector_size(arg1); | |
15087 | + p2 = _cimg_mp_vector_size(arg2); | |
15088 | + arg4 = p1/p2; | |
15089 | + if (arg4*p2!=p1) { | |
15090 | + *se = saved_char; cimg::strellipsize(expr,64); | |
15091 | + throw CImgArgumentException("[_cimg_math_parser] " | |
15092 | + "CImg<%s>::%s: %s: Sizes of left-hand and right-hand operands " | |
15093 | + "('%s' and '%s') do not match, in expression '%s%s%s'.", | |
15094 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
15095 | + s_type(arg1)._data,s_type(arg2)._data, | |
15096 | + (ss - 4)>expr._data?"...":"", | |
15097 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
15098 | + se<&expr.back()?"...":""); | |
15099 | + } | |
15100 | + pos = vector(arg4); | |
15101 | + CImg<uptrT>::vector((uptrT)mp_matrix_mul,pos,arg1,arg2,arg4,p2,1).move_to(code); | |
15102 | + _cimg_mp_return(pos); | |
15103 | + } | |
14042 | 15104 | } |
14043 | - if (*ss=='y') { // ym | |
14044 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14045 | - if (reserved_label[12]!=~0U) _cimg_mp_return(reserved_label[12]); _cimg_mp_opcode0(mp_ym); | |
15105 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2); | |
15106 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2); | |
15107 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]); | |
15108 | + _cimg_mp_scalar2(mp_mul,arg1,arg2); | |
15109 | + } | |
15110 | + | |
15111 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
15112 | + if (*s=='/' && *ns=='/' && level[s - expr._data]==clevel) { // Complex division ('//') | |
15113 | + s_op = "Operator '//'"; | |
15114 | + arg1 = compile(ss,s,depth1,0); | |
15115 | + 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); | |
15118 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) { | |
15119 | + pos = vector(2); | |
15120 | + CImg<uptrT>::vector((uptrT)mp_complex_div_vv,pos,arg1,arg2).move_to(code); | |
15121 | + _cimg_mp_return(pos); | |
14046 | 15122 | } |
14047 | - if (*ss=='z') { // zm | |
14048 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14049 | - if (reserved_label[13]!=~0U) _cimg_mp_return(reserved_label[13]); _cimg_mp_opcode0(mp_zm); | |
15123 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2); | |
15124 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) { | |
15125 | + pos = vector(2); | |
15126 | + CImg<uptrT>::vector((uptrT)mp_complex_div_sv,pos,arg1,arg2).move_to(code); | |
15127 | + _cimg_mp_return(pos); | |
14050 | 15128 | } |
14051 | - if (*ss=='c') { // cm | |
14052 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14053 | - if (reserved_label[14]!=~0U) _cimg_mp_return(reserved_label[14]); _cimg_mp_opcode0(mp_cm); | |
15129 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]); | |
15130 | + _cimg_mp_scalar2(mp_div,arg1,arg2); | |
15131 | + } | |
15132 | + | |
15133 | + for (s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { // Multiplication ('*') | |
15134 | + arg1 = compile(ss,s,depth1,0); | |
15135 | + arg2 = compile(s + 1,se,depth1,0); | |
15136 | + _cimg_mp_check_type(arg2,2,"operator '*'",3,_cimg_mp_vector_size(arg1)); | |
15137 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_mul,arg1,arg2); | |
15138 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2); | |
15139 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2); | |
15140 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]); | |
15141 | + _cimg_mp_scalar2(mp_mul,arg1,arg2); | |
15142 | + } | |
15143 | + | |
15144 | + | |
15145 | + for (s = se2; s>ss; --s) if (*s=='/' && level[s - expr._data]==clevel) { // Division ('/') | |
15146 | + arg1 = compile(ss,s,depth1,0); | |
15147 | + arg2 = compile(s + 1,se,depth1,0); | |
15148 | + _cimg_mp_check_type(arg2,2,"operator '/'",3,_cimg_mp_vector_size(arg1)); | |
15149 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_div,arg1,arg2); | |
15150 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2); | |
15151 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_div,arg1,arg2); | |
15152 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]); | |
15153 | + _cimg_mp_scalar2(mp_div,arg1,arg2); | |
15154 | + } | |
15155 | + | |
15156 | + for (s = se2, ns = se1; s>ss; --s, --ns) | |
15157 | + if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) { // Modulo ('%') | |
15158 | + arg1 = compile(ss,s,depth1,0); | |
15159 | + arg2 = compile(s + 1,se,depth1,0); | |
15160 | + _cimg_mp_check_type(arg2,2,"operator '%'",3,_cimg_mp_vector_size(arg1)); | |
15161 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_modulo,arg1,arg2); | |
15162 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_modulo,arg1,arg2); | |
15163 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_modulo,arg1,arg2); | |
15164 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
15165 | + _cimg_mp_constant(cimg::mod(mem[arg1],mem[arg2])); | |
15166 | + _cimg_mp_scalar2(mp_modulo,arg1,arg2); | |
15167 | + } | |
15168 | + | |
15169 | + if (se1>ss) { | |
15170 | + if (*ss=='+' && (*ss1!='+' || (ss2<se && *ss2>='0' && *ss2<='9'))) // Unary plus ('+') | |
15171 | + _cimg_mp_return(compile(ss1,se,depth1,0)); | |
15172 | + | |
15173 | + if (*ss=='-' && (*ss1!='-' || (ss2<se && *ss2>='0' && *ss2<='9'))) { // Unary minus ('-') | |
15174 | + arg1 = compile(ss1,se,depth1,0); | |
15175 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_minus,arg1); | |
15176 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(-mem[arg1]); | |
15177 | + _cimg_mp_scalar1(mp_minus,arg1); | |
15178 | + } | |
15179 | + | |
15180 | + if (*ss=='!') { // Logical not ('!') | |
15181 | + arg1 = compile(ss1,se,depth1,0); | |
15182 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_logical_not,arg1); | |
15183 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(!mem[arg1]); | |
15184 | + _cimg_mp_scalar1(mp_logical_not,arg1); | |
15185 | + } | |
15186 | + | |
15187 | + if (*ss=='~') { // Bitwise not ('~') | |
15188 | + arg1 = compile(ss1,se,depth1,0); | |
15189 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bitwise_not,arg1); | |
15190 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(~(unsigned long)mem[arg1]); | |
15191 | + _cimg_mp_scalar1(mp_bitwise_not,arg1); | |
15192 | + } | |
15193 | + } | |
15194 | + | |
15195 | + for (s = se3, ns = se2; s>ss; --s, --ns) | |
15196 | + if (*s=='^' && *ns=='^' && level[s - expr._data]==clevel) { // Complex power ('^^') | |
15197 | + s_op = "Operator '^^'"; | |
15198 | + arg1 = compile(ss,s,depth1,0); | |
15199 | + 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); | |
15202 | + pos = (_cimg_mp_is_vector(arg1) || _cimg_mp_is_vector(arg2))?vector(2):0; | |
15203 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) { | |
15204 | + CImg<uptrT>::vector((uptrT)mp_complex_pow_vv,pos,arg1,arg2).move_to(code); | |
15205 | + _cimg_mp_return(pos); | |
14054 | 15206 | } |
14055 | - } | |
14056 | - if (*ss1=='M') { | |
14057 | - if (*ss=='x') { // xM | |
14058 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14059 | - if (reserved_label[15]!=~0U) _cimg_mp_return(reserved_label[15]); _cimg_mp_opcode0(mp_xM); | |
15207 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) { | |
15208 | + CImg<uptrT>::vector((uptrT)mp_complex_pow_vs,pos,arg1,arg2).move_to(code); | |
15209 | + _cimg_mp_return(pos); | |
14060 | 15210 | } |
14061 | - if (*ss=='y') { // yM | |
14062 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14063 | - if (reserved_label[16]!=~0U) _cimg_mp_return(reserved_label[16]); _cimg_mp_opcode0(mp_yM); | |
15211 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) { | |
15212 | + CImg<uptrT>::vector((uptrT)mp_complex_pow_sv,pos,arg1,arg2).move_to(code); | |
15213 | + _cimg_mp_return(pos); | |
14064 | 15214 | } |
14065 | - if (*ss=='z') { // zM | |
14066 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14067 | - if (reserved_label[17]!=~0U) _cimg_mp_return(reserved_label[17]); _cimg_mp_opcode0(mp_zM); | |
15215 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
15216 | + _cimg_mp_constant(std::pow(mem[arg1],mem[arg2])); | |
15217 | + switch (arg2) { | |
15218 | + case 0 : _cimg_mp_return(1); | |
15219 | + case 1 : _cimg_mp_return(arg1); | |
15220 | + case 2 : _cimg_mp_scalar1(mp_sqr,arg1); | |
15221 | + case 3 : _cimg_mp_scalar1(mp_pow3,arg1); | |
15222 | + case 4 : _cimg_mp_scalar1(mp_pow4,arg1); | |
15223 | + default : _cimg_mp_scalar2(mp_pow,arg1,arg2); | |
14068 | 15224 | } |
14069 | - if (*ss=='c') { // cM | |
14070 | - if (!reference_stats) reference.get_stats().move_to(reference_stats); | |
14071 | - if (reserved_label[18]!=~0U) _cimg_mp_return(reserved_label[18]); _cimg_mp_opcode0(mp_cM); | |
15225 | + } | |
15226 | + | |
15227 | + for (s = se2; s>ss; --s) | |
15228 | + if (*s=='^' && level[s - expr._data]==clevel) { // Power ('^') | |
15229 | + arg1 = compile(ss,s,depth1,0); | |
15230 | + arg2 = compile(s + 1,se,depth1,0); | |
15231 | + _cimg_mp_check_type(arg2,2,"operator '^'",3,_cimg_mp_vector_size(arg1)); | |
15232 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_pow,arg1,arg2); | |
15233 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_pow,arg1,arg2); | |
15234 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_pow,arg1,arg2); | |
15235 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
15236 | + _cimg_mp_constant(std::pow(mem[arg1],mem[arg2])); | |
15237 | + switch (arg2) { | |
15238 | + case 0 : _cimg_mp_return(1); | |
15239 | + case 1 : _cimg_mp_return(arg1); | |
15240 | + case 2 : _cimg_mp_scalar1(mp_sqr,arg1); | |
15241 | + case 3 : _cimg_mp_scalar1(mp_pow3,arg1); | |
15242 | + case 4 : _cimg_mp_scalar1(mp_pow4,arg1); | |
15243 | + default : _cimg_mp_scalar2(mp_pow,arg1,arg2); | |
14072 | 15244 | } |
14073 | 15245 | } |
14074 | - } else if (ss3==se) { // Three-chars variable. | |
14075 | - if (*ss=='w' && *ss1=='h' && *ss2=='d') _cimg_mp_return(reserved_label[1]); // whd | |
14076 | - } else if (ss4==se) { // Four-chars variable. | |
14077 | - if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') _cimg_mp_return(reserved_label[2]); // whds | |
14078 | - } | |
14079 | 15246 | |
14080 | - // Look for variable declarations. | |
14081 | - for (char *s = se2; s>ss; --s) | |
14082 | - if (*s==';' && level[s - expr._data]==clevel) { compile(ss,s); _cimg_mp_return(compile(s + 1,se)); } | |
14083 | - for (char *s = ss1, *ps = ss, *ns = ss2; s<se1; ++s, ++ps, ++ns) | |
14084 | - if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' && level[s - expr._data]==clevel) { | |
14085 | - CImg<charT> variable_name(ss,(unsigned int)(s - ss + 1)); | |
14086 | - variable_name.back() = 0; | |
14087 | - cimg::strpare(variable_name); | |
14088 | - bool is_valid_name = true; | |
14089 | - if (*variable_name>='0' && *variable_name<='9') is_valid_name = false; | |
14090 | - else for (const char *ns = variable_name._data + 1; *ns; ++ns) | |
14091 | - if ((*ns<'a' || *ns>'z') && (*ns<'A' || *ns>'Z') && (*ns<'0' || *ns>'9') && *ns!='_') { | |
14092 | - is_valid_name = false; break; | |
14093 | - } | |
14094 | - if (!is_valid_name) { | |
14095 | - *se = saved_char; | |
14096 | - throw CImgArgumentException("[_cimg_math_parser] " | |
14097 | - "CImg<%s>::%s(): Invalid variable name '%s' in specified expression " | |
14098 | - "'%s%s%s'.", | |
14099 | - pixel_type(),calling_function, | |
14100 | - variable_name._data, | |
14101 | - (ss - 8)>expr._data?"...":"", | |
14102 | - (ss - 8)>expr._data?ss - 8:expr._data, | |
14103 | - se<&expr.back()?"...":""); | |
15247 | + is_sth = ss1<se1 && (*ss=='+' || *ss=='-') && *ss1==*ss; // is pre-? | |
15248 | + 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 | + | |
15252 | + ref.assign(7); | |
15253 | + arg1 = is_sth?compile(ss2,se,depth1,ref):compile(ss,se2,depth1,ref); // Variable slot | |
15254 | + | |
15255 | + if (*ref>0 && !_cimg_mp_is_temp(arg1)) { // Apply operator on a copy if necessary. | |
15256 | + if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1); | |
15257 | + else arg1 = scalar1(mp_copy,arg1); | |
15258 | + } | |
15259 | + | |
15260 | + if (is_sth) pos = arg1; // Determine return indice, depending on pre/post action | |
15261 | + else { | |
15262 | + if (_cimg_mp_is_vector(arg1)) pos = vector_copy(arg1); | |
15263 | + else pos = scalar1(mp_copy,arg1); | |
15264 | + } | |
15265 | + | |
15266 | + if (*ref==1) { // Vector value (scalar): V[k]++ | |
15267 | + arg3 = ref[1]; // Vector slot | |
15268 | + arg4 = ref[2]; // Index | |
15269 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
15270 | + CImg<uptrT>::vector((uptrT)op,arg1,1).move_to(code); | |
15271 | + CImg<uptrT>::vector((uptrT)mp_vector_set_off,arg1,arg3,(uptrT)_cimg_mp_vector_size(arg3),arg4,arg1). | |
15272 | + move_to(code); | |
15273 | + _cimg_mp_return(pos); | |
15274 | + } | |
15275 | + | |
15276 | + if (*ref==2) { // Image value (scalar): i/j[_#ind,off]++ | |
15277 | + p1 = ref[1]; // Index | |
15278 | + is_relative = (bool)ref[2]; | |
15279 | + arg3 = ref[3]; // Offset | |
15280 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
15281 | + CImg<uptrT>::vector((uptrT)op,arg1).move_to(code); | |
15282 | + if (p1!=~0U) { | |
15283 | + if (!listout) _cimg_mp_return(pos); | |
15284 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_joff:mp_list_set_ioff), | |
15285 | + arg1,p1,arg3).move_to(code); | |
15286 | + } else { | |
15287 | + if (!imgout) _cimg_mp_return(pos); | |
15288 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_joff:mp_set_ioff), | |
15289 | + arg1,arg3).move_to(code); | |
14104 | 15290 | } |
14105 | - const unsigned int pos = compile(s + 1,se); | |
14106 | - | |
14107 | - // Check for particular case of a reserved variable. | |
14108 | - if (variable_name[1] && !variable_name[2]) { // Two-chars variable. | |
14109 | - const char c1 = variable_name[0], c2 = variable_name[1]; | |
14110 | - if (c1=='w' && c2=='h') variable_name.fill((char)0,(char)0); // wh | |
14111 | - else if (c1=='p' && c2=='i') variable_name.fill(3,0); // pi | |
14112 | - else if (c1=='i') { | |
14113 | - if (c2=='m') variable_name.fill(4,0); // im | |
14114 | - else if (c2=='M') variable_name.fill(5,0); // iM | |
14115 | - else if (c2=='a') variable_name.fill(6,0); // ia | |
14116 | - else if (c2=='v') variable_name.fill(7,0); // iv | |
14117 | - else if (c2=='s') variable_name.fill(8,0); // is | |
14118 | - else if (c2=='p') variable_name.fill(9,0); // ip | |
14119 | - else if (c2=='c') variable_name.fill(10,0); // ic | |
14120 | - } else if (c2=='m') { | |
14121 | - if (c1=='x') variable_name.fill(11,0); // xm | |
14122 | - else if (c1=='y') variable_name.fill(12,0); // ym | |
14123 | - else if (c1=='z') variable_name.fill(13,0); // zm | |
14124 | - else if (c1=='c') variable_name.fill(14,0); // cm | |
14125 | - } else if (c2=='M') { | |
14126 | - if (c1=='x') variable_name.fill(15,0); // xM | |
14127 | - else if (c1=='y') variable_name.fill(16,0); // yM | |
14128 | - else if (c1=='z') variable_name.fill(17,0); // zM | |
14129 | - else if (c1=='c') variable_name.fill(18,0); // cM | |
14130 | - } | |
14131 | - } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable. | |
14132 | - const char c1 = variable_name[0], c2 = variable_name[1], c3 = variable_name[2]; | |
14133 | - if (c1=='w' && c2=='h' && c3=='d') variable_name.fill(1,0,0); // whd | |
14134 | - } else if (variable_name[1] && variable_name[2] && variable_name[3] && | |
14135 | - !variable_name[4]) { // Four-chars variable. | |
14136 | - const char c1 = variable_name[0], c2 = variable_name[1], c3 = variable_name[2], | |
14137 | - c4 = variable_name[3]; | |
14138 | - if (c1=='w' && c2=='h' && c3=='d' && c4=='s') variable_name.fill(2,0,0,0); // whds | |
15291 | + _cimg_mp_return(pos); | |
15292 | + } | |
15293 | + | |
15294 | + if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c)++ | |
15295 | + p1 = ref[1]; // Index | |
15296 | + is_relative = (bool)ref[2]; | |
15297 | + arg3 = ref[3]; // X | |
15298 | + arg4 = ref[4]; // Y | |
15299 | + arg5 = ref[5]; // Z | |
15300 | + arg6 = ref[6]; // C | |
15301 | + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); | |
15302 | + CImg<uptrT>::vector((uptrT)op,arg1).move_to(code); | |
15303 | + if (p1!=~0U) { | |
15304 | + if (!listout) _cimg_mp_return(pos); | |
15305 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), | |
15306 | + arg1,p1,arg3,arg4,arg5,arg6).move_to(code); | |
15307 | + } else { | |
15308 | + if (!imgout) _cimg_mp_return(pos); | |
15309 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), | |
15310 | + arg1,arg3,arg4,arg5,arg6).move_to(code); | |
15311 | + } | |
15312 | + _cimg_mp_return(pos); | |
15313 | + } | |
15314 | + | |
15315 | + if (*ref==4) { // Image value (vector): I/J[_#ind,off]++ | |
15316 | + p1 = ref[1]; // Index | |
15317 | + is_relative = (bool)ref[2]; | |
15318 | + arg3 = ref[3]; // Offset | |
15319 | + 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); | |
15323 | + if (p1!=~0U) { | |
15324 | + if (!listout) _cimg_mp_return(pos); | |
15325 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), | |
15326 | + arg1,p1,arg3).move_to(code); | |
15327 | + } else { | |
15328 | + if (!imgout) _cimg_mp_return(pos); | |
15329 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), | |
15330 | + arg1,arg3).move_to(code); | |
14139 | 15331 | } |
15332 | + _cimg_mp_return(pos); | |
15333 | + } | |
14140 | 15334 | |
14141 | - // Set new variable value. | |
14142 | - if (!variable_name[1]) reserved_label[*variable_name] = pos; | |
14143 | - else { | |
14144 | - int label_pos = -1; | |
14145 | - cimglist_for(labelM,i) // Check for existing variable with same name. | |
14146 | - if (!std::strcmp(variable_name,labelM[i])) { label_pos = i; break; } | |
14147 | - if (label_pos<0) { // If new variable. | |
14148 | - if (labelM._width>=labelMpos._width) labelMpos.resize(-200,1,1,1,0); | |
14149 | - label_pos = labelM.width(); | |
14150 | - variable_name.move_to(labelM); | |
14151 | - } | |
14152 | - labelMpos[label_pos] = pos; | |
15335 | + if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c)++ | |
15336 | + p1 = ref[1]; // Index | |
15337 | + is_relative = (bool)ref[2]; | |
15338 | + arg3 = ref[3]; // X | |
15339 | + arg4 = ref[4]; // Y | |
15340 | + arg5 = ref[5]; // Z | |
15341 | + 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); | |
15345 | + if (p1!=~0U) { | |
15346 | + if (!listout) _cimg_mp_return(pos); | |
15347 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), | |
15348 | + arg1,p1,arg3,arg4,arg5).move_to(code); | |
15349 | + } else { | |
15350 | + if (!imgout) _cimg_mp_return(pos); | |
15351 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), | |
15352 | + arg1,arg3,arg4,arg5).move_to(code); | |
14153 | 15353 | } |
14154 | 15354 | _cimg_mp_return(pos); |
14155 | 15355 | } |
14156 | 15356 | |
14157 | - // Look for unary/binary operators. The operator precedences is defined as in C++. | |
14158 | - for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { | |
14159 | - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 2,se); | |
14160 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
14161 | - const unsigned int pos = mempos++; | |
14162 | - CImg<longT>::vector(_cimg_mp_enfunc(mp_logical_or),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); | |
15357 | + 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); | |
14163 | 15361 | _cimg_mp_return(pos); |
14164 | 15362 | } |
14165 | - for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { | |
14166 | - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 2,se); | |
14167 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
14168 | - const unsigned int pos = mempos++; | |
14169 | - CImg<longT>::vector(_cimg_mp_enfunc(mp_logical_and),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); | |
15363 | + | |
15364 | + if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s++ | |
15365 | + CImg<uptrT>::vector((uptrT)op,arg1).move_to(code); | |
14170 | 15366 | _cimg_mp_return(pos); |
14171 | 15367 | } |
14172 | - for (char *s = se2; s>ss; --s) | |
14173 | - if (*s=='|' && level[s - expr._data]==clevel) | |
14174 | - _cimg_mp_opcode2(mp_bitwise_or,compile(ss,s),compile(s + 1,se)); | |
14175 | - for (char *s = se2; s>ss; --s) | |
14176 | - if (*s=='&' && level[s - expr._data]==clevel) | |
14177 | - _cimg_mp_opcode2(mp_bitwise_and,compile(ss,s),compile(s + 1,se)); | |
14178 | - for (char *s = se3, *ns = se2; s>ss; --s, --ns) | |
14179 | - if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) | |
14180 | - _cimg_mp_opcode2(mp_noteq,compile(ss,s),compile(s + 2,se)); | |
14181 | - for (char *s = se3, *ns = se2; s>ss; --s, --ns) | |
14182 | - if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) | |
14183 | - _cimg_mp_opcode2(mp_eqeq,compile(ss,s),compile(s + 2,se)); | |
14184 | - for (char *s = se3, *ns = se2; s>ss; --s, --ns) | |
14185 | - if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) | |
14186 | - _cimg_mp_opcode2(mp_infeq,compile(ss,s),compile(s + 2,se)); | |
14187 | - for (char *s = se3, *ns = se2; s>ss; --s, --ns) | |
14188 | - if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) | |
14189 | - _cimg_mp_opcode2(mp_supeq,compile(ss,s),compile(s + 2,se)); | |
14190 | - for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps) | |
14191 | - if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) | |
14192 | - _cimg_mp_opcode2(mp_inf,compile(ss,s),compile(s + 1,se)); | |
14193 | - for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps) | |
14194 | - if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) | |
14195 | - _cimg_mp_opcode2(mp_sup,compile(ss,s),compile(s + 1,se)); | |
14196 | - for (char *s = se3, *ns = se2; s>ss; --s, --ns) | |
14197 | - if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) | |
14198 | - _cimg_mp_opcode2(mp_lsl,compile(ss,s),compile(s + 2,se)); | |
14199 | - for (char *s = se3, *ns = se2; s>ss; --s, --ns) | |
14200 | - if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) | |
14201 | - _cimg_mp_opcode2(mp_lsr,compile(ss,s),compile(s + 2,se)); | |
14202 | - for (char *s = se2, *ps = se3; s>ss; --s, --ps) | |
14203 | - if (*s=='+' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && | |
14204 | - *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && | |
14205 | - (*ps!='e' || !(ps>ss && (*(ps - 1)=='.' || (*(ps - 1)>='0' && *(ps - 1)<='9')))) && | |
14206 | - level[s - expr._data]==clevel) | |
14207 | - _cimg_mp_opcode2(mp_add,compile(ss,s),compile(s + 1,se)); | |
14208 | - for (char *s = se2, *ps = se3; s>ss; --s, --ps) | |
14209 | - if (*s=='-' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && | |
14210 | - *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && | |
14211 | - (*ps!='e' || !(ps>ss && (*(ps - 1)=='.' || (*(ps - 1)>='0' && *(ps - 1)<='9')))) && | |
14212 | - level[s - expr._data]==clevel) | |
14213 | - _cimg_mp_opcode2(mp_sub,compile(ss,s),compile(s + 1,se)); | |
14214 | - for (char *s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { | |
14215 | - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 1,se); | |
14216 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
14217 | - const unsigned int pos = mempos++; | |
14218 | - CImg<longT>::vector(_cimg_mp_enfunc(mp_mul),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); | |
15368 | + | |
15369 | + if (is_sth) variable_name.assign(ss2,(unsigned int)(se - ss1)); | |
15370 | + else variable_name.assign(ss,(unsigned int)(se1 - ss)); | |
15371 | + variable_name.back() = 0; | |
15372 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
15373 | + throw CImgArgumentException("[_cimg_math_parser] " | |
15374 | + "CImg<%s>::%s: %s: Invalid operand '%s', " | |
15375 | + "in expression '%s%s%s'.", | |
15376 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
15377 | + variable_name._data, | |
15378 | + (ss - 4)>expr._data?"...":"", | |
15379 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
15380 | + se<&expr.back()?"...":""); | |
15381 | + } | |
15382 | + | |
15383 | + // Array-like access to vectors and image values 'i/j[_#ind,offset,_boundary]' and 'vector[offset]'. | |
15384 | + if (*se1==']' && *ss!='[') { | |
15385 | + s_op = "Operator '[]'"; | |
15386 | + is_relative = *ss=='j' || *ss=='J'; | |
15387 | + | |
15388 | + if ((*ss=='I' || *ss=='J') && *ss1=='[' && | |
15389 | + (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a vector | |
15390 | + if (*ss2=='#') { // Index specified | |
15391 | + s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0; | |
15392 | + p1 = compile(ss3,s0++,depth1,0); | |
15393 | + } else { p1 = ~0U; s0 = ss2; } | |
15394 | + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15395 | + arg1 = compile(s0,s1,depth1,0); // Offset | |
15396 | + arg2 = s1<se1?compile(s1 + 1,se1,depth1,0):~0U; // Boundary | |
15397 | + if (p_ref && arg2==~0U) { | |
15398 | + *p_ref = 4; | |
15399 | + p_ref[1] = p1; | |
15400 | + p_ref[2] = (unsigned int)is_relative; | |
15401 | + p_ref[3] = arg1; | |
15402 | + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization | |
15403 | + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1; | |
15404 | + } | |
15405 | + p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any | |
15406 | + if (p1==~0U) p2 = imgin._spectrum; | |
15407 | + else if (_cimg_mp_is_constant(p1)) { | |
15408 | + p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width()); | |
15409 | + p2 = listin[p3]._spectrum; | |
15410 | + } | |
15411 | + _cimg_mp_check_vector0(p2,s_op); | |
15412 | + pos = vector(p2); | |
15413 | + if (p1!=~0U) { | |
15414 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_Joff:mp_list_Ioff), | |
15415 | + pos,p1,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code); | |
15416 | + } else { | |
15417 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_Joff:mp_Ioff), | |
15418 | + pos,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code); | |
15419 | + } | |
14219 | 15420 | _cimg_mp_return(pos); |
14220 | 15421 | } |
14221 | - for (char *s = se2; s>ss; --s) | |
14222 | - if (*s=='/' && level[s - expr._data]==clevel) | |
14223 | - _cimg_mp_opcode2(mp_div,compile(ss,s),compile(s + 1,se)); | |
14224 | - for (char *s = se2, *ns = se1; s>ss; --s, --ns) | |
14225 | - if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) | |
14226 | - _cimg_mp_opcode2(mp_modulo,compile(ss,s),compile(s + 1,se)); | |
14227 | - if (ss<se1) { | |
14228 | - if (*ss=='+') _cimg_mp_return(compile(ss1,se)); | |
14229 | - if (*ss=='-') _cimg_mp_opcode1(mp_minus,compile(ss1,se)); | |
14230 | - if (*ss=='!') _cimg_mp_opcode1(mp_logical_not,compile(ss1,se)); | |
14231 | - if (*ss=='~') _cimg_mp_opcode1(mp_bitwise_not,compile(ss1,se)); | |
14232 | - } | |
14233 | - for (char *s = se2; s>ss; --s) | |
14234 | - if (*s=='^' && level[s - expr._data]==clevel) | |
14235 | - _cimg_mp_opcode2(mp_pow,compile(ss,s),compile(s + 1,se)); | |
14236 | 15422 | |
14237 | - // Array-like access to image values 'i[]' and 'j[]'. | |
14238 | - if (*se1==']') { | |
14239 | - const bool is_relative = *ss=='j'; | |
14240 | - if ((*ss=='i' || is_relative) && *ss1=='[') { | |
14241 | - if (*ss2==']') _cimg_mp_opcode0(mp_i); | |
14242 | - _cimg_mp_opcode1(is_relative?mp_joff:mp_ioff,compile(ss2,se1)); | |
15423 | + if ((*ss=='i' || *ss=='j') && *ss1=='[' && | |
15424 | + (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a scalar | |
15425 | + if (*ss2=='#') { // Index specified | |
15426 | + s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0; | |
15427 | + p1 = compile(ss3,s0++,depth1,0); | |
15428 | + } else { p1 = ~0U; s0 = ss2; } | |
15429 | + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15430 | + arg1 = compile(s0,s1,depth1,0); // Offset | |
15431 | + arg2 = s1<se1?compile(s1 + 1,se1,depth1,0):~0U; // Boundary | |
15432 | + if (p_ref && arg2==~0U) { | |
15433 | + *p_ref = 2; | |
15434 | + p_ref[1] = p1; | |
15435 | + p_ref[2] = (unsigned int)is_relative; | |
15436 | + p_ref[3] = arg1; | |
15437 | + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization | |
15438 | + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1; | |
15439 | + } | |
15440 | + if (p1!=~0U) { | |
15441 | + if (!listin) _cimg_mp_return(0); | |
15442 | + pos = scalar3(is_relative?mp_list_joff:mp_list_ioff,p1,arg1,arg2==~0U?reserved_label[30]:arg2); | |
15443 | + } else { | |
15444 | + if (!imgin) _cimg_mp_return(0); | |
15445 | + pos = scalar2(is_relative?mp_joff:mp_ioff,arg1,arg2==~0U?reserved_label[30]:arg2); | |
15446 | + } | |
15447 | + memtype[pos] = -1; // Create it as a variable to prevent from being used in further optimization | |
15448 | + _cimg_mp_return(pos); | |
15449 | + } | |
15450 | + | |
15451 | + s0 = se1; while (s0>ss && *s0!='[') --s0; | |
15452 | + if (s0>ss) { // Vector value | |
15453 | + arg1 = compile(ss,s0,depth1,0); | |
15454 | + s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15455 | + | |
15456 | + if (s1<se1) { // Two arguments -> sub-vector extraction | |
15457 | + arg2 = compile(++s0,s1,depth1,0); | |
15458 | + 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); | |
15461 | + p1 = (unsigned int)mem[arg2]; | |
15462 | + p2 = (unsigned int)mem[arg3]; | |
15463 | + p3 = _cimg_mp_vector_size(arg1); | |
15464 | + if (p1>=p3 || p2>=p3) { | |
15465 | + variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0; | |
15466 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
15467 | + throw CImgArgumentException("[_cimg_math_parser] " | |
15468 | + "CImg<%s>::%s: %s: Out-of-bounds request for sub-vector '%s[%d,%d]' " | |
15469 | + "(vector '%s' has dimension %u), " | |
15470 | + "in expression '%s%s%s'.", | |
15471 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
15472 | + variable_name._data,(int)mem[arg2],(int)mem[arg3], | |
15473 | + variable_name._data,p3, | |
15474 | + (ss - 4)>expr._data?"...":"", | |
15475 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
15476 | + se<&expr.back()?"...":""); | |
15477 | + } | |
15478 | + if (p1>p2) cimg::swap(p1,p2); | |
15479 | + (p2-=p1)++; | |
15480 | + pos = vector(p2); | |
15481 | + CImg<uptrT>::vector((uptrT)mp_vector_crop,pos,arg1,p1,p2).move_to(code); | |
15482 | + _cimg_mp_return(pos); | |
15483 | + } | |
15484 | + | |
15485 | + // One argument -> vector value reference | |
15486 | + if (_cimg_mp_is_scalar(arg1)) { | |
15487 | + variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0; | |
15488 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
15489 | + throw CImgArgumentException("[_cimg_math_parser] " | |
15490 | + "CImg<%s>::%s: %s: Array brackets used on non-vector variable '%s', " | |
15491 | + "in expression '%s%s%s'.", | |
15492 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
15493 | + variable_name._data, | |
15494 | + (ss - 4)>expr._data?"...":"", | |
15495 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
15496 | + se<&expr.back()?"...":""); | |
15497 | + } | |
15498 | + | |
15499 | + arg2 = compile(++s0,se1,depth1,0); | |
15500 | + if (_cimg_mp_is_constant(arg2)) { // Constant index | |
15501 | + nb = (int)mem[arg2]; | |
15502 | + if (nb>=0 && nb<(int)_cimg_mp_vector_size(arg1)) _cimg_mp_return(arg1 + 1 + nb); | |
15503 | + variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0; | |
15504 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
15505 | + throw CImgArgumentException("[_cimg_math_parser] " | |
15506 | + "CImg<%s>::%s: Out-of-bounds reference '%s[%d]' " | |
15507 | + "(vector '%s' has dimension %u), " | |
15508 | + "in expression '%s%s%s'.", | |
15509 | + pixel_type(),_cimg_mp_calling_function, | |
15510 | + variable_name._data,nb, | |
15511 | + variable_name._data,_cimg_mp_vector_size(arg1), | |
15512 | + (ss - 4)>expr._data?"...":"", | |
15513 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
15514 | + se<&expr.back()?"...":""); | |
15515 | + } | |
15516 | + if (p_ref) { | |
15517 | + *p_ref = 1; | |
15518 | + p_ref[1] = arg1; | |
15519 | + p_ref[2] = arg2; | |
15520 | + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; // Prevent from being used in further optimization | |
15521 | + } | |
15522 | + _cimg_mp_scalar3(mp_vector_off,arg1,(uptrT)_cimg_mp_vector_size(arg1),arg2); | |
14243 | 15523 | } |
14244 | 15524 | } |
14245 | 15525 | |
14246 | - // Look for a function call or a parenthesis. | |
15526 | + // Look for a function call, an access to image value, or a parenthesis. | |
14247 | 15527 | if (*se1==')') { |
14248 | - if (*ss=='(') _cimg_mp_return(compile(ss1,se1)); | |
14249 | - | |
14250 | - const bool is_relative = *ss=='j'; | |
14251 | - if ((*ss=='i' || is_relative) && *ss1=='(') { | |
14252 | - if (*ss2==')') _cimg_mp_opcode0(mp_i); | |
14253 | - unsigned int | |
14254 | - indx = is_relative?0U:16U, indy = is_relative?0U:17U, | |
14255 | - indz = is_relative?0U:18U, indc = is_relative?0U:19U, | |
14256 | - borders = 0, interpolation = 0; | |
14257 | - if (ss2!=se1) { | |
14258 | - char *s1 = ss2; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14259 | - indx = compile(ss2,s1==se2?++s1:s1); | |
14260 | - if (s1<se1) { | |
14261 | - char *s2 = s1 + 1; while (s2<se2 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
14262 | - indy = compile(s1 + 1,s2==se2?++s2:s2); | |
15528 | + if (*ss=='(') _cimg_mp_return(compile(ss1,se1,depth1,p_ref)); // Simple parentheses | |
15529 | + is_relative = *ss=='j' || *ss=='J'; | |
15530 | + | |
15531 | + // I/J(_#ind,_x,_y,_z,_c,_interpolation,_boundary) | |
15532 | + if ((*ss=='I' || *ss=='J') && *ss1=='(') { // Image value as scalar | |
15533 | + if (*ss2=='#') { // Index specified | |
15534 | + s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0; | |
15535 | + p1 = compile(ss3,s0++,depth1,0); | |
15536 | + } else { p1 = ~0U; s0 = ss2; } | |
15537 | + arg1 = is_relative?0U:(unsigned int)_cimg_mp_x; | |
15538 | + arg2 = is_relative?0U:(unsigned int)_cimg_mp_y; | |
15539 | + arg3 = is_relative?0U:(unsigned int)_cimg_mp_z; | |
15540 | + arg4 = arg5 = ~0U; | |
15541 | + if (s0<se1) { | |
15542 | + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15543 | + arg1 = compile(s0,s1,depth1,0); | |
15544 | + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z] | |
15545 | + p2 = _cimg_mp_vector_size(arg1); | |
15546 | + arg1 = arg1 + 1; | |
15547 | + if (p2>1) { | |
15548 | + arg2 = arg1 + 1; | |
15549 | + if (p2>2) arg3 = arg2 + 1; | |
15550 | + } | |
15551 | + if (s1<se1) { | |
15552 | + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
15553 | + arg4 = compile(s1,s2,depth1,0); | |
15554 | + if (s2<se1) arg5 = compile(++s2,se1,depth1,0); | |
15555 | + } | |
15556 | + } else if (s1<se1) { | |
15557 | + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
15558 | + arg2 = compile(s1,s2,depth1,0); | |
14263 | 15559 | if (s2<se1) { |
14264 | - char *s3 = s2 + 1; while (s3<se2 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3; | |
14265 | - indz = compile(s2 + 1,s3==se2?++s3:s3); | |
15560 | + s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3; | |
15561 | + arg3 = compile(s2,s3,depth1,0); | |
14266 | 15562 | if (s3<se1) { |
14267 | - char *s4 = s3 + 1; while (s4<se2 && (*s4!=',' || level[s4 - expr._data]!=clevel1)) ++s4; | |
14268 | - indc = compile(s3 + 1,s4==se2?++s4:s4); | |
14269 | - if (s4<se1) { | |
14270 | - char *s5 = s4 + 1; while (s5<se2 && (*s5!=',' || level[s5 - expr._data]!=clevel1)) ++s5; | |
14271 | - interpolation = compile(s4 + 1,s5==se2?++s5:s5); | |
14272 | - if (s5<se1) borders = compile(s5 + 1,se1); | |
14273 | - } | |
15563 | + s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
15564 | + arg4 = compile(s3,s2,depth1,0); | |
15565 | + if (s2<se1) arg5 = compile(++s2,se1,depth1,0); | |
14274 | 15566 | } |
14275 | 15567 | } |
14276 | 15568 | } |
14277 | 15569 | } |
14278 | - _cimg_mp_opcode6(is_relative?mp_jxyzc:mp_ixyzc,indx,indy,indz,indc,interpolation,borders); | |
14279 | - } | |
14280 | - if (!std::strncmp(ss,"sin(",4)) _cimg_mp_opcode1(mp_sin,compile(ss4,se1)); | |
14281 | - if (!std::strncmp(ss,"cos(",4)) _cimg_mp_opcode1(mp_cos,compile(ss4,se1)); | |
14282 | - if (!std::strncmp(ss,"tan(",4)) _cimg_mp_opcode1(mp_tan,compile(ss4,se1)); | |
14283 | - if (!std::strncmp(ss,"log(",4)) _cimg_mp_opcode1(mp_log,compile(ss4,se1)); | |
14284 | - if (!std::strncmp(ss,"exp(",4)) _cimg_mp_opcode1(mp_exp,compile(ss4,se1)); | |
14285 | - if (!std::strncmp(ss,"abs(",4)) _cimg_mp_opcode1(mp_abs,compile(ss4,se1)); | |
14286 | - if (!std::strncmp(ss,"int(",4)) _cimg_mp_opcode1(mp_int,compile(ss4,se1)); | |
14287 | - if (!std::strncmp(ss,"sqr(",4)) _cimg_mp_opcode1(mp_sqr,compile(ss4,se1)); | |
14288 | - if (!std::strncmp(ss,"asin(",5)) _cimg_mp_opcode1(mp_asin,compile(ss5,se1)); | |
14289 | - if (!std::strncmp(ss,"acos(",5)) _cimg_mp_opcode1(mp_acos,compile(ss5,se1)); | |
14290 | - if (!std::strncmp(ss,"atan(",5)) _cimg_mp_opcode1(mp_atan,compile(ss5,se1)); | |
14291 | - if (!std::strncmp(ss,"sinh(",5)) _cimg_mp_opcode1(mp_sinh,compile(ss5,se1)); | |
14292 | - if (!std::strncmp(ss,"cosh(",5)) _cimg_mp_opcode1(mp_cosh,compile(ss5,se1)); | |
14293 | - if (!std::strncmp(ss,"tanh(",5)) _cimg_mp_opcode1(mp_tanh,compile(ss5,se1)); | |
14294 | - if (!std::strncmp(ss,"log2(",5)) _cimg_mp_opcode1(mp_log2,compile(ss5,se1)); | |
14295 | - if (!std::strncmp(ss,"sqrt(",5)) _cimg_mp_opcode1(mp_sqrt,compile(ss5,se1)); | |
14296 | - if (!std::strncmp(ss,"cbrt(",5)) _cimg_mp_opcode1(mp_cbrt,compile(ss5,se1)); | |
14297 | - if (!std::strncmp(ss,"sign(",5)) _cimg_mp_opcode1(mp_sign,compile(ss5,se1)); | |
14298 | - if (!std::strncmp(ss,"sinc(",5)) _cimg_mp_opcode1(mp_sinc,compile(ss5,se1)); | |
14299 | - if (!std::strncmp(ss,"log10(",6)) _cimg_mp_opcode1(mp_log10,compile(ss6,se1)); | |
14300 | - | |
14301 | - if ((*ss=='?' || *ss=='u') && *ss1=='(') { | |
14302 | - if (*ss2==')') _cimg_mp_opcode2(mp_u,0,1); | |
14303 | - char *s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14304 | - if (s1<se1) _cimg_mp_opcode2(mp_u,compile(ss2,s1),compile(s1 + 1,se1)); | |
14305 | - _cimg_mp_opcode2(mp_u,0,compile(ss2,s1)); | |
14306 | - } | |
14307 | - if (*ss=='i' && *ss1=='f' && *ss2=='(') { | |
14308 | - char *s1 = ss3; while (s1<se4 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14309 | - char *s2 = s1 + 1; while (s2<se2 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
14310 | - const unsigned int mem_cond = compile(ss3,s1), bp1 = code._width, mem_A = compile(s1 + 1,s2), | |
14311 | - bp2 = code._width, mem_B = compile(s2 + 1,se1); | |
14312 | - if (mempos>=mem._width) mem.resize(-200,1,1,1,0); | |
14313 | - const unsigned int pos = mempos++; | |
14314 | - CImg<longT>::vector(_cimg_mp_enfunc(mp_if),pos,mem_cond,mem_A,mem_B,bp2 - bp1,code._width - bp2). | |
14315 | - move_to(code,bp1); | |
15570 | + if (p_ref && arg4==~0U && arg5==~0U) { | |
15571 | + *p_ref = 5; | |
15572 | + p_ref[1] = p1; | |
15573 | + p_ref[2] = (unsigned int)is_relative; | |
15574 | + p_ref[3] = arg1; | |
15575 | + p_ref[4] = arg2; | |
15576 | + p_ref[5] = arg3; | |
15577 | + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization | |
15578 | + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1; | |
15579 | + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; | |
15580 | + if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1; | |
15581 | + } | |
15582 | + p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any | |
15583 | + if (p1==~0U) p2 = imgin._spectrum; | |
15584 | + else if (_cimg_mp_is_constant(p1)) { | |
15585 | + p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width()); | |
15586 | + p2 = listin[p3]._spectrum; | |
15587 | + } | |
15588 | + _cimg_mp_check_vector0(p2,"operator '()'"); | |
15589 | + pos = vector(p2); | |
15590 | + if (p1!=~0U) | |
15591 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_Jxyz:mp_list_Ixyz), | |
15592 | + pos,p1,arg1,arg2,arg3, | |
15593 | + arg4==~0U?reserved_label[29]:arg4, | |
15594 | + arg5==~0U?reserved_label[30]:arg5).move_to(code); | |
15595 | + else | |
15596 | + CImg<uptrT>::vector((uptrT)(is_relative?mp_Jxyz:mp_Ixyz), | |
15597 | + pos,arg1,arg2,arg3, | |
15598 | + arg4==~0U?reserved_label[29]:arg4, | |
15599 | + arg5==~0U?reserved_label[30]:arg5).move_to(code); | |
14316 | 15600 | _cimg_mp_return(pos); |
14317 | 15601 | } |
14318 | - if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4) || | |
14319 | - !std::strncmp(ss,"med(",4) || !std::strncmp(ss,"kth(",4) || | |
14320 | - !std::strncmp(ss,"arg(",4)) { | |
14321 | - CImgList<longT> opcode; | |
14322 | - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); | |
14323 | - const unsigned int pos = mempos++; | |
14324 | - CImg<longT>::vector(_cimg_mp_enfunc(*ss=='a'?mp_arg:*ss=='k'?mp_kth:ss[1]=='i'?mp_min: | |
14325 | - ss[1]=='a'?mp_max:mp_med),pos). | |
14326 | - move_to(opcode); | |
14327 | - for (char *s = ss4; s<se; ++s) { | |
14328 | - char *ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
14329 | - (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
14330 | - CImg<longT>::vector(compile(s,ns)).move_to(opcode); | |
14331 | - s = ns; | |
15602 | + | |
15603 | + // i/j(_#ind,_x,_y,_z,_c,_interpolation,_boundary) | |
15604 | + if ((*ss=='i' || *ss=='j') && *ss1=='(') { // Image value as scalar | |
15605 | + if (*ss2=='#') { // Index specified | |
15606 | + s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0; | |
15607 | + p1 = compile(ss3,s0++,depth1,0); | |
15608 | + } else { p1 = ~0U; s0 = ss2; } | |
15609 | + arg1 = is_relative?0U:(unsigned int)_cimg_mp_x; | |
15610 | + arg2 = is_relative?0U:(unsigned int)_cimg_mp_y; | |
15611 | + arg3 = is_relative?0U:(unsigned int)_cimg_mp_z; | |
15612 | + arg4 = is_relative?0U:(unsigned int)_cimg_mp_c; | |
15613 | + arg5 = arg6 = ~0U; | |
15614 | + if (s0<se1) { | |
15615 | + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15616 | + arg1 = compile(s0,s1,depth1,0); | |
15617 | + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z,C] | |
15618 | + p2 = _cimg_mp_vector_size(arg1); | |
15619 | + arg1 = arg1 + 1; | |
15620 | + if (p2>1) { | |
15621 | + arg2 = arg1 + 1; | |
15622 | + if (p2>2) { | |
15623 | + arg3 = arg2 + 1; | |
15624 | + if (p2>3) arg4 = arg3 + 1; | |
15625 | + } | |
15626 | + } | |
15627 | + if (s1<se1) { | |
15628 | + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
15629 | + arg5 = compile(s1,s2,depth1,0); | |
15630 | + if (s2<se1) arg6 = compile(++s2,se1,depth1,0); | |
15631 | + } | |
15632 | + } else if (s1<se1) { | |
15633 | + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
15634 | + arg2 = compile(s1,s2,depth1,0); | |
15635 | + if (s2<se1) { | |
15636 | + s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3; | |
15637 | + arg3 = compile(s2,s3,depth1,0); | |
15638 | + if (s3<se1) { | |
15639 | + s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
15640 | + arg4 = compile(s3,s2,depth1,0); | |
15641 | + if (s2<se1) { | |
15642 | + s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3; | |
15643 | + arg5 = compile(s2,s3,depth1,0); | |
15644 | + if (s3<se1) arg6 = compile(++s3,se1,depth1,0); | |
15645 | + } | |
15646 | + } | |
15647 | + } | |
15648 | + } | |
14332 | 15649 | } |
14333 | - (opcode>'y').move_to(code); | |
14334 | - _cimg_mp_return(pos); | |
14335 | - } | |
14336 | - if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { | |
14337 | - unsigned int value = 0, nb = 1; | |
14338 | - char *s1 = ss4; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1; | |
14339 | - value = compile(ss4,s1==se2?++s1:s1); | |
14340 | - if (s1<se1) { | |
14341 | - char *s2 = s1 + 1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2; | |
14342 | - nb = compile(s1 + 1,se1); | |
14343 | - } | |
14344 | - _cimg_mp_opcode2(*ss2=='l'?mp_rol:mp_ror,value,nb); | |
14345 | - } | |
14346 | - if (!std::strncmp(ss,"narg(",5)) { | |
14347 | - if (*ss5==')') _cimg_mp_return(0); | |
14348 | - unsigned int nb_args = 0; | |
14349 | - for (char *s = ss5; s<se; ++s) { | |
14350 | - char *ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
14351 | - (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
14352 | - ++nb_args; s = ns; | |
14353 | - } | |
14354 | - if (nb_args==0 || nb_args==1) _cimg_mp_return(nb_args); | |
14355 | - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); | |
14356 | - const unsigned int pos = mempos++; | |
14357 | - mem[pos] = nb_args; | |
14358 | - _cimg_mp_return(pos); | |
14359 | - } | |
14360 | - if (!std::strncmp(ss,"atan2(",6)) { | |
14361 | - char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14362 | - _cimg_mp_opcode2(mp_atan2,compile(ss6,s1),compile(s1 + 1,se1)); | |
14363 | - } | |
14364 | - if (!std::strncmp(ss,"hypot(",6)) { | |
14365 | - char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14366 | - _cimg_mp_opcode2(mp_hypot,compile(ss6,s1),compile(s1 + 1,se1)); | |
14367 | - } | |
14368 | - if (!std::strncmp(ss,"round(",6)) { | |
14369 | - unsigned int value = 0, round = 1, direction = 0; | |
14370 | - char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14371 | - value = compile(ss6,s1==se2?++s1:s1); | |
14372 | - if (s1<se1) { | |
14373 | - char *s2 = s1 + 1; while (s2<se2 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
14374 | - round = compile(s1 + 1,s2==se2?++s2:s2); | |
14375 | - if (s2<se1) direction = compile(s2 + 1,se1); | |
14376 | - } | |
14377 | - _cimg_mp_opcode3(mp_round,value,round,direction); | |
14378 | - } | |
14379 | - unsigned int norm_type = ~0U; | |
14380 | - if ((std::sscanf(ss,"norm%u%c",&norm_type,&sep)==2 && sep=='(') || | |
14381 | - !std::strncmp(ss,"norminf(",8)) { | |
14382 | - CImgList<longT> opcode; | |
14383 | - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); | |
14384 | - const unsigned int pos = mempos++; | |
14385 | - CImg<longT>::vector(_cimg_mp_enfunc(mp_norm),pos,(longT)(norm_type==~0U?-1:(int)norm_type)). | |
14386 | - move_to(opcode); | |
14387 | - for (char *s = std::strchr(ss5,'(') + 1; s<se; ++s) { | |
14388 | - char *ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
14389 | - (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
14390 | - CImg<longT>::vector(compile(s,ns)).move_to(opcode); | |
14391 | - s = ns; | |
15650 | + if (p_ref && arg5==~0U && arg6==~0U) { | |
15651 | + *p_ref = 3; | |
15652 | + p_ref[1] = p1; | |
15653 | + p_ref[2] = (unsigned int)is_relative; | |
15654 | + p_ref[3] = arg1; | |
15655 | + p_ref[4] = arg2; | |
15656 | + p_ref[5] = arg3; | |
15657 | + p_ref[6] = arg4; | |
15658 | + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization | |
15659 | + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1; | |
15660 | + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; | |
15661 | + if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1; | |
15662 | + if (_cimg_mp_is_temp(arg4)) memtype[arg4] = -1; | |
15663 | + } | |
15664 | + | |
15665 | + if (p1!=~0U) { | |
15666 | + if (!listin) _cimg_mp_return(0); | |
15667 | + pos = scalar7(is_relative?mp_list_jxyzc:mp_list_ixyzc, | |
15668 | + p1,arg1,arg2,arg3,arg4, | |
15669 | + arg5==~0U?reserved_label[29]:arg5, | |
15670 | + arg6==~0U?reserved_label[30]:arg6); | |
15671 | + } else { | |
15672 | + if (!imgin) _cimg_mp_return(0); | |
15673 | + pos = scalar6(is_relative?mp_jxyzc:mp_ixyzc, | |
15674 | + arg1,arg2,arg3,arg4, | |
15675 | + arg5==~0U?reserved_label[29]:arg5, | |
15676 | + arg6==~0U?reserved_label[30]:arg6); | |
14392 | 15677 | } |
14393 | - (opcode>'y').move_to(code); | |
15678 | + memtype[pos] = -1; // Create it as a variable to prevent from being used in further optimization | |
14394 | 15679 | _cimg_mp_return(pos); |
14395 | 15680 | } |
14396 | - if (!std::strncmp(ss,"date(",5)) { | |
14397 | - char *s1 = ss5; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14398 | - unsigned int attr; | |
14399 | - int d = -1; | |
14400 | - if (cimg_sscanf(ss5,"%u%c",&attr,&sep)==2 && sep==')') { | |
14401 | - *se1 = 0; | |
14402 | - d = cimg::date(attr); | |
14403 | - *se1 = ')'; | |
15681 | + | |
15682 | + // Mathematical functions. | |
15683 | + switch (*ss) { | |
15684 | + case 'a' : | |
15685 | + if (!std::strncmp(ss,"abs(",4)) { // Absolute value | |
15686 | + arg1 = compile(ss4,se1,depth1,0); | |
15687 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_abs,arg1); | |
15688 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::abs(mem[arg1])); | |
15689 | + _cimg_mp_scalar1(mp_abs,arg1); | |
14404 | 15690 | } |
14405 | - if (d==0 || d==1) _cimg_mp_return((unsigned int)d); | |
14406 | - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); | |
14407 | - const unsigned int pos = mempos++; | |
14408 | - mem[pos] = d; | |
14409 | - _cimg_mp_return(pos); | |
14410 | - } | |
14411 | - if (!std::strncmp(ss,"fdate(",6)) { | |
14412 | - char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
14413 | - unsigned int attr; | |
14414 | - int d = -1; | |
14415 | - if (cimg_sscanf(ss6,"%u%c",&attr,&(sep=0))==2 && sep) { | |
15691 | + | |
15692 | + if (!std::strncmp(ss,"acos(",5)) { // Arccos | |
15693 | + arg1 = compile(ss5,se1,depth1,0); | |
15694 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_acos,arg1); | |
15695 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::acos(mem[arg1])); | |
15696 | + _cimg_mp_scalar1(mp_acos,arg1); | |
15697 | + } | |
15698 | + | |
15699 | + if (!std::strncmp(ss,"asin(",5)) { // Arcsin | |
15700 | + arg1 = compile(ss5,se1,depth1,0); | |
15701 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_asin,arg1); | |
15702 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::asin(mem[arg1])); | |
15703 | + _cimg_mp_scalar1(mp_asin,arg1); | |
15704 | + } | |
15705 | + | |
15706 | + if (!std::strncmp(ss,"atan(",5)) { // Arctan | |
15707 | + arg1 = compile(ss5,se1,depth1,0); | |
15708 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_atan,arg1); | |
15709 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::atan(mem[arg1])); | |
15710 | + _cimg_mp_scalar1(mp_atan,arg1); | |
15711 | + } | |
15712 | + | |
15713 | + if (!std::strncmp(ss,"atan2(",6)) { // Arctan2 | |
15714 | + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15715 | + 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)); | |
15718 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_atan2,arg1,arg2); | |
15719 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_atan2,arg1,arg2); | |
15720 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_atan2,arg1,arg2); | |
15721 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
15722 | + _cimg_mp_constant(std::atan2(mem[arg1],mem[arg2])); | |
15723 | + _cimg_mp_scalar2(mp_atan2,arg1,arg2); | |
15724 | + } | |
15725 | + break; | |
15726 | + | |
15727 | + case 'c' : | |
15728 | + if (!std::strncmp(ss,"cabs(",5)) { // Complex absolute value | |
15729 | + arg1 = compile(ss5,se1,depth1,0); | |
15730 | + _cimg_mp_check_type(arg1,0,"Function 'cabs()'",2,2); | |
15731 | + _cimg_mp_scalar2(mp_hypot,arg1 + 1,arg1 + 2); | |
15732 | + } | |
15733 | + | |
15734 | + if (!std::strncmp(ss,"carg(",5)) { // Complex argument | |
15735 | + arg1 = compile(ss5,se1,depth1,0); | |
15736 | + _cimg_mp_check_type(arg1,0,"Function 'carg()'",2,2); | |
15737 | + _cimg_mp_scalar2(mp_atan2,arg1 + 2,arg1 + 1); | |
15738 | + } | |
15739 | + | |
15740 | + if (!std::strncmp(ss,"cbrt(",5)) { // Cubic root | |
15741 | + arg1 = compile(ss5,se1,depth1,0); | |
15742 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cbrt,arg1); | |
15743 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::pow(mem[arg1],1.0/3)); | |
15744 | + _cimg_mp_scalar1(mp_cbrt,arg1); | |
15745 | + } | |
15746 | + | |
15747 | + if (!std::strncmp(ss,"cconj(",6)) { // Complex conjugate | |
15748 | + arg1 = compile(ss6,se1,depth1,0); | |
15749 | + _cimg_mp_check_type(arg1,0,"Function 'cconj()'",2,2); | |
15750 | + pos = vector(2); | |
15751 | + CImg<uptrT>::vector((uptrT)mp_complex_conj,pos,arg1).move_to(code); | |
15752 | + _cimg_mp_return(pos); | |
15753 | + } | |
15754 | + | |
15755 | + if (!std::strncmp(ss,"cexp(",5)) { // Complex exponential | |
15756 | + arg1 = compile(ss5,se1,depth1,0); | |
15757 | + _cimg_mp_check_type(arg1,0,"Function 'cexp()'",2,2); | |
15758 | + pos = vector(2); | |
15759 | + CImg<uptrT>::vector((uptrT)mp_complex_exp,pos,arg1).move_to(code); | |
15760 | + _cimg_mp_return(pos); | |
15761 | + } | |
15762 | + | |
15763 | + if (!std::strncmp(ss,"clog(",5)) { // Complex logarithm | |
15764 | + arg1 = compile(ss5,se1,depth1,0); | |
15765 | + _cimg_mp_check_type(arg1,0,"Function 'clog()'",2,2); | |
15766 | + pos = vector(2); | |
15767 | + CImg<uptrT>::vector((uptrT)mp_complex_log,pos,arg1).move_to(code); | |
15768 | + _cimg_mp_return(pos); | |
15769 | + } | |
15770 | + | |
15771 | + if (!std::strncmp(ss,"cos(",4)) { // Cosine | |
15772 | + arg1 = compile(ss4,se1,depth1,0); | |
15773 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cos,arg1); | |
15774 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cos(mem[arg1])); | |
15775 | + _cimg_mp_scalar1(mp_cos,arg1); | |
15776 | + } | |
15777 | + | |
15778 | + if (!std::strncmp(ss,"cosh(",5)) { // Hyperbolic cosine | |
15779 | + arg1 = compile(ss5,se1,depth1,0); | |
15780 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cosh,arg1); | |
15781 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cosh(mem[arg1])); | |
15782 | + _cimg_mp_scalar1(mp_cosh,arg1); | |
15783 | + } | |
15784 | + | |
15785 | + if (!std::strncmp(ss,"cross(",6)) { // Cross product | |
15786 | + s_op = "Function 'cross()"; | |
15787 | + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15788 | + 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); | |
15792 | + pos = vector(3); | |
15793 | + CImg<uptrT>::vector((uptrT)mp_cross,pos,arg1,arg2).move_to(code); | |
15794 | + _cimg_mp_return(pos); | |
15795 | + } | |
15796 | + | |
15797 | + if (!std::strncmp(ss,"cut(",4)) { // Cut | |
15798 | + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15799 | + arg1 = compile(ss4,s1==se2?++s1:s1,depth1,0); | |
15800 | + 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); | |
15803 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_cut,arg1,arg2,arg3); | |
15804 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3)) { | |
15805 | + val = mem[arg1]; | |
15806 | + val1 = mem[arg2]; | |
15807 | + val2 = mem[arg3]; | |
15808 | + _cimg_mp_constant(val<val1?val1:val>val2?val2:val); | |
15809 | + } | |
15810 | + _cimg_mp_scalar3(mp_cut,arg1,arg2,arg3); | |
15811 | + } | |
15812 | + break; | |
15813 | + | |
15814 | + case 'd' : | |
15815 | + if (!std::strncmp(ss,"date(",5)) { // Date and file date | |
15816 | + s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15817 | + arg1 = 0; | |
15818 | + is_sth = s1!=se1; // is_fdate | |
15819 | + if (s1==se1 && ss5!=se1 && // Exactly one argument | |
15820 | + (cimg_sscanf(ss5,"%u%c",&arg1,&sep)!=2 || sep!=')')) is_sth = true; | |
15821 | + if (is_sth) { | |
15822 | + 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 = ')'; | |
15824 | + } else val = (double)cimg::date(arg1); | |
15825 | + _cimg_mp_constant(val); | |
15826 | + } | |
15827 | + | |
15828 | + if (!std::strncmp(ss,"debug(",6)) { // Print debug info | |
15829 | + p1 = code._width; | |
15830 | + arg1 = compile(ss6,se1,depth1,p_ref); | |
14416 | 15831 | *se1 = 0; |
14417 | - d = cimg::fdate(s1+1,attr); | |
15832 | + ((CImg<uptrT>::vector((uptrT)mp_debug,arg1,code._width - p1), | |
15833 | + CImg<uptrT>::string(ss6).unroll('y'))>'y').move_to(code,p1); | |
14418 | 15834 | *se1 = ')'; |
15835 | + _cimg_mp_return(arg1); | |
15836 | + } | |
15837 | + | |
15838 | + if (!std::strncmp(ss,"dot(",4)) { // Dot product | |
15839 | + s_op = "Function 'dot()'"; | |
15840 | + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15841 | + 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); | |
15845 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_scalar3(mp_dot,arg1,arg2,_cimg_mp_vector_size(arg1)); | |
15846 | + _cimg_mp_scalar2(mp_mul,arg1,arg2); | |
15847 | + } | |
15848 | + | |
15849 | + if (!std::strncmp(ss,"dowhile",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // Do..while | |
15850 | + if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace | |
15851 | + s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15852 | + p1 = code._width; | |
15853 | + 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); | |
15857 | + CImg<uptrT>::vector((uptrT)mp_dowhile,arg1,arg2,code._width - p1).move_to(code,p1); | |
15858 | + _cimg_mp_return(arg1); | |
14419 | 15859 | } |
14420 | - if (d==0 || d==1) _cimg_mp_return((unsigned int)d); | |
14421 | - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); | |
14422 | - const unsigned int pos = mempos++; | |
14423 | - mem[pos] = d; | |
14424 | - _cimg_mp_return(pos); | |
14425 | - } | |
15860 | + break; | |
14426 | 15861 | |
14427 | - // Sub-family of 'is_?()' functions. | |
14428 | - if (*ss=='i' && *ss1=='s') { | |
14429 | - if (!std::strncmp(ss,"isin(",5)) { | |
14430 | - CImgList<longT> opcode; | |
14431 | - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); | |
14432 | - const unsigned int pos = mempos++; | |
14433 | - CImg<longT>::vector(_cimg_mp_enfunc(mp_isin),pos).move_to(opcode); | |
14434 | - for (char *s = ss5; s<se; ++s) { | |
14435 | - char *ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
14436 | - (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
14437 | - CImg<longT>::vector(compile(s,ns)).move_to(opcode); | |
14438 | - s = ns; | |
15862 | + case 'e' : | |
15863 | + if (!std::strncmp(ss,"exp(",4)) { // Exponential | |
15864 | + arg1 = compile(ss4,se1,depth1,0); | |
15865 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_exp,arg1); | |
15866 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::exp(mem[arg1])); | |
15867 | + _cimg_mp_scalar1(mp_exp,arg1); | |
15868 | + } | |
15869 | + break; | |
15870 | + | |
15871 | + case 'f' : | |
15872 | + if (*ss1=='o' && *ss2=='r' && (*ss3=='(' || (*ss3 && *ss3<=' ' && *ss4=='('))) { // For loop | |
15873 | + if (*ss3<=' ') cimg::swap(*ss3,*ss4); // Allow space before opening brace | |
15874 | + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15875 | + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
15876 | + s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3; | |
15877 | + compile(ss4,s1,depth1,0); | |
15878 | + p1 = code._width; | |
15879 | + arg1 = compile(s1 + 1,s2,depth1,0); | |
15880 | + 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); | |
15884 | + arg2 = _cimg_mp_is_vector(pos)?_cimg_mp_vector_size(pos):0; // Output vector size (or 0 if scalar) | |
15885 | + CImg<uptrT>::vector((uptrT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1); | |
15886 | + _cimg_mp_return(pos); | |
15887 | + } | |
15888 | + break; | |
15889 | + | |
15890 | + case 'g' : | |
15891 | + if (!std::strncmp(ss,"gauss(",6)) { // Gaussian function | |
15892 | + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15893 | + 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); | |
15900 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(mp_gauss,arg1,arg2); | |
15901 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) { | |
15902 | + val1 = mem[arg1]; | |
15903 | + val2 = mem[arg2]; | |
15904 | + _cimg_mp_constant(std::exp(-val1*val1/(2*val2*val2))/std::sqrt(2*val2*val2*cimg::PI)); | |
15905 | + } | |
15906 | + _cimg_mp_scalar2(mp_gauss,arg1,arg2); | |
15907 | + } | |
15908 | + break; | |
15909 | + | |
15910 | + case 'h' : | |
15911 | + if (!std::strncmp(ss,"hypot(",6)) { // Hypothenuse | |
15912 | + s_op = "Function 'hypot()'"; | |
15913 | + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15914 | + 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); | |
15918 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) { | |
15919 | + val1 = cimg::abs(mem[arg1]); | |
15920 | + val2 = cimg::abs(mem[arg2]); | |
15921 | + if (val1<val2) { val = val1; val1 = val2; } else val = val2; | |
15922 | + if (val1>0) { val/=val1; _cimg_mp_constant(val1*std::sqrt(1+val*val)); } | |
15923 | + _cimg_mp_constant(0); | |
14439 | 15924 | } |
14440 | - (opcode>'y').move_to(code); | |
15925 | + _cimg_mp_scalar2(mp_hypot,arg1,arg2); | |
15926 | + } | |
15927 | + break; | |
15928 | + | |
15929 | + case 'i' : | |
15930 | + if (*ss1=='f' && (*ss2=='(' || (*ss2 && *ss2<=' ' && *ss3=='('))) { // If..then[..else.] | |
15931 | + s_op = "Function 'if()'"; | |
15932 | + if (*ss2<=' ') cimg::swap(*ss2,*ss3); // Allow space before opening brace | |
15933 | + s1 = ss3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
15934 | + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2; | |
15935 | + arg1 = compile(ss3,s1,depth1,0); | |
15936 | + p2 = code._width; | |
15937 | + arg2 = compile(s1 + 1,s2,depth1,0); | |
15938 | + 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]); | |
15944 | + arg4 = _cimg_mp_is_vector(arg2)?_cimg_mp_vector_size(arg2):0; // Output vector size (or 0 if scalar) | |
15945 | + if (arg4) pos = vector(arg4); else pos = scalar(); | |
15946 | + CImg<uptrT>::vector((uptrT)mp_if,pos,arg1,arg2,arg3, | |
15947 | + p3 - p2,code._width - p3,arg4).move_to(code,p2); | |
14441 | 15948 | _cimg_mp_return(pos); |
14442 | 15949 | } |
14443 | - if (!std::strncmp(ss,"isval(",6)) { | |
14444 | - double val = 0; | |
14445 | - if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1); | |
14446 | - _cimg_mp_return(0); | |
15950 | + | |
15951 | + if (!std::strncmp(ss,"init(",5)) { // Init | |
15952 | + if (ss0!=expr._data || code.width()) { // (only allowed as the first instruction) | |
15953 | + *se = saved_char; cimg::strellipsize(expr,64); | |
15954 | + throw CImgArgumentException("[_cimg_math_parser] " | |
15955 | + "CImg<%s>::%s: Function 'init()': Init invokation not done at the " | |
15956 | + "beginning of expression '%s%s%s'.", | |
15957 | + pixel_type(),_cimg_mp_calling_function, | |
15958 | + (ss - 4)>expr._data?"...":"", | |
15959 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
15960 | + se<&expr.back()?"...":""); | |
15961 | + } | |
15962 | + arg1 = compile(ss5,se1,depth1,p_ref); | |
15963 | + init_size = code.width(); | |
15964 | + _cimg_mp_return(arg1); | |
14447 | 15965 | } |
14448 | - if (!std::strncmp(ss,"isdir(",6)) { | |
14449 | - *se1 = 0; | |
14450 | - const bool is_dir = cimg::is_directory(ss6); | |
14451 | - *se1 = ')'; | |
14452 | - _cimg_mp_return(is_dir?1U:0U); | |
15966 | + | |
15967 | + if (!std::strncmp(ss,"int(",4)) { // Integer cast | |
15968 | + arg1 = compile(ss4,se1,depth1,0); | |
15969 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_int,arg1); | |
15970 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant((long)mem[arg1]); | |
15971 | + _cimg_mp_scalar1(mp_int,arg1); | |
14453 | 15972 | } |
14454 | - if (!std::strncmp(ss,"isfile(",7)) { | |
14455 | - *se1 = 0; | |
14456 | - const bool is_file = cimg::is_file(ss7); | |
14457 | - *se1 = ')'; | |
14458 | - _cimg_mp_return(is_file?1U:0U); | |
15973 | + | |
15974 | + if (*ss1=='s') { // Family of 'is_?()' functions | |
15975 | + | |
15976 | + if (!std::strncmp(ss,"isbool(",7)) { // Is boolean? | |
15977 | + if (ss7==se1) _cimg_mp_return(0); | |
15978 | + arg1 = compile(ss7,se1,depth1,0); | |
15979 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isbool,arg1); | |
15980 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_return(mem[arg1]==0.0 || mem[arg1]==1.0); | |
15981 | + _cimg_mp_scalar1(mp_isbool,arg1); | |
15982 | + } | |
15983 | + | |
15984 | + if (!std::strncmp(ss,"isdir(",6)) { // Is directory? | |
15985 | + *se1 = 0; | |
15986 | + is_sth = cimg::is_directory(ss6); | |
15987 | + *se1 = ')'; | |
15988 | + _cimg_mp_return(is_sth?1U:0U); | |
15989 | + } | |
15990 | + | |
15991 | + if (!std::strncmp(ss,"isfile(",7)) { // Is file? | |
15992 | + *se1 = 0; | |
15993 | + is_sth = cimg::is_file(ss7); | |
15994 | + *se1 = ')'; | |
15995 | + _cimg_mp_return(is_sth?1U:0U); | |
15996 | + } | |
15997 | + | |
15998 | + if (!std::strncmp(ss,"isin(",5)) { // Is in sequence/vector? | |
15999 | + pos = scalar(); | |
16000 | + CImg<uptrT>::vector((uptrT)mp_isin,pos).move_to(_opcode); | |
16001 | + for (s = ss5; s<se; ++s) { | |
16002 | + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
16003 | + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
16004 | + arg1 = compile(s,ns,depth1,0); | |
16005 | + if (_cimg_mp_is_vector(arg1)) | |
16006 | + CImg<uptrT>::sequence((uptrT)_cimg_mp_vector_size(arg1),arg1 + 1, | |
16007 | + arg1 + (uptrT)_cimg_mp_vector_size(arg1)). | |
16008 | + move_to(_opcode); | |
16009 | + else CImg<uptrT>::vector(arg1).move_to(_opcode); | |
16010 | + s = ns; | |
16011 | + } | |
16012 | + (_opcode>'y').move_to(code); | |
16013 | + _cimg_mp_return(pos); | |
16014 | + } | |
16015 | + | |
16016 | + if (!std::strncmp(ss,"isinf(",6)) { // Is infinite? | |
16017 | + if (ss6==se1) _cimg_mp_return(0); | |
16018 | + arg1 = compile(ss6,se1,depth1,0); | |
16019 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isinf,arg1); | |
16020 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type<double>::is_inf(mem[arg1])); | |
16021 | + _cimg_mp_scalar1(mp_isinf,arg1); | |
16022 | + } | |
16023 | + | |
16024 | + if (!std::strncmp(ss,"isint(",6)) { // Is integer? | |
16025 | + if (ss6==se1) _cimg_mp_return(0); | |
16026 | + arg1 = compile(ss6,se1,depth1,0); | |
16027 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isint,arg1); | |
16028 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::mod(mem[arg1],1.0)==0); | |
16029 | + _cimg_mp_scalar1(mp_isint,arg1); | |
16030 | + } | |
16031 | + | |
16032 | + if (!std::strncmp(ss,"isnan(",6)) { // Is NaN? | |
16033 | + if (ss6==se1) _cimg_mp_return(0); | |
16034 | + arg1 = compile(ss6,se1,depth1,0); | |
16035 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isnan,arg1); | |
16036 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type<double>::is_nan(mem[arg1])); | |
16037 | + _cimg_mp_scalar1(mp_isnan,arg1); | |
16038 | + } | |
16039 | + | |
16040 | + if (!std::strncmp(ss,"isval(",6)) { // Is value? | |
16041 | + val = 0; | |
16042 | + if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1); | |
16043 | + _cimg_mp_return(0); | |
16044 | + } | |
16045 | + | |
14459 | 16046 | } |
14460 | - if (!std::strncmp(ss,"isnan(",6)) _cimg_mp_opcode1(mp_isnan,compile(ss6,se1)); | |
14461 | - if (!std::strncmp(ss,"isinf(",6)) _cimg_mp_opcode1(mp_isinf,compile(ss6,se1)); | |
14462 | - if (!std::strncmp(ss,"isint(",6)) _cimg_mp_opcode1(mp_isint,compile(ss6,se1)); | |
14463 | - if (!std::strncmp(ss,"isbool(",7)) _cimg_mp_opcode1(mp_isbool,compile(ss7,se1)); | |
14464 | - } | |
14465 | - } | |
16047 | + break; | |
14466 | 16048 | |
14467 | - // No known item found, assuming this is an already initialized variable. | |
14468 | - CImg<charT> variable_name(ss,(unsigned int)(se - ss + 1)); | |
14469 | - variable_name.back() = 0; | |
14470 | - if (variable_name[1]) { // Multi-char variable. | |
14471 | - cimglist_for(labelM,i) if (!std::strcmp(variable_name,labelM[i])) _cimg_mp_return(labelMpos[i]); | |
14472 | - } else if (reserved_label[*variable_name]!=~0U) // Single-char variable. | |
14473 | - _cimg_mp_return(reserved_label[*variable_name]); | |
14474 | - *se = saved_char; | |
14475 | - throw CImgArgumentException("[_cimg_math_parser] " | |
14476 | - "CImg<%s>::%s(): Invalid item '%s' in specified expression '%s%s%s'.\n", | |
14477 | - pixel_type(),calling_function, | |
14478 | - variable_name._data, | |
14479 | - (ss - 8)>expr._data?"...":"", | |
14480 | - (ss - 8)>expr._data?ss - 8:expr._data, | |
14481 | - se<&expr.back()?"...":""); | |
14482 | - } | |
16049 | + case 'l' : | |
16050 | + if (!std::strncmp(ss,"log(",4)) { // Natural logarithm | |
16051 | + arg1 = compile(ss4,se1,depth1,0); | |
16052 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log,arg1); | |
16053 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log(mem[arg1])); | |
16054 | + _cimg_mp_scalar1(mp_log,arg1); | |
16055 | + } | |
14483 | 16056 | |
14484 | - // Evaluation functions, known by the parser. | |
14485 | - // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(ulong), so we can store pointers to them | |
14486 | - // directly in the opcode vectors. | |
14487 | - static double mp_u(_cimg_math_parser& mp) { | |
14488 | - return mp.mem[mp.opcode(2)] + cimg::rand()*(mp.mem[mp.opcode(3)] - mp.mem[mp.opcode(2)]); | |
14489 | - } | |
14490 | - static double mp_g(_cimg_math_parser& mp) { | |
14491 | - cimg::unused(mp); | |
14492 | - return cimg::grand(); | |
14493 | - } | |
14494 | - static double mp_i(_cimg_math_parser& mp) { | |
14495 | - return (double)mp.reference.atXYZC((int)mp.mem[16],(int)mp.mem[17],(int)mp.mem[18],(int)mp.mem[19],0); | |
14496 | - } | |
14497 | - static double mp_logical_and(_cimg_math_parser& mp) { | |
14498 | - const bool is_A = (bool)mp.mem[mp.opcode(2)]; | |
14499 | - const CImg<longT> *const pE = ++mp.p_code + mp.opcode(4); | |
14500 | - if (!is_A) { mp.p_code = pE - 1; return 0; } | |
14501 | - const unsigned int mem_B = (unsigned int)mp.opcode(3); | |
14502 | - for ( ; mp.p_code<pE; ++mp.p_code) { | |
14503 | - const CImg<longT> &op = *mp.p_code; | |
14504 | - mp.opcode._data = op._data; mp.opcode._height = op._height; | |
14505 | - const unsigned int target = (unsigned int)mp.opcode[1]; | |
14506 | - mp.mem[target] = _cimg_mp_defunc(mp); | |
14507 | - } | |
14508 | - --mp.p_code; | |
14509 | - return (double)(bool)mp.mem[mem_B]; | |
14510 | - } | |
14511 | - static double mp_logical_or(_cimg_math_parser& mp) { | |
14512 | - const bool is_A = (bool)mp.mem[mp.opcode(2)]; | |
14513 | - const CImg<longT> *const pE = ++mp.p_code + mp.opcode(4); | |
14514 | - if (is_A) { mp.p_code = pE - 1; return 1; } | |
14515 | - const unsigned int mem_B = (unsigned int)mp.opcode(3); | |
14516 | - for ( ; mp.p_code<pE; ++mp.p_code) { | |
14517 | - const CImg<longT> &op = *mp.p_code; | |
14518 | - mp.opcode._data = op._data; mp.opcode._height = op._height; | |
14519 | - const unsigned int target = (unsigned int)mp.opcode[1]; | |
14520 | - mp.mem[target] = _cimg_mp_defunc(mp); | |
14521 | - } | |
14522 | - --mp.p_code; | |
14523 | - return (double)(bool)mp.mem[mem_B]; | |
14524 | - } | |
14525 | - static double mp_infeq(_cimg_math_parser& mp) { | |
14526 | - return (double)(mp.mem[mp.opcode(2)]<=mp.mem[mp.opcode(3)]); | |
14527 | - } | |
14528 | - static double mp_supeq(_cimg_math_parser& mp) { | |
14529 | - return (double)(mp.mem[mp.opcode(2)]>=mp.mem[mp.opcode(3)]); | |
14530 | - } | |
14531 | - static double mp_noteq(_cimg_math_parser& mp) { | |
14532 | - return (double)(mp.mem[mp.opcode(2)]!=mp.mem[mp.opcode(3)]); | |
14533 | - } | |
14534 | - static double mp_eqeq(_cimg_math_parser& mp) { | |
14535 | - return (double)(mp.mem[mp.opcode(2)]==mp.mem[mp.opcode(3)]); | |
14536 | - } | |
14537 | - static double mp_inf(_cimg_math_parser& mp) { | |
14538 | - return (double)(mp.mem[mp.opcode(2)]<mp.mem[mp.opcode(3)]); | |
14539 | - } | |
14540 | - static double mp_sup(_cimg_math_parser& mp) { | |
14541 | - return (double)(mp.mem[mp.opcode(2)]>mp.mem[mp.opcode(3)]); | |
14542 | - } | |
14543 | - static double mp_add(_cimg_math_parser& mp) { | |
14544 | - return mp.mem[mp.opcode(2)] + mp.mem[mp.opcode(3)]; | |
14545 | - } | |
14546 | - static double mp_sub(_cimg_math_parser& mp) { | |
14547 | - return mp.mem[mp.opcode(2)] - mp.mem[mp.opcode(3)]; | |
14548 | - } | |
14549 | - static double mp_mul(_cimg_math_parser& mp) { | |
14550 | - const double A = mp.mem[mp.opcode(2)]; | |
14551 | - const CImg<longT> *const pE = ++mp.p_code + mp.opcode(4); | |
14552 | - if (!A) { mp.p_code = pE - 1; return 0; } | |
14553 | - const unsigned int mem_B = (unsigned int)mp.opcode(3); | |
14554 | - for ( ; mp.p_code<pE; ++mp.p_code) { | |
14555 | - const CImg<longT> &op = *mp.p_code; | |
14556 | - mp.opcode._data = op._data; mp.opcode._height = op._height; | |
14557 | - const unsigned int target = (unsigned int)mp.opcode[1]; | |
14558 | - mp.mem[target] = _cimg_mp_defunc(mp); | |
16057 | + if (!std::strncmp(ss,"log2(",5)) { // Base-2 logarithm | |
16058 | + arg1 = compile(ss5,se1,depth1,0); | |
16059 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log2,arg1); | |
16060 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::log2(mem[arg1])); | |
16061 | + _cimg_mp_scalar1(mp_log2,arg1); | |
16062 | + } | |
16063 | + | |
16064 | + if (!std::strncmp(ss,"log10(",6)) { // Base-10 logarithm | |
16065 | + arg1 = compile(ss6,se1,depth1,0); | |
16066 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log10,arg1); | |
16067 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log10(mem[arg1])); | |
16068 | + _cimg_mp_scalar1(mp_log10,arg1); | |
16069 | + } | |
16070 | + break; | |
16071 | + | |
16072 | + 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); | |
16120 | + 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); | |
16126 | + p1 = _cimg_mp_vector_size(arg1); | |
16127 | + p2 = _cimg_mp_vector_size(arg2); | |
16128 | + p3 = (unsigned int)mem[arg3]; | |
16129 | + arg5 = p2/p3; | |
16130 | + arg4 = p1/arg5; | |
16131 | + if (arg4*arg5!=p1 || arg5*p3!=p2) { | |
16132 | + *se = saved_char; cimg::strellipsize(expr,64); | |
16133 | + throw CImgArgumentException("[_cimg_math_parser] " | |
16134 | + "CImg<%s>::%s: %s: Sizes of first and second arguments ('%s' and '%s') " | |
16135 | + "do not match for third argument 'nb_colsB=%u', " | |
16136 | + "in expression '%s%s%s'.", | |
16137 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
16138 | + s_type(arg1)._data,s_type(arg2)._data,p3, | |
16139 | + (ss - 4)>expr._data?"...":"", | |
16140 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
16141 | + se<&expr.back()?"...":""); | |
16142 | + } | |
16143 | + pos = vector(arg4*p3); | |
16144 | + CImg<uptrT>::vector((uptrT)mp_matrix_mul,pos,arg1,arg2,arg4,arg5,p3).move_to(code); | |
16145 | + _cimg_mp_return(pos); | |
16146 | + } | |
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 | + break; | |
16232 | + | |
16233 | + case 'n' : | |
16234 | + if (!std::strncmp(ss,"narg(",5)) { // Number of arguments | |
16235 | + if (*ss5==')') _cimg_mp_return(0); | |
16236 | + arg1 = 0; | |
16237 | + for (s = ss5; s<se; ++s) { | |
16238 | + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
16239 | + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
16240 | + ++arg1; s = ns; | |
16241 | + } | |
16242 | + _cimg_mp_constant(arg1); | |
16243 | + } | |
16244 | + | |
16245 | + if ((cimg_sscanf(ss,"norm%u%c",&(arg1=~0U),&sep)==2 && sep=='(') || | |
16246 | + !std::strncmp(ss,"norminf(",8)) { // Lp norm | |
16247 | + pos = scalar(); | |
16248 | + switch (arg1) { | |
16249 | + case 0 : CImg<uptrT>::vector((uptrT)mp_norm0,pos).move_to(_opcode); break; | |
16250 | + case 1 : CImg<uptrT>::vector((uptrT)mp_norm1,pos).move_to(_opcode); break; | |
16251 | + case 2 : CImg<uptrT>::vector((uptrT)mp_norm2,pos).move_to(_opcode); break; | |
16252 | + case ~0U : CImg<uptrT>::vector((uptrT)mp_norminf,pos).move_to(_opcode); break; | |
16253 | + default : | |
16254 | + CImg<uptrT>::vector((uptrT)mp_normp,pos,(uptrT)(arg1==~0U?-1:(int)arg1)). | |
16255 | + move_to(_opcode); | |
16256 | + } | |
16257 | + for (s = std::strchr(ss5,'(') + 1; s<se; ++s) { | |
16258 | + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
16259 | + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
16260 | + arg2 = compile(s,ns,depth1,0); | |
16261 | + if (_cimg_mp_is_vector(arg2)) | |
16262 | + CImg<uptrT>::sequence((uptrT)_cimg_mp_vector_size(arg2),arg2 + 1, | |
16263 | + arg2 + (uptrT)_cimg_mp_vector_size(arg2)). | |
16264 | + move_to(_opcode); | |
16265 | + else CImg<uptrT>::vector(arg2).move_to(_opcode); | |
16266 | + s = ns; | |
16267 | + } | |
16268 | + (_opcode>'y').move_to(code); | |
16269 | + _cimg_mp_return(pos); | |
16270 | + } | |
16271 | + break; | |
16272 | + | |
16273 | + case 'p' : | |
16274 | + if (!std::strncmp(ss,"print(",6)) { // Print expression | |
16275 | + pos = compile(ss6,se1,depth1,p_ref); | |
16276 | + *se1 = 0; | |
16277 | + if (_cimg_mp_is_vector(pos)) // Vector | |
16278 | + ((CImg<uptrT>::vector((uptrT)mp_vector_print,pos,(uptrT)_cimg_mp_vector_size(pos)), | |
16279 | + CImg<uptrT>::string(ss6).unroll('y'))>'y').move_to(code); | |
16280 | + else // Scalar | |
16281 | + ((CImg<uptrT>::vector((uptrT)mp_print,pos), | |
16282 | + CImg<uptrT>::string(ss6).unroll('y'))>'y').move_to(code); | |
16283 | + *se1 = ')'; | |
16284 | + _cimg_mp_return(pos); | |
16285 | + } | |
16286 | + break; | |
16287 | + | |
16288 | + case 'r' : | |
16289 | + if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { // Bitwise rotation | |
16290 | + 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); | |
16298 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(*ss2=='l'?mp_rol:mp_ror,arg1,arg2); | |
16299 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) | |
16300 | + _cimg_mp_constant(*ss2=='l'?cimg::rol(mem[arg1],(unsigned int)mem[arg2]): | |
16301 | + cimg::ror(mem[arg1],(unsigned int)mem[arg2])); | |
16302 | + _cimg_mp_scalar2(*ss2=='l'?mp_rol:mp_ror,arg1,arg2); | |
16303 | + } | |
16304 | + | |
16305 | + if (!std::strncmp(ss,"round(",6)) { // Value rounding | |
16306 | + s_op = "Function 'round()'"; | |
16307 | + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
16308 | + arg1 = compile(ss6,s1==se2?++s1:s1,depth1,0); | |
16309 | + arg2 = 1; | |
16310 | + arg3 = 0; | |
16311 | + if (s1<se1) { | |
16312 | + 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); | |
16315 | + } | |
16316 | + _cimg_mp_check_type(arg2,2,s_op,1,0); | |
16317 | + _cimg_mp_check_type(arg3,3,s_op,1,0); | |
16318 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_round,arg1,arg2,arg3); | |
16319 | + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3)) | |
16320 | + _cimg_mp_constant(cimg::round(mem[arg1],mem[arg2],(int)mem[arg3])); | |
16321 | + _cimg_mp_scalar3(mp_round,arg1,arg2,arg3); | |
16322 | + } | |
16323 | + break; | |
16324 | + | |
16325 | + case 's' : | |
16326 | + if (!std::strncmp(ss,"sign(",5)) { // Sign | |
16327 | + arg1 = compile(ss5,se1,depth1,0); | |
16328 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sign,arg1); | |
16329 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sign(mem[arg1])); | |
16330 | + _cimg_mp_scalar1(mp_sign,arg1); | |
16331 | + } | |
16332 | + | |
16333 | + if (!std::strncmp(ss,"sin(",4)) { // Sine | |
16334 | + arg1 = compile(ss4,se1,depth1,0); | |
16335 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sin,arg1); | |
16336 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sin(mem[arg1])); | |
16337 | + _cimg_mp_scalar1(mp_sin,arg1); | |
16338 | + } | |
16339 | + | |
16340 | + if (!std::strncmp(ss,"sinc(",5)) { // Sine cardinal | |
16341 | + arg1 = compile(ss5,se1,depth1,0); | |
16342 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinc,arg1); | |
16343 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sinc(mem[arg1])); | |
16344 | + _cimg_mp_scalar1(mp_sinc,arg1); | |
16345 | + } | |
16346 | + | |
16347 | + if (!std::strncmp(ss,"sinh(",5)) { // Hyperbolic sine | |
16348 | + arg1 = compile(ss5,se1,depth1,0); | |
16349 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinh,arg1); | |
16350 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sinh(mem[arg1])); | |
16351 | + _cimg_mp_scalar1(mp_sinh,arg1); | |
16352 | + } | |
16353 | + | |
16354 | + if (!std::strncmp(ss,"size(",5)) { // Vector size. | |
16355 | + arg1 = compile(ss5,se1,depth1,0); | |
16356 | + _cimg_mp_constant(_cimg_mp_is_scalar(arg1)?0:_cimg_mp_vector_size(arg1)); | |
16357 | + } | |
16358 | + | |
16359 | + if (!std::strncmp(ss,"sort(",5)) { // Sort vector | |
16360 | + s_op = "Function 'sort()'"; | |
16361 | + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
16362 | + 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); | |
16366 | + p1 = _cimg_mp_vector_size(arg1); | |
16367 | + pos = vector(p1); | |
16368 | + CImg<uptrT>::vector((uptrT)mp_vector_sort,pos,arg1,p1,arg2).move_to(code); | |
16369 | + _cimg_mp_return(pos); | |
16370 | + } | |
16371 | + | |
16372 | + if (!std::strncmp(ss,"sqr(",4)) { // Square | |
16373 | + arg1 = compile(ss4,se1,depth1,0); | |
16374 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqr,arg1); | |
16375 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sqr(mem[arg1])); | |
16376 | + _cimg_mp_scalar1(mp_sqr,arg1); | |
16377 | + } | |
16378 | + | |
16379 | + if (!std::strncmp(ss,"sqrt(",5)) { // Square root | |
16380 | + arg1 = compile(ss5,se1,depth1,0); | |
16381 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqrt,arg1); | |
16382 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sqrt(mem[arg1])); | |
16383 | + _cimg_mp_scalar1(mp_sqrt,arg1); | |
16384 | + } | |
16385 | + break; | |
16386 | + | |
16387 | + case 't' : | |
16388 | + if (!std::strncmp(ss,"tan(",4)) { // Tangent | |
16389 | + arg1 = compile(ss4,se1,depth1,0); | |
16390 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tan,arg1); | |
16391 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tan(mem[arg1])); | |
16392 | + _cimg_mp_scalar1(mp_tan,arg1); | |
16393 | + } | |
16394 | + | |
16395 | + if (!std::strncmp(ss,"tanh(",5)) { // Hyperbolic tangent | |
16396 | + arg1 = compile(ss5,se1,depth1,0); | |
16397 | + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tanh,arg1); | |
16398 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tanh(mem[arg1])); | |
16399 | + _cimg_mp_scalar1(mp_tanh,arg1); | |
16400 | + } | |
16401 | + break; | |
16402 | + | |
16403 | + case 'u' : | |
16404 | + if (*ss1=='(') { // Random value with uniform distribution | |
16405 | + if (*ss2==')') _cimg_mp_scalar2(mp_u,0,1); | |
16406 | + s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
16407 | + 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)); | |
16410 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_u,arg1,arg2); | |
16411 | + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_u,arg1,arg2); | |
16412 | + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_u,arg1,arg2); | |
16413 | + _cimg_mp_scalar2(mp_u,arg1,arg2); | |
16414 | + } | |
16415 | + break; | |
16416 | + | |
16417 | + case 'v' : | |
16418 | + if ((cimg_sscanf(ss,"vector%u%c",&(arg1=~0U),&sep)==2 && sep=='(' && arg1>0) || | |
16419 | + !std::strncmp(ss,"vector(",7)) { // Vector | |
16420 | + arg2 = 0; // Number of specified values. | |
16421 | + s = std::strchr(ss6,'(') + 1; | |
16422 | + if (*s!=')' || arg1==~0U) for (; s<se; ++s) { | |
16423 | + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
16424 | + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
16425 | + arg3 = compile(s,ns,depth1,0); | |
16426 | + if (_cimg_mp_is_vector(arg3)) { | |
16427 | + arg4 = _cimg_mp_vector_size(arg3); | |
16428 | + CImg<uptrT>::sequence(arg4,arg3 + 1,arg3 + arg4).move_to(_opcode); | |
16429 | + arg2+=arg4; | |
16430 | + } else { CImg<uptrT>::vector(arg3).move_to(_opcode); ++arg2; } | |
16431 | + s = ns; | |
16432 | + } | |
16433 | + if (arg1==~0U) arg1 = arg2; | |
16434 | + _cimg_mp_check_vector0(arg1,"Function 'vector()'"); | |
16435 | + pos = vector(arg1); | |
16436 | + _opcode.insert(CImg<uptrT>::vector((uptrT)mp_vector_init,pos,arg1),0); | |
16437 | + (_opcode>'y').move_to(code); | |
16438 | + _cimg_mp_return(pos); | |
16439 | + } | |
16440 | + break; | |
16441 | + | |
16442 | + case 'w' : | |
16443 | + if (!std::strncmp(ss,"whiledo",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // While...do | |
16444 | + if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace | |
16445 | + s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1; | |
16446 | + p1 = code._width; | |
16447 | + arg1 = compile(ss8,s1,depth1,0); | |
16448 | + p2 = code._width; | |
16449 | + pos = compile(s1 + 1,se1,depth1,0); | |
16450 | + _cimg_mp_check_type(arg1,1,"Function 'whiledo()'",1,0); | |
16451 | + arg2 = _cimg_mp_is_vector(pos)?_cimg_mp_vector_size(pos):0; // Output vector size (or 0 if scalar) | |
16452 | + CImg<uptrT>::vector((uptrT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1); | |
16453 | + _cimg_mp_return(pos); | |
16454 | + } | |
16455 | + break; | |
16456 | + } | |
16457 | + | |
16458 | + if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4) || | |
16459 | + !std::strncmp(ss,"med(",4) || !std::strncmp(ss,"kth(",4) || | |
16460 | + !std::strncmp(ss,"arg(",4) || | |
16461 | + !std::strncmp(ss,"argmin(",7) || !std::strncmp(ss,"argmax(",7)) { // Multi-argument functions | |
16462 | + pos = scalar(); | |
16463 | + is_sth = *ss=='a' && ss[3]!='('; | |
16464 | + 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). | |
16467 | + move_to(_opcode); | |
16468 | + for (s = is_sth?ss7:ss4; s<se; ++s) { | |
16469 | + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
16470 | + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
16471 | + arg2 = compile(s,ns,depth1,0); | |
16472 | + if (_cimg_mp_is_vector(arg2)) | |
16473 | + CImg<uptrT>::sequence((uptrT)_cimg_mp_vector_size(arg2),arg2 + 1, | |
16474 | + arg2 + (uptrT)_cimg_mp_vector_size(arg2)). | |
16475 | + move_to(_opcode); | |
16476 | + else CImg<uptrT>::vector(arg2).move_to(_opcode); | |
16477 | + s = ns; | |
16478 | + } | |
16479 | + (_opcode>'y').move_to(code); | |
16480 | + _cimg_mp_return(pos); | |
16481 | + } | |
16482 | + | |
16483 | + // No corresponding built-in function -> Look for a user-defined function. | |
16484 | + s0 = strchr(ss,'('); | |
16485 | + if (s0) { | |
16486 | + variable_name.assign(ss,s0 - ss + 1).back() = 0; | |
16487 | + cimglist_for(function_def,l) if (!std::strcmp(function_def[l],variable_name)) { | |
16488 | + p2 = (unsigned int)function_def[l].back(); // Number of required arguments | |
16489 | + CImg<charT> _expr = function_body[l]; // Expression to be substituted | |
16490 | + p1 = 1; // Indice of current parsed argument | |
16491 | + for (s = s0 + 1; s<=se1; ++p1, s = ns + 1) { // Parse function arguments | |
16492 | + while (*s && *s<=' ') ++s; | |
16493 | + if (*s==')' && p1==1) break; // Function has no arguments | |
16494 | + if (p1>p2) { ++p1; break; } | |
16495 | + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
16496 | + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns; | |
16497 | + | |
16498 | + variable_name.assign(s,ns - s + 1).back() = 0; // Argument to write | |
16499 | + | |
16500 | + cimg_forX(_expr,k) if (_expr[k]==(char)p1) { // Perform argument substitution | |
16501 | + _expr.resize(_expr._width + variable_name._width,1,1,1,0); | |
16502 | + _expr[k++] = '('; | |
16503 | + std::memmove(_expr._data + k + variable_name._width,_expr._data + k, | |
16504 | + _expr._width - variable_name._width - k); | |
16505 | + std::memcpy(_expr._data + k,variable_name,variable_name._width - 1); | |
16506 | + k+=variable_name._width - 1; | |
16507 | + _expr[k++] = ')'; | |
16508 | + } | |
16509 | + *ns = 0; | |
16510 | + } | |
16511 | + | |
16512 | + if (p1!=p2+1) { // Number of specified argument do not fit | |
16513 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
16514 | + throw CImgArgumentException("[_cimg_math_parser] " | |
16515 | + "CImg<%s>::%s: function '%s()': Number of specified arguments does not " | |
16516 | + "match function declaration (%u argument%s required), " | |
16517 | + "in expression '%s%s%s'.", | |
16518 | + pixel_type(),_cimg_mp_calling_function,variable_name._data, | |
16519 | + p2,p2!=1?"s":"", | |
16520 | + (ss - 4)>expr._data?"...":"", | |
16521 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
16522 | + se<&expr.back()?"...":""); | |
16523 | + } | |
16524 | + | |
16525 | + // Recompute 'pexpr' and 'level' for evaluating substituted expression. | |
16526 | + CImg<charT> _pexpr(_expr._width); | |
16527 | + ns = _pexpr._data; | |
16528 | + for (ps = _expr._data, c1 = ' '; *ps; ++ps) { | |
16529 | + if (*ps!=' ') c1 = *ps; | |
16530 | + *(ns++) = c1; | |
16531 | + } | |
16532 | + *ns = 0; | |
16533 | + | |
16534 | + CImg<uintT> _level(_expr._width - 1); | |
16535 | + unsigned int *pd = _level._data; | |
16536 | + nb = 0; | |
16537 | + for (ps = _expr._data; *ps && nb>=0; ++ps) | |
16538 | + *(pd++) = (unsigned int)(*ps=='('||*ps=='['?nb++:*ps==')'||*ps==']'?--nb:nb); | |
16539 | + | |
16540 | + expr.swap(_expr); pexpr.swap(_pexpr); level.swap(_level); | |
16541 | + s0 = user_function; | |
16542 | + user_function = function_def[l]; | |
16543 | + pos = compile(expr._data,expr._data + expr._width - 1,depth1,p_ref); | |
16544 | + user_function = s0; | |
16545 | + expr.swap(_expr); pexpr.swap(_pexpr); level.swap(_level); | |
16546 | + _cimg_mp_return(pos); | |
16547 | + } | |
16548 | + } | |
16549 | + } // if (se1==')') | |
16550 | + | |
16551 | + // Vector specification using initializer '[ ... ]'. | |
16552 | + if (*ss=='[' && *se1==']') { | |
16553 | + arg1 = 0; // Number of specified values. | |
16554 | + if (*ss1!=']') for (s = ss1; s<se; ++s) { | |
16555 | + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) && | |
16556 | + (*ns!=']' || level[ns - expr._data]!=clevel)) ++ns; | |
16557 | + arg2 = compile(s,ns,depth1,0); | |
16558 | + if (_cimg_mp_is_vector(arg2)) { | |
16559 | + arg3 = _cimg_mp_vector_size(arg2); | |
16560 | + CImg<uptrT>::sequence(arg3,arg2 + 1,arg2 + arg3).move_to(_opcode); | |
16561 | + arg1+=arg3; | |
16562 | + } else { CImg<uptrT>::vector(arg2).move_to(_opcode); ++arg1; } | |
16563 | + s = ns; | |
16564 | + } | |
16565 | + _cimg_mp_check_vector0(arg1,"operator '[]'"); | |
16566 | + pos = vector(arg1); | |
16567 | + _opcode.insert(CImg<uptrT>::vector((uptrT)mp_vector_init,pos,arg1),0); | |
16568 | + (_opcode>'y').move_to(code); | |
16569 | + _cimg_mp_return(pos); | |
14559 | 16570 | } |
14560 | - --mp.p_code; | |
14561 | - return A*(double)mp.mem[mem_B]; | |
16571 | + | |
16572 | + // Variables related to the input list of images. | |
16573 | + if (*ss1=='#' && ss2<se) { | |
16574 | + arg1 = compile(ss2,se,depth1,0); | |
16575 | + p1 = (unsigned int)(listin._width && _cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0); | |
16576 | + switch (*ss) { | |
16577 | + case 'w' : // w#ind | |
16578 | + if (!listin) _cimg_mp_return(0); | |
16579 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width); | |
16580 | + _cimg_mp_scalar1(mp_list_width,arg1); | |
16581 | + case 'h' : // h#ind | |
16582 | + if (!listin) _cimg_mp_return(0); | |
16583 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._height); | |
16584 | + _cimg_mp_scalar1(mp_list_height,arg1); | |
16585 | + case 'd' : // d#ind | |
16586 | + if (!listin) _cimg_mp_return(0); | |
16587 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._depth); | |
16588 | + _cimg_mp_scalar1(mp_list_depth,arg1); | |
16589 | + case 'r' : // r#ind | |
16590 | + if (!listin) _cimg_mp_return(0); | |
16591 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._is_shared); | |
16592 | + _cimg_mp_scalar1(mp_list_is_shared,arg1); | |
16593 | + case 's' : // s#ind | |
16594 | + if (!listin) _cimg_mp_return(0); | |
16595 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._spectrum); | |
16596 | + _cimg_mp_scalar1(mp_list_spectrum,arg1); | |
16597 | + case 'i' : // i#ind | |
16598 | + if (!listin) _cimg_mp_return(0); | |
16599 | + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,_cimg_mp_c, | |
16600 | + reserved_label[29],reserved_label[30]); | |
16601 | + case 'R' : // R#ind | |
16602 | + if (!listin) _cimg_mp_return(0); | |
16603 | + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,0, | |
16604 | + reserved_label[29],reserved_label[30]); | |
16605 | + case 'G' : // G#ind | |
16606 | + if (!listin) _cimg_mp_return(0); | |
16607 | + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,1, | |
16608 | + reserved_label[29],reserved_label[30]); | |
16609 | + case 'B' : // B#ind | |
16610 | + if (!listin) _cimg_mp_return(0); | |
16611 | + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,2, | |
16612 | + reserved_label[29],reserved_label[30]); | |
16613 | + case 'A' : // A#ind | |
16614 | + if (!listin) _cimg_mp_return(0); | |
16615 | + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,3, | |
16616 | + reserved_label[29],reserved_label[30]); | |
16617 | + } | |
16618 | + } | |
16619 | + | |
16620 | + if (*ss1 && *ss2=='#' && ss3<se) { | |
16621 | + arg1 = compile(ss3,se,depth1,0); | |
16622 | + p1 = (unsigned int)(listin._width && _cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0); | |
16623 | + if (*ss=='w' && *ss1=='h') { // wh#ind | |
16624 | + if (!listin) _cimg_mp_return(0); | |
16625 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height); | |
16626 | + _cimg_mp_scalar1(mp_list_wh,arg1); | |
16627 | + } | |
16628 | + arg2 = ~0U; | |
16629 | + | |
16630 | + if (*ss=='i') { | |
16631 | + if (*ss1=='c') { // ic#ind | |
16632 | + if (!listin) _cimg_mp_return(0); | |
16633 | + if (_cimg_mp_is_constant(arg1)) { | |
16634 | + if (!list_median) list_median.assign(listin._width); | |
16635 | + if (!list_median[p1]) CImg<doubleT>::vector(listin[p1].median()).move_to(list_median[p1]); | |
16636 | + _cimg_mp_constant(*list_median[p1]); | |
16637 | + } | |
16638 | + _cimg_mp_scalar1(mp_list_median,arg1); | |
16639 | + } | |
16640 | + if (*ss1>='0' && *ss1<='9') { // i0#ind...i9#ind | |
16641 | + if (!listin) _cimg_mp_return(0); | |
16642 | + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,*ss1 - '0', | |
16643 | + reserved_label[29],reserved_label[30]); | |
16644 | + } | |
16645 | + switch (*ss1) { | |
16646 | + case 'm' : arg2 = 0; break; // im#ind | |
16647 | + case 'M' : arg2 = 1; break; // iM#ind | |
16648 | + case 'a' : arg2 = 2; break; // ia#ind | |
16649 | + case 'v' : arg2 = 3; break; // iv#ind | |
16650 | + case 's' : arg2 = 12; break; // is#ind | |
16651 | + case 'p' : arg2 = 13; break; // ip#ind | |
16652 | + } | |
16653 | + } else if (*ss1=='m') switch (*ss) { | |
16654 | + case 'x' : arg2 = 4; break; // xm#ind | |
16655 | + case 'y' : arg2 = 5; break; // ym#ind | |
16656 | + case 'z' : arg2 = 6; break; // zm#ind | |
16657 | + case 'c' : arg2 = 7; break; // cm#ind | |
16658 | + } else if (*ss1=='M') switch (*ss) { | |
16659 | + case 'x' : arg2 = 8; break; // xM#ind | |
16660 | + case 'y' : arg2 = 9; break; // yM#ind | |
16661 | + case 'z' : arg2 = 10; break; // zM#ind | |
16662 | + case 'c' : arg2 = 11; break; // cM#ind | |
16663 | + } | |
16664 | + if (arg2!=~0U) { | |
16665 | + if (!listin) _cimg_mp_return(0); | |
16666 | + if (_cimg_mp_is_constant(arg1)) { | |
16667 | + if (!list_stats) list_stats.assign(listin._width); | |
16668 | + if (!list_stats[p1]) list_stats[p1].assign(1,14,1,1,0).fill(listin[p1].get_stats(),false); | |
16669 | + _cimg_mp_constant(list_stats(p1,arg2)); | |
16670 | + } | |
16671 | + _cimg_mp_scalar2(mp_list_stats,arg1,arg2); | |
16672 | + } | |
16673 | + } | |
16674 | + | |
16675 | + if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='#' && ss4<se) { // whd#ind | |
16676 | + arg1 = compile(ss4,se,depth1,0); | |
16677 | + if (!listin) _cimg_mp_return(0); | |
16678 | + p1 = (unsigned int)(_cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0); | |
16679 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height*listin[p1]._depth); | |
16680 | + _cimg_mp_scalar1(mp_list_whd,arg1); | |
16681 | + } | |
16682 | + if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s' && *ss4=='#' && ss5<se) { // whds#ind | |
16683 | + arg1 = compile(ss5,se,depth1,0); | |
16684 | + if (!listin) _cimg_mp_return(0); | |
16685 | + p1 = (unsigned int)(_cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0); | |
16686 | + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height*listin[p1]._depth* | |
16687 | + listin[p1]._spectrum); | |
16688 | + _cimg_mp_scalar1(mp_list_whds,arg1); | |
16689 | + } | |
16690 | + | |
16691 | + if (!std::strcmp(ss,"interpolation")) _cimg_mp_return(reserved_label[29]); // interpolation | |
16692 | + if (!std::strcmp(ss,"boundary")) _cimg_mp_return(reserved_label[30]); // boundary | |
16693 | + | |
16694 | + // No known item found, assuming this is an already initialized variable. | |
16695 | + variable_name.assign(ss,(unsigned int)(se + 1 - ss)).back() = 0; | |
16696 | + if (variable_name[1]) { // Multi-char variable | |
16697 | + cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i])) | |
16698 | + _cimg_mp_return(variable_pos[i]); | |
16699 | + } else if (reserved_label[*variable_name]!=~0U) // Single-char variable | |
16700 | + _cimg_mp_return(reserved_label[*variable_name]); | |
16701 | + | |
16702 | + // Reached an unknown item -> error. | |
16703 | + is_sth = true; // is_valid_variable_name | |
16704 | + if (*variable_name>='0' && *variable_name<='9') is_sth = false; | |
16705 | + else for (ns = variable_name._data + 1; *ns; ++ns) | |
16706 | + if (!is_varchar(*ns)) { is_sth = false; break; } | |
16707 | + | |
16708 | + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64); | |
16709 | + if (is_sth) | |
16710 | + throw CImgArgumentException("[_cimg_math_parser] " | |
16711 | + "CImg<%s>::%s: Undefined variable '%s' in expression '%s%s%s'.", | |
16712 | + pixel_type(),_cimg_mp_calling_function, | |
16713 | + variable_name._data, | |
16714 | + (ss - 4)>expr._data?"...":"", | |
16715 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
16716 | + se<&expr.back()?"...":""); | |
16717 | + s0 = std::strchr(ss,'('); | |
16718 | + if (s0 && *se1==')') s_op = "function call"; else s_op = "item"; | |
16719 | + throw CImgArgumentException("[_cimg_math_parser] " | |
16720 | + "CImg<%s>::%s: Unrecognized %s '%s' in expression '%s%s%s'.", | |
16721 | + pixel_type(),_cimg_mp_calling_function, | |
16722 | + s_op,variable_name._data, | |
16723 | + (ss - 4)>expr._data?"...":"", | |
16724 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
16725 | + se<&expr.back()?"...":""); | |
14562 | 16726 | } |
14563 | - static double mp_div(_cimg_math_parser& mp) { | |
14564 | - return mp.mem[mp.opcode(2)] / mp.mem[mp.opcode(3)]; | |
16727 | + | |
16728 | + // Evaluation procedure. | |
16729 | + double operator()(const double x, const double y, const double z, const double c) { | |
16730 | + mem[_cimg_mp_x] = x; mem[_cimg_mp_y] = y; mem[_cimg_mp_z] = z; mem[_cimg_mp_c] = c; | |
16731 | + for (p_code = p_code_begin; p_code<p_code_end; ++p_code) { | |
16732 | + const CImg<uptrT> &op = *p_code; | |
16733 | + opcode._data = op._data; opcode._height = op._height; | |
16734 | + const uptrT target = opcode[1]; | |
16735 | + mem[target] = _cimg_mp_defunc(*this); | |
16736 | + } | |
16737 | + return *result; | |
14565 | 16738 | } |
14566 | - static double mp_minus(_cimg_math_parser& mp) { | |
14567 | - return -mp.mem[mp.opcode(2)]; | |
16739 | + | |
16740 | + // Evaluation procedure (return output values in vector 'output'). | |
16741 | + template<typename t> | |
16742 | + void operator()(const double x, const double y, const double z, const double c, t *const output) { | |
16743 | + mem[_cimg_mp_x] = x; mem[_cimg_mp_y] = y; mem[_cimg_mp_z] = z; mem[_cimg_mp_c] = c; | |
16744 | + for (p_code = p_code_begin; p_code<p_code_end; ++p_code) { | |
16745 | + const CImg<uptrT> &op = *p_code; | |
16746 | + opcode._data = op._data; opcode._height = op._height; | |
16747 | + const uptrT target = opcode[1]; | |
16748 | + mem[target] = _cimg_mp_defunc(*this); | |
16749 | + } | |
16750 | + if (result_dim) { | |
16751 | + const double *ptrs = result + 1; | |
16752 | + t *ptrd = output; | |
16753 | + for (unsigned int k = 0; k<result_dim; ++k) *(ptrd++) = (t)*(ptrs++); | |
16754 | + } else *output = (t)*result; | |
14568 | 16755 | } |
14569 | - static double mp_logical_not(_cimg_math_parser& mp) { | |
14570 | - return !mp.mem[mp.opcode(2)]; | |
16756 | + | |
16757 | + // Return type of a memory element as a string. | |
16758 | + CImg<charT> s_type(const unsigned int arg) const { | |
16759 | + CImg<charT> res; | |
16760 | + if (_cimg_mp_is_vector(arg)) { // Vector | |
16761 | + CImg<charT>::string("vectorXXXXXXXXXXXXXXXX").move_to(res); | |
16762 | + std::sprintf(res._data + 6,"%u",_cimg_mp_vector_size(arg)); | |
16763 | + } else CImg<charT>::string("scalar").move_to(res); | |
16764 | + return res; | |
14571 | 16765 | } |
14572 | - static double mp_bitwise_not(_cimg_math_parser& mp) { | |
14573 | - return ~(unsigned long)mp.mem[mp.opcode(2)]; | |
16766 | + | |
16767 | + // Insert constant value in memory. | |
16768 | + unsigned int constant(const double val) { | |
16769 | + if (val==(double)(int)val) { | |
16770 | + if (val>=0 && val<=9) return (unsigned int)val; | |
16771 | + if (val<0 && val>=-5) return (unsigned int)(10 - val); | |
16772 | + } | |
16773 | + if (val==0.5) return 16; | |
16774 | + if (cimg::type<double>::is_nan(val)) return 28; | |
16775 | + if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(-200,1,1,1,0); } | |
16776 | + const unsigned int pos = mempos++; | |
16777 | + mem[pos] = val; | |
16778 | + memtype[pos] = 1; // Set constant property | |
16779 | + return pos; | |
14574 | 16780 | } |
14575 | - static double mp_modulo(_cimg_math_parser& mp) { | |
14576 | - return cimg::mod(mp.mem[mp.opcode(2)],mp.mem[mp.opcode(3)]); | |
16781 | + | |
16782 | + // Insert code instructions for processing scalars. | |
16783 | + unsigned int scalar() { // Insert new scalar in memory. | |
16784 | + if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(mem._width,1,1,1,0); } | |
16785 | + return mempos++; | |
14577 | 16786 | } |
14578 | - static double mp_bitwise_and(_cimg_math_parser& mp) { | |
14579 | - return ((unsigned long)mp.mem[mp.opcode(2)] & (unsigned long)mp.mem[mp.opcode(3)]); | |
16787 | + | |
16788 | + unsigned int scalar0(const mp_func op) { | |
16789 | + const unsigned int pos = scalar(); | |
16790 | + CImg<uptrT>::vector((uptrT)op,pos).move_to(code); | |
16791 | + return pos; | |
14580 | 16792 | } |
14581 | - static double mp_bitwise_or(_cimg_math_parser& mp) { | |
14582 | - return ((unsigned long)mp.mem[mp.opcode(2)] | (unsigned long)mp.mem[mp.opcode(3)]); | |
16793 | + | |
16794 | + unsigned int scalar1(const mp_func op, const unsigned int arg1) { | |
16795 | + const unsigned int pos = | |
16796 | + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:scalar(); | |
16797 | + CImg<uptrT>::vector((uptrT)op,pos,arg1).move_to(code); | |
16798 | + return pos; | |
14583 | 16799 | } |
14584 | - static double mp_pow(_cimg_math_parser& mp) { | |
14585 | - const double v = mp.mem[mp.opcode(2)], p = mp.mem[mp.opcode(3)]; | |
14586 | - if (p==0) return 1; | |
14587 | - if (p==0.5) return std::sqrt(v); | |
14588 | - if (p==1) return v; | |
14589 | - if (p==2) return v*v; | |
14590 | - if (p==3) return v*v*v; | |
14591 | - if (p==4) return v*v*v*v; | |
14592 | - return std::pow(v,p); | |
16800 | + | |
16801 | + unsigned int scalar2(const mp_func op, const unsigned int arg1, const unsigned int arg2) { | |
16802 | + const unsigned int pos = | |
16803 | + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1: | |
16804 | + arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:scalar(); | |
16805 | + CImg<uptrT>::vector((uptrT)op,pos,arg1,arg2).move_to(code); | |
16806 | + return pos; | |
14593 | 16807 | } |
14594 | - static double mp_sin(_cimg_math_parser& mp) { | |
14595 | - return std::sin(mp.mem[mp.opcode(2)]); | |
16808 | + | |
16809 | + unsigned int scalar3(const mp_func op, | |
16810 | + const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) { | |
16811 | + const unsigned int pos = | |
16812 | + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1: | |
16813 | + arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2: | |
16814 | + arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3:scalar(); | |
16815 | + CImg<uptrT>::vector((uptrT)op,pos,arg1,arg2,arg3).move_to(code); | |
16816 | + return pos; | |
14596 | 16817 | } |
14597 | - static double mp_cos(_cimg_math_parser& mp) { | |
14598 | - return std::cos(mp.mem[mp.opcode(2)]); | |
16818 | + | |
16819 | + unsigned int scalar6(const mp_func op, | |
16820 | + const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, | |
16821 | + const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) { | |
16822 | + const unsigned int pos = | |
16823 | + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1: | |
16824 | + arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2: | |
16825 | + arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3: | |
16826 | + arg4>_cimg_mp_c && _cimg_mp_is_temp(arg4)?arg4: | |
16827 | + arg5>_cimg_mp_c && _cimg_mp_is_temp(arg5)?arg5: | |
16828 | + arg6>_cimg_mp_c && _cimg_mp_is_temp(arg6)?arg6:scalar(); | |
16829 | + CImg<uptrT>::vector((uptrT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code); | |
16830 | + return pos; | |
14599 | 16831 | } |
14600 | - static double mp_tan(_cimg_math_parser& mp) { | |
14601 | - return std::tan(mp.mem[mp.opcode(2)]); | |
16832 | + | |
16833 | + unsigned int scalar7(const mp_func op, | |
16834 | + const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, | |
16835 | + const unsigned int arg4, const unsigned int arg5, const unsigned int arg6, | |
16836 | + const unsigned int arg7) { | |
16837 | + const unsigned int pos = | |
16838 | + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1: | |
16839 | + arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2: | |
16840 | + arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3: | |
16841 | + arg4>_cimg_mp_c && _cimg_mp_is_temp(arg4)?arg4: | |
16842 | + arg5>_cimg_mp_c && _cimg_mp_is_temp(arg5)?arg5: | |
16843 | + arg6>_cimg_mp_c && _cimg_mp_is_temp(arg6)?arg6: | |
16844 | + arg7>_cimg_mp_c && _cimg_mp_is_temp(arg7)?arg7:scalar(); | |
16845 | + CImg<uptrT>::vector((uptrT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6,arg7).move_to(code); | |
16846 | + return pos; | |
14602 | 16847 | } |
14603 | - static double mp_asin(_cimg_math_parser& mp) { | |
14604 | - return std::asin(mp.mem[mp.opcode(2)]); | |
16848 | + | |
16849 | + // Return a string that defines the calling function + the user-defined function scope. | |
16850 | + CImg<charT> calling_function_s() const { | |
16851 | + CImg<charT> res; | |
16852 | + const unsigned int | |
16853 | + l1 = calling_function?std::strlen(calling_function):0, | |
16854 | + l2 = user_function?std::strlen(user_function):0; | |
16855 | + if (l2) { | |
16856 | + res.assign(l1 + l2 + 48); | |
16857 | + cimg_snprintf(res,res._width,"%s(): When substituting function '%s()'",calling_function,user_function); | |
16858 | + } else { | |
16859 | + res.assign(l1 + l2 + 4); | |
16860 | + cimg_snprintf(res,res._width,"%s()",calling_function); | |
16861 | + } | |
16862 | + return res; | |
14605 | 16863 | } |
16864 | + | |
16865 | + // Return true if specified argument can be a part of an allowed variable name. | |
16866 | + bool is_varchar(const char c) const { | |
16867 | + return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; | |
16868 | + } | |
16869 | + | |
16870 | + // Insert code instructions for processing vectors. | |
16871 | + bool is_tmp_vector(const unsigned int arg) const { | |
16872 | + unsigned int siz = _cimg_mp_vector_size(arg); | |
16873 | + if (siz>8) return false; | |
16874 | + const int *ptr = memtype.data(arg + 1); | |
16875 | + bool is_tmp = true; | |
16876 | + while (siz-->0) if (*(ptr++)) { is_tmp = false; break; } | |
16877 | + return is_tmp; | |
16878 | + } | |
16879 | + | |
16880 | + void set_variable_vector(const unsigned int arg) { | |
16881 | + unsigned int siz = _cimg_mp_vector_size(arg); | |
16882 | + int *ptr = memtype.data(arg + 1); | |
16883 | + while (siz-->0) *(ptr++) = -1; | |
16884 | + } | |
16885 | + | |
16886 | + unsigned int vector(const unsigned int siz) { // Insert new vector of specified size in memory. | |
16887 | + if (mempos + siz>=mem._width) { | |
16888 | + mem.resize(2*mem._width + siz,1,1,1,0); | |
16889 | + memtype.resize(mem._width,1,1,1,0); | |
16890 | + } | |
16891 | + const unsigned int pos = mempos++; | |
16892 | + mem[pos] = cimg::type<double>::nan(); | |
16893 | + memtype[pos] = siz + 1; | |
16894 | + mempos+=siz; | |
16895 | + return pos; | |
16896 | + } | |
16897 | + | |
16898 | + unsigned int vector_copy(const unsigned int arg) { // Insert new copy of specified vector in memory. | |
16899 | + const unsigned int | |
16900 | + siz = _cimg_mp_vector_size(arg), | |
16901 | + pos = vector(siz); | |
16902 | + CImg<uptrT>::vector((uptrT)mp_vector_copy,pos,arg,siz).move_to(code); | |
16903 | + return pos; | |
16904 | + } | |
16905 | + | |
16906 | + unsigned int vector1_v(const mp_func op, const unsigned int arg1) { | |
16907 | + const unsigned int | |
16908 | + siz = _cimg_mp_vector_size(arg1), | |
16909 | + 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); | |
16911 | + return pos; | |
16912 | + } | |
16913 | + | |
16914 | + unsigned int vector2_vv(const mp_func op, const unsigned int arg1, const unsigned int arg2) { | |
16915 | + const unsigned int | |
16916 | + siz = _cimg_mp_vector_size(arg1), | |
16917 | + 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); | |
16919 | + return pos; | |
16920 | + } | |
16921 | + | |
16922 | + unsigned int vector2_vs(const mp_func op, const unsigned int arg1, const unsigned int arg2) { | |
16923 | + const unsigned int | |
16924 | + siz = _cimg_mp_vector_size(arg1), | |
16925 | + 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); | |
16927 | + return pos; | |
16928 | + } | |
16929 | + | |
16930 | + unsigned int vector2_sv(const mp_func op, const unsigned int arg1, const unsigned int arg2) { | |
16931 | + const unsigned int | |
16932 | + siz = _cimg_mp_vector_size(arg2), | |
16933 | + 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); | |
16935 | + return pos; | |
16936 | + } | |
16937 | + | |
16938 | + unsigned int vector3_vss(const mp_func op, const unsigned int arg1, const unsigned int arg2, | |
16939 | + const unsigned int arg3) { | |
16940 | + const unsigned int | |
16941 | + siz = _cimg_mp_vector_size(arg1), | |
16942 | + 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); | |
16944 | + return pos; | |
16945 | + } | |
16946 | + | |
16947 | + // 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, | |
16949 | + const bool is_strictly_positive, | |
16950 | + const char *const ss, char *const se, const char saved_char) { | |
16951 | + _cimg_mp_check_type(arg,n_arg,s_op,1,0); | |
16952 | + 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 "; | |
16954 | + *se = saved_char; cimg::strellipsize(expr,64); | |
16955 | + throw CImgArgumentException("[_cimg_math_parser] " | |
16956 | + "CImg<%s>::%s(): %s: %s%s (of type '%s') is not a %spositive integer constant, " | |
16957 | + "in expression '%s%s%s'.", | |
16958 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
16959 | + s_arg,*s_arg?"argument":"Argument",s_type(arg)._data, | |
16960 | + is_strictly_positive?"strictly ":"", | |
16961 | + (ss - 4)>expr._data?"...":"", | |
16962 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
16963 | + se<&expr.back()?"...":""); | |
16964 | + } | |
16965 | + } | |
16966 | + | |
16967 | + // Check a matrix is square. | |
16968 | + void check_matrix_square(const unsigned int arg, const unsigned int n_arg, const char *const s_op, | |
16969 | + const char *const ss, char *const se, const char saved_char) { | |
16970 | + _cimg_mp_check_type(arg,n_arg,s_op,2,0); | |
16971 | + const unsigned int | |
16972 | + siz = _cimg_mp_vector_size(arg), | |
16973 | + n = (unsigned int)std::sqrt((float)siz); | |
16974 | + if (n*n!=siz) { | |
16975 | + const char *s_arg; | |
16976 | + if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand "; | |
16977 | + else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One "; | |
16978 | + *se = saved_char; cimg::strellipsize(expr,64); | |
16979 | + throw CImgArgumentException("[_cimg_math_parser] " | |
16980 | + "CImg<%s>::%s(): %s: %s%s (of type '%s') " | |
16981 | + "cannot be considered as a square matrix, in expression '%s%s%s'.", | |
16982 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
16983 | + s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"), | |
16984 | + s_type(arg)._data, | |
16985 | + (ss - 4)>expr._data?"...":"", | |
16986 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
16987 | + se<&expr.back()?"...":""); | |
16988 | + } | |
16989 | + } | |
16990 | + | |
16991 | + // Check type compatibility for one argument. | |
16992 | + // Bits of 'mode' tells what types are allowed: | |
16993 | + // { 1 = scalar | 2 = vectorN }. | |
16994 | + // 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, | |
16996 | + const unsigned int mode, const unsigned int N, | |
16997 | + const char *const ss, char *const se, const char saved_char) { | |
16998 | + const bool | |
16999 | + is_scalar = _cimg_mp_is_scalar(arg), | |
17000 | + is_vector = _cimg_mp_is_vector(arg) && (!N || _cimg_mp_vector_size(arg)==N); | |
17001 | + bool cond = false; | |
17002 | + if (mode&1) cond|=is_scalar; | |
17003 | + if (mode&2) cond|=is_vector; | |
17004 | + if (!cond) { | |
17005 | + const char *s_arg; | |
17006 | + 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 "; | |
17008 | + CImg<charT> sb_type(32); | |
17009 | + if (mode==1) cimg_snprintf(sb_type,sb_type._width,"'scalar'"); | |
17010 | + else if (mode==2) { | |
17011 | + if (N) cimg_snprintf(sb_type,sb_type._width,"'vector%u'",N); | |
17012 | + else cimg_snprintf(sb_type,sb_type._width,"'vector'"); | |
17013 | + } else { | |
17014 | + if (N) cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector%u'",N); | |
17015 | + else cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector'"); | |
17016 | + } | |
17017 | + *se = saved_char; cimg::strellipsize(expr,64); | |
17018 | + throw CImgArgumentException("[_cimg_math_parser] " | |
17019 | + "CImg<%s>::%s(): %s: %s%s has invalid type '%s' (should be %s), " | |
17020 | + "in expression '%s%s%s'.", | |
17021 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
17022 | + s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"), | |
17023 | + s_type(arg)._data,sb_type._data, | |
17024 | + (ss - 4)>expr._data?"...":"", | |
17025 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
17026 | + se<&expr.back()?"...":""); | |
17027 | + } | |
17028 | + } | |
17029 | + | |
17030 | + // 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, | |
17032 | + const char *const ss, char *const se, const char saved_char) { | |
17033 | + if (!dim) { | |
17034 | + *se = saved_char; cimg::strellipsize(expr,64); | |
17035 | + throw CImgArgumentException("[_cimg_math_parser] " | |
17036 | + "CImg<%s>::%s(): %s: Invalid construction of a 0-dimensional vector, " | |
17037 | + "in expression '%s%s%s'.", | |
17038 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
17039 | + (ss - 4)>expr._data?"...":"", | |
17040 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
17041 | + se<&expr.back()?"...":""); | |
17042 | + } else if (dim==~0U) { | |
17043 | + *se = saved_char; cimg::strellipsize(expr,64); | |
17044 | + throw CImgArgumentException("[_cimg_math_parser] " | |
17045 | + "CImg<%s>::%s(): %s: Invalid construction of a vector with dynamic size, " | |
17046 | + "in expression '%s%s%s'.", | |
17047 | + pixel_type(),_cimg_mp_calling_function,s_op, | |
17048 | + (ss - 4)>expr._data?"...":"", | |
17049 | + (ss - 4)>expr._data?ss - 4:expr._data, | |
17050 | + se<&expr.back()?"...":""); | |
17051 | + } | |
17052 | + } | |
17053 | + | |
17054 | + // Evaluation functions, known by the parser. | |
17055 | + // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(uptrT), | |
17056 | + // so we can store pointers to them directly in the opcode vectors. | |
17057 | +#ifdef _mp_arg | |
17058 | +#undef _mp_arg | |
17059 | +#endif | |
17060 | +#define _mp_arg(x) mp.mem[mp.opcode[x]] | |
17061 | + | |
17062 | + static double mp_abs(_cimg_math_parser& mp) { | |
17063 | + return cimg::abs(_mp_arg(2)); | |
17064 | + } | |
17065 | + | |
17066 | + static double mp_add(_cimg_math_parser& mp) { | |
17067 | + return _mp_arg(2) + _mp_arg(3); | |
17068 | + } | |
17069 | + | |
14606 | 17070 | static double mp_acos(_cimg_math_parser& mp) { |
14607 | - return std::acos(mp.mem[mp.opcode(2)]); | |
17071 | + return std::acos(_mp_arg(2)); | |
14608 | 17072 | } |
14609 | - static double mp_atan(_cimg_math_parser& mp) { | |
14610 | - return std::atan(mp.mem[mp.opcode(2)]); | |
17073 | + | |
17074 | + static double mp_arg(_cimg_math_parser& mp) { | |
17075 | + const int _ind = (int)_mp_arg(2); | |
17076 | + const unsigned int nb_args = mp.opcode._height - 2, ind = _ind<0?_ind + nb_args:(unsigned int)_ind; | |
17077 | + if (ind>=nb_args) return 0; | |
17078 | + return _mp_arg(ind + 2); | |
14611 | 17079 | } |
14612 | - static double mp_sinh(_cimg_math_parser& mp) { | |
14613 | - return std::sinh(mp.mem[mp.opcode(2)]); | |
17080 | + | |
17081 | + static double mp_argmin(_cimg_math_parser& mp) { | |
17082 | + double val = _mp_arg(2); | |
17083 | + unsigned int argval = 0; | |
17084 | + for (unsigned int i = 3; i<mp.opcode._height; ++i) { | |
17085 | + const double _val = _mp_arg(i); | |
17086 | + if (_val<val) { val = _val; argval = i - 2; } | |
17087 | + } | |
17088 | + return (double)argval; | |
14614 | 17089 | } |
14615 | - static double mp_cosh(_cimg_math_parser& mp) { | |
14616 | - return std::cosh(mp.mem[mp.opcode(2)]); | |
17090 | + | |
17091 | + static double mp_argmax(_cimg_math_parser& mp) { | |
17092 | + double val = _mp_arg(2); | |
17093 | + unsigned int argval = 0; | |
17094 | + for (unsigned int i = 3; i<mp.opcode._height; ++i) { | |
17095 | + const double _val = _mp_arg(i); | |
17096 | + if (_val>val) { val = _val; argval = i - 2; } | |
17097 | + } | |
17098 | + return (double)argval; | |
14617 | 17099 | } |
14618 | - static double mp_tanh(_cimg_math_parser& mp) { | |
14619 | - return std::tanh(mp.mem[mp.opcode(2)]); | |
17100 | + | |
17101 | + static double mp_asin(_cimg_math_parser& mp) { | |
17102 | + return std::asin(_mp_arg(2)); | |
14620 | 17103 | } |
14621 | - static double mp_log10(_cimg_math_parser& mp) { | |
14622 | - return std::log10(mp.mem[mp.opcode(2)]); | |
17104 | + | |
17105 | + static double mp_atan(_cimg_math_parser& mp) { | |
17106 | + return std::atan(_mp_arg(2)); | |
14623 | 17107 | } |
14624 | - static double mp_log2(_cimg_math_parser& mp) { | |
14625 | - return cimg::log2(mp.mem[mp.opcode(2)]); | |
17108 | + | |
17109 | + static double mp_atan2(_cimg_math_parser& mp) { | |
17110 | + return std::atan2(_mp_arg(2),_mp_arg(3)); | |
14626 | 17111 | } |
14627 | - static double mp_log(_cimg_math_parser& mp) { | |
14628 | - return std::log(mp.mem[mp.opcode(2)]); | |
17112 | + | |
17113 | + static double mp_bitwise_and(_cimg_math_parser& mp) { | |
17114 | + return (double)((unsigned long)_mp_arg(2) & (unsigned long)_mp_arg(3)); | |
14629 | 17115 | } |
14630 | - static double mp_exp(_cimg_math_parser& mp) { | |
14631 | - return std::exp(mp.mem[mp.opcode(2)]); | |
17116 | + | |
17117 | + static double mp_bitwise_left_shift(_cimg_math_parser& mp) { | |
17118 | + return (double)((long)_mp_arg(2)<<(unsigned int)_mp_arg(3)); | |
14632 | 17119 | } |
14633 | - static double mp_sqr(_cimg_math_parser& mp) { | |
14634 | - return cimg::sqr(mp.mem[mp.opcode(2)]); | |
17120 | + | |
17121 | + static double mp_bitwise_not(_cimg_math_parser& mp) { | |
17122 | + return (double)~(unsigned long)_mp_arg(2); | |
14635 | 17123 | } |
14636 | - static double mp_sqrt(_cimg_math_parser& mp) { | |
14637 | - return std::sqrt(mp.mem[mp.opcode(2)]); | |
17124 | + | |
17125 | + static double mp_bitwise_or(_cimg_math_parser& mp) { | |
17126 | + return (double)((unsigned long)_mp_arg(2) | (unsigned long)_mp_arg(3)); | |
14638 | 17127 | } |
17128 | + | |
17129 | + static double mp_bitwise_right_shift(_cimg_math_parser& mp) { | |
17130 | + return (double)((long)_mp_arg(2)>>(unsigned int)_mp_arg(3)); | |
17131 | + } | |
17132 | + | |
14639 | 17133 | static double mp_cbrt(_cimg_math_parser& mp) { |
14640 | - return std::pow(mp.mem[mp.opcode(2)],1.0/3); | |
17134 | + return std::pow(_mp_arg(2),1.0/3); | |
14641 | 17135 | } |
14642 | - static double mp_hypot(_cimg_math_parser& mp) { | |
14643 | - double | |
14644 | - x = cimg::abs(mp.mem[mp.opcode(2)]), | |
14645 | - y = cimg::abs(mp.mem[mp.opcode(3)]), | |
14646 | - t; | |
14647 | - if (x<y) { t = x; x = y; } else t = y; | |
14648 | - if (x>0) { t/=x; return x*std::sqrt(1+t*t); } | |
14649 | - return 0; | |
17136 | + | |
17137 | + static double mp_complex_conj(_cimg_math_parser& mp) { | |
17138 | + const double *ptrs = &_mp_arg(2) + 1; | |
17139 | + double *ptrd = &_mp_arg(1) + 1; | |
17140 | + *(ptrd++) = *(ptrs++); | |
17141 | + *ptrd = -*(ptrs); | |
17142 | + return cimg::type<double>::nan(); | |
14650 | 17143 | } |
14651 | - static double mp_norm(_cimg_math_parser& mp) { | |
14652 | - const unsigned int norm_type = (unsigned int)mp.opcode(2); | |
14653 | - double res = 0; | |
14654 | - switch (norm_type) { | |
14655 | - case 0 : // L0-norm. | |
14656 | - for (unsigned int i = 3; i<mp.opcode._height; ++i) | |
14657 | - res+=mp.mem[mp.opcode(i)]==0?0:1; | |
14658 | - break; | |
14659 | - case 1 : // L1-norm. | |
14660 | - for (unsigned int i = 3; i<mp.opcode._height; ++i) | |
14661 | - res+=cimg::abs(mp.mem[mp.opcode(i)]); | |
14662 | - break; | |
14663 | - case 2 : // L2-norm. | |
14664 | - for (unsigned int i = 3; i<mp.opcode._height; ++i) { | |
14665 | - const double val = mp.mem[mp.opcode(i)]; | |
14666 | - res+=val*val; | |
14667 | - } | |
14668 | - res = std::sqrt(res); | |
14669 | - break; | |
14670 | - case ~0U : // Linf-norm. | |
14671 | - for (unsigned int i = 3; i<mp.opcode._height; ++i) { | |
14672 | - const double val = cimg::abs(mp.mem[mp.opcode(i)]); | |
14673 | - if (val>res) res = val; | |
14674 | - } | |
14675 | - break; | |
14676 | - default: // Lp-norm. | |
14677 | - for (unsigned int i = 3; i<mp.opcode._height; ++i) | |
14678 | - res+=std::pow(cimg::abs(mp.mem[mp.opcode(i)]),(double)norm_type); | |
14679 | - res = std::pow(res,1.0/norm_type); | |
17144 | + | |
17145 | + static double mp_complex_div_sv(_cimg_math_parser& mp) { | |
17146 | + const double | |
17147 | + *ptr2 = &_mp_arg(3) + 1, | |
17148 | + r1 = _mp_arg(2), | |
17149 | + r2 = *(ptr2++), i2 = *ptr2; | |
17150 | + double *ptrd = &_mp_arg(1) + 1; | |
17151 | + const double denom = r2*r2 + i2*i2; | |
17152 | + *(ptrd++) = r1*r2/denom; | |
17153 | + *ptrd = -r1*i2/denom; | |
17154 | + return cimg::type<double>::nan(); | |
17155 | + } | |
17156 | + | |
17157 | + static double mp_complex_div_vv(_cimg_math_parser& mp) { | |
17158 | + const double | |
17159 | + *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1, | |
17160 | + r1 = *(ptr1++), i1 = *ptr1, | |
17161 | + r2 = *(ptr2++), i2 = *ptr2; | |
17162 | + double *ptrd = &_mp_arg(1) + 1; | |
17163 | + const double denom = r2*r2 + i2*i2; | |
17164 | + *(ptrd++) = (r1*r2 + i1*i2)/denom; | |
17165 | + *ptrd = (r2*i1 - r1*i2)/denom; | |
17166 | + return cimg::type<double>::nan(); | |
17167 | + } | |
17168 | + | |
17169 | + static double mp_complex_exp(_cimg_math_parser& mp) { | |
17170 | + double *ptrd = &_mp_arg(1) + 1; | |
17171 | + const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs), er = std::exp(r); | |
17172 | + *(ptrd++) = er*std::cos(i); | |
17173 | + *(ptrd++) = er*std::sin(i); | |
17174 | + return cimg::type<double>::nan(); | |
17175 | + } | |
17176 | + | |
17177 | + static double mp_complex_log(_cimg_math_parser& mp) { | |
17178 | + double *ptrd = &_mp_arg(1) + 1; | |
17179 | + const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs); | |
17180 | + *(ptrd++) = std::log(std::sqrt(r*r + i*i)); | |
17181 | + *(ptrd++) = std::atan2(i,r); | |
17182 | + return cimg::type<double>::nan(); | |
17183 | + } | |
17184 | + | |
17185 | + static double mp_complex_mul(_cimg_math_parser& mp) { | |
17186 | + const double | |
17187 | + *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1, | |
17188 | + r1 = *(ptr1++), i1 = *ptr1, | |
17189 | + r2 = *(ptr2++), i2 = *ptr2; | |
17190 | + double *ptrd = &_mp_arg(1) + 1; | |
17191 | + *(ptrd++) = r1*r2 - i1*i2; | |
17192 | + *(ptrd++) = r1*i2 + r2*i1; | |
17193 | + return cimg::type<double>::nan(); | |
17194 | + } | |
17195 | + | |
17196 | + static void _mp_complex_pow(const double r1, const double i1, | |
17197 | + const double r2, const double i2, | |
17198 | + double *ptrd) { | |
17199 | + double ro, io; | |
17200 | + if (cimg::abs(i2)<1e-15) { // Exponent is real | |
17201 | + if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) { | |
17202 | + if (cimg::abs(r2)<1e-15) { ro = 1; io = 0; } | |
17203 | + else ro = io = 0; | |
17204 | + } else { | |
17205 | + const double | |
17206 | + mod1_2 = r1*r1 + i1*i1, | |
17207 | + phi1 = std::atan2(i1,r1), | |
17208 | + modo = std::pow(mod1_2,0.5*r2), | |
17209 | + phio = r2*phi1; | |
17210 | + ro = modo*std::cos(phio); | |
17211 | + io = modo*std::sin(phio); | |
17212 | + } | |
17213 | + } else { // Exponent is complex | |
17214 | + if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) ro = io = 0; | |
17215 | + const double | |
17216 | + mod1_2 = r1*r1 + i1*i1, | |
17217 | + phi1 = std::atan2(i1,r1), | |
17218 | + modo = std::pow(mod1_2,0.5*r2)*std::exp(-i2*phi1), | |
17219 | + phio = r2*phi1 + 0.5*i2*std::log(mod1_2); | |
17220 | + ro = modo*std::cos(phio); | |
17221 | + io = modo*std::sin(phio); | |
14680 | 17222 | } |
14681 | - return res>0?res:0.0; | |
17223 | + *(ptrd++) = ro; | |
17224 | + *ptrd = io; | |
14682 | 17225 | } |
14683 | - static double mp_sign(_cimg_math_parser& mp) { | |
14684 | - return cimg::sign(mp.mem[mp.opcode(2)]); | |
17226 | + | |
17227 | + static double mp_complex_pow_sv(_cimg_math_parser& mp) { | |
17228 | + const double val1 = _mp_arg(2), *ptr2 = &_mp_arg(3) + 1; | |
17229 | + double *ptrd = &_mp_arg(1) + 1; | |
17230 | + _mp_complex_pow(val1,0,ptr2[0],ptr2[1],ptrd); | |
17231 | + return cimg::type<double>::nan(); | |
17232 | + } | |
17233 | + | |
17234 | + static double mp_complex_pow_vs(_cimg_math_parser& mp) { | |
17235 | + const double *ptr1 = &_mp_arg(2) + 1, val2 = _mp_arg(3); | |
17236 | + double *ptrd = &_mp_arg(1) + 1; | |
17237 | + _mp_complex_pow(ptr1[0],ptr1[1],val2,0,ptrd); | |
17238 | + return cimg::type<double>::nan(); | |
17239 | + } | |
17240 | + | |
17241 | + static double mp_complex_pow_vv(_cimg_math_parser& mp) { | |
17242 | + const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1; | |
17243 | + double *ptrd = &_mp_arg(1) + 1; | |
17244 | + _mp_complex_pow(ptr1[0],ptr1[1],ptr2[0],ptr2[1],ptrd); | |
17245 | + return cimg::type<double>::nan(); | |
17246 | + } | |
17247 | + | |
17248 | + static double mp_cos(_cimg_math_parser& mp) { | |
17249 | + return std::cos(_mp_arg(2)); | |
14685 | 17250 | } |
14686 | - static double mp_time(_cimg_math_parser& mp) { | |
17251 | + | |
17252 | + static double mp_cosh(_cimg_math_parser& mp) { | |
17253 | + return std::cosh(_mp_arg(2)); | |
17254 | + } | |
17255 | + | |
17256 | + static double mp_cross(_cimg_math_parser& mp) { | |
17257 | + CImg<doubleT> | |
17258 | + vout(&_mp_arg(1) + 1,1,3,1,1,true), | |
17259 | + v1(&_mp_arg(2) + 1,1,3,1,1,true), | |
17260 | + v2(&_mp_arg(3) + 1,1,3,1,1,true); | |
17261 | + (vout = v1).cross(v2); | |
17262 | + return cimg::type<double>::nan(); | |
17263 | + } | |
17264 | + | |
17265 | + static double mp_cut(_cimg_math_parser& mp) { | |
17266 | + double val = _mp_arg(2), cmin = _mp_arg(3), cmax = _mp_arg(4); | |
17267 | + return val<cmin?cmin:val>cmax?cmax:val; | |
17268 | + } | |
17269 | + | |
17270 | + 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 | + CImg<charT> expr(mp.opcode._height - 3); | |
17277 | + const uptrT *ptrs = mp.opcode._data + 3; | |
17278 | + cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++); | |
17279 | + cimg::strellipsize(expr); | |
17280 | + 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 | + | |
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++); | |
17298 | + | |
17299 | + const uptrT target = mp.opcode[1]; | |
17300 | + mp.mem[target] = _cimg_mp_defunc(mp); | |
17301 | + std::fprintf(cimg::output(), | |
17302 | + "\n[_cimg_math_parser] %p[thread #%u]:%*c" | |
17303 | + "Opcode %p = [ %p,%s ] -> mem[%u] = %g", | |
17304 | + (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]); | |
17307 | + std::fflush(cimg::output()); | |
17308 | + } | |
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 | + return mp.mem[g_target]; | |
17318 | + } | |
17319 | + | |
17320 | + static double mp_decrement(_cimg_math_parser& mp) { | |
17321 | + return _mp_arg(2) - 1; | |
17322 | + } | |
17323 | + | |
17324 | + static double mp_dot(_cimg_math_parser& mp) { | |
17325 | + const unsigned int siz = (unsigned int)mp.opcode[4]; | |
17326 | + return CImg<doubleT>(&_mp_arg(2) + 1,1,siz,1,1,true). | |
17327 | + dot(CImg<doubleT>(&_mp_arg(3) + 1,1,siz,1,1,true)); | |
17328 | + } | |
17329 | + | |
17330 | + static double mp_dowhile(_cimg_math_parser& mp) { | |
17331 | + const uptrT | |
17332 | + mem_proc = mp.opcode[1], | |
17333 | + mem_cond = mp.opcode[2]; | |
17334 | + const CImg<uptrT> | |
17335 | + *const p_proc = ++mp.p_code, | |
17336 | + *const p_end = p_proc + mp.opcode[3]; | |
17337 | + do { | |
17338 | + for (mp.p_code = p_proc; mp.p_code<p_end; ++mp.p_code) { // Evaluate loop iteration + condition | |
17339 | + const CImg<uptrT> &op = *mp.p_code; | |
17340 | + mp.opcode._data = op._data; mp.opcode._height = op._height; | |
17341 | + const uptrT target = mp.opcode[1]; | |
17342 | + mp.mem[target] = _cimg_mp_defunc(mp); | |
17343 | + } | |
17344 | + } while (mp.mem[mem_cond]); | |
17345 | + --mp.p_code; | |
17346 | + return mp.mem[mem_proc]; | |
17347 | + } | |
17348 | + | |
17349 | + static double mp_div(_cimg_math_parser& mp) { | |
17350 | + return _mp_arg(2)/_mp_arg(3); | |
17351 | + } | |
17352 | + | |
17353 | + static double mp_eq(_cimg_math_parser& mp) { | |
17354 | + return (double)(_mp_arg(2)==_mp_arg(3)); | |
17355 | + } | |
17356 | + | |
17357 | + static double mp_exp(_cimg_math_parser& mp) { | |
17358 | + return std::exp(_mp_arg(2)); | |
17359 | + } | |
17360 | + | |
17361 | + static double mp_g(_cimg_math_parser& mp) { | |
14687 | 17362 | cimg::unused(mp); |
14688 | - return (double)cimg::time(); | |
17363 | + return cimg::grand(); | |
14689 | 17364 | } |
14690 | - static double mp_abs(_cimg_math_parser& mp) { | |
14691 | - return cimg::abs(mp.mem[mp.opcode(2)]); | |
17365 | + | |
17366 | + static double mp_gauss(_cimg_math_parser& mp) { | |
17367 | + const double x = _mp_arg(2), s = _mp_arg(3); | |
17368 | + return std::exp(-x*x/(2*s*s))/std::sqrt(2*s*s*cimg::PI); | |
14692 | 17369 | } |
14693 | - static double mp_atan2(_cimg_math_parser& mp) { | |
14694 | - return std::atan2(mp.mem[mp.opcode(2)],mp.mem[mp.opcode(3)]); | |
17370 | + | |
17371 | + static double mp_gt(_cimg_math_parser& mp) { | |
17372 | + return (double)(_mp_arg(2)>_mp_arg(3)); | |
14695 | 17373 | } |
17374 | + | |
17375 | + static double mp_gte(_cimg_math_parser& mp) { | |
17376 | + return (double)(_mp_arg(2)>=_mp_arg(3)); | |
17377 | + } | |
17378 | + | |
17379 | + static double mp_hypot(_cimg_math_parser& mp) { | |
17380 | + return cimg::hypot(_mp_arg(2),_mp_arg(3)); | |
17381 | + } | |
17382 | + | |
17383 | + static double mp_i(_cimg_math_parser& mp) { | |
17384 | + return (double)mp.imgin.atXYZC((int)mp.mem[_cimg_mp_x],(int)mp.mem[_cimg_mp_y], | |
17385 | + (int)mp.mem[_cimg_mp_z],(int)mp.mem[_cimg_mp_c],0); | |
17386 | + } | |
17387 | + | |
14696 | 17388 | static double mp_if(_cimg_math_parser& mp) { |
14697 | - const bool is_cond = (bool)mp.mem[mp.opcode(2)]; | |
14698 | - const unsigned int mem_A = (unsigned int)mp.opcode(3), mem_B = (unsigned int)mp.opcode(4); | |
14699 | - const CImg<longT> | |
14700 | - *const pB = ++mp.p_code + mp.opcode(5), | |
14701 | - *const pE = pB + mp.opcode(6); | |
14702 | - if (is_cond) { // Evaluate on-the-fly only the correct argument. | |
14703 | - for ( ; mp.p_code<pB; ++mp.p_code) { | |
14704 | - const CImg<longT> &op = *mp.p_code; | |
17389 | + const bool is_cond = (bool)_mp_arg(2); | |
17390 | + const uptrT | |
17391 | + mem_left = mp.opcode[3], | |
17392 | + mem_right = mp.opcode[4]; | |
17393 | + const CImg<uptrT> | |
17394 | + *const p_right = ++mp.p_code + mp.opcode[5], | |
17395 | + *const p_end = p_right + mp.opcode[6]; | |
17396 | + const unsigned int vtarget = mp.opcode[1], vsiz = mp.opcode[7]; | |
17397 | + if (is_cond) { | |
17398 | + for ( ; mp.p_code<p_right; ++mp.p_code) { | |
17399 | + const CImg<uptrT> &op = *mp.p_code; | |
14705 | 17400 | mp.opcode._data = op._data; mp.opcode._height = op._height; |
14706 | - const unsigned int target = (unsigned int)mp.opcode[1]; | |
17401 | + const uptrT target = mp.opcode[1]; | |
14707 | 17402 | mp.mem[target] = _cimg_mp_defunc(mp); |
14708 | 17403 | } |
14709 | - mp.p_code = pE - 1; | |
14710 | - return mp.mem[mem_A]; | |
17404 | + mp.p_code = p_end - 1; | |
17405 | + if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[mem_left] + 1,sizeof(double)*vsiz); | |
17406 | + return mp.mem[mem_left]; | |
14711 | 17407 | } |
14712 | - for (mp.p_code = pB; mp.p_code<pE; ++mp.p_code) { | |
14713 | - const CImg<longT> &op = *mp.p_code; | |
17408 | + for (mp.p_code = p_right; mp.p_code<p_end; ++mp.p_code) { | |
17409 | + const CImg<uptrT> &op = *mp.p_code; | |
14714 | 17410 | mp.opcode._data = op._data; mp.opcode._height = op._height; |
14715 | - const unsigned int target = (unsigned int)mp.opcode[1]; | |
17411 | + const uptrT target = mp.opcode[1]; | |
14716 | 17412 | mp.mem[target] = _cimg_mp_defunc(mp); |
14717 | 17413 | } |
14718 | 17414 | --mp.p_code; |
14719 | - return mp.mem[mem_B]; | |
17415 | + if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[mem_right] + 1,sizeof(double)*vsiz); | |
17416 | + return mp.mem[mem_right]; | |
14720 | 17417 | } |
14721 | - static double mp_round(_cimg_math_parser& mp) { | |
14722 | - return cimg::round(mp.mem[mp.opcode(2)],mp.mem[mp.opcode(3)],(int)mp.mem[mp.opcode(4)]); | |
17418 | + | |
17419 | + static double mp_increment(_cimg_math_parser& mp) { | |
17420 | + return _mp_arg(2) + 1; | |
17421 | + } | |
17422 | + | |
17423 | + static double mp_int(_cimg_math_parser& mp) { | |
17424 | + return (double)(long)_mp_arg(2); | |
17425 | + } | |
17426 | + | |
17427 | + static double mp_ioff(_cimg_math_parser& mp) { | |
17428 | + const unsigned int | |
17429 | + boundary_conditions = (unsigned int)_mp_arg(3); | |
17430 | + const CImg<T> &img = mp.imgin; | |
17431 | + const long | |
17432 | + off = (long)_mp_arg(2), | |
17433 | + whds = (long)img.size(); | |
17434 | + if (off<0 || off>=whds) | |
17435 | + switch (boundary_conditions) { | |
17436 | + case 2 : // Periodic boundary | |
17437 | + if (img) return (double)img[cimg::mod(off,whds)]; | |
17438 | + return 0; | |
17439 | + case 1 : // Neumann boundary | |
17440 | + if (img) return (double)(off<0?*img:img.back()); | |
17441 | + return 0; | |
17442 | + default : // Dirichet boundary | |
17443 | + return 0; | |
17444 | + } | |
17445 | + return (double)img[off]; | |
17446 | + } | |
17447 | + | |
17448 | + static double mp_isbool(_cimg_math_parser& mp) { | |
17449 | + const double val = _mp_arg(2); | |
17450 | + return (double)(val==0.0 || val==1.0); | |
17451 | + } | |
17452 | + | |
17453 | + static double mp_isin(_cimg_math_parser& mp) { | |
17454 | + const double val = _mp_arg(2); | |
17455 | + for (unsigned int i = 3; i<mp.opcode._height; ++i) | |
17456 | + if (val==_mp_arg(i)) return 1.0; | |
17457 | + return 0.0; | |
17458 | + } | |
17459 | + | |
17460 | + static double mp_isinf(_cimg_math_parser& mp) { | |
17461 | + return (double)cimg::type<double>::is_inf(_mp_arg(2)); | |
17462 | + } | |
17463 | + | |
17464 | + static double mp_isint(_cimg_math_parser& mp) { | |
17465 | + return (double)(cimg::mod(_mp_arg(2),1.0)==0); | |
17466 | + } | |
17467 | + | |
17468 | + static double mp_isnan(_cimg_math_parser& mp) { | |
17469 | + return (double)cimg::type<double>::is_nan(_mp_arg(2)); | |
14723 | 17470 | } |
17471 | + | |
14724 | 17472 | static double mp_ixyzc(_cimg_math_parser& mp) { |
17473 | + const unsigned int | |
17474 | + interpolation = (unsigned int)_mp_arg(6), | |
17475 | + boundary_conditions = (unsigned int)_mp_arg(7); | |
17476 | + const CImg<T> &img = mp.imgin; | |
14725 | 17477 | const double |
14726 | - x = mp.mem[mp.opcode(2)], y = mp.mem[mp.opcode(3)], z = mp.mem[mp.opcode(4)], c = mp.mem[mp.opcode(5)]; | |
14727 | - const int i = (int)mp.mem[mp.opcode(6)], b = (int)mp.mem[mp.opcode(7)]; | |
14728 | - if (i==0) { // Nearest neighbor interpolation. | |
14729 | - if (b==2) return (double)mp.reference.atXYZC(cimg::mod((int)x,mp.reference.width()), | |
14730 | - cimg::mod((int)y,mp.reference.height()), | |
14731 | - cimg::mod((int)z,mp.reference.depth()), | |
14732 | - cimg::mod((int)c,mp.reference.spectrum())); | |
14733 | - if (b==1) return (double)mp.reference.atXYZC((int)x,(int)y,(int)z,(int)c); | |
14734 | - return (double)mp.reference.atXYZC((int)x,(int)y,(int)z,(int)c,0); | |
14735 | - } else { // Linear interpolation. | |
14736 | - if (b==2) return (double)mp.reference.linear_atXYZC(cimg::mod((float)x,(float)mp.reference.width()), | |
14737 | - cimg::mod((float)y,(float)mp.reference.height()), | |
14738 | - cimg::mod((float)z,(float)mp.reference.depth()), | |
14739 | - cimg::mod((float)c,(float)mp.reference.spectrum())); | |
14740 | - if (b==1) return (double)mp.reference.linear_atXYZC((float)x,(float)y,(float)z,(float)c); | |
14741 | - return (double)mp.reference.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); | |
17478 | + x = _mp_arg(2), y = _mp_arg(3), | |
17479 | + z = _mp_arg(4), c = _mp_arg(5); | |
17480 | + if (interpolation==0) { // Nearest neighbor interpolation | |
17481 | + if (boundary_conditions==2) | |
17482 | + return (double)img.atXYZC(cimg::mod((int)x,img.width()), | |
17483 | + cimg::mod((int)y,img.height()), | |
17484 | + cimg::mod((int)z,img.depth()), | |
17485 | + cimg::mod((int)c,img.spectrum())); | |
17486 | + if (boundary_conditions==1) | |
17487 | + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c); | |
17488 | + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0); | |
17489 | + } else { // Linear interpolation | |
17490 | + if (boundary_conditions==2) | |
17491 | + return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()), | |
17492 | + cimg::mod((float)y,(float)img.height()), | |
17493 | + cimg::mod((float)z,(float)img.depth()), | |
17494 | + cimg::mod((float)c,(float)img.spectrum())); | |
17495 | + if (boundary_conditions==1) | |
17496 | + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c); | |
17497 | + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); | |
14742 | 17498 | } |
14743 | 17499 | } |
17500 | + | |
17501 | + static double mp_joff(_cimg_math_parser& mp) { | |
17502 | + const unsigned int | |
17503 | + boundary_conditions = (unsigned int)_mp_arg(3); | |
17504 | + const int | |
17505 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], | |
17506 | + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; | |
17507 | + const CImg<T> &img = mp.imgin; | |
17508 | + const long | |
17509 | + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(2), | |
17510 | + whds = (long)img.size(); | |
17511 | + if (off<0 || off>=whds) | |
17512 | + switch (boundary_conditions) { | |
17513 | + case 2 : // Periodic boundary | |
17514 | + if (img) return (double)img[cimg::mod(off,whds)]; | |
17515 | + return 0; | |
17516 | + case 1 : // Neumann boundary | |
17517 | + if (img) return (double)(off<0?*img:img.back()); | |
17518 | + return 0; | |
17519 | + default : // Dirichet boundary | |
17520 | + return 0; | |
17521 | + } | |
17522 | + return (double)img[off]; | |
17523 | + } | |
17524 | + | |
14744 | 17525 | static double mp_jxyzc(_cimg_math_parser& mp) { |
14745 | - const double x = mp.mem[16], y = mp.mem[17], z = mp.mem[18], c = mp.mem[19]; | |
17526 | + const unsigned int | |
17527 | + interpolation = (unsigned int)_mp_arg(6), | |
17528 | + boundary_conditions = (unsigned int)_mp_arg(7); | |
17529 | + const CImg<T> &img = mp.imgin; | |
14746 | 17530 | const double |
14747 | - dx = mp.mem[mp.opcode(2)], dy = mp.mem[mp.opcode(3)], dz = mp.mem[mp.opcode(4)], dc = mp.mem[mp.opcode(5)]; | |
14748 | - const int i = (int)mp.mem[mp.opcode(6)], b = (int)mp.mem[mp.opcode(7)]; | |
14749 | - if (i==0) { // Nearest neighbor interpolation. | |
14750 | - if (b==2) return (double)mp.reference.atXYZC(cimg::mod((int)(x + dx),mp.reference.width()), | |
14751 | - cimg::mod((int)(y + dy),mp.reference.height()), | |
14752 | - cimg::mod((int)(z + dz),mp.reference.depth()), | |
14753 | - cimg::mod((int)(c + dc),mp.reference.spectrum())); | |
14754 | - if (b==1) return (double)mp.reference.atXYZC((int)(x + dx),(int)(y + dy),(int)(z + dz),(int)(c + dc)); | |
14755 | - return (double)mp.reference.atXYZC((int)(x + dx),(int)(y + dy),(int)(z + dz),(int)(c + dc),0); | |
14756 | - } else { // Linear interpolation. | |
14757 | - if (b==2) | |
14758 | - return (double)mp.reference.linear_atXYZC(cimg::mod((float)(x + dx),(float)mp.reference.width()), | |
14759 | - cimg::mod((float)(y + dy),(float)mp.reference.height()), | |
14760 | - cimg::mod((float)(z + dz),(float)mp.reference.depth()), | |
14761 | - cimg::mod((float)(c + dc),(float)mp.reference.spectrum())); | |
14762 | - if (b==1) return (double)mp.reference.linear_atXYZC((float)(x + dx),(float)(y + dy), | |
14763 | - (float)(z + dz),(float)(c + dc)); | |
14764 | - return (double)mp.reference.linear_atXYZC((float)(x + dx),(float)(y + dy),(float)(z + dz),(float)(c + dc),0); | |
17531 | + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], | |
17532 | + oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c], | |
17533 | + x = ox + _mp_arg(2), y = oy + _mp_arg(3), | |
17534 | + z = oz + _mp_arg(4), c = oc + _mp_arg(5); | |
17535 | + if (interpolation==0) { // Nearest neighbor interpolation | |
17536 | + if (boundary_conditions==2) | |
17537 | + return (double)img.atXYZC(cimg::mod((int)x,img.width()), | |
17538 | + cimg::mod((int)y,img.height()), | |
17539 | + cimg::mod((int)z,img.depth()), | |
17540 | + cimg::mod((int)c,img.spectrum())); | |
17541 | + if (boundary_conditions==1) | |
17542 | + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c); | |
17543 | + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0); | |
17544 | + } else { // Linear interpolation | |
17545 | + if (boundary_conditions==2) | |
17546 | + return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()), | |
17547 | + cimg::mod((float)y,(float)img.height()), | |
17548 | + cimg::mod((float)z,(float)img.depth()), | |
17549 | + cimg::mod((float)c,(float)img.spectrum())); | |
17550 | + if (boundary_conditions==1) | |
17551 | + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c); | |
17552 | + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); | |
14765 | 17553 | } |
14766 | 17554 | } |
14767 | - static double mp_min(_cimg_math_parser& mp) { | |
14768 | - double val = mp.mem[mp.opcode(2)]; | |
14769 | - for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::min(val,mp.mem[mp.opcode(i)]); | |
17555 | + | |
17556 | + static double mp_kth(_cimg_math_parser& mp) { | |
17557 | + CImg<doubleT> vals(mp.opcode._height - 3); | |
17558 | + double *p = vals.data(); | |
17559 | + for (unsigned int i = 3; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i); | |
17560 | + int ind = (int)cimg::round(_mp_arg(2)); | |
17561 | + if (ind<0) ind+=vals.width() + 1; | |
17562 | + ind = cimg::max(1,cimg::min(vals.width(),ind)); | |
17563 | + return vals.kth_smallest(ind - 1); | |
17564 | + } | |
17565 | + | |
17566 | + static double mp_list_depth(_cimg_math_parser& mp) { | |
17567 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17568 | + return (double)mp.listin[ind]._depth; | |
17569 | + } | |
17570 | + | |
17571 | + static double mp_list_height(_cimg_math_parser& mp) { | |
17572 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17573 | + return (double)mp.listin[ind]._height; | |
17574 | + } | |
17575 | + | |
17576 | + static double mp_list_ioff(_cimg_math_parser& mp) { | |
17577 | + const unsigned int | |
17578 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
17579 | + boundary_conditions = (unsigned int)_mp_arg(4); | |
17580 | + const CImg<T> &img = mp.listin[ind]; | |
17581 | + const long | |
17582 | + off = (long)_mp_arg(3), | |
17583 | + whds = (long)img.size(); | |
17584 | + if (off<0 || off>=whds) | |
17585 | + switch (boundary_conditions) { | |
17586 | + case 2 : // Periodic boundary | |
17587 | + if (img) return (double)img[cimg::mod(off,whds)]; | |
17588 | + return 0; | |
17589 | + case 1 : // Neumann boundary | |
17590 | + if (img) return (double)(off<0?*img:img.back()); | |
17591 | + return 0; | |
17592 | + default : // Dirichet boundary | |
17593 | + return 0; | |
17594 | + } | |
17595 | + return (double)img[off]; | |
17596 | + } | |
17597 | + | |
17598 | + static double mp_list_is_shared(_cimg_math_parser& mp) { | |
17599 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17600 | + return (double)mp.listin[ind]._is_shared; | |
17601 | + } | |
17602 | + | |
17603 | + static double mp_list_ixyzc(_cimg_math_parser& mp) { | |
17604 | + const unsigned int | |
17605 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
17606 | + interpolation = (unsigned int)_mp_arg(7), | |
17607 | + boundary_conditions = (unsigned int)_mp_arg(8); | |
17608 | + const CImg<T> &img = mp.listin[ind]; | |
17609 | + const double | |
17610 | + x = _mp_arg(3), y = _mp_arg(4), | |
17611 | + z = _mp_arg(5), c = _mp_arg(6); | |
17612 | + if (interpolation==0) { // Nearest neighbor interpolation | |
17613 | + if (boundary_conditions==2) | |
17614 | + return (double)img.atXYZC(cimg::mod((int)x,img.width()), | |
17615 | + cimg::mod((int)y,img.height()), | |
17616 | + cimg::mod((int)z,img.depth()), | |
17617 | + cimg::mod((int)c,img.spectrum())); | |
17618 | + if (boundary_conditions==1) | |
17619 | + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c); | |
17620 | + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0); | |
17621 | + } else { // Linear interpolation | |
17622 | + if (boundary_conditions==2) | |
17623 | + return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()), | |
17624 | + cimg::mod((float)y,(float)img.height()), | |
17625 | + cimg::mod((float)z,(float)img.depth()), | |
17626 | + cimg::mod((float)c,(float)img.spectrum())); | |
17627 | + if (boundary_conditions==1) | |
17628 | + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c); | |
17629 | + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); | |
17630 | + } | |
17631 | + } | |
17632 | + | |
17633 | + static double mp_list_joff(_cimg_math_parser& mp) { | |
17634 | + const unsigned int | |
17635 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
17636 | + boundary_conditions = (unsigned int)_mp_arg(4); | |
17637 | + const int | |
17638 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], | |
17639 | + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; | |
17640 | + const CImg<T> &img = mp.listin[ind]; | |
17641 | + const long | |
17642 | + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(3), | |
17643 | + whds = (long)img.size(); | |
17644 | + if (off<0 || off>=whds) | |
17645 | + switch (boundary_conditions) { | |
17646 | + case 2 : // Periodic boundary | |
17647 | + if (img) return (double)img(ind,cimg::mod(off,whds)); | |
17648 | + return 0; | |
17649 | + case 1 : // Neumann boundary | |
17650 | + if (img) return (double)(off<0?*img:img.back()); | |
17651 | + return 0; | |
17652 | + default : // Dirichet boundary | |
17653 | + return 0; | |
17654 | + } | |
17655 | + return (double)img[off]; | |
17656 | + } | |
17657 | + | |
17658 | + static double mp_list_jxyzc(_cimg_math_parser& mp) { | |
17659 | + const unsigned int | |
17660 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
17661 | + interpolation = (unsigned int)_mp_arg(7), | |
17662 | + boundary_conditions = (unsigned int)_mp_arg(8); | |
17663 | + const CImg<T> &img = mp.listin[ind]; | |
17664 | + const double | |
17665 | + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], | |
17666 | + oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c], | |
17667 | + x = ox + _mp_arg(3), y = oy + _mp_arg(4), | |
17668 | + z = oz + _mp_arg(5), c = oc + _mp_arg(6); | |
17669 | + if (interpolation==0) { // Nearest neighbor interpolation | |
17670 | + if (boundary_conditions==2) | |
17671 | + return (double)img.atXYZC(cimg::mod((int)x,img.width()), | |
17672 | + cimg::mod((int)y,img.height()), | |
17673 | + cimg::mod((int)z,img.depth()), | |
17674 | + cimg::mod((int)c,img.spectrum())); | |
17675 | + if (boundary_conditions==1) | |
17676 | + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c); | |
17677 | + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0); | |
17678 | + } else { // Linear interpolation | |
17679 | + if (boundary_conditions==2) | |
17680 | + return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()), | |
17681 | + cimg::mod((float)y,(float)img.height()), | |
17682 | + cimg::mod((float)z,(float)img.depth()), | |
17683 | + cimg::mod((float)c,(float)img.spectrum())); | |
17684 | + if (boundary_conditions==1) | |
17685 | + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c); | |
17686 | + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); | |
17687 | + } | |
17688 | + } | |
17689 | + | |
17690 | + static double mp_list_median(_cimg_math_parser& mp) { | |
17691 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17692 | + if (!mp.list_median) mp.list_median.assign(mp.listin._width); | |
17693 | + if (!mp.list_median[ind]) CImg<doubleT>::vector(mp.listin[ind].median()).move_to(mp.list_median[ind]); | |
17694 | + return *mp.list_median[ind]; | |
17695 | + } | |
17696 | + | |
17697 | + static double mp_list_set_ioff(_cimg_math_parser& mp) { | |
17698 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17699 | + CImg<T> &img = mp.listout[ind]; | |
17700 | + const long | |
17701 | + off = (long)_mp_arg(3), | |
17702 | + whds = (long)img.size(); | |
17703 | + const double val = _mp_arg(1); | |
17704 | + if (off>=0 && off<whds) img[off] = (T)val; | |
17705 | + return val; | |
17706 | + } | |
17707 | + | |
17708 | + static double mp_list_set_ixyzc(_cimg_math_parser& mp) { | |
17709 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17710 | + CImg<T> &img = mp.listout[ind]; | |
17711 | + const int | |
17712 | + x = (int)_mp_arg(3), y = (int)_mp_arg(4), | |
17713 | + z = (int)_mp_arg(5), c = (int)_mp_arg(6); | |
17714 | + const double val = _mp_arg(1); | |
17715 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && | |
17716 | + z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) { | |
17717 | + img(x,y,z,c) = (T)val; | |
17718 | + } | |
17719 | + return val; | |
17720 | + } | |
17721 | + | |
17722 | + static double mp_list_set_joff(_cimg_math_parser& mp) { | |
17723 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17724 | + CImg<T> &img = mp.listout[ind]; | |
17725 | + const int | |
17726 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], | |
17727 | + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; | |
17728 | + const long | |
17729 | + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(3), | |
17730 | + whds = (long)img.size(); | |
17731 | + const double val = _mp_arg(1); | |
17732 | + if (off>=0 && off<whds) img[off] = (T)val; | |
14770 | 17733 | return val; |
14771 | 17734 | } |
17735 | + | |
17736 | + static double mp_list_set_jxyzc(_cimg_math_parser& mp) { | |
17737 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17738 | + CImg<T> &img = mp.listout[ind]; | |
17739 | + const double | |
17740 | + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], | |
17741 | + oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c]; | |
17742 | + const int | |
17743 | + x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), | |
17744 | + z = (int)(oz + _mp_arg(5)), c = (int)(oc + _mp_arg(6)); | |
17745 | + const double val = _mp_arg(1); | |
17746 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && | |
17747 | + z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) { | |
17748 | + img(x,y,z,c) = (T)val; | |
17749 | + } | |
17750 | + return val; | |
17751 | + } | |
17752 | + | |
17753 | + static double mp_list_set_Ioff_s(_cimg_math_parser& mp) { | |
17754 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17755 | + CImg<T> &img = mp.listout[ind]; | |
17756 | + const long | |
17757 | + off = (long)_mp_arg(3), | |
17758 | + whd = img.width()*img.height()*img.depth(); | |
17759 | + const T val = (T)_mp_arg(1); | |
17760 | + if (off>=0 && off<whd) { | |
17761 | + T *ptrd = &img[off]; | |
17762 | + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; } | |
17763 | + } | |
17764 | + return _mp_arg(1); | |
17765 | + } | |
17766 | + | |
17767 | + static double mp_list_set_Ioff_v(_cimg_math_parser& mp) { | |
17768 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17769 | + CImg<T> &img = mp.listout[ind]; | |
17770 | + const long | |
17771 | + off = (long)_mp_arg(3), | |
17772 | + whd = img.width()*img.height()*img.depth(); | |
17773 | + const double *ptrs = &_mp_arg(1) + 1; | |
17774 | + if (off>=0 && off<whd) { | |
17775 | + T *ptrd = &img[off]; | |
17776 | + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; } | |
17777 | + } | |
17778 | + return cimg::type<double>::nan(); | |
17779 | + } | |
17780 | + | |
17781 | + static double mp_list_set_Ixyz_s(_cimg_math_parser& mp) { | |
17782 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17783 | + CImg<T> &img = mp.listout[ind]; | |
17784 | + const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5); | |
17785 | + const T val = (T)_mp_arg(1); | |
17786 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) { | |
17787 | + T *ptrd = &img(x,y,z); | |
17788 | + const unsigned long whd = img._width*img._height*img._depth; | |
17789 | + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; } | |
17790 | + } | |
17791 | + return _mp_arg(1); | |
17792 | + } | |
17793 | + | |
17794 | + static double mp_list_set_Ixyz_v(_cimg_math_parser& mp) { | |
17795 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17796 | + CImg<T> &img = mp.listout[ind]; | |
17797 | + const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5); | |
17798 | + const double *ptrs = &_mp_arg(1) + 1; | |
17799 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) { | |
17800 | + T *ptrd = &img(x,y,z); | |
17801 | + const unsigned long whd = img._width*img._height*img._depth; | |
17802 | + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; } | |
17803 | + } | |
17804 | + return cimg::type<double>::nan(); | |
17805 | + } | |
17806 | + | |
17807 | + static double mp_list_set_Joff_s(_cimg_math_parser& mp) { | |
17808 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17809 | + CImg<T> &img = mp.listout[ind]; | |
17810 | + const int | |
17811 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], | |
17812 | + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; | |
17813 | + const long | |
17814 | + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(3), | |
17815 | + whd = img.width()*img.height()*img.depth(); | |
17816 | + const T val = (T)_mp_arg(1); | |
17817 | + if (off>=0 && off<whd) { | |
17818 | + T *ptrd = &img[off]; | |
17819 | + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; } | |
17820 | + } | |
17821 | + return _mp_arg(1); | |
17822 | + } | |
17823 | + | |
17824 | + static double mp_list_set_Joff_v(_cimg_math_parser& mp) { | |
17825 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17826 | + CImg<T> &img = mp.listout[ind]; | |
17827 | + const int | |
17828 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], | |
17829 | + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; | |
17830 | + const long | |
17831 | + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(3), | |
17832 | + whd = img.width()*img.height()*img.depth(); | |
17833 | + const double *ptrs = &_mp_arg(1) + 1; | |
17834 | + if (off>=0 && off<whd) { | |
17835 | + T *ptrd = &img[off]; | |
17836 | + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; } | |
17837 | + } | |
17838 | + return cimg::type<double>::nan(); | |
17839 | + } | |
17840 | + | |
17841 | + static double mp_list_set_Jxyz_s(_cimg_math_parser& mp) { | |
17842 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17843 | + CImg<T> &img = mp.listout[ind]; | |
17844 | + const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z]; | |
17845 | + const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5)); | |
17846 | + const T val = (T)_mp_arg(1); | |
17847 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) { | |
17848 | + T *ptrd = &img(x,y,z); | |
17849 | + const unsigned long whd = img._width*img._height*img._depth; | |
17850 | + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; } | |
17851 | + } | |
17852 | + return _mp_arg(1); | |
17853 | + } | |
17854 | + | |
17855 | + static double mp_list_set_Jxyz_v(_cimg_math_parser& mp) { | |
17856 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17857 | + CImg<T> &img = mp.listout[ind]; | |
17858 | + const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z]; | |
17859 | + const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5)); | |
17860 | + const double *ptrs = &_mp_arg(1) + 1; | |
17861 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) { | |
17862 | + T *ptrd = &img(x,y,z); | |
17863 | + const unsigned long whd = img._width*img._height*img._depth; | |
17864 | + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; } | |
17865 | + } | |
17866 | + return cimg::type<double>::nan(); | |
17867 | + } | |
17868 | + | |
17869 | + static double mp_list_spectrum(_cimg_math_parser& mp) { | |
17870 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17871 | + return (double)mp.listin[ind]._spectrum; | |
17872 | + } | |
17873 | + | |
17874 | + static double mp_list_stats(_cimg_math_parser& mp) { | |
17875 | + const unsigned int | |
17876 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
17877 | + k = (unsigned int)_mp_arg(3); | |
17878 | + if (!mp.list_stats) mp.list_stats.assign(mp.listin._width); | |
17879 | + if (!mp.list_stats[ind]) mp.list_stats[ind].assign(1,14,1,1,0).fill(mp.listin[ind].get_stats(),false); | |
17880 | + return mp.list_stats(ind,k); | |
17881 | + } | |
17882 | + | |
17883 | + static double mp_list_wh(_cimg_math_parser& mp) { | |
17884 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17885 | + return (double)mp.listin[ind]._width*mp.listin[ind]._height; | |
17886 | + } | |
17887 | + | |
17888 | + static double mp_list_whd(_cimg_math_parser& mp) { | |
17889 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17890 | + return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth; | |
17891 | + } | |
17892 | + | |
17893 | + static double mp_list_whds(_cimg_math_parser& mp) { | |
17894 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17895 | + return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth*mp.listin[ind]._spectrum; | |
17896 | + } | |
17897 | + | |
17898 | + static double mp_list_width(_cimg_math_parser& mp) { | |
17899 | + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()); | |
17900 | + return (double)mp.listin[ind]._width; | |
17901 | + } | |
17902 | + | |
17903 | + static double mp_list_Ioff(_cimg_math_parser& mp) { | |
17904 | + double *ptrd = &_mp_arg(1) + 1; | |
17905 | + const unsigned int | |
17906 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
17907 | + boundary_conditions = (unsigned int)_mp_arg(4); | |
17908 | + const CImg<T> &img = mp.listin[ind]; | |
17909 | + const long | |
17910 | + off = (long)_mp_arg(3), | |
17911 | + whd = img.width()*img.height()*img.depth(); | |
17912 | + const T *ptrs; | |
17913 | + if (off<0 || off>=whd) | |
17914 | + switch (boundary_conditions) { | |
17915 | + case 2 : // Periodic boundary | |
17916 | + if (!img) { | |
17917 | + ptrs = &img[cimg::mod(off,whd)]; | |
17918 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
17919 | + } else std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
17920 | + return cimg::type<double>::nan(); | |
17921 | + case 1 : // Neumann boundary | |
17922 | + if (img) { | |
17923 | + ptrs = off<0?img._data:&img.back(); | |
17924 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
17925 | + } else std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
17926 | + return cimg::type<double>::nan(); | |
17927 | + default : // Dirichet boundary | |
17928 | + std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
17929 | + return cimg::type<double>::nan(); | |
17930 | + } | |
17931 | + ptrs = &img[off]; | |
17932 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
17933 | + return cimg::type<double>::nan(); | |
17934 | + } | |
17935 | + | |
17936 | + static double mp_list_Ixyz(_cimg_math_parser& mp) { | |
17937 | + double *ptrd = &_mp_arg(1) + 1; | |
17938 | + const unsigned int | |
17939 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
17940 | + interpolation = (unsigned int)_mp_arg(6), | |
17941 | + boundary_conditions = (unsigned int)_mp_arg(7); | |
17942 | + const CImg<T> &img = mp.listin[ind]; | |
17943 | + const double x = _mp_arg(3), y = _mp_arg(4), z = _mp_arg(5); | |
17944 | + if (interpolation==0) { // Nearest neighbor interpolation | |
17945 | + if (boundary_conditions==2) | |
17946 | + cimg_forC(img,c) | |
17947 | + *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()), | |
17948 | + cimg::mod((int)y,img.height()), | |
17949 | + cimg::mod((int)z,img.depth()), | |
17950 | + c); | |
17951 | + else if (boundary_conditions==1) | |
17952 | + cimg_forC(img,c) | |
17953 | + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c); | |
17954 | + else | |
17955 | + cimg_forC(img,c) | |
17956 | + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0); | |
17957 | + } else { // Linear interpolation | |
17958 | + if (boundary_conditions==2) | |
17959 | + cimg_forC(img,c) | |
17960 | + *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()), | |
17961 | + cimg::mod((float)y,(float)img.height()), | |
17962 | + cimg::mod((float)z,(float)img.depth()),c); | |
17963 | + else if (boundary_conditions==1) | |
17964 | + cimg_forC(img,c) | |
17965 | + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c); | |
17966 | + else | |
17967 | + cimg_forC(img,c) | |
17968 | + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0); | |
17969 | + } | |
17970 | + return cimg::type<double>::nan(); | |
17971 | + } | |
17972 | + | |
17973 | + static double mp_list_Joff(_cimg_math_parser& mp) { | |
17974 | + double *ptrd = &_mp_arg(1) + 1; | |
17975 | + const unsigned int | |
17976 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
17977 | + boundary_conditions = (unsigned int)_mp_arg(4); | |
17978 | + const int | |
17979 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z]; | |
17980 | + const CImg<T> &img = mp.listin[ind]; | |
17981 | + const long | |
17982 | + off = img.offset(ox,oy,oz) + (long)_mp_arg(3), | |
17983 | + whd = img.width()*img.height()*img.depth(); | |
17984 | + const T *ptrs; | |
17985 | + if (off<0 || off>=whd) | |
17986 | + switch (boundary_conditions) { | |
17987 | + case 2 : // Periodic boundary | |
17988 | + if (!img) { | |
17989 | + ptrs = &img[cimg::mod(off,whd)]; | |
17990 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
17991 | + } else std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
17992 | + return cimg::type<double>::nan(); | |
17993 | + case 1 : // Neumann boundary | |
17994 | + if (img) { | |
17995 | + ptrs = off<0?img._data:&img.back(); | |
17996 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
17997 | + } else std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
17998 | + return cimg::type<double>::nan(); | |
17999 | + default : // Dirichet boundary | |
18000 | + std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
18001 | + return cimg::type<double>::nan(); | |
18002 | + } | |
18003 | + ptrs = &img[off]; | |
18004 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
18005 | + return cimg::type<double>::nan(); | |
18006 | + } | |
18007 | + | |
18008 | + static double mp_list_Jxyz(_cimg_math_parser& mp) { | |
18009 | + double *ptrd = &_mp_arg(1) + 1; | |
18010 | + const unsigned int | |
18011 | + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()), | |
18012 | + interpolation = (unsigned int)_mp_arg(6), | |
18013 | + boundary_conditions = (unsigned int)_mp_arg(7); | |
18014 | + const CImg<T> &img = mp.listin[ind]; | |
18015 | + const double | |
18016 | + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z], | |
18017 | + x = ox + _mp_arg(3), y = oy + _mp_arg(4), z = oz + _mp_arg(5); | |
18018 | + if (interpolation==0) { // Nearest neighbor interpolation | |
18019 | + if (boundary_conditions==2) | |
18020 | + cimg_forC(img,c) | |
18021 | + *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()), | |
18022 | + cimg::mod((int)y,img.height()), | |
18023 | + cimg::mod((int)z,img.depth()), | |
18024 | + c); | |
18025 | + else if (boundary_conditions==1) | |
18026 | + cimg_forC(img,c) | |
18027 | + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c); | |
18028 | + else | |
18029 | + cimg_forC(img,c) | |
18030 | + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0); | |
18031 | + } else { // Linear interpolation | |
18032 | + if (boundary_conditions==2) | |
18033 | + cimg_forC(img,c) | |
18034 | + *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()), | |
18035 | + cimg::mod((float)y,(float)img.height()), | |
18036 | + cimg::mod((float)z,(float)img.depth()),c); | |
18037 | + else if (boundary_conditions==1) | |
18038 | + cimg_forC(img,c) | |
18039 | + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c); | |
18040 | + else | |
18041 | + cimg_forC(img,c) | |
18042 | + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0); | |
18043 | + } | |
18044 | + return cimg::type<double>::nan(); | |
18045 | + } | |
18046 | + | |
18047 | + static double mp_log(_cimg_math_parser& mp) { | |
18048 | + return std::log(_mp_arg(2)); | |
18049 | + } | |
18050 | + | |
18051 | + static double mp_log10(_cimg_math_parser& mp) { | |
18052 | + return std::log10(_mp_arg(2)); | |
18053 | + } | |
18054 | + | |
18055 | + static double mp_log2(_cimg_math_parser& mp) { | |
18056 | + return cimg::log2(_mp_arg(2)); | |
18057 | + } | |
18058 | + | |
18059 | + static double mp_logical_and(_cimg_math_parser& mp) { | |
18060 | + const bool val_left = (bool)_mp_arg(2); | |
18061 | + const CImg<uptrT> *const p_end = ++mp.p_code + mp.opcode[4]; | |
18062 | + if (!val_left) { mp.p_code = p_end - 1; return 0; } | |
18063 | + const uptrT mem_right = mp.opcode[3]; | |
18064 | + for ( ; mp.p_code<p_end; ++mp.p_code) { | |
18065 | + const CImg<uptrT> &op = *mp.p_code; | |
18066 | + mp.opcode._data = op._data; mp.opcode._height = op._height; | |
18067 | + const uptrT target = mp.opcode[1]; | |
18068 | + mp.mem[target] = _cimg_mp_defunc(mp); | |
18069 | + } | |
18070 | + --mp.p_code; | |
18071 | + return (double)(bool)mp.mem[mem_right]; | |
18072 | + } | |
18073 | + | |
18074 | + static double mp_logical_not(_cimg_math_parser& mp) { | |
18075 | + return (double)!_mp_arg(2); | |
18076 | + } | |
18077 | + | |
18078 | + static double mp_logical_or(_cimg_math_parser& mp) { | |
18079 | + const bool val_left = (bool)_mp_arg(2); | |
18080 | + const CImg<uptrT> *const p_end = ++mp.p_code + mp.opcode[4]; | |
18081 | + if (val_left) { mp.p_code = p_end - 1; return 1; } | |
18082 | + const uptrT mem_right = mp.opcode[3]; | |
18083 | + for ( ; mp.p_code<p_end; ++mp.p_code) { | |
18084 | + const CImg<uptrT> &op = *mp.p_code; | |
18085 | + mp.opcode._data = op._data; mp.opcode._height = op._height; | |
18086 | + const uptrT target = mp.opcode[1]; | |
18087 | + mp.mem[target] = _cimg_mp_defunc(mp); | |
18088 | + } | |
18089 | + --mp.p_code; | |
18090 | + return (double)(bool)mp.mem[mem_right]; | |
18091 | + } | |
18092 | + | |
18093 | + | |
18094 | + static double mp_lt(_cimg_math_parser& mp) { | |
18095 | + return (double)(_mp_arg(2)<_mp_arg(3)); | |
18096 | + } | |
18097 | + | |
18098 | + static double mp_lte(_cimg_math_parser& mp) { | |
18099 | + return (double)(_mp_arg(2)<=_mp_arg(3)); | |
18100 | + } | |
18101 | + | |
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 | + static double mp_matrix_mul(_cimg_math_parser& mp) { | |
18143 | + double *ptrd = &_mp_arg(1) + 1; | |
18144 | + const double | |
18145 | + *ptr1 = &_mp_arg(2) + 1, | |
18146 | + *ptr2 = &_mp_arg(3) + 1; | |
18147 | + const unsigned int | |
18148 | + k = (unsigned int)mp.opcode(4), | |
18149 | + l = (unsigned int)mp.opcode(5), | |
18150 | + m = (unsigned int)mp.opcode(6); | |
18151 | + CImg<double>(ptrd,m,k,1,1,true) = CImg<double>(ptr1,l,k,1,1,true)*CImg<double>(ptr2,m,l,1,1,true); | |
18152 | + return cimg::type<double>::nan(); | |
18153 | + } | |
18154 | + | |
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 | + | |
14772 | 18191 | static double mp_max(_cimg_math_parser& mp) { |
14773 | - double val = mp.mem[mp.opcode(2)]; | |
14774 | - for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::max(val,mp.mem[mp.opcode(i)]); | |
18192 | + double val = _mp_arg(2); | |
18193 | + for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::max(val,_mp_arg(i)); | |
14775 | 18194 | return val; |
14776 | 18195 | } |
18196 | + | |
18197 | + static double mp_min(_cimg_math_parser& mp) { | |
18198 | + double val = _mp_arg(2); | |
18199 | + for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::min(val,_mp_arg(i)); | |
18200 | + return val; | |
18201 | + } | |
18202 | + | |
18203 | + static double mp_minus(_cimg_math_parser& mp) { | |
18204 | + return -_mp_arg(2); | |
18205 | + } | |
18206 | + | |
14777 | 18207 | static double mp_med(_cimg_math_parser& mp) { |
14778 | - CImg<doubleT> values(mp.opcode._height - 2); | |
14779 | - double *p = values.data(); | |
14780 | - for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = mp.mem[mp.opcode(i)]; | |
14781 | - return values.median(); | |
18208 | + CImg<doubleT> vals(mp.opcode._height - 2); | |
18209 | + double *p = vals.data(); | |
18210 | + for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i); | |
18211 | + return vals.median(); | |
14782 | 18212 | } |
14783 | - static double mp_kth(_cimg_math_parser& mp) { | |
14784 | - CImg<doubleT> values(mp.opcode._height - 3); | |
14785 | - double *p = values.data(); | |
14786 | - for (unsigned int i = 3; i<mp.opcode._height; ++i) *(p++) = mp.mem[mp.opcode(i)]; | |
14787 | - int ind = (int)cimg::round(mp.mem[mp.opcode(2)]); | |
14788 | - if (ind<0) ind+=values.width() + 1; | |
14789 | - ind = cimg::max(1,cimg::min(values.width(),ind)); | |
14790 | - return values.kth_smallest(ind - 1); | |
18213 | + | |
18214 | + static double mp_modulo(_cimg_math_parser& mp) { | |
18215 | + return cimg::mod(_mp_arg(2),_mp_arg(3)); | |
14791 | 18216 | } |
14792 | - static double mp_isin(_cimg_math_parser& mp) { | |
14793 | - double value = mp.mem[mp.opcode(2)]; | |
18217 | + | |
18218 | + static double mp_mul(_cimg_math_parser& mp) { | |
18219 | + return _mp_arg(2)*_mp_arg(3); | |
18220 | + } | |
18221 | + | |
18222 | + static double mp_neq(_cimg_math_parser& mp) { | |
18223 | + return (double)(_mp_arg(2)!=_mp_arg(3)); | |
18224 | + } | |
18225 | + | |
18226 | + static double mp_norm0(_cimg_math_parser& mp) { | |
18227 | + double res = 0; | |
18228 | + for (unsigned int i = 2; i<mp.opcode._height; ++i) | |
18229 | + res+=_mp_arg(i)==0?0:1; | |
18230 | + return res; | |
18231 | + } | |
18232 | + | |
18233 | + static double mp_norm1(_cimg_math_parser& mp) { | |
18234 | + double res = 0; | |
18235 | + for (unsigned int i = 2; i<mp.opcode._height; ++i) | |
18236 | + res+=cimg::abs(_mp_arg(i)); | |
18237 | + return res; | |
18238 | + } | |
18239 | + | |
18240 | + static double mp_norm2(_cimg_math_parser& mp) { | |
18241 | + double res = 0; | |
18242 | + for (unsigned int i = 2; i<mp.opcode._height; ++i) | |
18243 | + res+=cimg::sqr(_mp_arg(i)); | |
18244 | + return std::sqrt(res); | |
18245 | + } | |
18246 | + | |
18247 | + static double mp_norminf(_cimg_math_parser& mp) { | |
18248 | + double res = 0; | |
18249 | + for (unsigned int i = 2; i<mp.opcode._height; ++i) { | |
18250 | + const double val = cimg::abs(_mp_arg(i)); | |
18251 | + if (val>res) res = val; | |
18252 | + } | |
18253 | + return res; | |
18254 | + } | |
18255 | + | |
18256 | + static double mp_normp(_cimg_math_parser& mp) { | |
18257 | + const double p = (double)mp.opcode[2]; | |
18258 | + double res = 0; | |
14794 | 18259 | for (unsigned int i = 3; i<mp.opcode._height; ++i) |
14795 | - if (value==mp.mem[mp.opcode(i)]) return 1.0; | |
14796 | - return 0.0; | |
18260 | + res+=std::pow(cimg::abs(_mp_arg(i)),p); | |
18261 | + res = std::pow(res,1/p); | |
18262 | + return res>0?res:0.0; | |
14797 | 18263 | } |
14798 | - static double mp_isnan(_cimg_math_parser& mp) { | |
14799 | - const double val = mp.mem[mp.opcode(2)]; | |
14800 | - return cimg::type<double>::is_nan(val); | |
18264 | + | |
18265 | + static double mp_pow(_cimg_math_parser& mp) { | |
18266 | + const double v = _mp_arg(2), p = _mp_arg(3); | |
18267 | + return std::pow(v,p); | |
14801 | 18268 | } |
14802 | - static double mp_isinf(_cimg_math_parser& mp) { | |
14803 | - const double val = mp.mem[mp.opcode(2)]; | |
14804 | - return cimg::type<double>::is_inf(val); | |
18269 | + | |
18270 | + static double mp_pow3(_cimg_math_parser& mp) { | |
18271 | + const double val = _mp_arg(2); | |
18272 | + return val*val*val; | |
14805 | 18273 | } |
14806 | - static double mp_isint(_cimg_math_parser& mp) { | |
14807 | - const double val = mp.mem[mp.opcode(2)]; | |
14808 | - return (double)(cimg::mod(val,1.0)==0); | |
18274 | + | |
18275 | + static double mp_pow4(_cimg_math_parser& mp) { | |
18276 | + const double val = _mp_arg(2); | |
18277 | + return val*val*val*val; | |
14809 | 18278 | } |
14810 | - static double mp_isbool(_cimg_math_parser& mp) { | |
14811 | - const double val = mp.mem[mp.opcode(2)]; | |
14812 | - return (val==0.0 || val==1.0); | |
18279 | + | |
18280 | + static double mp_print(_cimg_math_parser& mp) { | |
18281 | + CImg<charT> expr(mp.opcode._height - 2); | |
18282 | + const uptrT *ptrs = mp.opcode._data + 2; | |
18283 | + cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++); | |
18284 | + cimg::strellipsize(expr); | |
18285 | + 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()); | |
18288 | + return val; | |
14813 | 18289 | } |
18290 | + | |
18291 | + static double mp_copy(_cimg_math_parser& mp) { | |
18292 | + return _mp_arg(2); | |
18293 | + } | |
18294 | + | |
14814 | 18295 | static double mp_rol(_cimg_math_parser& mp) { |
14815 | - return cimg::rol(mp.mem[mp.opcode(2)],(unsigned int)mp.mem[mp.opcode(3)]); | |
18296 | + return cimg::rol(_mp_arg(2),(unsigned int)_mp_arg(3)); | |
14816 | 18297 | } |
18298 | + | |
14817 | 18299 | static double mp_ror(_cimg_math_parser& mp) { |
14818 | - return cimg::ror(mp.mem[mp.opcode(2)],(unsigned int)mp.mem[mp.opcode(3)]); | |
18300 | + return cimg::ror(_mp_arg(2),(unsigned int)_mp_arg(3)); | |
14819 | 18301 | } |
14820 | - static double mp_lsl(_cimg_math_parser& mp) { | |
14821 | - return (long)mp.mem[mp.opcode(2)]<<(unsigned int)mp.mem[mp.opcode(3)]; | |
18302 | + | |
18303 | + static double mp_round(_cimg_math_parser& mp) { | |
18304 | + return cimg::round(_mp_arg(2),_mp_arg(3),(int)_mp_arg(4)); | |
14822 | 18305 | } |
14823 | - static double mp_lsr(_cimg_math_parser& mp) { | |
14824 | - return (long)mp.mem[mp.opcode(2)]>>(unsigned int)mp.mem[mp.opcode(3)]; | |
18306 | + | |
18307 | + static double mp_self_add(_cimg_math_parser& mp) { | |
18308 | + return _mp_arg(1)+=_mp_arg(2); | |
14825 | 18309 | } |
14826 | - static double mp_sinc(_cimg_math_parser& mp) { | |
14827 | - return cimg::sinc(mp.mem[mp.opcode(2)]); | |
18310 | + | |
18311 | + static double mp_self_bitwise_and(_cimg_math_parser& mp) { | |
18312 | + double &val = _mp_arg(1); | |
18313 | + return val = (double)((unsigned long)val & (unsigned long)_mp_arg(2)); | |
14828 | 18314 | } |
14829 | - static double mp_im(_cimg_math_parser& mp) { | |
14830 | - return mp.reference_stats?mp.reference_stats[0]:0; | |
18315 | + | |
18316 | + static double mp_self_bitwise_left_shift(_cimg_math_parser& mp) { | |
18317 | + double &val = _mp_arg(1); | |
18318 | + return val = (double)((long)val<<(unsigned int)_mp_arg(2)); | |
14831 | 18319 | } |
14832 | - static double mp_iM(_cimg_math_parser& mp) { | |
14833 | - return mp.reference_stats?mp.reference_stats[1]:0; | |
18320 | + | |
18321 | + static double mp_self_bitwise_or(_cimg_math_parser& mp) { | |
18322 | + double &val = _mp_arg(1); | |
18323 | + return val = (double)((unsigned long)val | (unsigned long)_mp_arg(2)); | |
14834 | 18324 | } |
14835 | - static double mp_ia(_cimg_math_parser& mp) { | |
14836 | - return mp.reference_stats?mp.reference_stats[2]:0; | |
18325 | + | |
18326 | + static double mp_self_bitwise_right_shift(_cimg_math_parser& mp) { | |
18327 | + double &val = _mp_arg(1); | |
18328 | + return val = (double)((long)val>>(unsigned int)_mp_arg(2)); | |
14837 | 18329 | } |
14838 | - static double mp_iv(_cimg_math_parser& mp) { | |
14839 | - return mp.reference_stats?mp.reference_stats[3]:0; | |
18330 | + | |
18331 | + static double mp_self_decrement(_cimg_math_parser& mp) { | |
18332 | + return --_mp_arg(1); | |
14840 | 18333 | } |
14841 | - static double mp_is(_cimg_math_parser& mp) { | |
14842 | - return mp.reference_stats?mp.reference_stats[12]:0; | |
18334 | + | |
18335 | + static double mp_self_increment(_cimg_math_parser& mp) { | |
18336 | + return ++_mp_arg(1); | |
14843 | 18337 | } |
14844 | - static double mp_ip(_cimg_math_parser& mp) { | |
14845 | - return mp.reference_stats?mp.reference_stats[13]:0; | |
18338 | + | |
18339 | + static double mp_self_map_vector_s(_cimg_math_parser& mp) { // Vector += scalar | |
18340 | + unsigned int | |
18341 | + ptrd = (unsigned int)mp.opcode[1] + 1, | |
18342 | + siz = (unsigned int)mp.opcode[2]; | |
18343 | + mp_func op = (mp_func)mp.opcode[3]; | |
18344 | + CImg<uptrT> l_opcode(1,3); | |
18345 | + l_opcode[2] = mp.opcode[4]; // Scalar argument. | |
18346 | + l_opcode.swap(mp.opcode); | |
18347 | + uptrT &target = mp.opcode[1]; | |
18348 | + while (siz-->0) { target = ptrd++; (*op)(mp); } | |
18349 | + l_opcode.swap(mp.opcode); | |
18350 | + return cimg::type<double>::nan(); | |
14846 | 18351 | } |
14847 | - static double mp_ic(_cimg_math_parser& mp) { | |
14848 | - return mp.is_median_value?mp.median_value:0; | |
18352 | + | |
18353 | + static double mp_self_map_vector_v(_cimg_math_parser& mp) { // Vector += vector | |
18354 | + unsigned int | |
18355 | + ptrd = (unsigned int)mp.opcode[1] + 1, | |
18356 | + siz = (unsigned int)mp.opcode[2], | |
18357 | + ptrs = (unsigned int)mp.opcode[4] + 1; | |
18358 | + mp_func op = (mp_func)mp.opcode[3]; | |
18359 | + CImg<uptrT> l_opcode(1,4); | |
18360 | + l_opcode.swap(mp.opcode); | |
18361 | + uptrT &target = mp.opcode[1], &argument = mp.opcode[2]; | |
18362 | + while (siz-->0) { target = ptrd++; argument = ptrs++; (*op)(mp); } | |
18363 | + l_opcode.swap(mp.opcode); | |
18364 | + return cimg::type<double>::nan(); | |
14849 | 18365 | } |
14850 | - static double mp_xm(_cimg_math_parser& mp) { | |
14851 | - return mp.reference_stats?mp.reference_stats[4]:0; | |
18366 | + | |
18367 | + static double mp_self_mul(_cimg_math_parser& mp) { | |
18368 | + return _mp_arg(1)*=_mp_arg(2); | |
14852 | 18369 | } |
14853 | - static double mp_ym(_cimg_math_parser& mp) { | |
14854 | - return mp.reference_stats?mp.reference_stats[5]:0; | |
18370 | + | |
18371 | + static double mp_self_div(_cimg_math_parser& mp) { | |
18372 | + return _mp_arg(1)/=_mp_arg(2); | |
14855 | 18373 | } |
14856 | - static double mp_zm(_cimg_math_parser& mp) { | |
14857 | - return mp.reference_stats?mp.reference_stats[6]:0; | |
18374 | + | |
18375 | + static double mp_self_modulo(_cimg_math_parser& mp) { | |
18376 | + double &val = _mp_arg(1); | |
18377 | + return val = cimg::mod(val,_mp_arg(2)); | |
14858 | 18378 | } |
14859 | - static double mp_cm(_cimg_math_parser& mp) { | |
14860 | - return mp.reference_stats?mp.reference_stats[7]:0; | |
18379 | + | |
18380 | + static double mp_self_pow(_cimg_math_parser& mp) { | |
18381 | + double &val = _mp_arg(1); | |
18382 | + return val = std::pow(val,_mp_arg(2)); | |
14861 | 18383 | } |
14862 | - static double mp_xM(_cimg_math_parser& mp) { | |
14863 | - return mp.reference_stats?mp.reference_stats[8]:0; | |
18384 | + | |
18385 | + static double mp_self_sub(_cimg_math_parser& mp) { | |
18386 | + return _mp_arg(1)-=_mp_arg(2); | |
14864 | 18387 | } |
14865 | - static double mp_yM(_cimg_math_parser& mp) { | |
14866 | - return mp.reference_stats?mp.reference_stats[9]:0; | |
18388 | + | |
18389 | + static double mp_set_ioff(_cimg_math_parser& mp) { | |
18390 | + CImg<T> &img = mp.imgout; | |
18391 | + const long | |
18392 | + off = (long)_mp_arg(2), | |
18393 | + whds = (long)img.size(); | |
18394 | + const double val = _mp_arg(1); | |
18395 | + if (off>=0 && off<whds) img[off] = (T)val; | |
18396 | + return val; | |
14867 | 18397 | } |
14868 | - static double mp_zM(_cimg_math_parser& mp) { | |
14869 | - return mp.reference_stats?mp.reference_stats[10]:0; | |
18398 | + | |
18399 | + static double mp_set_ixyzc(_cimg_math_parser& mp) { | |
18400 | + CImg<T> &img = mp.imgout; | |
18401 | + const int | |
18402 | + x = (int)_mp_arg(2), y = (int)_mp_arg(3), | |
18403 | + z = (int)_mp_arg(4), c = (int)_mp_arg(5); | |
18404 | + const double val = _mp_arg(1); | |
18405 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && | |
18406 | + z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) { | |
18407 | + img(x,y,z,c) = (T)val; | |
18408 | + } | |
18409 | + return val; | |
14870 | 18410 | } |
14871 | - static double mp_cM(_cimg_math_parser& mp) { | |
14872 | - return mp.reference_stats?mp.reference_stats[11]:0; | |
18411 | + | |
18412 | + static double mp_set_joff(_cimg_math_parser& mp) { | |
18413 | + CImg<T> &img = mp.imgout; | |
18414 | + const int | |
18415 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], | |
18416 | + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; | |
18417 | + const long | |
18418 | + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(2), | |
18419 | + whds = (long)img.size(); | |
18420 | + const double val = _mp_arg(1); | |
18421 | + if (off>=0 && off<whds) img[off] = (T)val; | |
18422 | + return val; | |
14873 | 18423 | } |
14874 | - static double mp_arg(_cimg_math_parser& mp) { | |
14875 | - const int _ind = (int)mp.mem[mp.opcode(2)]; | |
14876 | - const unsigned int nb_args = mp.opcode._height - 2, ind = _ind<0?_ind + nb_args:(unsigned int)_ind; | |
14877 | - if (ind>=nb_args) return 0; | |
14878 | - return mp.mem[mp.opcode(ind + 2)]; | |
18424 | + | |
18425 | + static double mp_set_jxyzc(_cimg_math_parser& mp) { | |
18426 | + CImg<T> &img = mp.imgout; | |
18427 | + const double | |
18428 | + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], | |
18429 | + oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c]; | |
18430 | + const int | |
18431 | + x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), | |
18432 | + z = (int)(oz + _mp_arg(4)), c = (int)(oc + _mp_arg(5)); | |
18433 | + const double val = _mp_arg(1); | |
18434 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && | |
18435 | + z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) { | |
18436 | + img(x,y,z,c) = (T)val; | |
18437 | + } | |
18438 | + return val; | |
14879 | 18439 | } |
14880 | - static double mp_int(_cimg_math_parser& mp) { | |
14881 | - return (double)(long)mp.mem[mp.opcode(2)]; | |
18440 | + | |
18441 | + static double mp_set_Ioff_s(_cimg_math_parser& mp) { | |
18442 | + CImg<T> &img = mp.imgout; | |
18443 | + const long | |
18444 | + off = (long)_mp_arg(2), | |
18445 | + whd = img.width()*img.height()*img.depth(); | |
18446 | + const T val = (T)_mp_arg(1); | |
18447 | + if (off>=0 && off<whd) { | |
18448 | + T *ptrd = &img[off]; | |
18449 | + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; } | |
18450 | + } | |
18451 | + return _mp_arg(1); | |
14882 | 18452 | } |
14883 | - static double mp_ioff(_cimg_math_parser& mp) { | |
14884 | - const unsigned long off = (unsigned long)mp.mem[mp.opcode(2)]; | |
14885 | - if (off>=mp.reference.size()) return 0; | |
14886 | - return (double)mp.reference[off]; | |
18453 | + | |
18454 | + static double mp_set_Ioff_v(_cimg_math_parser& mp) { | |
18455 | + CImg<T> &img = mp.imgout; | |
18456 | + const long | |
18457 | + off = (long)_mp_arg(2), | |
18458 | + whd = img.width()*img.height()*img.depth(); | |
18459 | + const double *ptrs = &_mp_arg(1) + 1; | |
18460 | + if (off>=0 && off<whd) { | |
18461 | + T *ptrd = &img[off]; | |
18462 | + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; } | |
18463 | + } | |
18464 | + return cimg::type<double>::nan(); | |
14887 | 18465 | } |
14888 | - static double mp_joff(_cimg_math_parser& mp) { | |
14889 | - const int x = (int)mp.mem[16], y = (int)mp.mem[17], z = (int)mp.mem[18], c = (int)mp.mem[19]; | |
14890 | - const unsigned long off = mp.reference.offset(x,y,z,c) + (unsigned long)(mp.mem[mp.opcode(2)]); | |
14891 | - if (off>=mp.reference.size()) return 0; | |
14892 | - return (double)mp.reference[off]; | |
18466 | + | |
18467 | + static double mp_set_Ixyz_s(_cimg_math_parser& mp) { | |
18468 | + CImg<T> &img = mp.imgout; | |
18469 | + const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4); | |
18470 | + const T val = (T)_mp_arg(1); | |
18471 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) { | |
18472 | + T *ptrd = &img(x,y,z); | |
18473 | + const unsigned long whd = img._width*img._height*img._depth; | |
18474 | + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; } | |
18475 | + } | |
18476 | + return _mp_arg(1); | |
14893 | 18477 | } |
14894 | 18478 | |
14895 | - // Evaluation procedure, with image data. | |
14896 | - double operator()(const double x, const double y, const double z, const double c) { | |
14897 | - if (!mem) return 0; | |
14898 | - mem[16] = x; mem[17] = y; mem[18] = z; mem[19] = c; | |
14899 | - opcode._is_shared = true; opcode._width = opcode._depth = opcode._spectrum = 1; | |
18479 | + static double mp_set_Ixyz_v(_cimg_math_parser& mp) { | |
18480 | + CImg<T> &img = mp.imgout; | |
18481 | + const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4); | |
18482 | + const double *ptrs = &_mp_arg(1) + 1; | |
18483 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) { | |
18484 | + T *ptrd = &img(x,y,z); | |
18485 | + const unsigned long whd = img._width*img._height*img._depth; | |
18486 | + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; } | |
18487 | + } | |
18488 | + return cimg::type<double>::nan(); | |
18489 | + } | |
14900 | 18490 | |
14901 | - for (p_code = code._data; p_code<code.end(); ++p_code) { | |
14902 | - const CImg<longT> &op = *p_code; | |
14903 | - // Allows to avoid parameter passing to evaluation functions. | |
14904 | - opcode._data = op._data; opcode._height = op._height; | |
14905 | - const unsigned int target = (unsigned int)opcode[1]; | |
14906 | - mem[target] = _cimg_mp_defunc(*this); | |
18491 | + static double mp_set_Joff_s(_cimg_math_parser& mp) { | |
18492 | + CImg<T> &img = mp.imgout; | |
18493 | + const int | |
18494 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], | |
18495 | + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; | |
18496 | + const long | |
18497 | + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(2), | |
18498 | + whd = img.width()*img.height()*img.depth(); | |
18499 | + const T val = (T)_mp_arg(1); | |
18500 | + if (off>=0 && off<whd) { | |
18501 | + T *ptrd = &img[off]; | |
18502 | + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; } | |
14907 | 18503 | } |
14908 | - return mem[result]; | |
18504 | + return _mp_arg(1); | |
18505 | + } | |
18506 | + | |
18507 | + static double mp_set_Joff_v(_cimg_math_parser& mp) { | |
18508 | + CImg<T> &img = mp.imgout; | |
18509 | + const int | |
18510 | + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], | |
18511 | + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c]; | |
18512 | + const long | |
18513 | + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(2), | |
18514 | + whd = img.width()*img.height()*img.depth(); | |
18515 | + const double *ptrs = &_mp_arg(1) + 1; | |
18516 | + if (off>=0 && off<whd) { | |
18517 | + T *ptrd = &img[off]; | |
18518 | + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; } | |
18519 | + } | |
18520 | + return cimg::type<double>::nan(); | |
18521 | + } | |
18522 | + | |
18523 | + static double mp_set_Jxyz_s(_cimg_math_parser& mp) { | |
18524 | + CImg<T> &img = mp.imgout; | |
18525 | + const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z]; | |
18526 | + const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4)); | |
18527 | + const T val = (T)_mp_arg(1); | |
18528 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) { | |
18529 | + T *ptrd = &img(x,y,z); | |
18530 | + const unsigned long whd = img._width*img._height*img._depth; | |
18531 | + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; } | |
18532 | + } | |
18533 | + return _mp_arg(1); | |
18534 | + } | |
18535 | + | |
18536 | + static double mp_set_Jxyz_v(_cimg_math_parser& mp) { | |
18537 | + CImg<T> &img = mp.imgout; | |
18538 | + const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z]; | |
18539 | + const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4)); | |
18540 | + const double *ptrs = &_mp_arg(1) + 1; | |
18541 | + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) { | |
18542 | + T *ptrd = &img(x,y,z); | |
18543 | + const unsigned long whd = img._width*img._height*img._depth; | |
18544 | + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; } | |
18545 | + } | |
18546 | + return cimg::type<double>::nan(); | |
18547 | + } | |
18548 | + | |
18549 | + static double mp_sign(_cimg_math_parser& mp) { | |
18550 | + return cimg::sign(_mp_arg(2)); | |
18551 | + } | |
18552 | + | |
18553 | + static double mp_sin(_cimg_math_parser& mp) { | |
18554 | + return std::sin(_mp_arg(2)); | |
18555 | + } | |
18556 | + | |
18557 | + static double mp_sinc(_cimg_math_parser& mp) { | |
18558 | + return cimg::sinc(_mp_arg(2)); | |
18559 | + } | |
18560 | + | |
18561 | + static double mp_sinh(_cimg_math_parser& mp) { | |
18562 | + return std::sinh(_mp_arg(2)); | |
18563 | + } | |
18564 | + | |
18565 | + static double mp_sqr(_cimg_math_parser& mp) { | |
18566 | + return cimg::sqr(_mp_arg(2)); | |
14909 | 18567 | } |
14910 | - }; | |
18568 | + | |
18569 | + static double mp_sqrt(_cimg_math_parser& mp) { | |
18570 | + return std::sqrt(_mp_arg(2)); | |
18571 | + } | |
18572 | + | |
18573 | + static double mp_sub(_cimg_math_parser& mp) { | |
18574 | + return _mp_arg(2) - _mp_arg(3); | |
18575 | + } | |
18576 | + | |
18577 | + static double mp_tan(_cimg_math_parser& mp) { | |
18578 | + return std::tan(_mp_arg(2)); | |
18579 | + } | |
18580 | + | |
18581 | + static double mp_tanh(_cimg_math_parser& mp) { | |
18582 | + return std::tanh(_mp_arg(2)); | |
18583 | + } | |
18584 | + | |
18585 | + static double mp_u(_cimg_math_parser& mp) { | |
18586 | + return cimg::rand(_mp_arg(2),_mp_arg(3)); | |
18587 | + } | |
18588 | + | |
18589 | + static double mp_vector_copy(_cimg_math_parser& mp) { | |
18590 | + std::memcpy(&_mp_arg(1) + 1,&_mp_arg(2) + 1,sizeof(double)*mp.opcode[3]); | |
18591 | + return cimg::type<double>::nan(); | |
18592 | + } | |
18593 | + | |
18594 | + static double mp_vector_crop(_cimg_math_parser& mp) { | |
18595 | + double *const ptrd = &_mp_arg(1) + 1; | |
18596 | + const double *const ptrs = &_mp_arg(2) + 1; | |
18597 | + const unsigned int p1 = mp.opcode[3], p2 = mp.opcode[4]; | |
18598 | + std::memcpy(ptrd,ptrs + p1,p2*sizeof(double)); | |
18599 | + return cimg::type<double>::nan(); | |
18600 | + } | |
18601 | + | |
18602 | + static double mp_vector_init(_cimg_math_parser& mp) { | |
18603 | + unsigned int | |
18604 | + ptrs = 3U, | |
18605 | + ptrd = (unsigned int)mp.opcode[1] + 1, | |
18606 | + siz = (unsigned int)mp.opcode[2]; | |
18607 | + switch (mp.opcode._height) { | |
18608 | + case 3 : std::memset(mp.mem._data + ptrd,0,siz*sizeof(double)); break; // 0 values given | |
18609 | + case 4 : { const double val = _mp_arg(ptrs); while (siz-->0) mp.mem[ptrd++] = val; } break; | |
18610 | + default : while (siz-->0) { mp.mem[ptrd++] = _mp_arg(ptrs++); if (ptrs>=mp.opcode._height) ptrs = 3U; } | |
18611 | + } | |
18612 | + return cimg::type<double>::nan(); | |
18613 | + } | |
18614 | + | |
18615 | + static double mp_vector_map_sv(_cimg_math_parser& mp) { // Operator(scalar,vector) | |
18616 | + unsigned int | |
18617 | + siz = (unsigned int)mp.opcode[2], | |
18618 | + ptrs = (unsigned int)mp.opcode[5] + 1; | |
18619 | + double *ptrd = &_mp_arg(1) + 1; | |
18620 | + mp_func op = (mp_func)mp.opcode[3]; | |
18621 | + CImg<uptrT> l_opcode(4); | |
18622 | + l_opcode[2] = mp.opcode[4]; // Scalar argument1 | |
18623 | + l_opcode.swap(mp.opcode); | |
18624 | + uptrT &argument2 = mp.opcode[3]; | |
18625 | + while (siz-->0) { argument2 = ptrs++; *(ptrd++) = (*op)(mp); } | |
18626 | + l_opcode.swap(mp.opcode); | |
18627 | + return cimg::type<double>::nan(); | |
18628 | + } | |
18629 | + | |
18630 | + static double mp_vector_map_v(_cimg_math_parser& mp) { // Operator(vector) | |
18631 | + unsigned int | |
18632 | + siz = (unsigned int)mp.opcode[2], | |
18633 | + ptrs = (unsigned int)mp.opcode[4] + 1; | |
18634 | + double *ptrd = &_mp_arg(1) + 1; | |
18635 | + mp_func op = (mp_func)mp.opcode[3]; | |
18636 | + CImg<uptrT> l_opcode(1,3); | |
18637 | + l_opcode.swap(mp.opcode); | |
18638 | + uptrT &argument = mp.opcode[2]; | |
18639 | + while (siz-->0) { argument = ptrs++; *(ptrd++) = (*op)(mp); } | |
18640 | + l_opcode.swap(mp.opcode); | |
18641 | + return cimg::type<double>::nan(); | |
18642 | + } | |
18643 | + | |
18644 | + static double mp_vector_map_vs(_cimg_math_parser& mp) { // Operator(vector,scalar) | |
18645 | + unsigned int | |
18646 | + siz = (unsigned int)mp.opcode[2], | |
18647 | + ptrs = (unsigned int)mp.opcode[4] + 1; | |
18648 | + double *ptrd = &_mp_arg(1) + 1; | |
18649 | + mp_func op = (mp_func)mp.opcode[3]; | |
18650 | + CImg<uptrT> l_opcode(1,4); | |
18651 | + l_opcode[3] = mp.opcode[5]; // Scalar argument2 | |
18652 | + l_opcode.swap(mp.opcode); | |
18653 | + uptrT &argument1 = mp.opcode[2]; | |
18654 | + while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); } | |
18655 | + l_opcode.swap(mp.opcode); | |
18656 | + return cimg::type<double>::nan(); | |
18657 | + } | |
18658 | + | |
18659 | + static double mp_vector_map_vss(_cimg_math_parser& mp) { // Operator(vector,scalar,scalar) | |
18660 | + unsigned int | |
18661 | + siz = (unsigned int)mp.opcode[2], | |
18662 | + ptrs = (unsigned int)mp.opcode[4] + 1; | |
18663 | + double *ptrd = &_mp_arg(1) + 1; | |
18664 | + mp_func op = (mp_func)mp.opcode[3]; | |
18665 | + CImg<uptrT> l_opcode(1,5); | |
18666 | + l_opcode[3] = mp.opcode[5]; // Scalar argument2 | |
18667 | + l_opcode[4] = mp.opcode[6]; // Scalar argument3 | |
18668 | + l_opcode.swap(mp.opcode); | |
18669 | + uptrT &argument1 = mp.opcode[2]; | |
18670 | + while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); } | |
18671 | + l_opcode.swap(mp.opcode); | |
18672 | + return cimg::type<double>::nan(); | |
18673 | + } | |
18674 | + | |
18675 | + static double mp_vector_map_vv(_cimg_math_parser& mp) { // Operator(vector,vector) | |
18676 | + unsigned int | |
18677 | + siz = (unsigned int)mp.opcode[2], | |
18678 | + ptrs1 = (unsigned int)mp.opcode[4] + 1, | |
18679 | + ptrs2 = (unsigned int)mp.opcode[5] + 1; | |
18680 | + double *ptrd = &_mp_arg(1) + 1; | |
18681 | + mp_func op = (mp_func)mp.opcode[3]; | |
18682 | + CImg<uptrT> l_opcode(1,4); | |
18683 | + l_opcode.swap(mp.opcode); | |
18684 | + uptrT &argument1 = mp.opcode[2], &argument2 = mp.opcode[3]; | |
18685 | + while (siz-->0) { argument1 = ptrs1++; argument2 = ptrs2++; *(ptrd++) = (*op)(mp); } | |
18686 | + l_opcode.swap(mp.opcode); | |
18687 | + return cimg::type<double>::nan(); | |
18688 | + } | |
18689 | + | |
18690 | + static double mp_vector_off(_cimg_math_parser& mp) { | |
18691 | + const unsigned int | |
18692 | + ptr = mp.opcode[2] + 1, | |
18693 | + siz = (int)mp.opcode[3]; | |
18694 | + const int off = (int)_mp_arg(4); | |
18695 | + return off>=0 && off<(int)siz?mp.mem[ptr + off]:cimg::type<double>::nan(); | |
18696 | + } | |
18697 | + | |
18698 | + static double mp_vector_set_off(_cimg_math_parser& mp) { | |
18699 | + const unsigned int | |
18700 | + ptr = mp.opcode[2] + 1, | |
18701 | + siz = mp.opcode[3]; | |
18702 | + const int off = (int)_mp_arg(4); | |
18703 | + if (off>=0 && off<(int)siz) mp.mem[ptr + off] = _mp_arg(5); | |
18704 | + return _mp_arg(5); | |
18705 | + } | |
18706 | + | |
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 | + static double mp_vector_print(_cimg_math_parser& mp) { | |
18717 | + CImg<charT> expr(mp.opcode._height - 3); | |
18718 | + const uptrT *ptrs = mp.opcode._data + 3; | |
18719 | + cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++); | |
18720 | + cimg::strellipsize(expr); | |
18721 | + unsigned int | |
18722 | + ptr = mp.opcode[1] + 1, | |
18723 | + siz = mp.opcode[2]; | |
18724 | + std::fprintf(cimg::output(),"\n[_cimg_math_parser] %s = [",expr._data); | |
18725 | + while (siz-->0) std::fprintf(cimg::output(),"%g%s",mp.mem[ptr++],siz?",":""); | |
18726 | + std::fputc(']',cimg::output()); | |
18727 | + std::fflush(cimg::output()); | |
18728 | + return cimg::type<double>::nan(); | |
18729 | + } | |
18730 | + | |
18731 | + static double mp_whiledo(_cimg_math_parser& mp) { // Used also by 'for()' | |
18732 | + const uptrT | |
18733 | + mem_proc = mp.opcode[1], | |
18734 | + mem_cond = mp.opcode[2]; | |
18735 | + const CImg<uptrT> | |
18736 | + *const p_cond = ++mp.p_code, | |
18737 | + *const p_proc = p_cond + mp.opcode[3], | |
18738 | + *const p_end = p_proc + mp.opcode[4]; | |
18739 | + const unsigned int vsiz = mp.opcode[5]; | |
18740 | + bool is_first_iter = true, is_cond = false; | |
18741 | + do { | |
18742 | + for (mp.p_code = p_cond; mp.p_code<p_proc; ++mp.p_code) { // Evaluate loop condition | |
18743 | + const CImg<uptrT> &op = *mp.p_code; | |
18744 | + mp.opcode._data = op._data; mp.opcode._height = op._height; | |
18745 | + const uptrT target = mp.opcode[1]; | |
18746 | + mp.mem[target] = _cimg_mp_defunc(mp); | |
18747 | + } | |
18748 | + is_cond = (bool)mp.mem[mem_cond]; | |
18749 | + if (is_cond) { // Evaluate loop iteration | |
18750 | + for ( ; mp.p_code<p_end; ++mp.p_code) { | |
18751 | + const CImg<uptrT> &op = *mp.p_code; | |
18752 | + mp.opcode._data = op._data; mp.opcode._height = op._height; | |
18753 | + const uptrT target = mp.opcode[1]; | |
18754 | + mp.mem[target] = _cimg_mp_defunc(mp); | |
18755 | + } | |
18756 | + is_first_iter = false; | |
18757 | + } | |
18758 | + } while (is_cond); | |
18759 | + mp.p_code = p_end - 1; | |
18760 | + if (vsiz && is_first_iter) std::memset(&mp.mem[mem_proc] + 1,0,vsiz*sizeof(double)); | |
18761 | + return is_first_iter?0:mp.mem[mem_proc]; | |
18762 | + } | |
18763 | + | |
18764 | + static double mp_Ioff(_cimg_math_parser& mp) { | |
18765 | + double *ptrd = &_mp_arg(1) + 1; | |
18766 | + const unsigned int | |
18767 | + boundary_conditions = (unsigned int)_mp_arg(3); | |
18768 | + const CImg<T> &img = mp.imgin; | |
18769 | + const long | |
18770 | + off = (long)_mp_arg(2), | |
18771 | + whd = img.width()*img.height()*img.depth(); | |
18772 | + const T *ptrs; | |
18773 | + if (off<0 || off>=whd) | |
18774 | + switch (boundary_conditions) { | |
18775 | + case 2 : // Periodic boundary | |
18776 | + if (!img) { | |
18777 | + ptrs = &img[cimg::mod(off,whd)]; | |
18778 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
18779 | + } else std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
18780 | + return cimg::type<double>::nan(); | |
18781 | + case 1 : // Neumann boundary | |
18782 | + if (img) { | |
18783 | + ptrs = off<0?img._data:&img.back(); | |
18784 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
18785 | + } else std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
18786 | + return cimg::type<double>::nan(); | |
18787 | + default : // Dirichet boundary | |
18788 | + std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
18789 | + return cimg::type<double>::nan(); | |
18790 | + } | |
18791 | + ptrs = &img[off]; | |
18792 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
18793 | + return cimg::type<double>::nan(); | |
18794 | + } | |
18795 | + | |
18796 | + static double mp_Ixyz(_cimg_math_parser& mp) { | |
18797 | + double *ptrd = &_mp_arg(1) + 1; | |
18798 | + const unsigned int | |
18799 | + interpolation = (unsigned int)_mp_arg(5), | |
18800 | + boundary_conditions = (unsigned int)_mp_arg(6); | |
18801 | + const CImg<T> &img = mp.imgin; | |
18802 | + const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4); | |
18803 | + if (interpolation==0) { // Nearest neighbor interpolation | |
18804 | + if (boundary_conditions==2) | |
18805 | + cimg_forC(img,c) | |
18806 | + *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()), | |
18807 | + cimg::mod((int)y,img.height()), | |
18808 | + cimg::mod((int)z,img.depth()), | |
18809 | + c); | |
18810 | + else if (boundary_conditions==1) | |
18811 | + cimg_forC(img,c) | |
18812 | + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c); | |
18813 | + else | |
18814 | + cimg_forC(img,c) | |
18815 | + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0); | |
18816 | + } else { // Linear interpolation | |
18817 | + if (boundary_conditions==2) | |
18818 | + cimg_forC(img,c) | |
18819 | + *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()), | |
18820 | + cimg::mod((float)y,(float)img.height()), | |
18821 | + cimg::mod((float)z,(float)img.depth()),c); | |
18822 | + else if (boundary_conditions==1) | |
18823 | + cimg_forC(img,c) | |
18824 | + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c); | |
18825 | + else | |
18826 | + cimg_forC(img,c) | |
18827 | + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0); | |
18828 | + } | |
18829 | + return cimg::type<double>::nan(); | |
18830 | + } | |
18831 | + | |
18832 | + static double mp_Joff(_cimg_math_parser& mp) { | |
18833 | + double *ptrd = &_mp_arg(1) + 1; | |
18834 | + const unsigned int | |
18835 | + boundary_conditions = (unsigned int)_mp_arg(3); | |
18836 | + const CImg<T> &img = mp.imgin; | |
18837 | + const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z]; | |
18838 | + const long | |
18839 | + off = img.offset(ox,oy,oz) + (long)_mp_arg(2), | |
18840 | + whd = img.width()*img.height()*img.depth(); | |
18841 | + const T *ptrs; | |
18842 | + if (off<0 || off>=whd) | |
18843 | + switch (boundary_conditions) { | |
18844 | + case 2 : // Periodic boundary | |
18845 | + if (!img) { | |
18846 | + ptrs = &img[cimg::mod(off,whd)]; | |
18847 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
18848 | + } else std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
18849 | + return cimg::type<double>::nan(); | |
18850 | + case 1 : // Neumann boundary | |
18851 | + if (img) { | |
18852 | + ptrs = off<0?img._data:&img.back(); | |
18853 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
18854 | + } else std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
18855 | + return cimg::type<double>::nan(); | |
18856 | + default : // Dirichet boundary | |
18857 | + std::memset(ptrd,0,img._spectrum*sizeof(double)); | |
18858 | + return cimg::type<double>::nan(); | |
18859 | + } | |
18860 | + ptrs = &img[off]; | |
18861 | + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; } | |
18862 | + return cimg::type<double>::nan(); | |
18863 | + } | |
18864 | + | |
18865 | + static double mp_Jxyz(_cimg_math_parser& mp) { | |
18866 | + double *ptrd = &_mp_arg(1) + 1; | |
18867 | + const unsigned int | |
18868 | + interpolation = (unsigned int)_mp_arg(5), | |
18869 | + boundary_conditions = (unsigned int)_mp_arg(6); | |
18870 | + const CImg<T> &img = mp.imgin; | |
18871 | + const double | |
18872 | + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z], | |
18873 | + x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4); | |
18874 | + if (interpolation==0) { // Nearest neighbor interpolation | |
18875 | + if (boundary_conditions==2) | |
18876 | + cimg_forC(img,c) | |
18877 | + *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()), | |
18878 | + cimg::mod((int)y,img.height()), | |
18879 | + cimg::mod((int)z,img.depth()), | |
18880 | + c); | |
18881 | + else if (boundary_conditions==1) | |
18882 | + cimg_forC(img,c) | |
18883 | + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c); | |
18884 | + else | |
18885 | + cimg_forC(img,c) | |
18886 | + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0); | |
18887 | + } else { // Linear interpolation | |
18888 | + if (boundary_conditions==2) | |
18889 | + cimg_forC(img,c) | |
18890 | + *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()), | |
18891 | + cimg::mod((float)y,(float)img.height()), | |
18892 | + cimg::mod((float)z,(float)img.depth()),c); | |
18893 | + else if (boundary_conditions==1) | |
18894 | + cimg_forC(img,c) | |
18895 | + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c); | |
18896 | + else | |
18897 | + cimg_forC(img,c) | |
18898 | + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0); | |
18899 | + } | |
18900 | + return cimg::type<double>::nan(); | |
18901 | + } | |
18902 | + | |
18903 | +#undef _mp_arg | |
18904 | + | |
18905 | + }; // struct _cimg_math_parser {} | |
14911 | 18906 | |
14912 | 18907 | //! Compute the square value of each pixel value. |
14913 | 18908 | /** |
... | ... | @@ -14925,7 +18920,7 @@ namespace cimg_library_suffixed { |
14925 | 18920 | CImg<T>& sqr() { |
14926 | 18921 | if (is_empty()) return *this; |
14927 | 18922 | #ifdef cimg_use_openmp |
14928 | -#pragma omp parallel for if (size()>=524288) | |
18923 | +#pragma omp parallel for cimg_openmp_if(size()>=524288) | |
14929 | 18924 | #endif |
14930 | 18925 | cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); }; |
14931 | 18926 | return *this; |
... | ... | @@ -14952,7 +18947,7 @@ namespace cimg_library_suffixed { |
14952 | 18947 | CImg<T>& sqrt() { |
14953 | 18948 | if (is_empty()) return *this; |
14954 | 18949 | #ifdef cimg_use_openmp |
14955 | -#pragma omp parallel for if (size()>=8192) | |
18950 | +#pragma omp parallel for cimg_openmp_if(size()>=8192) | |
14956 | 18951 | #endif |
14957 | 18952 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd); |
14958 | 18953 | return *this; |
... | ... | @@ -14973,7 +18968,7 @@ namespace cimg_library_suffixed { |
14973 | 18968 | CImg<T>& exp() { |
14974 | 18969 | if (is_empty()) return *this; |
14975 | 18970 | #ifdef cimg_use_openmp |
14976 | -#pragma omp parallel for if (size()>=4096) | |
18971 | +#pragma omp parallel for cimg_openmp_if(size()>=4096) | |
14977 | 18972 | #endif |
14978 | 18973 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd); |
14979 | 18974 | return *this; |
... | ... | @@ -14995,7 +18990,7 @@ namespace cimg_library_suffixed { |
14995 | 18990 | CImg<T>& log() { |
14996 | 18991 | if (is_empty()) return *this; |
14997 | 18992 | #ifdef cimg_use_openmp |
14998 | -#pragma omp parallel for if (size()>=262144) | |
18993 | +#pragma omp parallel for cimg_openmp_if(size()>=262144) | |
14999 | 18994 | #endif |
15000 | 18995 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd); |
15001 | 18996 | return *this; |
... | ... | @@ -15017,7 +19012,7 @@ namespace cimg_library_suffixed { |
15017 | 19012 | CImg<T>& log2() { |
15018 | 19013 | if (is_empty()) return *this; |
15019 | 19014 | #ifdef cimg_use_openmp |
15020 | -#pragma omp parallel for if (size()>=4096) | |
19015 | +#pragma omp parallel for cimg_openmp_if(size()>=4096) | |
15021 | 19016 | #endif |
15022 | 19017 | cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::log2((double)*ptrd); |
15023 | 19018 | return *this; |
... | ... | @@ -15039,7 +19034,7 @@ namespace cimg_library_suffixed { |
15039 | 19034 | CImg<T>& log10() { |
15040 | 19035 | if (is_empty()) return *this; |
15041 | 19036 | #ifdef cimg_use_openmp |
15042 | -#pragma omp parallel for if (size()>=4096) | |
19037 | +#pragma omp parallel for cimg_openmp_if(size()>=4096) | |
15043 | 19038 | #endif |
15044 | 19039 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd); |
15045 | 19040 | return *this; |
... | ... | @@ -15060,7 +19055,7 @@ namespace cimg_library_suffixed { |
15060 | 19055 | CImg<T>& abs() { |
15061 | 19056 | if (is_empty()) return *this; |
15062 | 19057 | #ifdef cimg_use_openmp |
15063 | -#pragma omp parallel for if (size()>=524288) | |
19058 | +#pragma omp parallel for cimg_openmp_if(size()>=524288) | |
15064 | 19059 | #endif |
15065 | 19060 | cimg_rof(*this,ptrd,T) *ptrd = cimg::abs(*ptrd); |
15066 | 19061 | return *this; |
... | ... | @@ -15086,7 +19081,7 @@ namespace cimg_library_suffixed { |
15086 | 19081 | CImg<T>& sign() { |
15087 | 19082 | if (is_empty()) return *this; |
15088 | 19083 | #ifdef cimg_use_openmp |
15089 | -#pragma omp parallel for if (size()>=32768) | |
19084 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
15090 | 19085 | #endif |
15091 | 19086 | cimg_rof(*this,ptrd,T) *ptrd = cimg::sign(*ptrd); |
15092 | 19087 | return *this; |
... | ... | @@ -15108,7 +19103,7 @@ namespace cimg_library_suffixed { |
15108 | 19103 | CImg<T>& cos() { |
15109 | 19104 | if (is_empty()) return *this; |
15110 | 19105 | #ifdef cimg_use_openmp |
15111 | -#pragma omp parallel for if (size()>=8192) | |
19106 | +#pragma omp parallel for cimg_openmp_if(size()>=8192) | |
15112 | 19107 | #endif |
15113 | 19108 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd); |
15114 | 19109 | return *this; |
... | ... | @@ -15130,7 +19125,7 @@ namespace cimg_library_suffixed { |
15130 | 19125 | CImg<T>& sin() { |
15131 | 19126 | if (is_empty()) return *this; |
15132 | 19127 | #ifdef cimg_use_openmp |
15133 | -#pragma omp parallel for if (size()>=8192) | |
19128 | +#pragma omp parallel for cimg_openmp_if(size()>=8192) | |
15134 | 19129 | #endif |
15135 | 19130 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd); |
15136 | 19131 | return *this; |
... | ... | @@ -15153,7 +19148,7 @@ namespace cimg_library_suffixed { |
15153 | 19148 | CImg<T>& sinc() { |
15154 | 19149 | if (is_empty()) return *this; |
15155 | 19150 | #ifdef cimg_use_openmp |
15156 | -#pragma omp parallel for if (size()>=2048) | |
19151 | +#pragma omp parallel for cimg_openmp_if(size()>=2048) | |
15157 | 19152 | #endif |
15158 | 19153 | cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd); |
15159 | 19154 | return *this; |
... | ... | @@ -15175,7 +19170,7 @@ namespace cimg_library_suffixed { |
15175 | 19170 | CImg<T>& tan() { |
15176 | 19171 | if (is_empty()) return *this; |
15177 | 19172 | #ifdef cimg_use_openmp |
15178 | -#pragma omp parallel for if (size()>=2048) | |
19173 | +#pragma omp parallel for cimg_openmp_if(size()>=2048) | |
15179 | 19174 | #endif |
15180 | 19175 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd); |
15181 | 19176 | return *this; |
... | ... | @@ -15197,7 +19192,7 @@ namespace cimg_library_suffixed { |
15197 | 19192 | CImg<T>& cosh() { |
15198 | 19193 | if (is_empty()) return *this; |
15199 | 19194 | #ifdef cimg_use_openmp |
15200 | -#pragma omp parallel for if (size()>=2048) | |
19195 | +#pragma omp parallel for cimg_openmp_if(size()>=2048) | |
15201 | 19196 | #endif |
15202 | 19197 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd); |
15203 | 19198 | return *this; |
... | ... | @@ -15219,7 +19214,7 @@ namespace cimg_library_suffixed { |
15219 | 19214 | CImg<T>& sinh() { |
15220 | 19215 | if (is_empty()) return *this; |
15221 | 19216 | #ifdef cimg_use_openmp |
15222 | -#pragma omp parallel for if (size()>=2048) | |
19217 | +#pragma omp parallel for cimg_openmp_if(size()>=2048) | |
15223 | 19218 | #endif |
15224 | 19219 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd); |
15225 | 19220 | return *this; |
... | ... | @@ -15241,7 +19236,7 @@ namespace cimg_library_suffixed { |
15241 | 19236 | CImg<T>& tanh() { |
15242 | 19237 | if (is_empty()) return *this; |
15243 | 19238 | #ifdef cimg_use_openmp |
15244 | -#pragma omp parallel for if (size()>=2048) | |
19239 | +#pragma omp parallel for cimg_openmp_if(size()>=2048) | |
15245 | 19240 | #endif |
15246 | 19241 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd); |
15247 | 19242 | return *this; |
... | ... | @@ -15263,7 +19258,7 @@ namespace cimg_library_suffixed { |
15263 | 19258 | CImg<T>& acos() { |
15264 | 19259 | if (is_empty()) return *this; |
15265 | 19260 | #ifdef cimg_use_openmp |
15266 | -#pragma omp parallel for if (size()>=8192) | |
19261 | +#pragma omp parallel for cimg_openmp_if(size()>=8192) | |
15267 | 19262 | #endif |
15268 | 19263 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd); |
15269 | 19264 | return *this; |
... | ... | @@ -15285,7 +19280,7 @@ namespace cimg_library_suffixed { |
15285 | 19280 | CImg<T>& asin() { |
15286 | 19281 | if (is_empty()) return *this; |
15287 | 19282 | #ifdef cimg_use_openmp |
15288 | -#pragma omp parallel for if (size()>=8192) | |
19283 | +#pragma omp parallel for cimg_openmp_if(size()>=8192) | |
15289 | 19284 | #endif |
15290 | 19285 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd); |
15291 | 19286 | return *this; |
... | ... | @@ -15307,7 +19302,7 @@ namespace cimg_library_suffixed { |
15307 | 19302 | CImg<T>& atan() { |
15308 | 19303 | if (is_empty()) return *this; |
15309 | 19304 | #ifdef cimg_use_openmp |
15310 | -#pragma omp parallel for if (size()>=8192) | |
19305 | +#pragma omp parallel for cimg_openmp_if(size()>=8192) | |
15311 | 19306 | #endif |
15312 | 19307 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd); |
15313 | 19308 | return *this; |
... | ... | @@ -15436,35 +19431,35 @@ namespace cimg_library_suffixed { |
15436 | 19431 | if (is_empty()) return *this; |
15437 | 19432 | if (p==-4) { |
15438 | 19433 | #ifdef cimg_use_openmp |
15439 | -#pragma omp parallel for if (size()>=32768) | |
19434 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
15440 | 19435 | #endif |
15441 | 19436 | cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val*val)); } |
15442 | 19437 | return *this; |
15443 | 19438 | } |
15444 | 19439 | if (p==-3) { |
15445 | 19440 | #ifdef cimg_use_openmp |
15446 | -#pragma omp parallel for if (size()>=32768) | |
19441 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
15447 | 19442 | #endif |
15448 | 19443 | cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val)); } |
15449 | 19444 | return *this; |
15450 | 19445 | } |
15451 | 19446 | if (p==-2) { |
15452 | 19447 | #ifdef cimg_use_openmp |
15453 | -#pragma omp parallel for if (size()>=32768) | |
19448 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
15454 | 19449 | #endif |
15455 | 19450 | cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val)); } |
15456 | 19451 | return *this; |
15457 | 19452 | } |
15458 | 19453 | if (p==-1) { |
15459 | 19454 | #ifdef cimg_use_openmp |
15460 | -#pragma omp parallel for if (size()>=32768) | |
19455 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
15461 | 19456 | #endif |
15462 | 19457 | cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/val); } |
15463 | 19458 | return *this; |
15464 | 19459 | } |
15465 | 19460 | if (p==-0.5) { |
15466 | 19461 | #ifdef cimg_use_openmp |
15467 | -#pragma omp parallel for if (size()>=8192) | |
19462 | +#pragma omp parallel for cimg_openmp_if(size()>=8192) | |
15468 | 19463 | #endif |
15469 | 19464 | cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1/std::sqrt((double)val)); } |
15470 | 19465 | return *this; |
... | ... | @@ -15475,20 +19470,20 @@ namespace cimg_library_suffixed { |
15475 | 19470 | if (p==2) return sqr(); |
15476 | 19471 | if (p==3) { |
15477 | 19472 | #ifdef cimg_use_openmp |
15478 | -#pragma omp parallel for if (size()>=262144) | |
19473 | +#pragma omp parallel for cimg_openmp_if(size()>=262144) | |
15479 | 19474 | #endif |
15480 | 19475 | cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; } |
15481 | 19476 | return *this; |
15482 | 19477 | } |
15483 | 19478 | if (p==4) { |
15484 | 19479 | #ifdef cimg_use_openmp |
15485 | -#pragma omp parallel for if (size()>=131072) | |
19480 | +#pragma omp parallel for cimg_openmp_if(size()>=131072) | |
15486 | 19481 | #endif |
15487 | 19482 | cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; } |
15488 | 19483 | return *this; |
15489 | 19484 | } |
15490 | 19485 | #ifdef cimg_use_openmp |
15491 | -#pragma omp parallel for if (size()>=1024) | |
19486 | +#pragma omp parallel for cimg_openmp_if(size()>=1024) | |
15492 | 19487 | #endif |
15493 | 19488 | cimg_rof(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p); |
15494 | 19489 | return *this; |
... | ... | @@ -15504,44 +19499,7 @@ namespace cimg_library_suffixed { |
15504 | 19499 | Similar to operator+=(const char*), except it performs a pointwise exponentiation instead of an addition. |
15505 | 19500 | **/ |
15506 | 19501 | CImg<T>& pow(const char *const expression) { |
15507 | - if (is_empty()) return *this; | |
15508 | - const unsigned int omode = cimg::exception_mode(); | |
15509 | - cimg::exception_mode(0); | |
15510 | - try { | |
15511 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
15512 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"pow"); | |
15513 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
15514 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp(x,y,z,c)); --ptrd; } | |
15515 | - else if (*expression=='>') | |
15516 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp(x,y,z,c)); ++ptrd; } | |
15517 | - else { | |
15518 | -#ifdef cimg_use_openmp | |
15519 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
15520 | -#pragma omp parallel | |
15521 | - { | |
15522 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
15523 | -#pragma omp for collapse(3) | |
15524 | - cimg_forYZC(*this,y,z,c) { | |
15525 | - T *ptrd = data(0,y,z,c); | |
15526 | - cimg_forX(*this,x) { *ptrd = (T)std::pow((double)*ptrd,lmp(x,y,z,c)); ++ptrd; } | |
15527 | - } | |
15528 | - } | |
15529 | - else | |
15530 | -#endif | |
15531 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp(x,y,z,c)); ++ptrd; } | |
15532 | - } | |
15533 | - } catch (CImgException&) { | |
15534 | - CImg<Tfloat> values(_width,_height,_depth,_spectrum); | |
15535 | - try { | |
15536 | - values.fill(expression,true); | |
15537 | - } catch (CImgException&) { | |
15538 | - cimg::exception_mode(omode); | |
15539 | - values.load(expression); | |
15540 | - } | |
15541 | - pow(values); | |
15542 | - } | |
15543 | - cimg::exception_mode(omode); | |
15544 | - return *this; | |
19502 | + return pow((+*this)._fill(expression,true,true,0,0,"pow",this)); | |
15545 | 19503 | } |
15546 | 19504 | |
15547 | 19505 | //! Raise each pixel value to a power, specified from an expression \newinstance. |
... | ... | @@ -15580,7 +19538,7 @@ namespace cimg_library_suffixed { |
15580 | 19538 | CImg<T>& rol(const unsigned int n=1) { |
15581 | 19539 | if (is_empty()) return *this; |
15582 | 19540 | #ifdef cimg_use_openmp |
15583 | -#pragma omp parallel for if (size()>=32768) | |
19541 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
15584 | 19542 | #endif |
15585 | 19543 | cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n); |
15586 | 19544 | return *this; |
... | ... | @@ -15596,45 +19554,7 @@ namespace cimg_library_suffixed { |
15596 | 19554 | Similar to operator<<=(const char*), except that it performs a left rotation instead of a left shift. |
15597 | 19555 | **/ |
15598 | 19556 | CImg<T>& rol(const char *const expression) { |
15599 | - if (is_empty()) return *this; | |
15600 | - const unsigned int omode = cimg::exception_mode(); | |
15601 | - cimg::exception_mode(0); | |
15602 | - try { | |
15603 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
15604 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"rol"); | |
15605 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
15606 | - if (*expression=='<') | |
15607 | - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp(x,y,z,c)); --ptrd; } | |
15608 | - else if (*expression=='>') | |
15609 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp(x,y,z,c)); ++ptrd; } | |
15610 | - else { | |
15611 | -#ifdef cimg_use_openmp | |
15612 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
15613 | -#pragma omp parallel | |
15614 | - { | |
15615 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
15616 | -#pragma omp for collapse(3) | |
15617 | - cimg_forYZC(*this,y,z,c) { | |
15618 | - T *ptrd = data(0,y,z,c); | |
15619 | - cimg_forX(*this,x) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)lmp(x,y,z,c)); ++ptrd; } | |
15620 | - } | |
15621 | - } | |
15622 | - else | |
15623 | -#endif | |
15624 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp(x,y,z,c)); ++ptrd; } | |
15625 | - } | |
15626 | - } catch (CImgException&) { | |
15627 | - CImg<Tfloat> values(_width,_height,_depth,_spectrum); | |
15628 | - try { | |
15629 | - values.fill(expression,true); | |
15630 | - } catch (CImgException&) { | |
15631 | - cimg::exception_mode(omode); | |
15632 | - values.load(expression); | |
15633 | - } | |
15634 | - rol(values); | |
15635 | - } | |
15636 | - cimg::exception_mode(omode); | |
15637 | - return *this; | |
19557 | + return rol((+*this)._fill(expression,true,true,0,0,"rol",this)); | |
15638 | 19558 | } |
15639 | 19559 | |
15640 | 19560 | //! Compute the bitwise left rotation of each pixel value \newinstance. |
... | ... | @@ -15673,7 +19593,7 @@ namespace cimg_library_suffixed { |
15673 | 19593 | CImg<T>& ror(const unsigned int n=1) { |
15674 | 19594 | if (is_empty()) return *this; |
15675 | 19595 | #ifdef cimg_use_openmp |
15676 | -#pragma omp parallel for if (size()>=32768) | |
19596 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
15677 | 19597 | #endif |
15678 | 19598 | cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n); |
15679 | 19599 | return *this; |
... | ... | @@ -15689,45 +19609,7 @@ namespace cimg_library_suffixed { |
15689 | 19609 | Similar to operator>>=(const char*), except that it performs a right rotation instead of a right shift. |
15690 | 19610 | **/ |
15691 | 19611 | CImg<T>& ror(const char *const expression) { |
15692 | - if (is_empty()) return *this; | |
15693 | - const unsigned int omode = cimg::exception_mode(); | |
15694 | - cimg::exception_mode(0); | |
15695 | - try { | |
15696 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
15697 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"ror"); | |
15698 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
15699 | - if (*expression=='<') | |
15700 | - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp(x,y,z,c)); --ptrd; } | |
15701 | - else if (*expression=='>') | |
15702 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp(x,y,z,c)); ++ptrd; } | |
15703 | - else { | |
15704 | -#ifdef cimg_use_openmp | |
15705 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
15706 | -#pragma omp parallel | |
15707 | - { | |
15708 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
15709 | -#pragma omp for collapse(3) | |
15710 | - cimg_forYZC(*this,y,z,c) { | |
15711 | - T *ptrd = data(0,y,z,c); | |
15712 | - cimg_forX(*this,x) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)lmp(x,y,z,c)); ++ptrd; } | |
15713 | - } | |
15714 | - } | |
15715 | - else | |
15716 | -#endif | |
15717 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp(x,y,z,c)); ++ptrd; } | |
15718 | - } | |
15719 | - } catch (CImgException&) { | |
15720 | - CImg<Tfloat> values(_width,_height,_depth,_spectrum); | |
15721 | - try { | |
15722 | - values.fill(expression,true); | |
15723 | - } catch (CImgException&) { | |
15724 | - cimg::exception_mode(omode); | |
15725 | - values.load(expression); | |
15726 | - } | |
15727 | - ror(values); | |
15728 | - } | |
15729 | - cimg::exception_mode(omode); | |
15730 | - return *this; | |
19612 | + return ror((+*this)._fill(expression,true,true,0,0,"ror",this)); | |
15731 | 19613 | } |
15732 | 19614 | |
15733 | 19615 | //! Compute the bitwise right rotation of each pixel value \newinstance. |
... | ... | @@ -15768,7 +19650,7 @@ namespace cimg_library_suffixed { |
15768 | 19650 | CImg<T>& min(const T& val) { |
15769 | 19651 | if (is_empty()) return *this; |
15770 | 19652 | #ifdef cimg_use_openmp |
15771 | -#pragma omp parallel for if (size()>=65536) | |
19653 | +#pragma omp parallel for cimg_openmp_if(size()>=65536) | |
15772 | 19654 | #endif |
15773 | 19655 | cimg_rof(*this,ptrd,T) *ptrd = cimg::min(*ptrd,val); |
15774 | 19656 | return *this; |
... | ... | @@ -15812,43 +19694,7 @@ namespace cimg_library_suffixed { |
15812 | 19694 | \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. |
15813 | 19695 | **/ |
15814 | 19696 | CImg<T>& min(const char *const expression) { |
15815 | - if (is_empty()) return *this; | |
15816 | - const unsigned int omode = cimg::exception_mode(); | |
15817 | - cimg::exception_mode(0); | |
15818 | - try { | |
15819 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
15820 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"min"); | |
15821 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
15822 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp(x,y,z,c)); --ptrd; } | |
15823 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } | |
15824 | - else { | |
15825 | -#ifdef cimg_use_openmp | |
15826 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
15827 | -#pragma omp parallel | |
15828 | - { | |
15829 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
15830 | -#pragma omp for collapse(3) | |
15831 | - cimg_forYZC(*this,y,z,c) { | |
15832 | - T *ptrd = data(0,y,z,c); | |
15833 | - cimg_forX(*this,x) { *ptrd = (T)cimg::min(*ptrd,(T)lmp(x,y,z,c)); ++ptrd; } | |
15834 | - } | |
15835 | - } | |
15836 | - else | |
15837 | -#endif | |
15838 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } | |
15839 | - } | |
15840 | - } catch (CImgException&) { | |
15841 | - CImg<T> values(_width,_height,_depth,_spectrum); | |
15842 | - try { | |
15843 | - values.fill(expression,true); | |
15844 | - } catch (CImgException&) { | |
15845 | - cimg::exception_mode(omode); | |
15846 | - values.load(expression); | |
15847 | - } | |
15848 | - min(values); | |
15849 | - } | |
15850 | - cimg::exception_mode(omode); | |
15851 | - return *this; | |
19697 | + return min((+*this)._fill(expression,true,true,0,0,"min",this)); | |
15852 | 19698 | } |
15853 | 19699 | |
15854 | 19700 | //! Pointwise min operator between an image and an expression \newinstance. |
... | ... | @@ -15865,7 +19711,7 @@ namespace cimg_library_suffixed { |
15865 | 19711 | CImg<T>& max(const T& val) { |
15866 | 19712 | if (is_empty()) return *this; |
15867 | 19713 | #ifdef cimg_use_openmp |
15868 | -#pragma omp parallel for if (size()>=65536) | |
19714 | +#pragma omp parallel for cimg_openmp_if(size()>=65536) | |
15869 | 19715 | #endif |
15870 | 19716 | cimg_rof(*this,ptrd,T) *ptrd = cimg::max(*ptrd,val); |
15871 | 19717 | return *this; |
... | ... | @@ -15909,43 +19755,7 @@ namespace cimg_library_suffixed { |
15909 | 19755 | \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. |
15910 | 19756 | **/ |
15911 | 19757 | CImg<T>& max(const char *const expression) { |
15912 | - if (is_empty()) return *this; | |
15913 | - const unsigned int omode = cimg::exception_mode(); | |
15914 | - cimg::exception_mode(0); | |
15915 | - try { | |
15916 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
15917 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"max"); | |
15918 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
15919 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp(x,y,z,c)); --ptrd; } | |
15920 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } | |
15921 | - else { | |
15922 | -#ifdef cimg_use_openmp | |
15923 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
15924 | -#pragma omp parallel | |
15925 | - { | |
15926 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
15927 | -#pragma omp for collapse(3) | |
15928 | - cimg_forYZC(*this,y,z,c) { | |
15929 | - T *ptrd = data(0,y,z,c); | |
15930 | - cimg_forX(*this,x) { *ptrd = (T)cimg::max(*ptrd,(T)lmp(x,y,z,c)); ++ptrd; } | |
15931 | - } | |
15932 | - } | |
15933 | - else | |
15934 | -#endif | |
15935 | - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } | |
15936 | - } | |
15937 | - } catch (CImgException&) { | |
15938 | - CImg<T> values(_width,_height,_depth,_spectrum); | |
15939 | - try { | |
15940 | - values.fill(expression,true); | |
15941 | - } catch (CImgException&) { | |
15942 | - cimg::exception_mode(omode); | |
15943 | - values.load(expression); | |
15944 | - } | |
15945 | - max(values); | |
15946 | - } | |
15947 | - cimg::exception_mode(omode); | |
15948 | - return *this; | |
19758 | + return max((+*this)._fill(expression,true,true,0,0,"max",this)); | |
15949 | 19759 | } |
15950 | 19760 | |
15951 | 19761 | //! Pointwise max operator between an image and an expression \newinstance. |
... | ... | @@ -16094,7 +19904,7 @@ namespace cimg_library_suffixed { |
16094 | 19904 | cimg_instance); |
16095 | 19905 | CImg<T> arr(*this); |
16096 | 19906 | unsigned int l = 0, ir = size() - 1; |
16097 | - for (;;) { | |
19907 | + for ( ; ; ) { | |
16098 | 19908 | if (ir<=l + 1) { |
16099 | 19909 | if (ir==l + 1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]); |
16100 | 19910 | return arr[k]; |
... | ... | @@ -16106,7 +19916,7 @@ namespace cimg_library_suffixed { |
16106 | 19916 | if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]); |
16107 | 19917 | unsigned int i = l + 1, j = ir; |
16108 | 19918 | const T pivot = arr[l + 1]; |
16109 | - for (;;) { | |
19919 | + for ( ; ; ) { | |
16110 | 19920 | do ++i; while (arr[i]<pivot); |
16111 | 19921 | do --j; while (arr[j]>pivot); |
16112 | 19922 | if (j<i) break; |
... | ... | @@ -16256,7 +20066,7 @@ namespace cimg_library_suffixed { |
16256 | 20066 | if (_depth==1) { |
16257 | 20067 | const double cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed. |
16258 | 20068 | #ifdef cimg_use_openmp |
16259 | -#pragma omp parallel for if (_width*_height>=262144 && _spectrum>=2) | |
20069 | +#pragma omp parallel for cimg_openmp_if(_width*_height>=262144 && _spectrum>=2) | |
16260 | 20070 | #endif |
16261 | 20071 | cimg_forC(*this,c) { |
16262 | 20072 | CImg_3x3(I,T); |
... | ... | @@ -16268,7 +20078,7 @@ namespace cimg_library_suffixed { |
16268 | 20078 | } else { |
16269 | 20079 | const double cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed. |
16270 | 20080 | #ifdef cimg_use_openmp |
16271 | -#pragma omp parallel for if (_width*_height*_depth>=262144 && _spectrum>=2) | |
20081 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=262144 && _spectrum>=2) | |
16272 | 20082 | #endif |
16273 | 20083 | cimg_forC(*this,c) { |
16274 | 20084 | CImg_3x3x3(I,T); |
... | ... | @@ -16348,9 +20158,25 @@ namespace cimg_library_suffixed { |
16348 | 20158 | \param y Value of the pre-defined variable \c y. |
16349 | 20159 | \param z Value of the pre-defined variable \c z. |
16350 | 20160 | \param c Value of the pre-defined variable \c c. |
20161 | + \param list_inputs A list of input images attached to the specified math formula. | |
20162 | + \param list_outputs A pointer to a list of output images attached to the specified math formula. | |
16351 | 20163 | **/ |
16352 | 20164 | double eval(const char *const expression, |
16353 | - const double x=0, const double y=0, const double z=0, const double c=0) const { | |
20165 | + const double x=0, const double y=0, const double z=0, const double c=0, | |
20166 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) { | |
20167 | + return _eval(this,expression,x,y,z,c,list_inputs,list_outputs); | |
20168 | + } | |
20169 | + | |
20170 | + //! Evaluate math formula \const. | |
20171 | + double eval(const char *const expression, | |
20172 | + const double x=0, const double y=0, const double z=0, const double c=0, | |
20173 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const { | |
20174 | + return _eval(0,expression,x,y,z,c,list_inputs,list_outputs); | |
20175 | + } | |
20176 | + | |
20177 | + double _eval(CImg<T> *const img_output, const char *const expression, | |
20178 | + const double x, const double y, const double z, const double c, | |
20179 | + const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const { | |
16354 | 20180 | if (!expression) return 0; |
16355 | 20181 | if (!expression[1]) switch (*expression) { // Single-char optimization. |
16356 | 20182 | case 'w' : return (double)_width; |
... | ... | @@ -16359,7 +20185,54 @@ namespace cimg_library_suffixed { |
16359 | 20185 | case 's' : return (double)_spectrum; |
16360 | 20186 | case 'r' : return (double)_is_shared; |
16361 | 20187 | } |
16362 | - return _cimg_math_parser(*this,expression,"eval")(x,y,z,c); | |
20188 | + _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*'?1:0),"eval", | |
20189 | + *this,img_output,list_inputs,list_outputs); | |
20190 | + return mp(x,y,z,c); | |
20191 | + } | |
20192 | + | |
20193 | + //! Evaluate math formula. | |
20194 | + /** | |
20195 | + \param[out] output Contains values of output vector returned by the evaluated expression | |
20196 | + (or is empty if the returned type is scalar). | |
20197 | + \param expression Math formula, as a C-string. | |
20198 | + \param x Value of the pre-defined variable \c x. | |
20199 | + \param y Value of the pre-defined variable \c y. | |
20200 | + \param z Value of the pre-defined variable \c z. | |
20201 | + \param c Value of the pre-defined variable \c c. | |
20202 | + \param list_inputs A list of input images attached to the specified math formula. | |
20203 | + \param list_outputs A pointer to a list of output images attached to the specified math formula. | |
20204 | + **/ | |
20205 | + template<typename t> | |
20206 | + void eval(CImg<t> &output, const char *const expression, | |
20207 | + const double x=0, const double y=0, const double z=0, const double c=0, | |
20208 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) { | |
20209 | + _eval(output,this,expression,x,y,z,c,list_inputs,list_outputs); | |
20210 | + } | |
20211 | + | |
20212 | + //! Evaluate math formula \const. | |
20213 | + template<typename t> | |
20214 | + void eval(CImg<t>& output, const char *const expression, | |
20215 | + const double x=0, const double y=0, const double z=0, const double c=0, | |
20216 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const { | |
20217 | + _eval(output,0,expression,x,y,z,c,list_inputs,list_outputs); | |
20218 | + } | |
20219 | + | |
20220 | + template<typename t> | |
20221 | + void _eval(CImg<t>& output, CImg<T> *const img_output, const char *const expression, | |
20222 | + const double x, const double y, const double z, const double c, | |
20223 | + const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const { | |
20224 | + if (!expression) { output.assign(1); *output = 0; } | |
20225 | + if (!expression[1]) switch (*expression) { // Single-char optimization. | |
20226 | + case 'w' : output.assign(1); *output = (t)_width; | |
20227 | + case 'h' : output.assign(1); *output = (t)_height; | |
20228 | + case 'd' : output.assign(1); *output = (t)_depth; | |
20229 | + case 's' : output.assign(1); *output = (t)_spectrum; | |
20230 | + case 'r' : output.assign(1); *output = (t)_is_shared; | |
20231 | + } | |
20232 | + _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*'?1:0),"eval", | |
20233 | + *this,img_output,list_inputs,list_outputs); | |
20234 | + output.assign(1,cimg::max(1U,mp.result_dim)); | |
20235 | + mp(x,y,z,c,output._data); | |
16363 | 20236 | } |
16364 | 20237 | |
16365 | 20238 | //! Evaluate math formula on a set of variables. |
... | ... | @@ -16368,10 +20241,24 @@ namespace cimg_library_suffixed { |
16368 | 20241 | \param xyzc Set of values (x,y,z,c) used for the evaluation. |
16369 | 20242 | **/ |
16370 | 20243 | template<typename t> |
16371 | - CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc) const { | |
20244 | + CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc, | |
20245 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) { | |
20246 | + return _eval(this,expression,xyzc,list_inputs,list_outputs); | |
20247 | + } | |
20248 | + | |
20249 | + //! Evaluate math formula on a set of variables \const. | |
20250 | + template<typename t> | |
20251 | + CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc, | |
20252 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const { | |
20253 | + return _eval(0,expression,xyzc,list_inputs,list_outputs); | |
20254 | + } | |
20255 | + | |
20256 | + template<typename t> | |
20257 | + CImg<doubleT> _eval(CImg<T> *const output, const char *const expression, const CImg<t>& xyzc, | |
20258 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const { | |
16372 | 20259 | CImg<doubleT> res(1,xyzc.size()/4); |
16373 | 20260 | if (!expression) return res.fill(0); |
16374 | - _cimg_math_parser mp(*this,expression,"eval"); | |
20261 | + _cimg_math_parser mp(expression,"eval",*this,output,list_inputs,list_outputs); | |
16375 | 20262 | #ifdef cimg_use_openmp |
16376 | 20263 | #pragma omp parallel if (res._height>=512 && std::strlen(expression)>=6) |
16377 | 20264 | { |
... | ... | @@ -18496,36 +22383,95 @@ namespace cimg_library_suffixed { |
18496 | 22383 | \param expression C-string describing a math formula, or a list of values. |
18497 | 22384 | \param repeat_values In case a list of values is provided, tells if this list must be repeated for the filling. |
18498 | 22385 | \param allow_formula tells if a formula is allowed or only a list of values. |
22386 | + \param list_inputs In case of a mathematical expression, attach a list of images to the specified expression. | |
22387 | + \param list_outputs In case of a mathematical expression, attach a list of images to the specified expression. | |
18499 | 22388 | **/ |
18500 | - CImg<T>& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true) { | |
22389 | + CImg<T>& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true, | |
22390 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) { | |
22391 | + return _fill(expression,repeat_values,allow_formula,list_inputs,list_outputs,"fill",0); | |
22392 | + } | |
22393 | + | |
22394 | + CImg<T>& _fill(const char *const expression, const bool repeat_values, const bool allow_formula, | |
22395 | + const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs, | |
22396 | + const char *const calling_function, const CImg<T> *provide_base) { | |
18501 | 22397 | if (is_empty() || !expression || !*expression) return *this; |
18502 | 22398 | const unsigned int omode = cimg::exception_mode(); |
18503 | 22399 | cimg::exception_mode(0); |
18504 | 22400 | CImg<charT> is_error; |
18505 | 22401 | |
18506 | - if (allow_formula) try { // Try to fill values according to a formula. | |
18507 | - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this; | |
18508 | - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"fill"); | |
18509 | - T *ptrd = *expression=='<'?end() - 1:_data; | |
18510 | - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) *(ptrd--) = (T)mp(x,y,z,c); | |
18511 | - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c); | |
18512 | - else { | |
22402 | + 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), | |
22409 | + calling_function,base,this,list_inputs,list_outputs); | |
22410 | + bool do_in_parallel = false; | |
22411 | +#ifdef cimg_use_openmp | |
22412 | + cimg_openmp_if(*expression=='*' || | |
22413 | + (is_parallelizable && _width>=320 && _height*_depth*_spectrum>=2 && | |
22414 | + std::strlen(expression)>=6)) | |
22415 | + do_in_parallel = true; | |
22416 | +#endif | |
22417 | + if (mp.result_dim) { // Vector-valued expression | |
22418 | + const unsigned int N = cimg::min(mp.result_dim,_spectrum); | |
22419 | + const unsigned long whd = _width*_height*_depth; | |
22420 | + T *ptrd = *expression=='<'?_data + _width*_height*_depth - 1:_data; | |
22421 | + if (*expression=='<') { | |
22422 | + CImg<doubleT> res(1,mp.result_dim); | |
22423 | + cimg_rofXYZ(*this,x,y,z) { | |
22424 | + mp(x,y,z,0,res._data); | |
22425 | + const double *ptrs = res._data; | |
22426 | + T *_ptrd = ptrd--; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } | |
22427 | + } | |
22428 | + } else if (*expression=='>' || !do_in_parallel) { | |
22429 | + CImg<doubleT> res(1,mp.result_dim); | |
22430 | + cimg_forXYZ(*this,x,y,z) { | |
22431 | + mp(x,y,z,0,res._data); | |
22432 | + const double *ptrs = res._data; | |
22433 | + T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } | |
22434 | + } | |
22435 | + } else { | |
18513 | 22436 | #ifdef cimg_use_openmp |
18514 | - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6) | |
18515 | 22437 | #pragma omp parallel |
18516 | - { | |
18517 | - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
18518 | -#pragma omp for collapse(3) | |
18519 | - cimg_forYZC(*this,y,z,c) { | |
18520 | - T *ptrd = data(0,y,z,c); | |
18521 | - cimg_forX(*this,x) *ptrd++ = (T)lmp(x,y,z,c); | |
22438 | + { | |
22439 | + _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
22440 | +#pragma omp for collapse(2) | |
22441 | + cimg_forYZ(*this,y,z) { | |
22442 | + CImg<doubleT> res(1,lmp.result_dim); | |
22443 | + T *ptrd = data(0,y,z,0); | |
22444 | + cimg_forX(*this,x) { | |
22445 | + lmp(x,y,z,0,res._data); | |
22446 | + const double *ptrs = res._data; | |
22447 | + T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } | |
22448 | + } | |
22449 | + } | |
18522 | 22450 | } |
22451 | +#endif | |
18523 | 22452 | } |
18524 | - else | |
22453 | + | |
22454 | + } else { // Scalar-valued expression | |
22455 | + T *ptrd = *expression=='<'?end() - 1:_data; | |
22456 | + if (*expression=='<') | |
22457 | + cimg_rofXYZC(*this,x,y,z,c) *(ptrd--) = (T)mp(x,y,z,c); | |
22458 | + else if (*expression=='>' || !do_in_parallel) | |
22459 | + cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c); | |
22460 | + else { | |
22461 | +#ifdef cimg_use_openmp | |
22462 | +#pragma omp parallel | |
22463 | + { | |
22464 | + _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp; | |
22465 | +#pragma omp for collapse(3) | |
22466 | + cimg_forYZC(*this,y,z,c) { | |
22467 | + T *ptrd = data(0,y,z,c); | |
22468 | + cimg_forX(*this,x) *ptrd++ = (T)lmp(x,y,z,c); | |
22469 | + } | |
22470 | + } | |
18525 | 22471 | #endif |
18526 | - cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c); | |
18527 | - } | |
18528 | - } catch (CImgException& e) { CImg<charT>::string(e._message).move_to(is_error); } | |
22472 | + } | |
22473 | + } | |
22474 | + } catch (CImgException& e) { CImg<charT>::string(e._message).move_to(is_error); } | |
18529 | 22475 | |
18530 | 22476 | // If failed, try to recognize a list of values. |
18531 | 22477 | if (!allow_formula || is_error) { |
... | ... | @@ -18547,8 +22493,8 @@ namespace cimg_library_suffixed { |
18547 | 22493 | if (nb<siz && (sep || *nexpression)) { |
18548 | 22494 | if (is_error) throw CImgArgumentException("%s",is_error._data); |
18549 | 22495 | else throw CImgArgumentException(_cimg_instance |
18550 | - "fill(): Invalid sequence of filling values '%s'.", | |
18551 | - cimg_instance,expression); | |
22496 | + "%s(): Invalid sequence of filling values '%s'.", | |
22497 | + cimg_instance,calling_function,expression); | |
18552 | 22498 | } |
18553 | 22499 | if (repeat_values && nb && nb<siz) |
18554 | 22500 | for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs; |
... | ... | @@ -18558,8 +22504,9 @@ namespace cimg_library_suffixed { |
18558 | 22504 | } |
18559 | 22505 | |
18560 | 22506 | //! Fill sequentially pixel values according to a given expression \newinstance. |
18561 | - CImg<T> get_fill(const char *const values, const bool repeat_values, const bool allow_formula=true) const { | |
18562 | - return (+*this).fill(values,repeat_values,allow_formula); | |
22507 | + CImg<T> get_fill(const char *const expression, const bool repeat_values, const bool allow_formula=true, | |
22508 | + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const { | |
22509 | + return (+*this).fill(expression,repeat_values,allow_formula,list_inputs,list_outputs); | |
18563 | 22510 | } |
18564 | 22511 | |
18565 | 22512 | //! Fill sequentially pixel values according to the values found in another image. |
... | ... | @@ -18811,9 +22758,9 @@ namespace cimg_library_suffixed { |
18811 | 22758 | |
18812 | 22759 | //! Fill image with random values in specified range. |
18813 | 22760 | /** |
18814 | - \param val_min Minimal random value. | |
18815 | - \param val_max Maximal random value. | |
18816 | - \note Random samples are following a uniform distribution. | |
22761 | + \param val_min Minimal authorized random value. | |
22762 | + \param val_max Maximal authorized random value. | |
22763 | + \note Random variables are uniformely distributed in [val_min,val_max]. | |
18817 | 22764 | **/ |
18818 | 22765 | CImg<T>& rand(const T& val_min, const T& val_max) { |
18819 | 22766 | const float delta = (float)val_max - (float)val_min + (cimg::type<T>::is_float()?0:1); |
... | ... | @@ -18838,7 +22785,7 @@ namespace cimg_library_suffixed { |
18838 | 22785 | CImg<T>& round(const double y=1, const int rounding_type=0) { |
18839 | 22786 | if (y>0) |
18840 | 22787 | #ifdef cimg_use_openmp |
18841 | -#pragma omp parallel for if (size()>=8192) | |
22788 | +#pragma omp parallel for cimg_openmp_if(size()>=8192) | |
18842 | 22789 | #endif |
18843 | 22790 | cimg_rof(*this,ptrd,T) *ptrd = cimg::round(*ptrd,y,rounding_type); |
18844 | 22791 | return *this; |
... | ... | @@ -18885,7 +22832,7 @@ namespace cimg_library_suffixed { |
18885 | 22832 | } break; |
18886 | 22833 | case 1 : { // Uniform noise |
18887 | 22834 | cimg_rof(*this,ptrd,T) { |
18888 | - Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::crand()); | |
22835 | + Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::rand(-1,1)); | |
18889 | 22836 | if (val>vmax) val = vmax; |
18890 | 22837 | if (val<vmin) val = vmin; |
18891 | 22838 | *ptrd = (T)val; |
... | ... | @@ -18894,7 +22841,7 @@ namespace cimg_library_suffixed { |
18894 | 22841 | case 2 : { // Salt & Pepper noise |
18895 | 22842 | if (nsigma<0) nsigma = -nsigma; |
18896 | 22843 | if (M==m) { m = 0; M = (Tfloat)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); } |
18897 | - cimg_rof(*this,ptrd,T) if (cimg::rand()*100<nsigma) *ptrd = (T)(cimg::rand()<0.5?M:m); | |
22844 | + cimg_rof(*this,ptrd,T) if (cimg::rand(100)<nsigma) *ptrd = (T)(cimg::rand()<0.5?M:m); | |
18898 | 22845 | } break; |
18899 | 22846 | case 3 : { // Poisson Noise |
18900 | 22847 | cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::prand(*ptrd); |
... | ... | @@ -18946,7 +22893,7 @@ namespace cimg_library_suffixed { |
18946 | 22893 | if (m==M) return fill(min_value); |
18947 | 22894 | if (m!=a || M!=b) |
18948 | 22895 | #ifdef cimg_use_openmp |
18949 | -#pragma omp parallel for if (size()>=65536) | |
22896 | +#pragma omp parallel for cimg_openmp_if(size()>=65536) | |
18950 | 22897 | #endif |
18951 | 22898 | cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd - fm)/(fM - fm)*(b - a) + a); |
18952 | 22899 | return *this; |
... | ... | @@ -19112,7 +23059,7 @@ namespace cimg_library_suffixed { |
19112 | 23059 | if (is_empty()) return *this; |
19113 | 23060 | const T a = min_value<max_value?min_value:max_value, b = min_value<max_value?max_value:min_value; |
19114 | 23061 | #ifdef cimg_use_openmp |
19115 | -#pragma omp parallel for if (size()>=32768) | |
23062 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
19116 | 23063 | #endif |
19117 | 23064 | cimg_rof(*this,ptrd,T) *ptrd = (*ptrd<a)?a:((*ptrd>b)?b:*ptrd); |
19118 | 23065 | return *this; |
... | ... | @@ -19145,14 +23092,14 @@ namespace cimg_library_suffixed { |
19145 | 23092 | if (range>0) { |
19146 | 23093 | if (keep_range) |
19147 | 23094 | #ifdef cimg_use_openmp |
19148 | -#pragma omp parallel for if (size()>=32768) | |
23095 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
19149 | 23096 | #endif |
19150 | 23097 | cimg_rof(*this,ptrd,T) { |
19151 | 23098 | const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); |
19152 | 23099 | *ptrd = (T)(m + cimg::min(val,nb_levels - 1)*range/nb_levels); |
19153 | 23100 | } else |
19154 | 23101 | #ifdef cimg_use_openmp |
19155 | -#pragma omp parallel for if (size()>=32768) | |
23102 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
19156 | 23103 | #endif |
19157 | 23104 | cimg_rof(*this,ptrd,T) { |
19158 | 23105 | const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); |
... | ... | @@ -19184,7 +23131,7 @@ namespace cimg_library_suffixed { |
19184 | 23131 | if (strict_threshold) { |
19185 | 23132 | if (soft_threshold) |
19186 | 23133 | #ifdef cimg_use_openmp |
19187 | -#pragma omp parallel for if (size()>=32768) | |
23134 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
19188 | 23135 | #endif |
19189 | 23136 | cimg_rof(*this,ptrd,T) { |
19190 | 23137 | const T v = *ptrd; |
... | ... | @@ -19192,13 +23139,13 @@ namespace cimg_library_suffixed { |
19192 | 23139 | } |
19193 | 23140 | else |
19194 | 23141 | #ifdef cimg_use_openmp |
19195 | -#pragma omp parallel for if (size()>=65536) | |
23142 | +#pragma omp parallel for cimg_openmp_if(size()>=65536) | |
19196 | 23143 | #endif |
19197 | 23144 | cimg_rof(*this,ptrd,T) *ptrd = *ptrd>value?(T)1:(T)0; |
19198 | 23145 | } else { |
19199 | 23146 | if (soft_threshold) |
19200 | 23147 | #ifdef cimg_use_openmp |
19201 | -#pragma omp parallel for if (size()>=32768) | |
23148 | +#pragma omp parallel for cimg_openmp_if(size()>=32768) | |
19202 | 23149 | #endif |
19203 | 23150 | cimg_rof(*this,ptrd,T) { |
19204 | 23151 | const T v = *ptrd; |
... | ... | @@ -19206,7 +23153,7 @@ namespace cimg_library_suffixed { |
19206 | 23153 | } |
19207 | 23154 | else |
19208 | 23155 | #ifdef cimg_use_openmp |
19209 | -#pragma omp parallel for if (size()>=65536) | |
23156 | +#pragma omp parallel for cimg_openmp_if(size()>=65536) | |
19210 | 23157 | #endif |
19211 | 23158 | cimg_rof(*this,ptrd,T) *ptrd = *ptrd>=value?(T)1:(T)0; |
19212 | 23159 | } |
... | ... | @@ -19290,7 +23237,7 @@ namespace cimg_library_suffixed { |
19290 | 23237 | cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; } |
19291 | 23238 | if (!cumul) cumul = 1; |
19292 | 23239 | #ifdef cimg_use_openmp |
19293 | -#pragma omp parallel for if (size()>=1048576) | |
23240 | +#pragma omp parallel for cimg_openmp_if(size()>=1048576) | |
19294 | 23241 | #endif |
19295 | 23242 | cimg_rof(*this,ptrd,T) { |
19296 | 23243 | const int pos = (int)((*ptrd-vmin)*(nb_levels - 1.)/(vmax-vmin)); |
... | ... | @@ -20903,7 +24850,7 @@ namespace cimg_library_suffixed { |
20903 | 24850 | cc = (int)(centering_c*((int)sc - spectrum())); |
20904 | 24851 | |
20905 | 24852 | switch (boundary_conditions) { |
20906 | - case 2 : { // Periodic borders. | |
24853 | + case 2 : { // Periodic boundary. | |
20907 | 24854 | res.assign(sx,sy,sz,sc); |
20908 | 24855 | const int |
20909 | 24856 | x0 = ((int)xc%width()) - width(), |
... | ... | @@ -20919,7 +24866,7 @@ namespace cimg_library_suffixed { |
20919 | 24866 | for (int x = x0; x<(int)sx; x+=width()) |
20920 | 24867 | res.draw_image(x,y,z,c,*this); |
20921 | 24868 | } break; |
20922 | - case 1 : { // Neumann borders. | |
24869 | + case 1 : { // Neumann boundary. | |
20923 | 24870 | res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this); |
20924 | 24871 | CImg<T> sprite; |
20925 | 24872 | if (xc>0) { // X-backward |
... | ... | @@ -20957,7 +24904,7 @@ namespace cimg_library_suffixed { |
20957 | 24904 | for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite); |
20958 | 24905 | } |
20959 | 24906 | } break; |
20960 | - default : // Dirichlet borders. | |
24907 | + default : // Dirichlet boundary. | |
20961 | 24908 | res.assign(sx,sy,sz,sc,0).draw_image(xc,yc,zc,cc,*this); |
20962 | 24909 | } |
20963 | 24910 | break; |
... | ... | @@ -21028,17 +24975,17 @@ namespace cimg_library_suffixed { |
21028 | 24975 | cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poff_x++); } |
21029 | 24976 | ++y; |
21030 | 24977 | unsigned long dy = *(poff_y++); |
21031 | - for (;!dy && y<dy; std::memcpy(ptrd,ptrd - sx,sizeof(T)*sx), ++y, ptrd+=sx, dy = *(poff_y++)) {} | |
24978 | + for ( ; !dy && y<dy; std::memcpy(ptrd,ptrd - sx,sizeof(T)*sx), ++y, ptrd+=sx, dy = *(poff_y++)) {} | |
21032 | 24979 | ptry+=dy; |
21033 | 24980 | } |
21034 | 24981 | ++z; |
21035 | 24982 | unsigned long dz = *(poff_z++); |
21036 | - for (;!dz && z<dz; std::memcpy(ptrd,ptrd-sxy,sizeof(T)*sxy), ++z, ptrd+=sxy, dz = *(poff_z++)) {} | |
24983 | + for ( ; !dz && z<dz; std::memcpy(ptrd,ptrd-sxy,sizeof(T)*sxy), ++z, ptrd+=sxy, dz = *(poff_z++)) {} | |
21037 | 24984 | ptrz+=dz; |
21038 | 24985 | } |
21039 | 24986 | ++c; |
21040 | 24987 | unsigned long dc = *(poff_c++); |
21041 | - for (;!dc && c<dc; std::memcpy(ptrd,ptrd-sxyz,sizeof(T)*sxyz), ++c, ptrd+=sxyz, dc = *(poff_c++)) {} | |
24988 | + for ( ; !dc && c<dc; std::memcpy(ptrd,ptrd-sxyz,sizeof(T)*sxyz), ++c, ptrd+=sxyz, dc = *(poff_c++)) {} | |
21042 | 24989 | ptrc+=dc; |
21043 | 24990 | } |
21044 | 24991 | } break; |
... | ... | @@ -21822,11 +25769,10 @@ namespace cimg_library_suffixed { |
21822 | 25769 | //! Resize image to half-size along XY axes, using an optimized filter \newinstance. |
21823 | 25770 | CImg<T> get_resize_halfXY() const { |
21824 | 25771 | if (is_empty()) return *this; |
21825 | - const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f, | |
21826 | - 0.1231940459f, 0.1935127547f, 0.1231940459f, | |
21827 | - 0.07842776544f, 0.1231940459f, 0.07842776544f }; | |
21828 | - T I[9] = { 0 }; | |
21829 | - CImg<T> res(_width/2,_height/2,_depth,_spectrum); | |
25772 | + static const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f, | |
25773 | + 0.1231940459f, 0.1935127547f, 0.1231940459f, | |
25774 | + 0.07842776544f, 0.1231940459f, 0.07842776544f }; | |
25775 | + CImg<T> I(9), res(_width/2,_height/2,_depth,_spectrum); | |
21830 | 25776 | T *ptrd = res._data; |
21831 | 25777 | cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T) |
21832 | 25778 | if (x%2 && y%2) *(ptrd++) = (T) |
... | ... | @@ -22895,7 +26841,7 @@ namespace cimg_library_suffixed { |
22895 | 26841 | cimg_forX(res,x) *(ptrd++) = atX(x - (int)*(ptrs0++),y,z,c,0); |
22896 | 26842 | } |
22897 | 26843 | } |
22898 | - } else { // Absolute warp. | |
26844 | + } else { // Backward-absolute warp. | |
22899 | 26845 | if (interpolation==2) { // Cubic interpolation. |
22900 | 26846 | if (boundary_conditions==2) // Periodic boundaries. |
22901 | 26847 | #ifdef cimg_use_openmp |
... | ... | @@ -23073,7 +27019,7 @@ namespace cimg_library_suffixed { |
23073 | 27019 | cimg_forX(res,x) *(ptrd++) = atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c,0); |
23074 | 27020 | } |
23075 | 27021 | } |
23076 | - } else { // Absolute warp. | |
27022 | + } else { // Backward-absolute warp. | |
23077 | 27023 | if (interpolation==2) { // Cubic interpolation. |
23078 | 27024 | if (boundary_conditions==2) // Periodic boundaries. |
23079 | 27025 | #ifdef cimg_use_openmp |
... | ... | @@ -23146,7 +27092,7 @@ namespace cimg_library_suffixed { |
23146 | 27092 | } |
23147 | 27093 | } |
23148 | 27094 | |
23149 | - } else if (warp._spectrum==3) { // 3d warping. | |
27095 | + } else { // 3d warping. | |
23150 | 27096 | if (mode>=3) { // Forward-relative warp. |
23151 | 27097 | res.fill(0); |
23152 | 27098 | if (interpolation>=1) // Linear interpolation. |
... | ... | @@ -23275,7 +27221,7 @@ namespace cimg_library_suffixed { |
23275 | 27221 | cimg_forX(res,x) *(ptrd++) = atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c,0); |
23276 | 27222 | } |
23277 | 27223 | } |
23278 | - } else { // Absolute warp. | |
27224 | + } else { // Backward-absolute warp. | |
23279 | 27225 | if (interpolation==2) { // Cubic interpolation. |
23280 | 27226 | if (boundary_conditions==2) // Periodic boundaries. |
23281 | 27227 | #ifdef cimg_use_openmp |
... | ... | @@ -23989,7 +27935,7 @@ namespace cimg_library_suffixed { |
23989 | 27935 | _cimg_math_parser *mp; |
23990 | 27936 | ~_functor4d_streamline_expr() { delete mp; } |
23991 | 27937 | _functor4d_streamline_expr(const char *const expr):mp(0) { |
23992 | - mp = new _cimg_math_parser(CImg<T>::empty(),expr,"streamline"); | |
27938 | + mp = new _cimg_math_parser(expr,"streamline",CImg<T>::const_empty(),0); | |
23993 | 27939 | } |
23994 | 27940 | float operator()(const float x, const float y, const float z, const unsigned int c) const { |
23995 | 27941 | return (float)(*mp)(x,y,z,c); |
... | ... | @@ -24214,7 +28160,7 @@ namespace cimg_library_suffixed { |
24214 | 28160 | res.assign(_width/dp + (_width%dp?1:0),1,1); |
24215 | 28161 | const unsigned int pe = _width - dp; |
24216 | 28162 | #ifdef cimg_use_openmp |
24217 | -#pragma omp parallel for if (res._width>=128 && _height*_depth*_spectrum>=128) | |
28163 | +#pragma omp parallel for cimg_openmp_if(res._width>=128 && _height*_depth*_spectrum>=128) | |
24218 | 28164 | #endif |
24219 | 28165 | for (unsigned int p = 0; p<pe; p+=dp) |
24220 | 28166 | get_crop(p,0,0,0,p + dp - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]); |
... | ... | @@ -24226,7 +28172,7 @@ namespace cimg_library_suffixed { |
24226 | 28172 | res.assign(_height/dp + (_height%dp?1:0),1,1); |
24227 | 28173 | const unsigned int pe = _height - dp; |
24228 | 28174 | #ifdef cimg_use_openmp |
24229 | -#pragma omp parallel for if (res._width>=128 && _width*_depth*_spectrum>=128) | |
28175 | +#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_depth*_spectrum>=128) | |
24230 | 28176 | #endif |
24231 | 28177 | for (unsigned int p = 0; p<pe; p+=dp) |
24232 | 28178 | get_crop(0,p,0,0,_width - 1,p + dp - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]); |
... | ... | @@ -24238,7 +28184,7 @@ namespace cimg_library_suffixed { |
24238 | 28184 | res.assign(_depth/dp + (_depth%dp?1:0),1,1); |
24239 | 28185 | const unsigned int pe = _depth - dp; |
24240 | 28186 | #ifdef cimg_use_openmp |
24241 | -#pragma omp parallel for if (res._width>=128 && _width*_height*_spectrum>=128) | |
28187 | +#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_height*_spectrum>=128) | |
24242 | 28188 | #endif |
24243 | 28189 | for (unsigned int p = 0; p<pe; p+=dp) |
24244 | 28190 | get_crop(0,0,p,0,_width - 1,_height - 1,p + dp - 1,_spectrum - 1).move_to(res[p/dp]); |
... | ... | @@ -24250,7 +28196,7 @@ namespace cimg_library_suffixed { |
24250 | 28196 | res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1); |
24251 | 28197 | const unsigned int pe = _spectrum - dp; |
24252 | 28198 | #ifdef cimg_use_openmp |
24253 | -#pragma omp parallel for if (res._width>=128 && _width*_height*_depth>=128) | |
28199 | +#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_height*_depth>=128) | |
24254 | 28200 | #endif |
24255 | 28201 | for (unsigned int p = 0; p<pe; p+=dp) |
24256 | 28202 | get_crop(0,0,0,p,_width - 1,_height - 1,_depth - 1,p + dp - 1).move_to(res[p/dp]); |
... | ... | @@ -24558,10 +28504,12 @@ namespace cimg_library_suffixed { |
24558 | 28504 | ((mask._depth==1 && mask._width<=5) || (mask._depth==mask._width && mask._width<=3))) { |
24559 | 28505 | // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with boundary_conditions=1) |
24560 | 28506 | Ttfloat *ptrd = res._data; |
28507 | + CImg<T> I; | |
24561 | 28508 | switch (mask._depth) { |
24562 | 28509 | case 3 : { |
24563 | - T I[27] = { 0 }; | |
28510 | + I.assign(27); | |
24564 | 28511 | cimg_forC(res,c) { |
28512 | + cimg_test_abort(); | |
24565 | 28513 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24566 | 28514 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24567 | 28515 | if (is_normalized) { |
... | ... | @@ -24599,8 +28547,9 @@ namespace cimg_library_suffixed { |
24599 | 28547 | } |
24600 | 28548 | } break; |
24601 | 28549 | case 2 : { |
24602 | - T I[8] = { 0 }; | |
28550 | + I.assign(8); | |
24603 | 28551 | cimg_forC(res,c) { |
28552 | + cimg_test_abort(); | |
24604 | 28553 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24605 | 28554 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24606 | 28555 | if (is_normalized) { |
... | ... | @@ -24626,8 +28575,9 @@ namespace cimg_library_suffixed { |
24626 | 28575 | case 1 : |
24627 | 28576 | switch (mask._width) { |
24628 | 28577 | case 6 : { |
24629 | - T I[36] = { 0 }; | |
28578 | + I.assign(36); | |
24630 | 28579 | cimg_forC(res,c) { |
28580 | + cimg_test_abort(); | |
24631 | 28581 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24632 | 28582 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24633 | 28583 | if (is_normalized) { |
... | ... | @@ -24665,8 +28615,9 @@ namespace cimg_library_suffixed { |
24665 | 28615 | } |
24666 | 28616 | } break; |
24667 | 28617 | case 5 : { |
24668 | - T I[25] = { 0 }; | |
28618 | + I.assign(25); | |
24669 | 28619 | cimg_forC(res,c) { |
28620 | + cimg_test_abort(); | |
24670 | 28621 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24671 | 28622 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24672 | 28623 | if (is_normalized) { |
... | ... | @@ -24696,8 +28647,9 @@ namespace cimg_library_suffixed { |
24696 | 28647 | } |
24697 | 28648 | } break; |
24698 | 28649 | case 4 : { |
24699 | - T I[16] = { 0 }; | |
28650 | + I.assign(16); | |
24700 | 28651 | cimg_forC(res,c) { |
28652 | + cimg_test_abort(); | |
24701 | 28653 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24702 | 28654 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24703 | 28655 | if (is_normalized) { |
... | ... | @@ -24721,8 +28673,9 @@ namespace cimg_library_suffixed { |
24721 | 28673 | } |
24722 | 28674 | } break; |
24723 | 28675 | case 3 : { |
24724 | - T I[9] = { 0 }; | |
28676 | + I.assign(9); | |
24725 | 28677 | cimg_forC(res,c) { |
28678 | + cimg_test_abort(); | |
24726 | 28679 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24727 | 28680 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24728 | 28681 | if (is_normalized) { |
... | ... | @@ -24742,8 +28695,9 @@ namespace cimg_library_suffixed { |
24742 | 28695 | } |
24743 | 28696 | } break; |
24744 | 28697 | case 2 : { |
24745 | - T I[4] = { 0 }; | |
28698 | + I.assign(4); | |
24746 | 28699 | cimg_forC(res,c) { |
28700 | + cimg_test_abort(); | |
24747 | 28701 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24748 | 28702 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24749 | 28703 | if (is_normalized) { |
... | ... | @@ -24762,6 +28716,7 @@ namespace cimg_library_suffixed { |
24762 | 28716 | case 1 : |
24763 | 28717 | if (is_normalized) res.fill(1); |
24764 | 28718 | else cimg_forC(res,c) { |
28719 | + cimg_test_abort(); | |
24765 | 28720 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24766 | 28721 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24767 | 28722 | res.get_shared_channel(c).assign(_img)*=_mask[0]; |
... | ... | @@ -24769,15 +28724,16 @@ namespace cimg_library_suffixed { |
24769 | 28724 | break; |
24770 | 28725 | } |
24771 | 28726 | } |
24772 | - } else { // Generic version for other masks and borders conditions. | |
28727 | + } else { // Generic version for other masks and boundary conditions. | |
24773 | 28728 | const int |
24774 | 28729 | mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2, |
24775 | 28730 | mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), |
24776 | 28731 | mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; |
24777 | 28732 | #ifdef cimg_use_openmp |
24778 | -#pragma omp parallel for if (res._spectrum>=2) | |
28733 | +#pragma omp parallel for cimg_openmp_if(res._spectrum>=2) | |
24779 | 28734 | #endif |
24780 | 28735 | cimg_forC(res,c) { |
28736 | + cimg_test_abort(); | |
24781 | 28737 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
24782 | 28738 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
24783 | 28739 | if (is_normalized) { // Normalized correlation. |
... | ... | @@ -25009,9 +28965,10 @@ namespace cimg_library_suffixed { |
25009 | 28965 | mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), |
25010 | 28966 | mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; |
25011 | 28967 | #ifdef cimg_use_openmp |
25012 | -#pragma omp parallel for if (_spectrum>=2) | |
28968 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) | |
25013 | 28969 | #endif |
25014 | 28970 | cimg_forC(*this,c) { |
28971 | + cimg_test_abort(); | |
25015 | 28972 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
25016 | 28973 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
25017 | 28974 | if (is_normalized) { // Normalized erosion. |
... | ... | @@ -25298,9 +29255,10 @@ namespace cimg_library_suffixed { |
25298 | 29255 | mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), |
25299 | 29256 | mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; |
25300 | 29257 | #ifdef cimg_use_openmp |
25301 | -#pragma omp parallel for if (_spectrum>=2) | |
29258 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) | |
25302 | 29259 | #endif |
25303 | 29260 | cimg_forC(*this,c) { |
29261 | + cimg_test_abort(); | |
25304 | 29262 | const CImg<T> _img = get_shared_channel(c%_spectrum); |
25305 | 29263 | const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); |
25306 | 29264 | if (is_normalized) { // Normalized dilation. |
... | ... | @@ -25614,44 +29572,44 @@ namespace cimg_library_suffixed { |
25614 | 29572 | |
25615 | 29573 | // Check labels of the neighbors. |
25616 | 29574 | bool is_same_label = true; |
25617 | - unsigned int label = 0; | |
29575 | + T label = 0; | |
25618 | 29576 | if (x - 1>=0) { |
25619 | 29577 | if ((*this)(x - 1,y,z)) { |
25620 | - if (!label) label = (unsigned int)(*this)(x - 1,y,z); | |
29578 | + if (!label) label = (*this)(x - 1,y,z); | |
25621 | 29579 | else if (label!=(*this)(x - 1,y,z)) is_same_label = false; |
25622 | 29580 | } else Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z); |
25623 | 29581 | } |
25624 | 29582 | if (x + 1<width()) { |
25625 | 29583 | if ((*this)(x + 1,y,z)) { |
25626 | - if (!label) label = (unsigned int)(*this)(x + 1,y,z); | |
29584 | + if (!label) label = (*this)(x + 1,y,z); | |
25627 | 29585 | else if (label!=(*this)(x + 1,y,z)) is_same_label = false; |
25628 | 29586 | } else Q._priority_queue_insert(is_queued,sizeQ,priority(x + 1,y,z),x + 1,y,z); |
25629 | 29587 | } |
25630 | 29588 | if (y - 1>=0) { |
25631 | 29589 | if ((*this)(x,y - 1,z)) { |
25632 | - if (!label) label = (unsigned int)(*this)(x,y - 1,z); | |
29590 | + if (!label) label = (*this)(x,y - 1,z); | |
25633 | 29591 | else if (label!=(*this)(x,y - 1,z)) is_same_label = false; |
25634 | 29592 | } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z); |
25635 | 29593 | } |
25636 | 29594 | if (y + 1<height()) { |
25637 | 29595 | if ((*this)(x,y + 1,z)) { |
25638 | - if (!label) label = (unsigned int)(*this)(x,y + 1,z); | |
29596 | + if (!label) label = (*this)(x,y + 1,z); | |
25639 | 29597 | else if (label!=(*this)(x,y + 1,z)) is_same_label = false; |
25640 | 29598 | } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y + 1,z),x,y + 1,z); |
25641 | 29599 | } |
25642 | 29600 | if (z - 1>=0) { |
25643 | 29601 | if ((*this)(x,y,z - 1)) { |
25644 | - if (!label) label = (unsigned int)(*this)(x,y,z - 1); | |
29602 | + if (!label) label = (*this)(x,y,z - 1); | |
25645 | 29603 | else if (label!=(*this)(x,y,z - 1)) is_same_label = false; |
25646 | 29604 | } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1); |
25647 | 29605 | } |
25648 | 29606 | if (z + 1<depth()) { |
25649 | 29607 | if ((*this)(x,y,z + 1)) { |
25650 | - if (!label) label = (unsigned int)(*this)(x,y,z + 1); | |
29608 | + if (!label) label = (*this)(x,y,z + 1); | |
25651 | 29609 | else if (label!=(*this)(x,y,z + 1)) is_same_label = false; |
25652 | 29610 | } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z + 1),x,y,z + 1); |
25653 | 29611 | } |
25654 | - if (is_same_label) (*this)(x,y,z) = (T)label; | |
29612 | + if (is_same_label) (*this)(x,y,z) = label; | |
25655 | 29613 | } |
25656 | 29614 | |
25657 | 29615 | // Fill lines. |
... | ... | @@ -26181,6 +30139,7 @@ namespace cimg_library_suffixed { |
26181 | 30139 | Tfloat *ptrd = velocity._data, veloc_max = 0; |
26182 | 30140 | if (is_3d) // 3d version |
26183 | 30141 | cimg_forC(*this,c) { |
30142 | + cimg_test_abort(); | |
26184 | 30143 | CImg_3x3x3(I,Tfloat); |
26185 | 30144 | cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { |
26186 | 30145 | const Tfloat |
... | ... | @@ -26198,6 +30157,7 @@ namespace cimg_library_suffixed { |
26198 | 30157 | } |
26199 | 30158 | else // 2d version |
26200 | 30159 | cimg_forZC(*this,z,c) { |
30160 | + cimg_test_abort(); | |
26201 | 30161 | CImg_3x3(I,Tfloat); |
26202 | 30162 | cimg_for3x3(*this,x,y,z,c,I,Tfloat) { |
26203 | 30163 | const Tfloat |
... | ... | @@ -26245,6 +30205,7 @@ namespace cimg_library_suffixed { |
26245 | 30205 | *(pd3++) = (Tfloat)n; |
26246 | 30206 | } |
26247 | 30207 | |
30208 | + cimg_test_abort(); | |
26248 | 30209 | #ifdef cimg_use_openmp |
26249 | 30210 | #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=2) firstprivate(val) |
26250 | 30211 | #endif |
... | ... | @@ -26338,8 +30299,9 @@ namespace cimg_library_suffixed { |
26338 | 30299 | *(pd2++) = (Tfloat)n; |
26339 | 30300 | } |
26340 | 30301 | |
30302 | + cimg_test_abort(); | |
26341 | 30303 | #ifdef cimg_use_openmp |
26342 | -#pragma omp parallel for if (_width>=256 && _height>=2) firstprivate(val) | |
30304 | +#pragma omp parallel for cimg_openmp_if(_width>=256 && _height>=2) firstprivate(val) | |
26343 | 30305 | #endif |
26344 | 30306 | cimg_forXY(*this,x,y) { |
26345 | 30307 | val.fill(0); |
... | ... | @@ -27017,7 +30979,7 @@ namespace cimg_library_suffixed { |
27017 | 30979 | const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1; |
27018 | 30980 | if (is_fast_approx) |
27019 | 30981 | #ifdef cimg_use_openmp |
27020 | -#pragma omp parallel for if (res._width>=32 && res._height>=4) firstprivate(P,Q) | |
30982 | +#pragma omp parallel for cimg_openmp_if(res._width>=32 && res._height>=4) firstprivate(P,Q) | |
27021 | 30983 | #endif |
27022 | 30984 | cimg_forXY(res,x,y) { // 2d fast approximation. |
27023 | 30985 | P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); |
... | ... | @@ -27036,7 +30998,7 @@ namespace cimg_library_suffixed { |
27036 | 30998 | else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); |
27037 | 30999 | } else |
27038 | 31000 | #ifdef cimg_use_openmp |
27039 | -#pragma omp parallel for if (res._width>=32 && res._height>=4) firstprivate(P,Q) | |
31001 | +#pragma omp parallel for cimg_openmp_if(res._width>=32 && res._height>=4) firstprivate(P,Q) | |
27040 | 31002 | #endif |
27041 | 31003 | cimg_forXY(res,x,y) { // 2d exact algorithm. |
27042 | 31004 | P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); |
... | ... | @@ -27130,7 +31092,7 @@ namespace cimg_library_suffixed { |
27130 | 31092 | else switch (n) { // Without threshold. |
27131 | 31093 | case 3 : { |
27132 | 31094 | #ifdef cimg_use_openmp |
27133 | -#pragma omp parallel for if (_spectrum>=2) | |
31095 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) | |
27134 | 31096 | #endif |
27135 | 31097 | cimg_forC(*this,c) { |
27136 | 31098 | T I[9] = { 0 }; |
... | ... | @@ -27150,7 +31112,7 @@ namespace cimg_library_suffixed { |
27150 | 31112 | } break; |
27151 | 31113 | case 5 : { |
27152 | 31114 | #ifdef cimg_use_openmp |
27153 | -#pragma omp parallel for if (_spectrum>=2) | |
31115 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) | |
27154 | 31116 | #endif |
27155 | 31117 | cimg_forC(*this,c) { |
27156 | 31118 | T I[25] = { 0 }; |
... | ... | @@ -27209,9 +31171,10 @@ namespace cimg_library_suffixed { |
27209 | 31171 | } |
27210 | 31172 | } else { // 1d |
27211 | 31173 | |
31174 | + CImg<T> I; | |
27212 | 31175 | if (threshold>0) |
27213 | 31176 | #ifdef cimg_use_openmp |
27214 | -#pragma omp parallel for if (_width>=16 && _spectrum>=2) | |
31177 | +#pragma omp parallel for cimg_openmp_if(_width>=16 && _spectrum>=2) | |
27215 | 31178 | #endif |
27216 | 31179 | cimg_forXC(*this,x,c) { // With threshold. |
27217 | 31180 | const int |
... | ... | @@ -27228,26 +31191,26 @@ namespace cimg_library_suffixed { |
27228 | 31191 | else switch (n) { // Without threshold. |
27229 | 31192 | case 2 : { |
27230 | 31193 | #ifdef cimg_use_openmp |
27231 | -#pragma omp parallel for if (_spectrum>=2) | |
31194 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) | |
27232 | 31195 | #endif |
27233 | 31196 | cimg_forC(*this,c) { |
27234 | - T I[4] = { 0 }; | |
31197 | + I.assign(4); | |
27235 | 31198 | cimg_for2x2(*this,x,y,0,c,I,T) res(x,c) = (T)(0.5f*(I[0] + I[1])); |
27236 | 31199 | } |
27237 | 31200 | } break; |
27238 | 31201 | case 3 : { |
27239 | 31202 | #ifdef cimg_use_openmp |
27240 | -#pragma omp parallel for if (_spectrum>=2) | |
31203 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) | |
27241 | 31204 | #endif |
27242 | 31205 | cimg_forC(*this,c) { |
27243 | - T I[9] = { 0 }; | |
31206 | + I.assign(9); | |
27244 | 31207 | cimg_for3x3(*this,x,y,0,c,I,T) |
27245 | 31208 | res(x,c) = I[3]<I[4]?(I[4]<I[5]?I[4]:(I[3]<I[5]?I[5]:I[3])):(I[3]<I[5]?I[3]:(I[4]<I[5]?I[5]:I[4])); |
27246 | 31209 | } |
27247 | 31210 | } break; |
27248 | 31211 | default : { |
27249 | 31212 | #ifdef cimg_use_openmp |
27250 | -#pragma omp parallel for if (_width>=16 && _spectrum>=2) | |
31213 | +#pragma omp parallel for cimg_openmp_if(_width>=16 && _spectrum>=2) | |
27251 | 31214 | #endif |
27252 | 31215 | cimg_forXC(*this,x,c) { |
27253 | 31216 | const int |
... | ... | @@ -27300,7 +31263,7 @@ namespace cimg_library_suffixed { |
27300 | 31263 | } |
27301 | 31264 | } |
27302 | 31265 | #ifdef cimg_use_openmp |
27303 | -#pragma omp parallel for if (_width*_height*_depth>=512 && _spectrum>=2) | |
31266 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=512 && _spectrum>=2) | |
27304 | 31267 | #endif |
27305 | 31268 | cimg_forC(*this,c) { |
27306 | 31269 | Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; |
... | ... | @@ -27347,7 +31310,7 @@ namespace cimg_library_suffixed { |
27347 | 31310 | CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors()); |
27348 | 31311 | if (sigma>0) G.blur(sigma); |
27349 | 31312 | #ifdef cimg_use_openmp |
27350 | -#pragma omp parallel for if (_width>=32 && _height>=16) | |
31313 | +#pragma omp parallel for cimg_openmp_if(_width>=32 && _height>=16) | |
27351 | 31314 | #endif |
27352 | 31315 | cimg_forY(G,y) { |
27353 | 31316 | CImg<Tfloat> val, vec; |
... | ... | @@ -27362,7 +31325,7 @@ namespace cimg_library_suffixed { |
27362 | 31325 | } |
27363 | 31326 | } |
27364 | 31327 | #ifdef cimg_use_openmp |
27365 | -#pragma omp parallel for if (_width*_height>=512 && _spectrum>=2) | |
31328 | +#pragma omp parallel for cimg_openmp_if(_width*_height>=512 && _spectrum>=2) | |
27366 | 31329 | #endif |
27367 | 31330 | cimg_forC(*this,c) { |
27368 | 31331 | Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; |
... | ... | @@ -27444,7 +31407,7 @@ namespace cimg_library_suffixed { |
27444 | 31407 | switch (scheme) { // 3d. |
27445 | 31408 | case -1 : { // Backward finite differences. |
27446 | 31409 | #ifdef cimg_use_openmp |
27447 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31410 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27448 | 31411 | #endif |
27449 | 31412 | cimg_forC(*this,c) { |
27450 | 31413 | const unsigned long off = c*_width*_height*_depth; |
... | ... | @@ -27459,7 +31422,7 @@ namespace cimg_library_suffixed { |
27459 | 31422 | } break; |
27460 | 31423 | case 1 : { // Forward finite differences. |
27461 | 31424 | #ifdef cimg_use_openmp |
27462 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31425 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27463 | 31426 | #endif |
27464 | 31427 | cimg_forC(*this,c) { |
27465 | 31428 | const unsigned long off = c*_width*_height*_depth; |
... | ... | @@ -27484,7 +31447,7 @@ namespace cimg_library_suffixed { |
27484 | 31447 | } break; |
27485 | 31448 | default : { // Central finite differences. |
27486 | 31449 | #ifdef cimg_use_openmp |
27487 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31450 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27488 | 31451 | #endif |
27489 | 31452 | cimg_forC(*this,c) { |
27490 | 31453 | const unsigned long off = c*_width*_height*_depth; |
... | ... | @@ -27612,7 +31575,7 @@ namespace cimg_library_suffixed { |
27612 | 31575 | if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3d |
27613 | 31576 | |
27614 | 31577 | #ifdef cimg_use_openmp |
27615 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31578 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27616 | 31579 | #endif |
27617 | 31580 | cimg_forC(*this,c) { |
27618 | 31581 | const unsigned long off = c*_width*_height*_depth; |
... | ... | @@ -27673,7 +31636,7 @@ namespace cimg_library_suffixed { |
27673 | 31636 | else if (axis1=='x' && axis2=='z') { // Ixz |
27674 | 31637 | valid_axis = true; |
27675 | 31638 | #ifdef cimg_use_openmp |
27676 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31639 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27677 | 31640 | #endif |
27678 | 31641 | cimg_forC(*this,c) { |
27679 | 31642 | Tfloat *ptrd = res[l2].data(0,0,0,c); |
... | ... | @@ -27695,7 +31658,7 @@ namespace cimg_library_suffixed { |
27695 | 31658 | else if (axis1=='y' && axis2=='z') { // Iyz |
27696 | 31659 | valid_axis = true; |
27697 | 31660 | #ifdef cimg_use_openmp |
27698 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31661 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27699 | 31662 | #endif |
27700 | 31663 | cimg_forC(*this,c) { |
27701 | 31664 | Tfloat *ptrd = res[l2].data(0,0,0,c); |
... | ... | @@ -27706,7 +31669,7 @@ namespace cimg_library_suffixed { |
27706 | 31669 | else if (axis1=='z' && axis2=='z') { // Izz |
27707 | 31670 | valid_axis = true; |
27708 | 31671 | #ifdef cimg_use_openmp |
27709 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31672 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27710 | 31673 | #endif |
27711 | 31674 | cimg_forC(*this,c) { |
27712 | 31675 | Tfloat *ptrd = res[l2].data(0,0,0,c); |
... | ... | @@ -27734,7 +31697,7 @@ namespace cimg_library_suffixed { |
27734 | 31697 | CImg<Tfloat> res(_width,_height,_depth,_spectrum); |
27735 | 31698 | if (_depth>1) { // 3d |
27736 | 31699 | #ifdef cimg_use_openmp |
27737 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31700 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27738 | 31701 | #endif |
27739 | 31702 | cimg_forC(*this,c) { |
27740 | 31703 | Tfloat *ptrd = res.data(0,0,0,c); |
... | ... | @@ -27743,7 +31706,7 @@ namespace cimg_library_suffixed { |
27743 | 31706 | } |
27744 | 31707 | } else if (_height>1) { // 2d |
27745 | 31708 | #ifdef cimg_use_openmp |
27746 | -#pragma omp parallel for if (_width*_height>=1048576 && _depth*_spectrum>=2) | |
31709 | +#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2) | |
27747 | 31710 | #endif |
27748 | 31711 | cimg_forC(*this,c) { |
27749 | 31712 | Tfloat *ptrd = res.data(0,0,0,c); |
... | ... | @@ -27752,7 +31715,7 @@ namespace cimg_library_suffixed { |
27752 | 31715 | } |
27753 | 31716 | } else { // 1d |
27754 | 31717 | #ifdef cimg_use_openmp |
27755 | -#pragma omp parallel for if (_width>=1048576 && _height*_depth*_spectrum>=2) | |
31718 | +#pragma omp parallel for cimg_openmp_if(_width>=1048576 && _height*_depth*_spectrum>=2) | |
27756 | 31719 | #endif |
27757 | 31720 | cimg_forC(*this,c) { |
27758 | 31721 | Tfloat *ptrd = res.data(0,0,0,c); |
... | ... | @@ -27765,22 +31728,21 @@ namespace cimg_library_suffixed { |
27765 | 31728 | |
27766 | 31729 | //! Compute the structure tensor field of an image. |
27767 | 31730 | /** |
27768 | - \param scheme Numerical scheme. Can be <tt>{ 0=central | 1=fwd/bwd1 | 2=fwd/bwd2 }</tt> | |
31731 | + \param is_fwbw_scheme scheme. Can be <tt>{ false=centered | true=forward-backward }</tt> | |
27769 | 31732 | **/ |
27770 | - CImg<T>& structure_tensors(const unsigned int scheme=2) { | |
27771 | - return get_structure_tensors(scheme).move_to(*this); | |
31733 | + CImg<T>& structure_tensors(const bool is_fwbw_scheme=false) { | |
31734 | + return get_structure_tensors(is_fwbw_scheme).move_to(*this); | |
27772 | 31735 | } |
27773 | 31736 | |
27774 | 31737 | //! Compute the structure tensor field of an image \newinstance. |
27775 | - CImg<Tfloat> get_structure_tensors(const unsigned int scheme=2) const { | |
31738 | + CImg<Tfloat> get_structure_tensors(const bool is_fwbw_scheme=false) const { | |
27776 | 31739 | if (is_empty()) return *this; |
27777 | 31740 | CImg<Tfloat> res; |
27778 | 31741 | if (_depth>1) { // 3d |
27779 | 31742 | res.assign(_width,_height,_depth,6,0); |
27780 | - switch (scheme) { | |
27781 | - case 0 : { // classical central finite differences | |
31743 | + if (!is_fwbw_scheme) { // Classical central finite differences | |
27782 | 31744 | #ifdef cimg_use_openmp |
27783 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31745 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27784 | 31746 | #endif |
27785 | 31747 | cimg_forC(*this,c) { |
27786 | 31748 | Tfloat |
... | ... | @@ -27800,33 +31762,9 @@ namespace cimg_library_suffixed { |
27800 | 31762 | *(ptrd5++)+=iz*iz; |
27801 | 31763 | } |
27802 | 31764 | } |
27803 | - } break; | |
27804 | - case 1 : { // Forward/backward finite differences (version 1). | |
27805 | -#ifdef cimg_use_openmp | |
27806 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
27807 | -#endif | |
27808 | - cimg_forC(*this,c) { | |
27809 | - Tfloat | |
27810 | - *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), | |
27811 | - *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); | |
27812 | - CImg_3x3x3(I,Tfloat); | |
27813 | - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { | |
27814 | - const Tfloat | |
27815 | - ixf = Incc - Iccc, ixb = Iccc - Ipcc, | |
27816 | - iyf = Icnc - Iccc, iyb = Iccc - Icpc, | |
27817 | - izf = Iccn - Iccc, izb = Iccc - Iccp; | |
27818 | - *(ptrd0++)+=(ixf*ixf + 2*ixf*ixb + ixb*ixb)/4; | |
27819 | - *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4; | |
27820 | - *(ptrd2++)+=(ixf*izf + ixf*izb + ixb*izf + ixb*izb)/4; | |
27821 | - *(ptrd3++)+=(iyf*iyf + 2*iyf*iyb + iyb*iyb)/4; | |
27822 | - *(ptrd4++)+=(iyf*izf + iyf*izb + iyb*izf + iyb*izb)/4; | |
27823 | - *(ptrd5++)+=(izf*izf + 2*izf*izb + izb*izb)/4; | |
27824 | - } | |
27825 | - } | |
27826 | - } break; | |
27827 | - default : { // Forward/backward finite differences (version 2). | |
31765 | + } else { // Forward/backward finite differences. | |
27828 | 31766 | #ifdef cimg_use_openmp |
27829 | -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) | |
31767 | +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2) | |
27830 | 31768 | #endif |
27831 | 31769 | cimg_forC(*this,c) { |
27832 | 31770 | Tfloat |
... | ... | @@ -27846,14 +31784,12 @@ namespace cimg_library_suffixed { |
27846 | 31784 | *(ptrd5++)+=(izf*izf + izb*izb)/2; |
27847 | 31785 | } |
27848 | 31786 | } |
27849 | - } break; | |
27850 | 31787 | } |
27851 | 31788 | } else { // 2d |
27852 | 31789 | res.assign(_width,_height,_depth,3,0); |
27853 | - switch (scheme) { | |
27854 | - case 0 : { // classical central finite differences | |
31790 | + if (!is_fwbw_scheme) { // Classical central finite differences | |
27855 | 31791 | #ifdef cimg_use_openmp |
27856 | -#pragma omp parallel for if (_width*_height>=1048576 && _depth*_spectrum>=2) | |
31792 | +#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2) | |
27857 | 31793 | #endif |
27858 | 31794 | cimg_forC(*this,c) { |
27859 | 31795 | Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); |
... | ... | @@ -27867,27 +31803,9 @@ namespace cimg_library_suffixed { |
27867 | 31803 | *(ptrd2++)+=iy*iy; |
27868 | 31804 | } |
27869 | 31805 | } |
27870 | - } break; | |
27871 | - case 1 : { // Forward/backward finite differences (version 1). | |
31806 | + } else { // Forward/backward finite differences (version 2). | |
27872 | 31807 | #ifdef cimg_use_openmp |
27873 | -#pragma omp parallel for if (_width*_height>=1048576 && _depth*_spectrum>=2) | |
27874 | -#endif | |
27875 | - cimg_forC(*this,c) { | |
27876 | - Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); | |
27877 | - CImg_3x3(I,Tfloat); | |
27878 | - cimg_for3x3(*this,x,y,0,c,I,Tfloat) { | |
27879 | - const Tfloat | |
27880 | - ixf = Inc - Icc, ixb = Icc - Ipc, | |
27881 | - iyf = Icn - Icc, iyb = Icc - Icp; | |
27882 | - *(ptrd0++)+=(ixf*ixf + 2*ixf*ixb + ixb*ixb)/4; | |
27883 | - *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4; | |
27884 | - *(ptrd2++)+=(iyf*iyf + 2*iyf*iyb + iyb*iyb)/4; | |
27885 | - } | |
27886 | - } | |
27887 | - } break; | |
27888 | - default : { // Forward/backward finite differences (version 2). | |
27889 | -#ifdef cimg_use_openmp | |
27890 | -#pragma omp parallel for if (_width*_height>=1048576 && _depth*_spectrum>=2) | |
31808 | +#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2) | |
27891 | 31809 | #endif |
27892 | 31810 | cimg_forC(*this,c) { |
27893 | 31811 | Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); |
... | ... | @@ -27901,7 +31819,6 @@ namespace cimg_library_suffixed { |
27901 | 31819 | *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2; |
27902 | 31820 | } |
27903 | 31821 | } |
27904 | - } break; | |
27905 | 31822 | } |
27906 | 31823 | } |
27907 | 31824 | return res; |
... | ... | @@ -27992,14 +31909,15 @@ namespace cimg_library_suffixed { |
27992 | 31909 | \param nb_scales Number of scales used to estimate the displacement field. |
27993 | 31910 | \param iteration_max Maximum number of iterations allowed for one scale. |
27994 | 31911 | \param is_backward If false, match I2(X + U(X)) = I1(X), else match I2(X) = I1(X - U(X)). |
27995 | - \param constraints A list of constrained pixels (as a Nx4 or Nx6 image), i.e defining N points | |
27996 | - of the estimated flow having a known value. | |
31912 | + \param guide Image used as the initial correspondence estimate for the algorithm. | |
31913 | + 'guide' may have a last channel with boolean values (0=false | other=true) that | |
31914 | + tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask). | |
27997 | 31915 | **/ |
27998 | 31916 | CImg<T>& displacement(const CImg<T>& source, const float smoothness=0.1f, const float precision=5.0f, |
27999 | 31917 | const unsigned int nb_scales=0, const unsigned int iteration_max=10000, |
28000 | 31918 | const bool is_backward=false, |
28001 | - const CImg<floatT>& constraints=CImg<floatT>::empty()) { | |
28002 | - return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,constraints). | |
31919 | + const CImg<floatT>& guide=CImg<floatT>::const_empty()) { | |
31920 | + return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,guide). | |
28003 | 31921 | move_to(*this); |
28004 | 31922 | } |
28005 | 31923 | |
... | ... | @@ -28008,7 +31926,7 @@ namespace cimg_library_suffixed { |
28008 | 31926 | const float smoothness=0.1f, const float precision=5.0f, |
28009 | 31927 | const unsigned int nb_scales=0, const unsigned int iteration_max=10000, |
28010 | 31928 | const bool is_backward=false, |
28011 | - const CImg<floatT>& constraints=CImg<floatT>::empty()) const { | |
31929 | + const CImg<floatT>& guide=CImg<floatT>::const_empty()) const { | |
28012 | 31930 | if (is_empty() || !source) return +*this; |
28013 | 31931 | if (!is_sameXYZC(source)) |
28014 | 31932 | throw CImgArgumentException(_cimg_instance |
... | ... | @@ -28022,7 +31940,18 @@ namespace cimg_library_suffixed { |
28022 | 31940 | "(should be >=0)", |
28023 | 31941 | cimg_instance, |
28024 | 31942 | precision); |
31943 | + | |
28025 | 31944 | const bool is_3d = source._depth>1; |
31945 | + const unsigned int constraint = is_3d?3:2; | |
31946 | + | |
31947 | + if (guide && | |
31948 | + (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<constraint)) | |
31949 | + throw CImgArgumentException(_cimg_instance | |
31950 | + "displacement(): Specified guide (%u,%u,%u,%u,%p) " | |
31951 | + "has invalid dimensions.", | |
31952 | + cimg_instance, | |
31953 | + guide._width,guide._height,guide._depth,guide._spectrum,guide._data); | |
31954 | + | |
28026 | 31955 | const unsigned int |
28027 | 31956 | mins = is_3d?cimg::min(_width,_height,_depth):cimg::min(_width,_height), |
28028 | 31957 | _nb_scales = nb_scales>0?nb_scales: |
... | ... | @@ -28032,14 +31961,7 @@ namespace cimg_library_suffixed { |
28032 | 31961 | float sm, sM = source.max_min(sm), tm, tM = max_min(tm); |
28033 | 31962 | const float sdelta = sm==sM?1:(sM - sm), tdelta = tm==tM?1:(tM - tm); |
28034 | 31963 | |
28035 | - if (constraints && (constraints.height()!=4 || is_3d) && (constraints.height()!=6 || !is_3d)) | |
28036 | - throw CImgArgumentException(_cimg_instance | |
28037 | - "displacement(): Invalid specified constraints image (%u,%u,%u,%u,%p) " | |
28038 | - " (should be a Nx4 or Nx6 image).", | |
28039 | - cimg_instance, | |
28040 | - constraints._width,constraints._height,constraints._depth,constraints._spectrum, | |
28041 | - constraints._data); | |
28042 | - CImg<floatT> U; | |
31964 | + CImg<floatT> U, V; | |
28043 | 31965 | floatT bound = 0; |
28044 | 31966 | for (int scale = (int)_nb_scales - 1; scale>=0; --scale) { |
28045 | 31967 | const float factor = (float)std::pow(1.5,(double)scale); |
... | ... | @@ -28051,36 +31973,21 @@ namespace cimg_library_suffixed { |
28051 | 31973 | const CImg<Tfloat> |
28052 | 31974 | I1 = (source.get_resize(sw,sh,sd,-100,2)-=sm)/=sdelta, |
28053 | 31975 | I2 = (get_resize(I1,2)-=tm)/=tdelta; |
31976 | + if (guide._spectrum>constraint) guide.get_resize(I2._width,I2._height,I2._depth,-100,1).move_to(V); | |
28054 | 31977 | if (U) (U*=1.5f).resize(I2._width,I2._height,I2._depth,-100,3); |
28055 | - else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0); | |
28056 | - if (constraints) { | |
28057 | - if (is_3d) cimg_forX(constraints,k) { | |
28058 | - const int | |
28059 | - cx = (int)(constraints(k,0)*U.width()/width()), | |
28060 | - cy = (int)(constraints(k,1)*U.height()/height()), | |
28061 | - cz = (int)(constraints(k,2)*U.depth()/depth()); | |
28062 | - if (U.contains(U(cx,cy,cz))) { | |
28063 | - U(cx,cy,cz,0) = (float)(constraints(k,3)/factor); | |
28064 | - U(cx,cy,cz,1) = (float)(constraints(k,4)/factor); | |
28065 | - U(cx,cy,cz,2) = (float)(constraints(k,5)/factor); | |
28066 | - } | |
28067 | - } | |
28068 | - else cimg_forX(constraints,k) { | |
28069 | - const int | |
28070 | - cx = (int)(constraints(k,0)*U.width()/width()), | |
28071 | - cy = (int)(constraints(k,1)*U.height()/height()); | |
28072 | - if (U.contains(U(cx,cy))) { | |
28073 | - U(cx,cy,0) = (float)(constraints(k,2)/factor); | |
28074 | - U(cx,cy,1) = (float)(constraints(k,3)/factor); | |
28075 | - } | |
28076 | - } | |
31978 | + else { | |
31979 | + if (guide) | |
31980 | + guide.get_shared_channels(0,is_3d?2:1).get_resize(I2._width,I2._height,I2._depth,-100,2).move_to(U); | |
31981 | + else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0); | |
28077 | 31982 | } |
28078 | 31983 | |
28079 | 31984 | float dt = 2, energy = cimg::type<float>::max(); |
28080 | 31985 | const CImgList<Tfloat> dI = is_backward?I1.get_gradient():I2.get_gradient(); |
28081 | 31986 | |
28082 | 31987 | for (unsigned int iteration = 0; iteration<iteration_max; ++iteration) { |
31988 | + cimg_test_abort(); | |
28083 | 31989 | float _energy = 0; |
31990 | + | |
28084 | 31991 | if (is_3d) { // 3d version. |
28085 | 31992 | if (smoothness>=0) // Isotropic regularization. |
28086 | 31993 | #ifdef cimg_use_openmp |
... | ... | @@ -28127,6 +32034,11 @@ namespace cimg_library_suffixed { |
28127 | 32034 | } |
28128 | 32035 | _energy+=delta_I*delta_I + smoothness*_energy_regul; |
28129 | 32036 | } |
32037 | + if (V) cimg_forXYZ(V,x,y,z) if (V(x,y,z,3)) { // Apply constraints. | |
32038 | + U(x,y,z,0) = V(x,y,z,0)/factor; | |
32039 | + U(x,y,z,1) = V(x,y,z,1)/factor; | |
32040 | + U(x,y,z,2) = V(x,y,z,2)/factor; | |
32041 | + } | |
28130 | 32042 | } else { // Anisotropic regularization. |
28131 | 32043 | const float nsmoothness = -smoothness; |
28132 | 32044 | #ifdef cimg_use_openmp |
... | ... | @@ -28188,23 +32100,17 @@ namespace cimg_library_suffixed { |
28188 | 32100 | } |
28189 | 32101 | _energy+=delta_I*delta_I + nsmoothness*_energy_regul; |
28190 | 32102 | } |
32103 | + if (V) cimg_forXYZ(V,x,y,z) if (V(x,y,z,3)) { // Apply constraints. | |
32104 | + U(x,y,z,0) = V(x,y,z,0)/factor; | |
32105 | + U(x,y,z,1) = V(x,y,z,1)/factor; | |
32106 | + U(x,y,z,2) = V(x,y,z,2)/factor; | |
32107 | + } | |
28191 | 32108 | } |
28192 | 32109 | } |
28193 | - if (constraints) cimg_forX(constraints,k) { | |
28194 | - const int | |
28195 | - cx = (int)(constraints(k,0)*U.width()/width()), | |
28196 | - cy = (int)(constraints(k,1)*U.height()/height()), | |
28197 | - cz = (int)(constraints(k,2)*U.depth()/depth()); | |
28198 | - if (U.contains(U(cx,cy,cz))) { | |
28199 | - U(cx,cy,cz,0) = (float)(constraints(k,3)/factor); | |
28200 | - U(cx,cy,cz,1) = (float)(constraints(k,4)/factor); | |
28201 | - U(cx,cy,cz,2) = (float)(constraints(k,5)/factor); | |
28202 | - } | |
28203 | - } | |
28204 | 32110 | } else { // 2d version. |
28205 | 32111 | if (smoothness>=0) // Isotropic regularization. |
28206 | 32112 | #ifdef cimg_use_openmp |
28207 | -#pragma omp parallel for if (_height>=8 && _width>=16) reduction(+:_energy) | |
32113 | +#pragma omp parallel for cimg_openmp_if(_height>=8 && _width>=16) reduction(+:_energy) | |
28208 | 32114 | #endif |
28209 | 32115 | cimg_forY(U,y) { |
28210 | 32116 | const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y; |
... | ... | @@ -28238,10 +32144,14 @@ namespace cimg_library_suffixed { |
28238 | 32144 | } |
28239 | 32145 | _energy+=delta_I*delta_I + smoothness*_energy_regul; |
28240 | 32146 | } |
32147 | + if (V) cimg_forX(V,x) if (V(x,y,2)) { // Apply constraints. | |
32148 | + U(x,y,0) = V(x,y,0)/factor; | |
32149 | + U(x,y,1) = V(x,y,1)/factor; | |
32150 | + } | |
28241 | 32151 | } else { // Anisotropic regularization. |
28242 | 32152 | const float nsmoothness = -smoothness; |
28243 | 32153 | #ifdef cimg_use_openmp |
28244 | -#pragma omp parallel for if (_height>=8 && _width>=16) reduction(+:_energy) | |
32154 | +#pragma omp parallel for cimg_openmp_if(_height>=8 && _width>=16) reduction(+:_energy) | |
28245 | 32155 | #endif |
28246 | 32156 | cimg_forY(U,y) { |
28247 | 32157 | const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y; |
... | ... | @@ -28283,17 +32193,12 @@ namespace cimg_library_suffixed { |
28283 | 32193 | } |
28284 | 32194 | _energy+=delta_I*delta_I + nsmoothness*_energy_regul; |
28285 | 32195 | } |
32196 | + if (V) cimg_forX(V,x) if (V(x,y,2)) { // Apply constraints. | |
32197 | + U(x,y,0) = V(x,y,0)/factor; | |
32198 | + U(x,y,1) = V(x,y,1)/factor; | |
32199 | + } | |
28286 | 32200 | } |
28287 | 32201 | } |
28288 | - if (constraints) cimg_forX(constraints,k) { | |
28289 | - const int | |
28290 | - cx = (int)(constraints(k,0)*U.width()/width()), | |
28291 | - cy = (int)(constraints(k,1)*U.height()/height()); | |
28292 | - if (U.contains(U(cx,cy))) { | |
28293 | - U(cx,cy,0) = (float)(constraints(k,2)/factor); | |
28294 | - U(cx,cy,1) = (float)(constraints(k,3)/factor); | |
28295 | - } | |
28296 | - } | |
28297 | 32202 | } |
28298 | 32203 | const float d_energy = (_energy - energy)/(sw*sh*sd); |
28299 | 32204 | if (d_energy<=0 && -d_energy<_precision) break; |
... | ... | @@ -28304,6 +32209,481 @@ namespace cimg_library_suffixed { |
28304 | 32209 | return U; |
28305 | 32210 | } |
28306 | 32211 | |
32212 | + //! Compute correspondence map between two images, using the patch-match algorithm. | |
32213 | + /** | |
32214 | + \param patch_image The image containing the reference patches to match with the instance image. | |
32215 | + \param patch_width Width of the patch used for matching. | |
32216 | + \param patch_height Height of the patch used for matching. | |
32217 | + \param patch_depth Depth of the patch used for matching. | |
32218 | + \param nb_iterations Number of patch-match iterations. | |
32219 | + \param nb_randoms Number of randomization attempts (per pixel). | |
32220 | + \param guide Image used as the initial correspondence estimate for the algorithm. | |
32221 | + 'guide' may have a last channel with boolean values (0=false | other=true) that | |
32222 | + tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask). | |
32223 | + \param[out] matching_score Returned as the image of matching scores. | |
32224 | + \note | |
32225 | + The patch-match algorithm is described in this paper: | |
32226 | + Connelly Barnes, Eli Shechtman, Adam Finkelstein, Dan B Goldman(2009), | |
32227 | + PatchMatch: A Randomized Correspondence Algorithm for Structural Image Editing | |
32228 | + **/ | |
32229 | + template<typename t1, typename t2> | |
32230 | + CImg<T>& patchmatch(const CImg<T>& patch_image, | |
32231 | + const unsigned int patch_width, | |
32232 | + const unsigned int patch_height, | |
32233 | + const unsigned int patch_depth, | |
32234 | + const unsigned int nb_iterations, | |
32235 | + const unsigned int nb_randoms, | |
32236 | + const CImg<t1> &guide, | |
32237 | + CImg<t2> &matching_score) { | |
32238 | + return get_patchmatch(patch_image,patch_width,patch_height,patch_depth, | |
32239 | + nb_iterations,nb_randoms,guide,matching_score).move_to(*this); | |
32240 | + } | |
32241 | + | |
32242 | + //! Compute correspondence map between two images, using the patch-match algorithm \newinstance. | |
32243 | + template<typename t1, typename t2> | |
32244 | + CImg<intT> get_patchmatch(const CImg<T>& patch_image, | |
32245 | + const unsigned int patch_width, | |
32246 | + const unsigned int patch_height, | |
32247 | + const unsigned int patch_depth, | |
32248 | + const unsigned int nb_iterations, | |
32249 | + const unsigned int nb_randoms, | |
32250 | + const CImg<t1> &guide, | |
32251 | + CImg<t2> &matching_score) const { | |
32252 | + return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth, | |
32253 | + nb_iterations,nb_randoms, | |
32254 | + guide,true,matching_score); | |
32255 | + } | |
32256 | + | |
32257 | + //! Compute correspondence map between two images, using the patch-match algorithm \overloading. | |
32258 | + template<typename t> | |
32259 | + CImg<T>& patchmatch(const CImg<T>& patch_image, | |
32260 | + const unsigned int patch_width, | |
32261 | + const unsigned int patch_height, | |
32262 | + const unsigned int patch_depth, | |
32263 | + const unsigned int nb_iterations, | |
32264 | + const unsigned int nb_randoms, | |
32265 | + const CImg<t> &guide) { | |
32266 | + return get_patchmatch(patch_image,patch_width,patch_height,patch_depth, | |
32267 | + nb_iterations,nb_randoms,guide).move_to(*this); | |
32268 | + } | |
32269 | + | |
32270 | + //! Compute correspondence map between two images, using the patch-match algorithm \overloading. | |
32271 | + template<typename t> | |
32272 | + CImg<intT> get_patchmatch(const CImg<T>& patch_image, | |
32273 | + const unsigned int patch_width, | |
32274 | + const unsigned int patch_height, | |
32275 | + const unsigned int patch_depth, | |
32276 | + const unsigned int nb_iterations, | |
32277 | + const unsigned int nb_randoms, | |
32278 | + const CImg<t> &guide) const { | |
32279 | + return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth, | |
32280 | + nb_iterations,nb_randoms, | |
32281 | + guide,false,CImg<T>::empty()); | |
32282 | + } | |
32283 | + | |
32284 | + //! Compute correspondence map between two images, using the patch-match algorithm \overloading. | |
32285 | + CImg<T>& patchmatch(const CImg<T>& patch_image, | |
32286 | + const unsigned int patch_width, | |
32287 | + const unsigned int patch_height, | |
32288 | + const unsigned int patch_depth=1, | |
32289 | + const unsigned int nb_iterations=5, | |
32290 | + const unsigned int nb_randoms=5) { | |
32291 | + return get_patchmatch(patch_image,patch_width,patch_height,patch_depth, | |
32292 | + nb_iterations,nb_randoms).move_to(*this); | |
32293 | + } | |
32294 | + | |
32295 | + //! Compute correspondence map between two images, using the patch-match algorithm \overloading. | |
32296 | + CImg<intT> get_patchmatch(const CImg<T>& patch_image, | |
32297 | + const unsigned int patch_width, | |
32298 | + const unsigned int patch_height, | |
32299 | + const unsigned int patch_depth=1, | |
32300 | + const unsigned int nb_iterations=5, | |
32301 | + const unsigned int nb_randoms=5) const { | |
32302 | + return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth, | |
32303 | + nb_iterations,nb_randoms, | |
32304 | + CImg<T>::const_empty(), | |
32305 | + false,CImg<T>::empty()); | |
32306 | + } | |
32307 | + | |
32308 | + template<typename t1, typename t2> | |
32309 | + CImg<intT> _get_patchmatch(const CImg<T>& patch_image, | |
32310 | + const unsigned int patch_width, | |
32311 | + const unsigned int patch_height, | |
32312 | + const unsigned int patch_depth, | |
32313 | + const unsigned int nb_iterations, | |
32314 | + const unsigned int nb_randoms, | |
32315 | + const CImg<t1> &guide, | |
32316 | + const bool is_matching_score, | |
32317 | + CImg<t2> &matching_score) const { | |
32318 | + if (is_empty()) return CImg<intT>::const_empty(); | |
32319 | + if (patch_image._spectrum!=_spectrum) | |
32320 | + throw CImgArgumentException(_cimg_instance | |
32321 | + "patchmatch(): Instance image and specified patch image (%u,%u,%u,%u,%p) " | |
32322 | + "have different spectrums.", | |
32323 | + cimg_instance, | |
32324 | + patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, | |
32325 | + patch_image._data); | |
32326 | + if (patch_width>_width || patch_height>_height || patch_depth>_depth) | |
32327 | + throw CImgArgumentException(_cimg_instance | |
32328 | + "patchmatch(): Specified patch size %ux%ux%u is bigger than the dimensions " | |
32329 | + "of the instance image.", | |
32330 | + cimg_instance,patch_width,patch_height,patch_depth); | |
32331 | + if (patch_width>patch_image._width || patch_height>patch_image._height || patch_depth>patch_image._depth) | |
32332 | + throw CImgArgumentException(_cimg_instance | |
32333 | + "patchmatch(): Specified patch size %ux%ux%u is bigger than the dimensions " | |
32334 | + "of the patch image image (%u,%u,%u,%u,%p).", | |
32335 | + cimg_instance,patch_width,patch_height,patch_depth, | |
32336 | + patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, | |
32337 | + patch_image._data); | |
32338 | + const unsigned int | |
32339 | + _constraint = patch_image._depth>1?3:2, | |
32340 | + constraint = guide._spectrum>_constraint?_constraint:0; | |
32341 | + | |
32342 | + if (guide && | |
32343 | + (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<_constraint)) | |
32344 | + throw CImgArgumentException(_cimg_instance | |
32345 | + "patchmatch(): Specified guide (%u,%u,%u,%u,%p) has invalid dimensions " | |
32346 | + "considering instance and patch image image (%u,%u,%u,%u,%p).", | |
32347 | + cimg_instance, | |
32348 | + guide._width,guide._height,guide._depth,guide._spectrum,guide._data, | |
32349 | + patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, | |
32350 | + patch_image._data); | |
32351 | + | |
32352 | + CImg<intT> map(_width,_height,_depth,patch_image._depth>1?3:2); | |
32353 | + CImg<floatT> score(_width,_height,_depth); | |
32354 | + const int | |
32355 | + psizew = (int)patch_width, psizew1 = psizew/2, psizew2 = psizew - psizew1 - 1, | |
32356 | + psizeh = (int)patch_height, psizeh1 = psizeh/2, psizeh2 = psizeh - psizeh1 - 1, | |
32357 | + psized = (int)patch_depth, psized1 = psized/2, psized2 = psized - psized1 - 1; | |
32358 | + | |
32359 | + if (_depth>1 || patch_image._depth>1) { // 3d version. | |
32360 | + | |
32361 | + // Initialize correspondence map. | |
32362 | + if (guide) cimg_forXYZ(*this,x,y,z) { // User-defined initialization. | |
32363 | + const int | |
32364 | + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1, | |
32365 | + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1, | |
32366 | + cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1, | |
32367 | + u = cimg::min(cimg::max((int)guide(x,y,z,0),cx1),patch_image.width() - 1 - cx2), | |
32368 | + v = cimg::min(cimg::max((int)guide(x,y,z,1),cy1),patch_image.height() - 1 - cy2), | |
32369 | + w = cimg::min(cimg::max((int)guide(x,y,z,2),cz1),patch_image.depth() - 1 - cz2); | |
32370 | + map(x,y,z,0) = u; | |
32371 | + map(x,y,z,1) = v; | |
32372 | + map(x,y,z,2) = w; | |
32373 | + score(x,y,z) = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32374 | + x - cx1,y - cy1,z - cz1, | |
32375 | + u - cx1,v - cy1,w - cz1,cimg::type<float>::inf()); | |
32376 | + } else cimg_forXYZ(*this,x,y,z) { // Random initialization. | |
32377 | + const int | |
32378 | + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1, | |
32379 | + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1, | |
32380 | + cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1, | |
32381 | + u = (int)cimg::round(cimg::rand(cx1,patch_image.width() - 1 - cx2)), | |
32382 | + v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2)), | |
32383 | + w = (int)cimg::round(cimg::rand(cz1,patch_image.depth() - 1 - cz2)); | |
32384 | + map(x,y,z,0) = u; | |
32385 | + map(x,y,z,1) = v; | |
32386 | + map(x,y,z,2) = w; | |
32387 | + score(x,y,z) = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32388 | + x - cx1,y - cy1,z - cz1, | |
32389 | + u - cx1,v - cy1,w - cz1,cimg::type<float>::inf()); | |
32390 | + } | |
32391 | + | |
32392 | + // Start iteration loop. | |
32393 | + for (unsigned int iter = 0; iter<nb_iterations; ++iter) { | |
32394 | + cimg_test_abort(); | |
32395 | + const bool is_even = !(iter%2); | |
32396 | + | |
32397 | +#ifdef cimg_use_openmp | |
32398 | +#pragma omp parallel for collapse(2) if (_width>64 && iter<nb_iterations-2) | |
32399 | +#endif | |
32400 | + cimg_forXYZ(*this,X,Y,Z) { | |
32401 | + const int | |
32402 | + x = is_even?X:width() - 1 - X, | |
32403 | + y = is_even?Y:height() - 1 - Y, | |
32404 | + z = is_even?Z:depth() - 1 - Z; | |
32405 | + if (score(x,y,z)<=1e-5 || (constraint && guide(x,y,z,constraint)!=0)) continue; | |
32406 | + const int | |
32407 | + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1, | |
32408 | + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1, | |
32409 | + cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1, | |
32410 | + xp = x - cx1, | |
32411 | + yp = y - cy1, | |
32412 | + zp = z - cz1; | |
32413 | + | |
32414 | + // Propagation. | |
32415 | + if (is_even) { | |
32416 | + if (x>0) { // Compare with left neighbor. | |
32417 | + const int u = map(x - 1,y,z,0), v = map(x - 1,y,z,1), w = map(x - 1,y,z,2); | |
32418 | + if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 && | |
32419 | + v>=cy1 && v<patch_image.height() - cy2 && | |
32420 | + w>=cz1 && w<patch_image.depth() - cz2) { | |
32421 | + const float | |
32422 | + current_score = score(x,y,z), | |
32423 | + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32424 | + xp,yp,zp,u + 1 - cx1,v - cy1,w - cz1,current_score); | |
32425 | + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u + 1; map(x,y,z,1) = v; map(x,y,z,2) = w; } | |
32426 | + } | |
32427 | + } | |
32428 | + if (y>0) { // Compare with up neighbor. | |
32429 | + const int u = map(x,y - 1,z,0), v = map(x,y - 1,z,1), w = map(x,y - 1,z,2); | |
32430 | + if (u>=cx1 && u<patch_image.width() - cx2 && | |
32431 | + v>=cy1 - 1 && v<patch_image.height() - 1 - cy2 && | |
32432 | + w>=cz1 && w<patch_image.depth() - cx2) { | |
32433 | + const float | |
32434 | + current_score = score(x,y,z), | |
32435 | + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32436 | + xp,yp,zp,u - cx1,v + 1 - cy1,w - cz1,current_score); | |
32437 | + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v + 1; map(x,y,z,2) = w; } | |
32438 | + } | |
32439 | + } | |
32440 | + if (z>0) { // Compare with backward neighbor. | |
32441 | + const int u = map(x,y,z - 1,0), v = map(x,y,z - 1,1), w = map(x,y,z - 1,2); | |
32442 | + if (u>=cx1 && u<patch_image.width() - cx2 && | |
32443 | + v>=cy1 && v<patch_image.height() - cy2 && | |
32444 | + w>=cz1 - 1 && w<patch_image.depth() - 1 - cz2) { | |
32445 | + const float | |
32446 | + current_score = score(x,y,z), | |
32447 | + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32448 | + xp,yp,zp,u - cx1,v - cy1,w + 1 - cz1,current_score); | |
32449 | + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v; map(x,y,z,2) = w + 1; } | |
32450 | + } | |
32451 | + } | |
32452 | + } else { | |
32453 | + if (x<width() - 1) { // Compare with right neighbor. | |
32454 | + const int u = map(x + 1,y,z,0), v = map(x + 1,y,z,1), w = map(x + 1,y,z,2); | |
32455 | + if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 && | |
32456 | + v>=cy1 && v<patch_image.height() - cy2 && | |
32457 | + w>=cz1 && w<patch_image.depth() - cz2) { | |
32458 | + const float | |
32459 | + current_score = score(x,y,z), | |
32460 | + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32461 | + xp,yp,zp,u - 1 - cx1,v - cy1,w - cz1,current_score); | |
32462 | + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u - 1; map(x,y,z,1) = v; map(x,y,z,2) = w; } | |
32463 | + } | |
32464 | + } | |
32465 | + if (y<height() - 1) { // Compare with bottom neighbor. | |
32466 | + const int u = map(x,y + 1,z,0), v = map(x,y + 1,z,1), w = map(x,y + 1,z,2); | |
32467 | + if (u>=cx1 && u<patch_image.width() - cx2 && | |
32468 | + v>=cy1 + 1 && v<patch_image.height() + 1 - cy2 && | |
32469 | + w>=cz1 && w<patch_image.depth() - cz2) { | |
32470 | + const float | |
32471 | + current_score = score(x,y,z), | |
32472 | + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32473 | + xp,yp,zp,u - cx1,v - 1 - cy1,w - cz1,current_score); | |
32474 | + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v - 1; map(x,y,z,2) = w; } | |
32475 | + } | |
32476 | + } | |
32477 | + if (z<depth() - 1) { // Compare with forward neighbor. | |
32478 | + const int u = map(x,y,z + 1,0), v = map(x,y,z + 1,1), w = map(x,y,z + 1,2); | |
32479 | + if (u>=cx1 && u<patch_image.width() - cx2 && | |
32480 | + v>=cy1 && v<patch_image.height() - cy2 && | |
32481 | + w>=cz1 + 1 && w<patch_image.depth() + 1 - cz2) { | |
32482 | + const float | |
32483 | + current_score = score(x,y,z), | |
32484 | + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32485 | + xp,yp,zp,u - cx1,v - cy1,w - 1 - cz1,current_score); | |
32486 | + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v; map(x,y,z,2) = w - 1; } | |
32487 | + } | |
32488 | + } | |
32489 | + } | |
32490 | + | |
32491 | + // Randomization. | |
32492 | + const int u = map(x,y,z,0), v = map(x,y,z,1), w = map(x,y,z,2); | |
32493 | + float dw = (float)patch_image.width(), dh = (float)patch_image.height(), dd = (float)patch_image.depth(); | |
32494 | + for (unsigned int i = 0; i<nb_randoms; ++i) { | |
32495 | + const int | |
32496 | + ui = (int)cimg::round(cimg::rand(cimg::max(cx1,u - dw), | |
32497 | + cimg::min(patch_image.width() - 1 - cx2,u + dw))), | |
32498 | + vi = (int)cimg::round(cimg::rand(cimg::max(cy1,v - dh), | |
32499 | + cimg::min(patch_image.height() - 1 - cy2,v + dh))), | |
32500 | + wi = (int)cimg::round(cimg::rand(cimg::max(cz1,w - dd), | |
32501 | + cimg::min(patch_image.depth() - 1 - cz2,w + dd))); | |
32502 | + if (ui!=u || vi!=v || wi!=w) { | |
32503 | + const float | |
32504 | + current_score = score(x,y,z), | |
32505 | + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth, | |
32506 | + xp,yp,zp,ui - cx1,vi - cy1,wi - cz1,current_score); | |
32507 | + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = ui; map(x,y,z,1) = vi; map(x,y,z,2) = wi; } | |
32508 | + dw = cimg::max(5.0f,dw*0.5f); dh = cimg::max(5.0f,dh*0.5f); dd = cimg::max(5.0f,dd*0.5f); | |
32509 | + } | |
32510 | + } | |
32511 | + } | |
32512 | + } | |
32513 | + | |
32514 | + } else { // 2d version. | |
32515 | + | |
32516 | + // Initialize correspondence map. | |
32517 | + if (guide) cimg_forXY(*this,x,y) { // Random initialization. | |
32518 | + const int | |
32519 | + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1, | |
32520 | + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1, | |
32521 | + u = cimg::min(cimg::max((int)guide(x,y,0),cx1),patch_image.width() - 1 - cx2), | |
32522 | + v = cimg::min(cimg::max((int)guide(x,y,1),cy1),patch_image.height() - 1 - cy2); | |
32523 | + map(x,y,0) = u; | |
32524 | + map(x,y,1) = v; | |
32525 | + score(x,y) = _patchmatch(*this,patch_image,patch_width,patch_height, | |
32526 | + x - cx1,y - cy1,u - cx1,v - cy1,cimg::type<float>::inf()); | |
32527 | + } else cimg_forXY(*this,x,y) { // Random initialization. | |
32528 | + const int | |
32529 | + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1, | |
32530 | + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1, | |
32531 | + u = (int)cimg::round(cimg::rand(cx1,patch_image.width() - 1 - cx2)), | |
32532 | + v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2)); | |
32533 | + map(x,y,0) = u; | |
32534 | + map(x,y,1) = v; | |
32535 | + score(x,y) = _patchmatch(*this,patch_image,patch_width,patch_height, | |
32536 | + x - cx1,y - cy1,u - cx1,v - cy1,cimg::type<float>::inf()); | |
32537 | + } | |
32538 | + | |
32539 | + // Start iteration loop. | |
32540 | + for (unsigned int iter = 0; iter<nb_iterations; ++iter) { | |
32541 | + const bool is_even = !(iter%2); | |
32542 | + | |
32543 | +#ifdef cimg_use_openmp | |
32544 | +#pragma omp parallel for cimg_openmp_if(_width>64 && iter<nb_iterations-2) | |
32545 | +#endif | |
32546 | + cimg_forXY(*this,X,Y) { | |
32547 | + const int | |
32548 | + x = is_even?X:width() - 1 - X, | |
32549 | + y = is_even?Y:height() - 1 - Y; | |
32550 | + if (score(x,y)<=1e-5 || (constraint && guide(x,y,constraint)!=0)) continue; | |
32551 | + const int | |
32552 | + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1, | |
32553 | + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1, | |
32554 | + xp = x - cx1, | |
32555 | + yp = y - cy1; | |
32556 | + | |
32557 | + // Propagation. | |
32558 | + if (is_even) { | |
32559 | + if (x>0) { // Compare with left neighbor. | |
32560 | + const int u = map(x - 1,y,0), v = map(x - 1,y,1); | |
32561 | + if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 && | |
32562 | + v>=cy1 && v<patch_image.height() - cy2) { | |
32563 | + const float | |
32564 | + current_score = score(x,y), | |
32565 | + D = _patchmatch(*this,patch_image,patch_width,patch_height, | |
32566 | + xp,yp,u + 1 - cx1,v - cy1,current_score); | |
32567 | + if (D<current_score) { score(x,y) = D; map(x,y,0) = u + 1; map(x,y,1) = v; } | |
32568 | + } | |
32569 | + } | |
32570 | + if (y>0) { // Compare with up neighbor. | |
32571 | + const int u = map(x,y - 1,0), v = map(x,y - 1,1); | |
32572 | + if (u>=cx1 && u<patch_image.width() - cx2 && | |
32573 | + v>=cy1 - 1 && v<patch_image.height() - 1 - cy2) { | |
32574 | + const float | |
32575 | + current_score = score(x,y), | |
32576 | + D = _patchmatch(*this,patch_image,patch_width,patch_height, | |
32577 | + xp,yp,u - cx1,v + 1 - cy1,current_score); | |
32578 | + if (D<current_score) { score(x,y) = D; map(x,y,0) = u; map(x,y,1) = v + 1; } | |
32579 | + } | |
32580 | + } | |
32581 | + } else { | |
32582 | + if (x<width() - 1) { // Compare with right neighbor. | |
32583 | + const int u = map(x + 1,y,0), v = map(x + 1,y,1); | |
32584 | + if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 && | |
32585 | + v>=cy1 && v<patch_image.height() - cy2) { | |
32586 | + const float | |
32587 | + current_score = score(x,y), | |
32588 | + D = _patchmatch(*this,patch_image,patch_width,patch_height, | |
32589 | + xp,yp,u - 1 - cx1,v - cy1,current_score); | |
32590 | + if (D<current_score) { score(x,y) = D; map(x,y,0) = u - 1; map(x,y,1) = v; } | |
32591 | + } | |
32592 | + } | |
32593 | + if (y<height() - 1) { // Compare with bottom neighbor. | |
32594 | + const int u = map(x,y + 1,0), v = map(x,y + 1,1); | |
32595 | + if (u>=cx1 && u<patch_image.width() - cx2 && | |
32596 | + v>=cy1 + 1 && v<patch_image.height() + 1 - cy2) { | |
32597 | + const float | |
32598 | + current_score = score(x,y), | |
32599 | + D = _patchmatch(*this,patch_image,patch_width,patch_height, | |
32600 | + xp,yp,u - cx1,v - 1 - cy1,current_score); | |
32601 | + if (D<current_score) { score(x,y) = D; map(x,y,0) = u; map(x,y,1) = v - 1; } | |
32602 | + } | |
32603 | + } | |
32604 | + } | |
32605 | + | |
32606 | + // Randomization. | |
32607 | + const int u = map(x,y,0), v = map(x,y,1); | |
32608 | + float dw = (float)patch_image.width(), dh = (float)patch_image.height(); | |
32609 | + for (unsigned int i = 0; i<nb_randoms; ++i) { | |
32610 | + const int | |
32611 | + ui = (int)cimg::round(cimg::rand(cimg::max(cx1,u - dw), | |
32612 | + cimg::min(patch_image.width() - 1 - cx2,u + dw))), | |
32613 | + vi = (int)cimg::round(cimg::rand(cimg::max(cy1,v - dh), | |
32614 | + cimg::min(patch_image.height() - 1 - cy2,v + dh))); | |
32615 | + if (ui!=u || vi!=v) { | |
32616 | + const float | |
32617 | + current_score = score(x,y), | |
32618 | + D = _patchmatch(*this,patch_image,patch_width,patch_height, | |
32619 | + xp,yp,ui - cx1,vi - cy1,current_score); | |
32620 | + if (D<current_score) { score(x,y) = D; map(x,y,0) = ui; map(x,y,1) = vi; } | |
32621 | + dw = cimg::max(5.0f,dw*0.5f); dh = cimg::max(5.0f,dh*0.5f); | |
32622 | + } | |
32623 | + } | |
32624 | + } | |
32625 | + } | |
32626 | + } | |
32627 | + if (is_matching_score) score.move_to(matching_score); | |
32628 | + return map; | |
32629 | + } | |
32630 | + | |
32631 | + // Compute SSD between two patches in different images. | |
32632 | + static float _patchmatch(const CImg<T>& img1, const CImg<T>& img2, | |
32633 | + const unsigned int psizew, const unsigned int psizeh, | |
32634 | + const int x1, const int y1, | |
32635 | + const int x2, const int y2, | |
32636 | + const float max_ssd) { // 2d version. | |
32637 | + const T *p1 = img1.data(x1,y1), *p2 = img2.data(x2,y2); | |
32638 | + const unsigned long | |
32639 | + offx1 = (unsigned long)img1._width - psizew, | |
32640 | + offx2 = (unsigned long)img2._width - psizew, | |
32641 | + offy1 = (unsigned long)img1._width*img1._height - psizeh*img1._width, | |
32642 | + offy2 = (unsigned long)img2._width*img2._height - psizeh*img2._width; | |
32643 | + float ssd = 0; | |
32644 | + cimg_forC(img1,c) { | |
32645 | + for (unsigned int j = 0; j<psizeh; ++j) { | |
32646 | + for (unsigned int i = 0; i<psizew; ++i) | |
32647 | + ssd += cimg::sqr(*(p1++) - *(p2++)); | |
32648 | + if (ssd>max_ssd) return max_ssd; | |
32649 | + p1+=offx1; p2+=offx2; | |
32650 | + } | |
32651 | + p1+=offy1; p2+=offy2; | |
32652 | + } | |
32653 | + return ssd; | |
32654 | + } | |
32655 | + | |
32656 | + static float _patchmatch(const CImg<T>& img1, const CImg<T>& img2, | |
32657 | + const unsigned int psizew, const unsigned int psizeh, const unsigned int psized, | |
32658 | + const int x1, const int y1, const int z1, | |
32659 | + const int x2, const int y2, const int z2, | |
32660 | + const float max_ssd) { // 3d version. | |
32661 | + const T *p1 = img1.data(x1,y1,z1), *p2 = img2.data(x2,y2,z2); | |
32662 | + const unsigned long | |
32663 | + offx1 = (unsigned long)img1._width - psizew, | |
32664 | + offx2 = (unsigned long)img2._width - psizew, | |
32665 | + offy1 = (unsigned long)img1._width*img1._height - psizeh*img1._width - psizew, | |
32666 | + offy2 = (unsigned long)img2._width*img2._height - psizeh*img2._width - psizew, | |
32667 | + offz1 = (unsigned long)img1._width*img1._height*img1._depth - psized*img1._width*img1._height - | |
32668 | + psizeh*img1._width - psizew, | |
32669 | + offz2 = (unsigned long)img2._width*img2._height*img2._depth - psized*img2._width*img2._height - | |
32670 | + psizeh*img2._width - psizew; | |
32671 | + float ssd = 0; | |
32672 | + cimg_forC(img1,c) { | |
32673 | + for (unsigned int k = 0; k<psized; ++k) { | |
32674 | + for (unsigned int j = 0; j<psizeh; ++j) { | |
32675 | + for (unsigned int i = 0; i<psizew; ++i) | |
32676 | + ssd += cimg::sqr(*(p1++) - *(p2++)); | |
32677 | + if (ssd>max_ssd) return max_ssd; | |
32678 | + p1+=offx1; p2+=offx2; | |
32679 | + } | |
32680 | + p1+=offy1; p2+=offy2; | |
32681 | + } | |
32682 | + p1+=offz1; p2+=offz2; | |
32683 | + } | |
32684 | + return ssd; | |
32685 | + } | |
32686 | + | |
28307 | 32687 | //! Compute Euclidean distance function to a specified value. |
28308 | 32688 | /** |
28309 | 32689 | \param value Reference value. |
... | ... | @@ -28388,7 +32768,7 @@ namespace cimg_library_suffixed { |
28388 | 32768 | |
28389 | 32769 | const unsigned long wh = (unsigned long)_width*_height; |
28390 | 32770 | #if defined(cimg_use_openmp) && !cimg_is_gcc49x |
28391 | -#pragma omp parallel for if (_spectrum>=2) | |
32771 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) | |
28392 | 32772 | #endif |
28393 | 32773 | cimg_forC(*this,c) { |
28394 | 32774 | CImg<longT> g(_width), dt(_width), s(_width), t(_width); |
... | ... | @@ -28441,7 +32821,7 @@ namespace cimg_library_suffixed { |
28441 | 32821 | if (!is_value) return fill(cimg::type<T>::max()); |
28442 | 32822 | const unsigned long wh = (unsigned long)_width*_height; |
28443 | 32823 | #ifdef cimg_use_openmp |
28444 | -#pragma omp parallel for if (_spectrum>=2) | |
32824 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) | |
28445 | 32825 | #endif |
28446 | 32826 | cimg_forC(*this,c) { |
28447 | 32827 | CImg<T> img = get_shared_channel(c); |
... | ... | @@ -28491,7 +32871,7 @@ namespace cimg_library_suffixed { |
28491 | 32871 | return get_distance_dijkstra(value,metric,is_high_connectivity,return_path).move_to(*this); |
28492 | 32872 | } |
28493 | 32873 | |
28494 | - //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm). \newinstance. | |
32874 | + //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm) \newinstance. | |
28495 | 32875 | template<typename t, typename to> |
28496 | 32876 | CImg<typename cimg::superset<t,long>::type> |
28497 | 32877 | get_distance_dijkstra(const T& value, const CImg<t>& metric, const bool is_high_connectivity, |
... | ... | @@ -28695,7 +33075,7 @@ namespace cimg_library_suffixed { |
28695 | 33075 | CImg<charT> state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen. |
28696 | 33076 | |
28697 | 33077 | #ifdef cimg_use_openmp |
28698 | -#pragma omp parallel for if (_spectrum>=2) firstprivate(Q,state) | |
33078 | +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) firstprivate(Q,state) | |
28699 | 33079 | #endif |
28700 | 33080 | cimg_forC(*this,c) { |
28701 | 33081 | const CImg<T> img = get_shared_channel(c); |
... | ... | @@ -29645,7 +34025,7 @@ namespace cimg_library_suffixed { |
29645 | 34025 | **/ |
29646 | 34026 | template<typename tp, typename tc, typename tt, typename tx> |
29647 | 34027 | const CImg<T>& texturize_object3d(CImgList<tp>& primitives, CImgList<tc>& colors, |
29648 | - const CImg<tt>& texture, const CImg<tx>& coords=CImg<tx>::empty()) const { | |
34028 | + const CImg<tt>& texture, const CImg<tx>& coords=CImg<tx>::const_empty()) const { | |
29649 | 34029 | if (is_empty()) return *this; |
29650 | 34030 | if (_height!=3) |
29651 | 34031 | throw CImgInstanceException(_cimg_instance |
... | ... | @@ -30551,7 +34931,9 @@ namespace cimg_library_suffixed { |
30551 | 34931 | |
30552 | 34932 | struct _functor2d_expr { |
30553 | 34933 | _cimg_math_parser *mp; |
30554 | - _functor2d_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(CImg<T>::empty(),expr,0); } | |
34934 | + _functor2d_expr(const char *const expr):mp(0) { | |
34935 | + mp = new _cimg_math_parser(expr,0,CImg<T>::const_empty(),0); | |
34936 | + } | |
30555 | 34937 | ~_functor2d_expr() { delete mp; } |
30556 | 34938 | float operator()(const float x, const float y) const { |
30557 | 34939 | return (float)(*mp)(x,y,0,0); |
... | ... | @@ -30577,7 +34959,9 @@ namespace cimg_library_suffixed { |
30577 | 34959 | struct _functor3d_expr { |
30578 | 34960 | _cimg_math_parser *mp; |
30579 | 34961 | ~_functor3d_expr() { delete mp; } |
30580 | - _functor3d_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(CImg<T>::empty(),expr,0); } | |
34962 | + _functor3d_expr(const char *const expr):mp(0) { | |
34963 | + mp = new _cimg_math_parser(expr,0,CImg<T>::const_empty(),0); | |
34964 | + } | |
30581 | 34965 | float operator()(const float x, const float y, const float z) const { |
30582 | 34966 | return (float)(*mp)(x,y,z,0); |
30583 | 34967 | } |
... | ... | @@ -35102,10 +39486,10 @@ namespace cimg_library_suffixed { |
35102 | 39486 | const t |
35103 | 39487 | *ptrs = sprite._data - |
35104 | 39488 | (bx?x0:0) - |
35105 | - (by?y0*sprite.width():0) - | |
35106 | - (bz?z0*sprite.width()*sprite.height():0) - | |
35107 | - (bc?c0*sprite.width()*sprite.height()*sprite.depth():0); | |
35108 | - const unsigned long | |
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); | |
39492 | + const uptrT | |
35109 | 39493 | offX = (unsigned long)_width - lX, |
35110 | 39494 | soffX = (unsigned long)sprite._width - lX, |
35111 | 39495 | offY = (unsigned long)_width*(_height - lY), |
... | ... | @@ -35146,9 +39530,9 @@ namespace cimg_library_suffixed { |
35146 | 39530 | const T |
35147 | 39531 | *ptrs = sprite._data - |
35148 | 39532 | (bx?x0:0) - |
35149 | - (by?y0*sprite.width():0) - | |
35150 | - (bz?z0*sprite.width()*sprite.height():0) - | |
35151 | - (bc?c0*sprite.width()*sprite.height()*sprite.depth():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); | |
35152 | 39536 | const unsigned long |
35153 | 39537 | offX = (unsigned long)_width - lX, |
35154 | 39538 | soffX = (unsigned long)sprite._width - lX, |
... | ... | @@ -35238,12 +39622,14 @@ namespace cimg_library_suffixed { |
35238 | 39622 | lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0), |
35239 | 39623 | lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0), |
35240 | 39624 | lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0); |
35241 | - const int | |
35242 | - coff = -(bx?x0:0) - (by?y0*mask.width():0) - (bz?z0*mask.width()*mask.height():0) - | |
35243 | - (bc?c0*mask.width()*mask.height()*mask.depth():0), | |
35244 | - ssize = mask.width()*mask.height()*mask.depth()*mask.spectrum(); | |
39625 | + 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), | |
39630 | + ssize = (uptrT)mask.width()*mask.height()*mask.depth()*mask.spectrum(); | |
35245 | 39631 | const ti *ptrs = sprite._data + coff; |
35246 | - const tm *ptrm = mask._data + coff; | |
39632 | + const tm *ptrm = mask._data + coff; | |
35247 | 39633 | const unsigned long |
35248 | 39634 | offX = (unsigned long)_width - lX, |
35249 | 39635 | soffX = (unsigned long)sprite._width - lX, |
... | ... | @@ -35568,32 +39954,32 @@ namespace cimg_library_suffixed { |
35568 | 39954 | if (is_empty()) return *this; |
35569 | 39955 | const int yt = (y + 3 + font_height)<_height?y + 3:y - 2 - (int)font_height; |
35570 | 39956 | const int siz = (int)values_x.size() - 1; |
35571 | - char txt[32] = { 0 }; | |
39957 | + CImg<charT> txt(32); | |
35572 | 39958 | CImg<T> label; |
35573 | 39959 | if (siz<=0) { // Degenerated case. |
35574 | 39960 | draw_line(0,y,_width - 1,y,color,opacity,pattern); |
35575 | 39961 | if (!siz) { |
35576 | - cimg_snprintf(txt,sizeof(txt),"%g",(double)*values_x); | |
39962 | + cimg_snprintf(txt,txt._width,"%g",(double)*values_x); | |
35577 | 39963 | label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); |
35578 | 39964 | const int |
35579 | 39965 | _xt = (width() - label.width())/2, |
35580 | 39966 | xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt; |
35581 | 39967 | draw_point(width()/2,y - 1,color,opacity).draw_point(width()/2,y + 1,color,opacity); |
35582 | - if (allow_zero || txt[0]!='0' || txt[1]!=0) | |
39968 | + if (allow_zero || *txt!='0' || txt[1]!=0) | |
35583 | 39969 | draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); |
35584 | 39970 | } |
35585 | 39971 | } else { // Regular case. |
35586 | 39972 | if (values_x[0]<values_x[siz]) draw_arrow(0,y,_width - 1,y,color,opacity,30,5,pattern); |
35587 | 39973 | else draw_arrow(_width - 1,y,0,y,color,opacity,30,5,pattern); |
35588 | 39974 | cimg_foroff(values_x,x) { |
35589 | - cimg_snprintf(txt,sizeof(txt),"%g",(double)values_x(x)); | |
39975 | + cimg_snprintf(txt,txt._width,"%g",(double)values_x(x)); | |
35590 | 39976 | label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); |
35591 | 39977 | const int |
35592 | 39978 | xi = (int)(x*(_width - 1)/siz), |
35593 | 39979 | _xt = xi - label.width()/2, |
35594 | 39980 | xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt; |
35595 | 39981 | draw_point(xi,y - 1,color,opacity).draw_point(xi,y + 1,color,opacity); |
35596 | - if (allow_zero || txt[0]!='0' || txt[1]!=0) | |
39982 | + if (allow_zero || *txt!='0' || txt[1]!=0) | |
35597 | 39983 | draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); |
35598 | 39984 | } |
35599 | 39985 | } |
... | ... | @@ -35617,12 +40003,12 @@ namespace cimg_library_suffixed { |
35617 | 40003 | const bool allow_zero=true) { |
35618 | 40004 | if (is_empty()) return *this; |
35619 | 40005 | int siz = (int)values_y.size() - 1; |
35620 | - char txt[32] = { 0 }; | |
40006 | + CImg<charT> txt(32); | |
35621 | 40007 | CImg<T> label; |
35622 | 40008 | if (siz<=0) { // Degenerated case. |
35623 | 40009 | draw_line(x,0,x,_height - 1,color,opacity,pattern); |
35624 | 40010 | if (!siz) { |
35625 | - cimg_snprintf(txt,sizeof(txt),"%g",(double)*values_y); | |
40011 | + cimg_snprintf(txt,txt._width,"%g",(double)*values_y); | |
35626 | 40012 | label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); |
35627 | 40013 | const int |
35628 | 40014 | _yt = (height() - label.height())/2, |
... | ... | @@ -35630,14 +40016,14 @@ namespace cimg_library_suffixed { |
35630 | 40016 | _xt = x - 2 - label.width(), |
35631 | 40017 | xt = _xt>=0?_xt:x + 3; |
35632 | 40018 | draw_point(x - 1,height()/2,color,opacity).draw_point(x + 1,height()/2,color,opacity); |
35633 | - if (allow_zero || txt[0]!='0' || txt[1]!=0) | |
40019 | + if (allow_zero || *txt!='0' || txt[1]!=0) | |
35634 | 40020 | draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); |
35635 | 40021 | } |
35636 | 40022 | } else { // Regular case. |
35637 | 40023 | if (values_y[0]<values_y[siz]) draw_arrow(x,0,x,_height - 1,color,opacity,30,5,pattern); |
35638 | 40024 | else draw_arrow(x,_height - 1,x,0,color,opacity,30,5,pattern); |
35639 | 40025 | cimg_foroff(values_y,y) { |
35640 | - cimg_snprintf(txt,sizeof(txt),"%g",(double)values_y(y)); | |
40026 | + cimg_snprintf(txt,txt._width,"%g",(double)values_y(y)); | |
35641 | 40027 | label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); |
35642 | 40028 | const int |
35643 | 40029 | yi = (int)(y*(_height - 1)/siz), |
... | ... | @@ -35646,7 +40032,7 @@ namespace cimg_library_suffixed { |
35646 | 40032 | _xt = x - 2 - label.width(), |
35647 | 40033 | xt = _xt>=0?_xt:x + 3; |
35648 | 40034 | draw_point(x - 1,yi,color,opacity).draw_point(x + 1,yi,color,opacity); |
35649 | - if (allow_zero || txt[0]!='0' || txt[1]!=0) | |
40035 | + if (allow_zero || *txt!='0' || txt[1]!=0) | |
35650 | 40036 | draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); |
35651 | 40037 | } |
35652 | 40038 | } |
... | ... | @@ -36186,7 +40572,8 @@ namespace cimg_library_suffixed { |
36186 | 40572 | for (int y0 = 0; y0<h; y0+=delta) |
36187 | 40573 | for (int x0 = 0; x0<w; x0+=delta) { |
36188 | 40574 | const int x1 = (x0 + delta)%w, y1 = (y0 + delta)%h, xc = (x0 + delta2)%w, yc = (y0 + delta2)%h; |
36189 | - const Tfloat val = (Tfloat)(0.25f*(ref(x0,y0) + ref(x0,y1) + ref(x0,y1) + ref(x1,y1)) + r*cimg::crand()); | |
40575 | + const Tfloat val = (Tfloat)(0.25f*(ref(x0,y0) + ref(x0,y1) + ref(x0,y1) + ref(x1,y1)) + | |
40576 | + r*cimg::rand(-1,1)); | |
36190 | 40577 | ref(xc,yc) = (T)(val<m?m:val>M?M:val); |
36191 | 40578 | } |
36192 | 40579 | |
... | ... | @@ -36195,21 +40582,24 @@ namespace cimg_library_suffixed { |
36195 | 40582 | for (int x0=0; x0<w; x0+=delta) { |
36196 | 40583 | const int y0 = cimg::mod(y,h), x1 = (x0 + delta)%w, y1 = (y + delta)%h, |
36197 | 40584 | xc = (x0 + delta2)%w, yc = (y + delta2)%h; |
36198 | - const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + r*cimg::crand()); | |
40585 | + const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + | |
40586 | + r*cimg::rand(-1,1)); | |
36199 | 40587 | ref(xc,yc) = (T)(val<m?m:val>M?M:val); |
36200 | 40588 | } |
36201 | 40589 | for (int y0 = 0; y0<h; y0+=delta) |
36202 | 40590 | for (int x = -delta2; x<w; x+=delta) { |
36203 | 40591 | const int x0 = cimg::mod(x,w), x1 = (x + delta)%w, y1 = (y0 + delta)%h, |
36204 | 40592 | xc = (x + delta2)%w, yc = (y0 + delta2)%h; |
36205 | - const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + r*cimg::crand()); | |
40593 | + const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + | |
40594 | + r*cimg::rand(-1,1)); | |
36206 | 40595 | ref(xc,yc) = (T)(val<m?m:val>M?M:val); |
36207 | 40596 | } |
36208 | 40597 | for (int y = -delta2; y<h; y+=delta) |
36209 | 40598 | for (int x = -delta2; x<w; x+=delta) { |
36210 | 40599 | const int x0 = cimg::mod(x,w), y0 = cimg::mod(y,h), x1 = (x + delta)%w, y1 = (y + delta)%h, |
36211 | 40600 | xc = (x + delta2)%w, yc = (y + delta2)%h; |
36212 | - const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + r*cimg::crand()); | |
40601 | + const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + | |
40602 | + r*cimg::rand(-1,1)); | |
36213 | 40603 | ref(xc,yc) = (T)(val<m?m:val>M?M:val); |
36214 | 40604 | } |
36215 | 40605 | } |
... | ... | @@ -36592,7 +40982,7 @@ namespace cimg_library_suffixed { |
36592 | 40982 | const bool is_double_sided=false, const float focale=700, |
36593 | 40983 | const float lightx=0, const float lighty=0, const float lightz=-5e8, |
36594 | 40984 | const float specular_lightness=0.2f, const float specular_shininess=0.1f) { |
36595 | - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::empty(), | |
40985 | + return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(), | |
36596 | 40986 | render_type,is_double_sided,focale,lightx,lighty,lightz, |
36597 | 40987 | specular_lightness,specular_shininess,CImg<floatT>::empty()); |
36598 | 40988 | } |
... | ... | @@ -36607,7 +40997,7 @@ namespace cimg_library_suffixed { |
36607 | 40997 | const float lightx, const float lighty, const float lightz, |
36608 | 40998 | const float specular_lightness, const float specular_shininess, |
36609 | 40999 | CImg<tz>& zbuffer) { |
36610 | - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::empty(), | |
41000 | + return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(), | |
36611 | 41001 | render_type,is_double_sided,focale,lightx,lighty,lightz, |
36612 | 41002 | specular_lightness,specular_shininess,zbuffer); |
36613 | 41003 | } |
... | ... | @@ -36622,7 +41012,7 @@ namespace cimg_library_suffixed { |
36622 | 41012 | const bool is_double_sided=false, const float focale=700, |
36623 | 41013 | const float lightx=0, const float lighty=0, const float lightz=-5e8, |
36624 | 41014 | const float specular_lightness=0.2f, const float specular_shininess=0.1f) { |
36625 | - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::empty(), | |
41015 | + return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(), | |
36626 | 41016 | render_type,is_double_sided,focale,lightx,lighty,lightz, |
36627 | 41017 | specular_lightness,specular_shininess,CImg<floatT>::empty()); |
36628 | 41018 | } |
... | ... | @@ -36637,7 +41027,7 @@ namespace cimg_library_suffixed { |
36637 | 41027 | const float lightx, const float lighty, const float lightz, |
36638 | 41028 | const float specular_lightness, const float specular_shininess, |
36639 | 41029 | CImg<tz>& zbuffer) { |
36640 | - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::empty(), | |
41030 | + return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(), | |
36641 | 41031 | render_type,is_double_sided,focale,lightx,lighty,lightz, |
36642 | 41032 | specular_lightness,specular_shininess,zbuffer); |
36643 | 41033 | } |
... | ... | @@ -36755,7 +41145,7 @@ namespace cimg_library_suffixed { |
36755 | 41145 | const float absfocale = focale?cimg::abs(focale):0; |
36756 | 41146 | if (absfocale) { |
36757 | 41147 | #ifdef cimg_use_openmp |
36758 | -#pragma omp parallel for if (projections.size()>4096) | |
41148 | +#pragma omp parallel for cimg_openmp_if(projections.size()>4096) | |
36759 | 41149 | #endif |
36760 | 41150 | cimg_forX(projections,l) { // Perspective projection |
36761 | 41151 | const tpfloat |
... | ... | @@ -36769,7 +41159,7 @@ namespace cimg_library_suffixed { |
36769 | 41159 | |
36770 | 41160 | } else { |
36771 | 41161 | #ifdef cimg_use_openmp |
36772 | -#pragma omp parallel for if (projections.size()>4096) | |
41162 | +#pragma omp parallel for cimg_openmp_if(projections.size()>4096) | |
36773 | 41163 | #endif |
36774 | 41164 | cimg_forX(projections,l) { // Parallel projection |
36775 | 41165 | const tpfloat |
... | ... | @@ -36792,7 +41182,7 @@ namespace cimg_library_suffixed { |
36792 | 41182 | bool is_forward = zbuffer?true:false; |
36793 | 41183 | |
36794 | 41184 | #ifdef cimg_use_openmp |
36795 | -#pragma omp parallel for if (primitives.size()>4096) | |
41185 | +#pragma omp parallel for cimg_openmp_if(primitives.size()>4096) | |
36796 | 41186 | #endif |
36797 | 41187 | cimglist_for(primitives,l) { |
36798 | 41188 | const CImg<tf>& primitive = primitives[l]; |
... | ... | @@ -36943,7 +41333,7 @@ namespace cimg_library_suffixed { |
36943 | 41333 | case 3 : { // Flat Shading |
36944 | 41334 | lightprops.assign(nb_visibles); |
36945 | 41335 | #ifdef cimg_use_openmp |
36946 | -#pragma omp parallel for if (nb_visibles>4096) | |
41336 | +#pragma omp parallel for cimg_openmp_if(nb_visibles>4096) | |
36947 | 41337 | #endif |
36948 | 41338 | cimg_forX(lightprops,l) { |
36949 | 41339 | const CImg<tf>& primitive = primitives(visibles(permutations(l))); |
... | ... | @@ -36977,7 +41367,7 @@ namespace cimg_library_suffixed { |
36977 | 41367 | case 5 : { // Phong-Shading |
36978 | 41368 | CImg<tpfloat> vertices_normals(vertices._width,6,1,1,0); |
36979 | 41369 | #ifdef cimg_use_openmp |
36980 | -#pragma omp parallel for if (nb_visibles>4096) | |
41370 | +#pragma omp parallel for cimg_openmp_if(nb_visibles>4096) | |
36981 | 41371 | #endif |
36982 | 41372 | for (unsigned int l = 0; l<nb_visibles; ++l) { |
36983 | 41373 | const CImg<tf>& primitive = primitives[visibles(l)]; |
... | ... | @@ -37030,7 +41420,7 @@ namespace cimg_library_suffixed { |
37030 | 41420 | if (render_type==4) { |
37031 | 41421 | lightprops.assign(vertices._width); |
37032 | 41422 | #ifdef cimg_use_openmp |
37033 | -#pragma omp parallel for if (nb_visibles>4096) | |
41423 | +#pragma omp parallel for cimg_openmp_if(nb_visibles>4096) | |
37034 | 41424 | #endif |
37035 | 41425 | cimg_forX(lightprops,l) { |
37036 | 41426 | const tpfloat |
... | ... | @@ -37051,7 +41441,7 @@ namespace cimg_library_suffixed { |
37051 | 41441 | lh2 = light_texture._height/2 - 1; |
37052 | 41442 | lightprops.assign(vertices._width,2); |
37053 | 41443 | #ifdef cimg_use_openmp |
37054 | -#pragma omp parallel for if (nb_visibles>4096) | |
41444 | +#pragma omp parallel for cimg_openmp_if(nb_visibles>4096) | |
37055 | 41445 | #endif |
37056 | 41446 | cimg_forX(lightprops,l) { |
37057 | 41447 | const tpfloat |
... | ... | @@ -37864,32 +42254,37 @@ namespace cimg_library_suffixed { |
37864 | 42254 | \param XYZ Pointer to 3 values X,Y,Z which tells about the projection point coordinates, for volumetric images. |
37865 | 42255 | **/ |
37866 | 42256 | CImg<T>& select(CImgDisplay &disp, |
37867 | - const unsigned int feature_type=2, unsigned int *const XYZ=0) { | |
37868 | - return get_select(disp,feature_type,XYZ).move_to(*this); | |
42257 | + const unsigned int feature_type=2, unsigned int *const XYZ=0, | |
42258 | + const bool exit_on_anykey=false) { | |
42259 | + return get_select(disp,feature_type,XYZ,exit_on_anykey).move_to(*this); | |
37869 | 42260 | } |
37870 | 42261 | |
37871 | 42262 | //! Simple interface to select a shape from an image \overloading. |
37872 | 42263 | CImg<T>& select(const char *const title, |
37873 | - const unsigned int feature_type=2, unsigned int *const XYZ=0) { | |
37874 | - return get_select(title,feature_type,XYZ).move_to(*this); | |
42264 | + const unsigned int feature_type=2, unsigned int *const XYZ=0, | |
42265 | + const bool exit_on_anykey=false) { | |
42266 | + return get_select(title,feature_type,XYZ,exit_on_anykey).move_to(*this); | |
37875 | 42267 | } |
37876 | 42268 | |
37877 | 42269 | //! Simple interface to select a shape from an image \newinstance. |
37878 | 42270 | CImg<intT> get_select(CImgDisplay &disp, |
37879 | - const unsigned int feature_type=2, unsigned int *const XYZ=0) const { | |
37880 | - return _get_select(disp,0,feature_type,XYZ,0,0,0,true,false); | |
42271 | + const unsigned int feature_type=2, unsigned int *const XYZ=0, | |
42272 | + const bool exit_on_anykey=false) const { | |
42273 | + return _get_select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false); | |
37881 | 42274 | } |
37882 | 42275 | |
37883 | 42276 | //! Simple interface to select a shape from an image \newinstance. |
37884 | 42277 | CImg<intT> get_select(const char *const title, |
37885 | - const unsigned int feature_type=2, unsigned int *const XYZ=0) const { | |
42278 | + const unsigned int feature_type=2, unsigned int *const XYZ=0, | |
42279 | + const bool exit_on_anykey=false) const { | |
37886 | 42280 | CImgDisplay disp; |
37887 | - return _get_select(disp,title,feature_type,XYZ,0,0,0,true,false); | |
42281 | + return _get_select(disp,title,feature_type,XYZ,0,0,0,exit_on_anykey,true,false); | |
37888 | 42282 | } |
37889 | 42283 | |
37890 | 42284 | CImg<intT> _get_select(CImgDisplay &disp, const char *const title, |
37891 | 42285 | const unsigned int feature_type, unsigned int *const XYZ, |
37892 | 42286 | const int origX, const int origY, const int origZ, |
42287 | + const bool exit_on_anykey, | |
37893 | 42288 | const bool reset_view3d, |
37894 | 42289 | const bool force_display_z_coord) const { |
37895 | 42290 | if (is_empty()) return CImg<intT>(1,feature_type==0?3:6,1,1,-1); |
... | ... | @@ -37898,13 +42293,18 @@ namespace cimg_library_suffixed { |
37898 | 42293 | if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum); |
37899 | 42294 | } else if (title) disp.set_title("%s",title); |
37900 | 42295 | |
42296 | + CImg<T> thumb; | |
42297 | + if (width()>disp.screen_width() || height()>disp.screen_height()) { | |
42298 | + const double ratio = cimg::min((double)disp.screen_width()/width(),(double)disp.screen_height()/height()); | |
42299 | + get_resize(cimg::max(1,(int)(ratio*width())),cimg::max(1,(int)(ratio*height())),-100,-100).move_to(thumb); | |
42300 | + } | |
42301 | + | |
37901 | 42302 | const unsigned int old_normalization = disp.normalization(); |
37902 | 42303 | bool old_is_resized = disp.is_resized(); |
37903 | 42304 | disp._normalization = 0; |
37904 | 42305 | disp.show().set_key(0).set_wheel().show_mouse(); |
37905 | - disp._mouse_x = disp._mouse_y = -1; | |
37906 | 42306 | |
37907 | - unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; | |
42307 | + static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; | |
37908 | 42308 | |
37909 | 42309 | int area = 0, starting_area = 0, clicked_area = 0, phase = 0, |
37910 | 42310 | X0 = (int)((XYZ?XYZ[0]:(_width - 1)/2)%_width), |
... | ... | @@ -37945,6 +42345,8 @@ namespace cimg_library_suffixed { |
37945 | 42345 | if (mX>=width() && mY>=height()) area = 4; |
37946 | 42346 | if (disp.button()) { if (!clicked_area) clicked_area = area; } else clicked_area = 0; |
37947 | 42347 | |
42348 | + CImg<charT> filename(32); | |
42349 | + | |
37948 | 42350 | switch (key = disp.key()) { |
37949 | 42351 | #if cimg_OS!=2 |
37950 | 42352 | case cimg::keyCTRLRIGHT : |
... | ... | @@ -37982,35 +42384,33 @@ namespace cimg_library_suffixed { |
37982 | 42384 | } break; |
37983 | 42385 | case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { |
37984 | 42386 | static unsigned int snap_number = 0; |
37985 | - char filename[32] = { 0 }; | |
37986 | 42387 | std::FILE *file; |
37987 | 42388 | do { |
37988 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.bmp",snap_number++); | |
42389 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); | |
37989 | 42390 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
37990 | 42391 | } while (file); |
37991 | 42392 | if (visu0) { |
37992 | 42393 | (+visu0).draw_text(0,0," Saving snapshot... ",foreground_color,background_color,0.7f,13).display(disp); |
37993 | 42394 | visu0.save(filename); |
37994 | - (+visu0).draw_text(0,0," Snapshot '%s' saved. ",foreground_color,background_color,0.7f,13,filename). | |
42395 | + (+visu0).draw_text(0,0," Snapshot '%s' saved. ",foreground_color,background_color,0.7f,13,filename._data). | |
37995 | 42396 | display(disp); |
37996 | 42397 | } |
37997 | 42398 | disp.set_key(key,false); key = 0; |
37998 | 42399 | } break; |
37999 | 42400 | case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { |
38000 | 42401 | static unsigned int snap_number = 0; |
38001 | - char filename[32] = { 0 }; | |
38002 | 42402 | std::FILE *file; |
38003 | 42403 | do { |
38004 | 42404 | #ifdef cimg_use_zlib |
38005 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimgz",snap_number++); | |
42405 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); | |
38006 | 42406 | #else |
38007 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimg",snap_number++); | |
42407 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); | |
38008 | 42408 | #endif |
38009 | 42409 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
38010 | 42410 | } while (file); |
38011 | 42411 | (+visu0).draw_text(0,0," Saving instance... ",foreground_color,background_color,0.7f,13).display(disp); |
38012 | 42412 | save(filename); |
38013 | - (+visu0).draw_text(0,0," Instance '%s' saved. ",foreground_color,background_color,0.7f,13,filename). | |
42413 | + (+visu0).draw_text(0,0," Instance '%s' saved. ",foreground_color,background_color,0.7f,13,filename._data). | |
38014 | 42414 | display(disp); |
38015 | 42415 | disp.set_key(key,false); key = 0; |
38016 | 42416 | } break; |
... | ... | @@ -38043,7 +42443,7 @@ namespace cimg_library_suffixed { |
38043 | 42443 | X0 = (int)X; Y0 = (int)Y; Z0 = (int)Z; |
38044 | 42444 | } |
38045 | 42445 | } |
38046 | - if (disp.button()&4) { // Reset positions. | |
42446 | + if (disp.button()&4) { | |
38047 | 42447 | X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = area = clicked_area = starting_area = 0; |
38048 | 42448 | visu0.assign(); |
38049 | 42449 | } |
... | ... | @@ -38146,7 +42546,9 @@ namespace cimg_library_suffixed { |
38146 | 42546 | if (mx!=omx || my!=omy || !visu0 || (_depth>1 && !view3d)) { |
38147 | 42547 | |
38148 | 42548 | if (!visu0) { // Create image of projected planes. |
38149 | - __get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0).resize(disp); | |
42549 | + if (thumb) thumb.__get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0); | |
42550 | + else __get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0); | |
42551 | + visu0.resize(disp); | |
38150 | 42552 | view3d.assign(); |
38151 | 42553 | points3d.assign(); |
38152 | 42554 | } |
... | ... | @@ -38409,6 +42811,10 @@ namespace cimg_library_suffixed { |
38409 | 42811 | } else if (!shape_selected) disp.wait(); |
38410 | 42812 | if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); } |
38411 | 42813 | omx = mx; omy = my; |
42814 | + if (!exit_on_anykey && key && key!=cimg::keyESC && | |
42815 | + (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { | |
42816 | + key = 0; | |
42817 | + } | |
38412 | 42818 | } |
38413 | 42819 | |
38414 | 42820 | // Return result. |
... | ... | @@ -38428,7 +42834,7 @@ namespace cimg_library_suffixed { |
38428 | 42834 | default : res[0] = X0; res[1] = Y0; res[2] = Z0; |
38429 | 42835 | } |
38430 | 42836 | } |
38431 | - disp.set_button(); | |
42837 | + if (!exit_on_anykey || !(disp.button()&4)) disp.set_button(); | |
38432 | 42838 | if (!visible_cursor) disp.show_mouse(); |
38433 | 42839 | disp._normalization = old_normalization; |
38434 | 42840 | disp._is_resized = old_is_resized; |
... | ... | @@ -38445,9 +42851,8 @@ namespace cimg_library_suffixed { |
38445 | 42851 | if (_depth>1) crop.get_projections2d(x,y,z).move_to(img2d); |
38446 | 42852 | else CImg<Tuchar>(crop,false).move_to(img2d); |
38447 | 42853 | |
38448 | - // Check for inf and nan values. | |
38449 | - if (cimg::type<T>::is_float() && disp._normalization && | |
38450 | - (disp._normalization!=3 || cimg::type<T>::string()!=cimg::type<unsigned char>::string())) { | |
42854 | + // Check for inf and NaN values. | |
42855 | + if (cimg::type<T>::is_float() && normalization) { | |
38451 | 42856 | bool is_inf = false, is_nan = false; |
38452 | 42857 | cimg_for(img2d,ptr,Tuchar) |
38453 | 42858 | if (cimg::type<T>::is_inf(*ptr)) { is_inf = true; break; } |
... | ... | @@ -38467,7 +42872,7 @@ namespace cimg_library_suffixed { |
38467 | 42872 | val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0); |
38468 | 42873 | if (is_nan) |
38469 | 42874 | cimg_for(img2d,ptr,Tuchar) |
38470 | - if (cimg::type<T>::is_nan(*ptr)) *ptr = val_minf; // Replace nan values. | |
42875 | + if (cimg::type<T>::is_nan(*ptr)) *ptr = val_minf; // Replace NaN values. | |
38471 | 42876 | if (is_inf) |
38472 | 42877 | cimg_for(img2d,ptr,Tuchar) |
38473 | 42878 | if (cimg::type<T>::is_inf(*ptr)) *ptr = (float)*ptr<0?val_minf:val_pinf; // Replace +-inf values. |
... | ... | @@ -38496,7 +42901,8 @@ namespace cimg_library_suffixed { |
38496 | 42901 | CImg<intT> get_select_graph(CImgDisplay &disp, |
38497 | 42902 | const unsigned int plot_type=1, const unsigned int vertex_type=1, |
38498 | 42903 | const char *const labelx=0, const double xmin=0, const double xmax=0, |
38499 | - const char *const labely=0, const double ymin=0, const double ymax=0) const { | |
42904 | + const char *const labely=0, const double ymin=0, const double ymax=0, | |
42905 | + const bool exit_on_anykey=false) const { | |
38500 | 42906 | if (is_empty()) |
38501 | 42907 | throw CImgInstanceException(_cimg_instance |
38502 | 42908 | "select_graph(): Empty instance.", |
... | ... | @@ -38512,8 +42918,8 @@ namespace cimg_library_suffixed { |
38512 | 42918 | if (nymin==nymax) { --nymin; ++nymax; } |
38513 | 42919 | if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; } |
38514 | 42920 | |
38515 | - const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 }, gray[] = { 220, 220, 220 }; | |
38516 | - const unsigned char gray2[] = { 110, 110, 110 }, ngray[] = { 35, 35, 35 }; | |
42921 | + static const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 }, gray[] = { 220, 220, 220 }; | |
42922 | + static const unsigned char gray2[] = { 110, 110, 110 }, ngray[] = { 35, 35, 35 }; | |
38517 | 42923 | static unsigned int odimv = 0; |
38518 | 42924 | static CImg<ucharT> colormap; |
38519 | 42925 | if (odimv!=_spectrum) { |
... | ... | @@ -38619,8 +43025,8 @@ namespace cimg_library_suffixed { |
38619 | 43025 | (double)(*this)(x,0,0,_spectrum - 1)); |
38620 | 43026 | else { |
38621 | 43027 | cimg_snprintf(message,message._width,"Value[%u:%g] = ( ",x,cx); |
38622 | - cimg_forC(*this,c) std::sprintf(message._data + std::strlen(message),"%g ",(double)(*this)(x,0,0,c)); | |
38623 | - std::sprintf(message._data + std::strlen(message),")"); | |
43028 | + cimg_forC(*this,c) cimg_sprintf(message._data + std::strlen(message),"%g ",(double)(*this)(x,0,0,c)); | |
43029 | + cimg_sprintf(message._data + std::strlen(message),")"); | |
38624 | 43030 | } |
38625 | 43031 | if (x0>=0 && x1>=0) { |
38626 | 43032 | const unsigned int |
... | ... | @@ -38634,10 +43040,10 @@ namespace cimg_library_suffixed { |
38634 | 43040 | cy0 = nymax - ny0*(nymax - nymin)/(visu._height - 32), |
38635 | 43041 | cy1 = nymax - ny1*(nymax - nymin)/(visu._height - 32); |
38636 | 43042 | if (y0>=0 && y1>=0) |
38637 | - std::sprintf(message._data + std::strlen(message)," - Range ( %u:%g, %g ) - ( %u:%g, %g )", | |
43043 | + cimg_sprintf(message._data + std::strlen(message)," - Range ( %u:%g, %g ) - ( %u:%g, %g )", | |
38638 | 43044 | x0,cx0,cy0,x1 + one,cx1,cy1); |
38639 | 43045 | else |
38640 | - std::sprintf(message._data + std::strlen(message)," - Range [ %u:%g - %u:%g ]", | |
43046 | + cimg_sprintf(message._data + std::strlen(message)," - Range [ %u:%g - %u:%g ]", | |
38641 | 43047 | x0,cx0,x1 + one,cx1); |
38642 | 43048 | } |
38643 | 43049 | text.assign().draw_text(0,0,message,white,ngray,1,13).resize(-100,-100,1,3); |
... | ... | @@ -38647,6 +43053,7 @@ namespace cimg_library_suffixed { |
38647 | 43053 | } |
38648 | 43054 | |
38649 | 43055 | // Test keys. |
43056 | + CImg<charT> filename(32); | |
38650 | 43057 | switch (okey = key) { |
38651 | 43058 | #if cimg_OS!=2 |
38652 | 43059 | case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT : |
... | ... | @@ -38678,15 +43085,14 @@ namespace cimg_library_suffixed { |
38678 | 43085 | static unsigned int snap_number = 0; |
38679 | 43086 | if (visu || visu0) { |
38680 | 43087 | CImg<ucharT> &screen = visu?visu:visu0; |
38681 | - char filename[32] = { 0 }; | |
38682 | 43088 | std::FILE *file; |
38683 | 43089 | do { |
38684 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.bmp",snap_number++); | |
43090 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); | |
38685 | 43091 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
38686 | 43092 | } while (file); |
38687 | 43093 | (+screen).draw_text(0,0," Saving snapshot... ",black,gray,1,13).display(disp); |
38688 | 43094 | screen.save(filename); |
38689 | - (+screen).draw_text(0,0," Snapshot '%s' saved. ",black,gray,1,13,filename).display(disp); | |
43095 | + (+screen).draw_text(0,0," Snapshot '%s' saved. ",black,gray,1,13,filename._data).display(disp); | |
38690 | 43096 | } |
38691 | 43097 | disp.set_key(key,false); okey = 0; |
38692 | 43098 | } break; |
... | ... | @@ -38694,19 +43100,18 @@ namespace cimg_library_suffixed { |
38694 | 43100 | static unsigned int snap_number = 0; |
38695 | 43101 | if (visu || visu0) { |
38696 | 43102 | CImg<ucharT> &screen = visu?visu:visu0; |
38697 | - char filename[32] = { 0 }; | |
38698 | 43103 | std::FILE *file; |
38699 | 43104 | do { |
38700 | 43105 | #ifdef cimg_use_zlib |
38701 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimgz",snap_number++); | |
43106 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); | |
38702 | 43107 | #else |
38703 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimg",snap_number++); | |
43108 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); | |
38704 | 43109 | #endif |
38705 | 43110 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
38706 | 43111 | } while (file); |
38707 | 43112 | (+screen).draw_text(0,0," Saving instance... ",black,gray,1,13).display(disp); |
38708 | 43113 | save(filename); |
38709 | - (+screen).draw_text(0,0," Instance '%s' saved. ",black,gray,1,13,filename).display(disp); | |
43114 | + (+screen).draw_text(0,0," Instance '%s' saved. ",black,gray,1,13,filename._data).display(disp); | |
38710 | 43115 | } |
38711 | 43116 | disp.set_key(key,false); okey = 0; |
38712 | 43117 | } break; |
... | ... | @@ -38733,6 +43138,11 @@ namespace cimg_library_suffixed { |
38733 | 43138 | } |
38734 | 43139 | if (disp.is_resized()) { disp.resize(false); visu0.assign(); } |
38735 | 43140 | if (visu && visu0) disp.wait(); |
43141 | + if (!exit_on_anykey && okey && okey!=cimg::keyESC && | |
43142 | + (okey!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { | |
43143 | + disp.set_key(key,false); | |
43144 | + okey = 0; | |
43145 | + } | |
38736 | 43146 | } |
38737 | 43147 | |
38738 | 43148 | disp._normalization = old_normalization; |
... | ... | @@ -39067,8 +43477,8 @@ namespace cimg_library_suffixed { |
39067 | 43477 | cimg_instance); |
39068 | 43478 | |
39069 | 43479 | std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); |
39070 | - unsigned char header[64] = { 0 }; | |
39071 | - cimg::fread(header,54,nfile); | |
43480 | + CImg<ucharT> header(54); | |
43481 | + cimg::fread(header._data,54,nfile); | |
39072 | 43482 | if (*header!='B' || header[1]!='M') { |
39073 | 43483 | if (!file) cimg::fclose(nfile); |
39074 | 43484 | throw CImgIOException(_cimg_instance |
... | ... | @@ -39093,7 +43503,7 @@ namespace cimg_library_suffixed { |
39093 | 43503 | file_size = (int)std::ftell(nfile); |
39094 | 43504 | std::fseek(nfile,54,SEEK_SET); |
39095 | 43505 | } |
39096 | - if (header_size>40) std::fseek(nfile, header_size - 40, SEEK_CUR); | |
43506 | + if (header_size>40) std::fseek(nfile,header_size - 40,SEEK_CUR); | |
39097 | 43507 | |
39098 | 43508 | const int |
39099 | 43509 | cimg_iobuffer = 24*1024*1024, |
... | ... | @@ -40037,7 +44447,7 @@ namespace cimg_library_suffixed { |
40037 | 44447 | - When libtiff is enabled, 2D and 3D (multipage) several |
40038 | 44448 | channel per pixel are supported for |
40039 | 44449 | <tt>char,uchar,short,ushort,float</tt> and \c double pixel types. |
40040 | - - If \c cimg_use_tif is not defined at compilation time the | |
44450 | + - If \c cimg_use_tif is not defined at compile time the | |
40041 | 44451 | function uses CImg<T>& load_other(const char*). |
40042 | 44452 | **/ |
40043 | 44453 | CImg<T>& load_tiff(const char *const filename, |
... | ... | @@ -40243,10 +44653,13 @@ namespace cimg_library_suffixed { |
40243 | 44653 | if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) |
40244 | 44654 | CImg<charT>::string(s_description).move_to(*description); |
40245 | 44655 | } |
40246 | - const unsigned int spectrum = is_spp?samplesperpixel:photo==3?3:1; | |
44656 | + const unsigned int spectrum = !is_spp || photo>=3?(photo>1?3:1):samplesperpixel; | |
40247 | 44657 | assign(nx,ny,1,spectrum); |
40248 | 44658 | |
40249 | - if (photo>=3 && sampleformat==1 && bitspersample==8 && (samplesperpixel==3 || samplesperpixel==4)) { | |
44659 | + if ((photo>=3 && sampleformat==1 && | |
44660 | + (bitspersample==4 || bitspersample==8) && | |
44661 | + (samplesperpixel==1 || samplesperpixel==3 || samplesperpixel==4)) || | |
44662 | + (bitspersample==1 && samplesperpixel==1)) { | |
40250 | 44663 | // Special case for unsigned color images. |
40251 | 44664 | uint32 *const raster = (uint32*)_TIFFmalloc(nx*ny*sizeof(uint32)); |
40252 | 44665 | if (!raster) { |
... | ... | @@ -40258,24 +44671,25 @@ namespace cimg_library_suffixed { |
40258 | 44671 | } |
40259 | 44672 | TIFFReadRGBAImage(tif,nx,ny,raster,0); |
40260 | 44673 | switch (spectrum) { |
40261 | - case 1 : { | |
40262 | - cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny - 1 - y) + x] + 128)/257); | |
40263 | - } break; | |
40264 | - case 3 : { | |
44674 | + case 1 : | |
44675 | + cimg_forXY(*this,x,y) | |
44676 | + (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]); | |
44677 | + break; | |
44678 | + case 3 : | |
40265 | 44679 | cimg_forXY(*this,x,y) { |
40266 | 44680 | (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]); |
40267 | 44681 | (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 -y) + x]); |
40268 | 44682 | (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 -y) + x]); |
40269 | 44683 | } |
40270 | - } break; | |
40271 | - case 4 : { | |
44684 | + break; | |
44685 | + case 4 : | |
40272 | 44686 | cimg_forXY(*this,x,y) { |
40273 | 44687 | (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]); |
40274 | 44688 | (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]); |
40275 | 44689 | (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]); |
40276 | 44690 | (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]); |
40277 | 44691 | } |
40278 | - } break; | |
44692 | + break; | |
40279 | 44693 | } |
40280 | 44694 | _TIFFfree(raster); |
40281 | 44695 | } else { // Other cases. |
... | ... | @@ -40432,11 +44846,11 @@ namespace cimg_library_suffixed { |
40432 | 44846 | const char *const ext = cimg::split_filename(filename,body); |
40433 | 44847 | if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file. |
40434 | 44848 | nfile_header = cimg::fopen(filename,"rb"); |
40435 | - std::sprintf(body._data + std::strlen(body),".img"); | |
44849 | + cimg_sprintf(body._data + std::strlen(body),".img"); | |
40436 | 44850 | nfile = cimg::fopen(body,"rb"); |
40437 | 44851 | } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file. |
40438 | 44852 | nfile = cimg::fopen(filename,"rb"); |
40439 | - std::sprintf(body._data + std::strlen(body),".hdr"); | |
44853 | + cimg_sprintf(body._data + std::strlen(body),".hdr"); | |
40440 | 44854 | nfile_header = cimg::fopen(body,"rb"); |
40441 | 44855 | } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file. |
40442 | 44856 | } else nfile_header = nfile = file; // File is a Niftii file. |
... | ... | @@ -40452,7 +44866,7 @@ namespace cimg_library_suffixed { |
40452 | 44866 | cimg::fread(&header_size,1,nfile_header); |
40453 | 44867 | if (!header_size) |
40454 | 44868 | throw CImgIOException(_cimg_instance |
40455 | - "load_analyze(): Invalid zero-sized header in file '%s'.", | |
44869 | + "load_analyze(): Invalid zero-size header in file '%s'.", | |
40456 | 44870 | cimg_instance, |
40457 | 44871 | filename?filename:"(FILE*)"); |
40458 | 44872 | |
... | ... | @@ -40661,8 +45075,8 @@ namespace cimg_library_suffixed { |
40661 | 45075 | } |
40662 | 45076 | |
40663 | 45077 | static void _load_inr_header(std::FILE *file, int out[8], float *const voxel_size) { |
40664 | - CImg<charT> item(1024); *item = 0; | |
40665 | - char tmp1[64] = { 0 }, tmp2[64] = { 0 }; | |
45078 | + CImg<charT> item(1024), tmp1(64), tmp2(64); | |
45079 | + *item = *tmp1 = *tmp2 = 0; | |
40666 | 45080 | out[0] = std::fscanf(file,"%63s",item._data); |
40667 | 45081 | out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1; |
40668 | 45082 | if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) |
... | ... | @@ -40680,19 +45094,19 @@ namespace cimg_library_suffixed { |
40680 | 45094 | cimg_sscanf(item," VY%*[^0-9.+-]%f",voxel_size + 1); |
40681 | 45095 | cimg_sscanf(item," VZ%*[^0-9.+-]%f",voxel_size + 2); |
40682 | 45096 | } |
40683 | - if (cimg_sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1; | |
40684 | - switch (cimg_sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) { | |
45097 | + if (cimg_sscanf(item," CPU%*[ =]%s",tmp1._data)) out[7] = cimg::strncasecmp(tmp1,"sun",3)?0:1; | |
45098 | + switch (cimg_sscanf(item," TYPE%*[ =]%s %s",tmp1._data,tmp2._data)) { | |
40685 | 45099 | case 0 : break; |
40686 | - case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strncpy(tmp1,tmp2,sizeof(tmp1) - 1); | |
45100 | + case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strncpy(tmp1,tmp2,tmp1._width - 1); | |
40687 | 45101 | case 1 : |
40688 | - if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0; | |
45102 | + if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0; | |
40689 | 45103 | if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1; |
40690 | - if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2; | |
45104 | + if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2; | |
40691 | 45105 | if (out[4]>=0) break; |
40692 | 45106 | default : |
40693 | 45107 | throw CImgIOException("CImg<%s>::load_inr(): Invalid pixel type '%s' defined in header.", |
40694 | 45108 | pixel_type(), |
40695 | - tmp2); | |
45109 | + tmp2._data); | |
40696 | 45110 | } |
40697 | 45111 | } |
40698 | 45112 | if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0) |
... | ... | @@ -40846,8 +45260,8 @@ namespace cimg_library_suffixed { |
40846 | 45260 | cimg_instance); |
40847 | 45261 | |
40848 | 45262 | std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); |
40849 | - char header[32] = { 0 }; | |
40850 | - cimg::fread(header,12,nfile); | |
45263 | + CImg<charT> header(32); | |
45264 | + cimg::fread(header._data,12,nfile); | |
40851 | 45265 | if (cimg::strncasecmp("PANDORE",header,7)) { |
40852 | 45266 | if (!file) cimg::fclose(nfile); |
40853 | 45267 | throw CImgIOException(_cimg_instance |
... | ... | @@ -40856,10 +45270,11 @@ namespace cimg_library_suffixed { |
40856 | 45270 | filename?filename:"(FILE*)"); |
40857 | 45271 | } |
40858 | 45272 | unsigned int imageid, dims[8] = { 0 }; |
45273 | + int ptbuf[4] = { 0 }; | |
40859 | 45274 | cimg::fread(&imageid,1,nfile); |
40860 | - const bool endian = (imageid>255); | |
45275 | + const bool endian = imageid>255; | |
40861 | 45276 | if (endian) cimg::invert_endianness(imageid); |
40862 | - cimg::fread(header,20,nfile); | |
45277 | + cimg::fread(header._data,20,nfile); | |
40863 | 45278 | |
40864 | 45279 | switch (imageid) { |
40865 | 45280 | case 2 : _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break; |
... | ... | @@ -40991,19 +45406,16 @@ namespace cimg_library_suffixed { |
40991 | 45406 | break; |
40992 | 45407 | case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break; |
40993 | 45408 | case 34 : { // Points 1d |
40994 | - int ptbuf[4] = { 0 }; | |
40995 | 45409 | cimg::fread(ptbuf,1,nfile); |
40996 | 45410 | if (endian) cimg::invert_endianness(ptbuf,1); |
40997 | 45411 | assign(1); (*this)(0) = (T)ptbuf[0]; |
40998 | 45412 | } break; |
40999 | 45413 | case 35 : { // Points 2d |
41000 | - int ptbuf[4] = { 0 }; | |
41001 | 45414 | cimg::fread(ptbuf,2,nfile); |
41002 | 45415 | if (endian) cimg::invert_endianness(ptbuf,2); |
41003 | 45416 | assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0]; |
41004 | 45417 | } break; |
41005 | 45418 | case 36 : { // Points 3d |
41006 | - int ptbuf[4] = { 0 }; | |
41007 | 45419 | cimg::fread(ptbuf,3,nfile); |
41008 | 45420 | if (endian) cimg::invert_endianness(ptbuf,3); |
41009 | 45421 | assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0]; |
... | ... | @@ -41886,11 +46298,11 @@ namespace cimg_library_suffixed { |
41886 | 46298 | const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz - 1, |
41887 | 46299 | mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U, width1 = _width - 1; |
41888 | 46300 | |
41889 | - char _title[64] = { 0 }; | |
41890 | - if (!title) cimg_snprintf(_title,sizeof(_title),"CImg<%s>",pixel_type()); | |
46301 | + CImg<charT> _title(64); | |
46302 | + if (!title) cimg_snprintf(_title,_title._width,"CImg<%s>",pixel_type()); | |
41891 | 46303 | |
41892 | 46304 | std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = (%u,%u,%u,%u) [%lu %s], %sdata%s = (%s*)%p", |
41893 | - cimg::t_magenta,cimg::t_bold,title?title:_title,cimg::t_normal, | |
46305 | + cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal, | |
41894 | 46306 | cimg::t_bold,cimg::t_normal,(void*)this, |
41895 | 46307 | cimg::t_bold,cimg::t_normal,_width,_height,_depth,_spectrum, |
41896 | 46308 | mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), |
... | ... | @@ -41934,8 +46346,9 @@ namespace cimg_library_suffixed { |
41934 | 46346 | \param disp Display window. |
41935 | 46347 | \param display_info Tells if image information are displayed on the standard output. |
41936 | 46348 | **/ |
41937 | - const CImg<T>& display(CImgDisplay &disp, const bool display_info, unsigned int *const XYZ=0) const { | |
41938 | - return _display(disp,0,display_info,XYZ,false); | |
46349 | + const CImg<T>& display(CImgDisplay &disp, const bool display_info, unsigned int *const XYZ=0, | |
46350 | + const bool exit_on_anykey=false) const { | |
46351 | + return _display(disp,0,display_info,XYZ,exit_on_anykey,false); | |
41939 | 46352 | } |
41940 | 46353 | |
41941 | 46354 | //! Display image into an interactive window. |
... | ... | @@ -41943,16 +46356,18 @@ namespace cimg_library_suffixed { |
41943 | 46356 | \param title Window title |
41944 | 46357 | \param display_info Tells if image information are displayed on the standard output. |
41945 | 46358 | **/ |
41946 | - const CImg<T>& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0) const { | |
46359 | + const CImg<T>& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0, | |
46360 | + const bool exit_on_anykey=false) const { | |
41947 | 46361 | CImgDisplay disp; |
41948 | - return _display(disp,title,display_info,XYZ,false); | |
46362 | + return _display(disp,title,display_info,XYZ,exit_on_anykey,false); | |
41949 | 46363 | } |
41950 | 46364 | |
41951 | - const CImg<T>& _display(CImgDisplay &disp, const char *const title, | |
41952 | - const bool display_info, unsigned int *const XYZ, | |
46365 | + const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info, | |
46366 | + unsigned int *const XYZ, const bool exit_on_anykey, | |
41953 | 46367 | const bool exit_on_simpleclick) const { |
41954 | 46368 | unsigned int oldw = 0, oldh = 0, _XYZ[3] = { 0 }, key = 0; |
41955 | - int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1; | |
46369 | + int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1, | |
46370 | + old_mouse_x = -1, old_mouse_y = -1; | |
41956 | 46371 | |
41957 | 46372 | if (!disp) { |
41958 | 46373 | disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1); |
... | ... | @@ -42010,14 +46425,21 @@ namespace cimg_library_suffixed { |
42010 | 46425 | _XYZ[1] = (unsigned int)(y1 - y0)/2; |
42011 | 46426 | _XYZ[2] = (unsigned int)(z1 - z0)/2; |
42012 | 46427 | } |
42013 | - const CImg<intT> selection = visu._get_select(disp,0,2,_XYZ,x0,y0,z0,is_first_select,_depth>1); | |
46428 | + | |
46429 | + disp._mouse_x = old_mouse_x; disp._mouse_y = old_mouse_y; | |
46430 | + const CImg<intT> selection = visu._get_select(disp,0,2,_XYZ,x0,y0,z0,true,is_first_select,_depth>1); | |
46431 | + old_mouse_x = disp._mouse_x; old_mouse_y = disp._mouse_y; | |
42014 | 46432 | is_first_select = false; |
42015 | 46433 | |
42016 | 46434 | if (disp.wheel()) { |
42017 | 46435 | if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { |
46436 | + go_down = !(go_up = disp.wheel()>0); | |
46437 | + } else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) { | |
46438 | + go_left = !(go_right = disp.wheel()>0); | |
46439 | + } | |
46440 | + else if (disp.is_keyALT() || disp.is_keyALTGR() || _depth==1) { | |
42018 | 46441 | go_out = !(go_in = disp.wheel()>0); go_in_center = false; |
42019 | - } else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) { go_left = !(go_right = disp.wheel()>0); } | |
42020 | - else if (disp.is_keyALT() || disp.is_keyALTGR() || _depth==1) { go_down = !(go_up = disp.wheel()>0); } | |
46442 | + } | |
42021 | 46443 | disp.set_wheel(); |
42022 | 46444 | } |
42023 | 46445 | |
... | ... | @@ -42175,6 +46597,10 @@ namespace cimg_library_suffixed { |
42175 | 46597 | else { z0+=(depth() - 1 - z1); z1 = depth() - 1; } |
42176 | 46598 | } |
42177 | 46599 | disp.wait(100); |
46600 | + if (!exit_on_anykey && key && key!=cimg::keyESC && | |
46601 | + (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { | |
46602 | + key = 0; | |
46603 | + } | |
42178 | 46604 | } |
42179 | 46605 | disp.set_key(key); |
42180 | 46606 | if (XYZ) { XYZ[0] = _XYZ[0]; XYZ[1] = _XYZ[1]; XYZ[2] = _XYZ[2]; } |
... | ... | @@ -42212,11 +46638,12 @@ namespace cimg_library_suffixed { |
42212 | 46638 | const bool is_double_sided=true, const float focale=700, |
42213 | 46639 | const float light_x=0, const float light_y=0, const float light_z=-5e8f, |
42214 | 46640 | const float specular_lightness=0.2f, const float specular_shininess=0.1f, |
42215 | - const bool display_axes=true, float *const pose_matrix=0) const { | |
46641 | + const bool display_axes=true, float *const pose_matrix=0, | |
46642 | + const bool exit_on_anykey=false) const { | |
42216 | 46643 | return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static, |
42217 | 46644 | render_motion,is_double_sided,focale, |
42218 | 46645 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42219 | - display_axes,pose_matrix); | |
46646 | + display_axes,pose_matrix,exit_on_anykey); | |
42220 | 46647 | } |
42221 | 46648 | |
42222 | 46649 | //! Display object 3d in an interactive window \simplification. |
... | ... | @@ -42231,12 +46658,13 @@ namespace cimg_library_suffixed { |
42231 | 46658 | const bool is_double_sided=true, const float focale=700, |
42232 | 46659 | const float light_x=0, const float light_y=0, const float light_z=-5e8f, |
42233 | 46660 | const float specular_lightness=0.2f, const float specular_shininess=0.1f, |
42234 | - const bool display_axes=true, float *const pose_matrix=0) const { | |
46661 | + const bool display_axes=true, float *const pose_matrix=0, | |
46662 | + const bool exit_on_anykey=false) const { | |
42235 | 46663 | CImgDisplay disp; |
42236 | 46664 | return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static, |
42237 | 46665 | render_motion,is_double_sided,focale, |
42238 | 46666 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42239 | - display_axes,pose_matrix); | |
46667 | + display_axes,pose_matrix,exit_on_anykey); | |
42240 | 46668 | } |
42241 | 46669 | |
42242 | 46670 | //! Display object 3d in an interactive window \simplification. |
... | ... | @@ -42250,11 +46678,12 @@ namespace cimg_library_suffixed { |
42250 | 46678 | const bool is_double_sided=true, const float focale=700, |
42251 | 46679 | const float light_x=0, const float light_y=0, const float light_z=-5e8f, |
42252 | 46680 | const float specular_lightness=0.2f, const float specular_shininess=0.1f, |
42253 | - const bool display_axes=true, float *const pose_matrix=0) const { | |
46681 | + const bool display_axes=true, float *const pose_matrix=0, | |
46682 | + const bool exit_on_anykey=false) const { | |
42254 | 46683 | return display_object3d(disp,vertices,primitives,colors,CImgList<floatT>(),centering, |
42255 | 46684 | render_static,render_motion,is_double_sided,focale, |
42256 | 46685 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42257 | - display_axes,pose_matrix); | |
46686 | + display_axes,pose_matrix,exit_on_anykey); | |
42258 | 46687 | } |
42259 | 46688 | |
42260 | 46689 | //! Display object 3d in an interactive window \simplification. |
... | ... | @@ -42268,11 +46697,12 @@ namespace cimg_library_suffixed { |
42268 | 46697 | const bool is_double_sided=true, const float focale=700, |
42269 | 46698 | const float light_x=0, const float light_y=0, const float light_z=-5e8f, |
42270 | 46699 | const float specular_lightness=0.2f, const float specular_shininess=0.1f, |
42271 | - const bool display_axes=true, float *const pose_matrix=0) const { | |
46700 | + const bool display_axes=true, float *const pose_matrix=0, | |
46701 | + const bool exit_on_anykey=false) const { | |
42272 | 46702 | return display_object3d(title,vertices,primitives,colors,CImgList<floatT>(),centering, |
42273 | 46703 | render_static,render_motion,is_double_sided,focale, |
42274 | 46704 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42275 | - display_axes,pose_matrix); | |
46705 | + display_axes,pose_matrix,exit_on_anykey); | |
42276 | 46706 | } |
42277 | 46707 | |
42278 | 46708 | //! Display object 3d in an interactive window \simplification. |
... | ... | @@ -42285,11 +46715,12 @@ namespace cimg_library_suffixed { |
42285 | 46715 | const bool is_double_sided=true, const float focale=700, |
42286 | 46716 | const float light_x=0, const float light_y=0, const float light_z=-5e8f, |
42287 | 46717 | const float specular_lightness=0.2f, const float specular_shininess=0.1f, |
42288 | - const bool display_axes=true, float *const pose_matrix=0) const { | |
46718 | + const bool display_axes=true, float *const pose_matrix=0, | |
46719 | + const bool exit_on_anykey=false) const { | |
42289 | 46720 | return display_object3d(disp,vertices,primitives,CImgList<T>(),centering, |
42290 | 46721 | render_static,render_motion,is_double_sided,focale, |
42291 | 46722 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42292 | - display_axes,pose_matrix); | |
46723 | + display_axes,pose_matrix,exit_on_anykey); | |
42293 | 46724 | } |
42294 | 46725 | |
42295 | 46726 | |
... | ... | @@ -42303,11 +46734,12 @@ namespace cimg_library_suffixed { |
42303 | 46734 | const bool is_double_sided=true, const float focale=700, |
42304 | 46735 | const float light_x=0, const float light_y=0, const float light_z=-5e8f, |
42305 | 46736 | const float specular_lightness=0.2f, const float specular_shininess=0.1f, |
42306 | - const bool display_axes=true, float *const pose_matrix=0) const { | |
46737 | + const bool display_axes=true, float *const pose_matrix=0, | |
46738 | + const bool exit_on_anykey=false) const { | |
42307 | 46739 | return display_object3d(title,vertices,primitives,CImgList<T>(),centering, |
42308 | 46740 | render_static,render_motion,is_double_sided,focale, |
42309 | 46741 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42310 | - display_axes,pose_matrix); | |
46742 | + display_axes,pose_matrix,exit_on_anykey); | |
42311 | 46743 | } |
42312 | 46744 | |
42313 | 46745 | //! Display object 3d in an interactive window \simplification. |
... | ... | @@ -42319,11 +46751,12 @@ namespace cimg_library_suffixed { |
42319 | 46751 | const bool is_double_sided=true, const float focale=700, |
42320 | 46752 | const float light_x=0, const float light_y=0, const float light_z=-5e8f, |
42321 | 46753 | const float specular_lightness=0.2f, const float specular_shininess=0.1f, |
42322 | - const bool display_axes=true, float *const pose_matrix=0) const { | |
46754 | + const bool display_axes=true, float *const pose_matrix=0, | |
46755 | + const bool exit_on_anykey=false) const { | |
42323 | 46756 | return display_object3d(disp,vertices,CImgList<uintT>(),centering, |
42324 | 46757 | render_static,render_motion,is_double_sided,focale, |
42325 | 46758 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42326 | - display_axes,pose_matrix); | |
46759 | + display_axes,pose_matrix,exit_on_anykey); | |
42327 | 46760 | } |
42328 | 46761 | |
42329 | 46762 | //! Display object 3d in an interactive window \simplification. |
... | ... | @@ -42335,11 +46768,12 @@ namespace cimg_library_suffixed { |
42335 | 46768 | const bool is_double_sided=true, const float focale=700, |
42336 | 46769 | const float light_x=0, const float light_y=0, const float light_z=-5e8f, |
42337 | 46770 | const float specular_lightness=0.2f, const float specular_shininess=0.1f, |
42338 | - const bool display_axes=true, float *const pose_matrix=0) const { | |
46771 | + const bool display_axes=true, float *const pose_matrix=0, | |
46772 | + const bool exit_on_anykey=false) const { | |
42339 | 46773 | return display_object3d(title,vertices,CImgList<uintT>(),centering, |
42340 | 46774 | render_static,render_motion,is_double_sided,focale, |
42341 | 46775 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42342 | - display_axes,pose_matrix); | |
46776 | + display_axes,pose_matrix,exit_on_anykey); | |
42343 | 46777 | } |
42344 | 46778 | |
42345 | 46779 | template<typename tp, typename tf, typename tc, typename to> |
... | ... | @@ -42353,7 +46787,8 @@ namespace cimg_library_suffixed { |
42353 | 46787 | const bool is_double_sided, const float focale, |
42354 | 46788 | const float light_x, const float light_y, const float light_z, |
42355 | 46789 | const float specular_lightness, const float specular_shininess, |
42356 | - const bool display_axes, float *const pose_matrix) const { | |
46790 | + const bool display_axes, float *const pose_matrix, | |
46791 | + const bool exit_on_anykey) const { | |
42357 | 46792 | typedef typename cimg::superset<tp,float>::type tpfloat; |
42358 | 46793 | |
42359 | 46794 | // Check input arguments |
... | ... | @@ -42362,14 +46797,14 @@ namespace cimg_library_suffixed { |
42362 | 46797 | _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, |
42363 | 46798 | render_static,render_motion,is_double_sided,focale, |
42364 | 46799 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42365 | - display_axes,pose_matrix); | |
46800 | + display_axes,pose_matrix,exit_on_anykey); | |
42366 | 46801 | else return CImg<T>(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2, |
42367 | 46802 | CImgDisplay::screen_height()/2,1), |
42368 | 46803 | 1,(colors && colors[0].size()==1)?1:3,3). |
42369 | 46804 | _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, |
42370 | 46805 | render_static,render_motion,is_double_sided,focale, |
42371 | 46806 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42372 | - display_axes,pose_matrix); | |
46807 | + display_axes,pose_matrix,exit_on_anykey); | |
42373 | 46808 | } else { if (disp) disp.resize(*this,false); } |
42374 | 46809 | CImg<charT> error_message(1024); |
42375 | 46810 | if (!vertices.is_object3d(primitives,colors,opacities,true,error_message)) |
... | ... | @@ -42382,7 +46817,7 @@ namespace cimg_library_suffixed { |
42382 | 46817 | return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering, |
42383 | 46818 | render_static,render_motion,is_double_sided,focale, |
42384 | 46819 | light_x,light_y,light_z,specular_lightness,specular_shininess, |
42385 | - display_axes,pose_matrix); | |
46820 | + display_axes,pose_matrix,exit_on_anykey); | |
42386 | 46821 | } |
42387 | 46822 | if (!disp) { |
42388 | 46823 | disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3); |
... | ... | @@ -42583,6 +47018,7 @@ namespace cimg_library_suffixed { |
42583 | 47018 | } |
42584 | 47019 | } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; } |
42585 | 47020 | |
47021 | + CImg<charT> filename(32); | |
42586 | 47022 | switch (key = disp.key()) { |
42587 | 47023 | #if cimg_OS!=2 |
42588 | 47024 | case cimg::keyCTRLRIGHT : |
... | ... | @@ -42661,43 +47097,40 @@ namespace cimg_library_suffixed { |
42661 | 47097 | } break; |
42662 | 47098 | case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot |
42663 | 47099 | static unsigned int snap_number = 0; |
42664 | - char filename[32] = { 0 }; | |
42665 | 47100 | std::FILE *file; |
42666 | 47101 | do { |
42667 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.bmp",snap_number++); | |
47102 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); | |
42668 | 47103 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
42669 | 47104 | } while (file); |
42670 | 47105 | (+visu).draw_text(0,0," Saving snapshot... ", |
42671 | 47106 | foreground_color._data,background_color._data,0.7f,13).display(disp); |
42672 | 47107 | visu.save(filename); |
42673 | 47108 | (+visu).draw_text(0,0," Snapshot '%s' saved. ", |
42674 | - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); | |
47109 | + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); | |
42675 | 47110 | disp.set_key(key,false); key = 0; |
42676 | 47111 | } break; |
42677 | 47112 | case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file |
42678 | 47113 | static unsigned int snap_number = 0; |
42679 | - char filename[32] = { 0 }; | |
42680 | 47114 | std::FILE *file; |
42681 | 47115 | do { |
42682 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.off",snap_number++); | |
47116 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.off",snap_number++); | |
42683 | 47117 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
42684 | 47118 | } while (file); |
42685 | 47119 | (+visu).draw_text(0,0," Saving object... ", |
42686 | 47120 | foreground_color._data,background_color._data,0.7f,13).display(disp); |
42687 | 47121 | vertices.save_off(reverse_primitives?reverse_primitives:primitives,colors,filename); |
42688 | 47122 | (+visu).draw_text(0,0," Object '%s' saved. ", |
42689 | - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); | |
47123 | + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); | |
42690 | 47124 | disp.set_key(key,false); key = 0; |
42691 | 47125 | } break; |
42692 | 47126 | case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file |
42693 | 47127 | static unsigned int snap_number = 0; |
42694 | - char filename[32] = { 0 }; | |
42695 | 47128 | std::FILE *file; |
42696 | 47129 | do { |
42697 | 47130 | #ifdef cimg_use_zlib |
42698 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimgz",snap_number++); | |
47131 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); | |
42699 | 47132 | #else |
42700 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimg",snap_number++); | |
47133 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); | |
42701 | 47134 | #endif |
42702 | 47135 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
42703 | 47136 | } while (file); |
... | ... | @@ -42706,16 +47139,15 @@ namespace cimg_library_suffixed { |
42706 | 47139 | vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities). |
42707 | 47140 | save(filename); |
42708 | 47141 | (+visu).draw_text(0,0," Object '%s' saved. ", |
42709 | - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); | |
47142 | + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); | |
42710 | 47143 | disp.set_key(key,false); key = 0; |
42711 | 47144 | } break; |
42712 | 47145 | #ifdef cimg_use_board |
42713 | 47146 | case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file |
42714 | 47147 | static unsigned int snap_number = 0; |
42715 | - char filename[32] = { 0 }; | |
42716 | 47148 | std::FILE *file; |
42717 | 47149 | do { |
42718 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.eps",snap_number++); | |
47150 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.eps",snap_number++); | |
42719 | 47151 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
42720 | 47152 | } while (file); |
42721 | 47153 | (+visu).draw_text(0,0," Saving EPS snapshot... ", |
... | ... | @@ -42731,15 +47163,14 @@ namespace cimg_library_suffixed { |
42731 | 47163 | sprite_scale); |
42732 | 47164 | board.saveEPS(filename); |
42733 | 47165 | (+visu).draw_text(0,0," Object '%s' saved. ", |
42734 | - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); | |
47166 | + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); | |
42735 | 47167 | disp.set_key(key,false); key = 0; |
42736 | 47168 | } break; |
42737 | 47169 | case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file |
42738 | 47170 | static unsigned int snap_number = 0; |
42739 | - char filename[32] = { 0 }; | |
42740 | 47171 | std::FILE *file; |
42741 | 47172 | do { |
42742 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.svg",snap_number++); | |
47173 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.svg",snap_number++); | |
42743 | 47174 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
42744 | 47175 | } while (file); |
42745 | 47176 | (+visu).draw_text(0,0," Saving SVG snapshot... ", |
... | ... | @@ -42755,7 +47186,7 @@ namespace cimg_library_suffixed { |
42755 | 47186 | sprite_scale); |
42756 | 47187 | board.saveSVG(filename); |
42757 | 47188 | (+visu).draw_text(0,0," Object '%s' saved. ", |
42758 | - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); | |
47189 | + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp); | |
42759 | 47190 | disp.set_key(key,false); key = 0; |
42760 | 47191 | } break; |
42761 | 47192 | #endif |
... | ... | @@ -42765,6 +47196,10 @@ namespace cimg_library_suffixed { |
42765 | 47196 | if (zbuffer) zbuffer.assign(disp.width(),disp.height()); |
42766 | 47197 | redraw = true; |
42767 | 47198 | } |
47199 | + if (!exit_on_anykey && key && key!=cimg::keyESC && | |
47200 | + (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { | |
47201 | + key = 0; | |
47202 | + } | |
42768 | 47203 | } |
42769 | 47204 | if (pose_matrix) { |
42770 | 47205 | std::memcpy(pose_matrix,pose._data,12*sizeof(float)); |
... | ... | @@ -42789,23 +47224,26 @@ namespace cimg_library_suffixed { |
42789 | 47224 | const CImg<T>& display_graph(CImgDisplay &disp, |
42790 | 47225 | const unsigned int plot_type=1, const unsigned int vertex_type=1, |
42791 | 47226 | const char *const labelx=0, const double xmin=0, const double xmax=0, |
42792 | - const char *const labely=0, const double ymin=0, const double ymax=0) const { | |
42793 | - return _display_graph(disp,0,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax); | |
47227 | + const char *const labely=0, const double ymin=0, const double ymax=0, | |
47228 | + const bool exit_on_anykey=false) const { | |
47229 | + return _display_graph(disp,0,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey); | |
42794 | 47230 | } |
42795 | 47231 | |
42796 | 47232 | //! Display 1d graph in an interactive window \overloading. |
42797 | 47233 | const CImg<T>& display_graph(const char *const title=0, |
42798 | 47234 | const unsigned int plot_type=1, const unsigned int vertex_type=1, |
42799 | 47235 | const char *const labelx=0, const double xmin=0, const double xmax=0, |
42800 | - const char *const labely=0, const double ymin=0, const double ymax=0) const { | |
47236 | + const char *const labely=0, const double ymin=0, const double ymax=0, | |
47237 | + const bool exit_on_anykey=false) const { | |
42801 | 47238 | CImgDisplay disp; |
42802 | - return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax); | |
47239 | + return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey); | |
42803 | 47240 | } |
42804 | 47241 | |
42805 | 47242 | const CImg<T>& _display_graph(CImgDisplay &disp, const char *const title=0, |
42806 | - const unsigned int plot_type=1, const unsigned int vertex_type=1, | |
42807 | - const char *const labelx=0, const double xmin=0, const double xmax=0, | |
42808 | - const char *const labely=0, const double ymin=0, const double ymax=0) const { | |
47243 | + const unsigned int plot_type=1, const unsigned int vertex_type=1, | |
47244 | + const char *const labelx=0, const double xmin=0, const double xmax=0, | |
47245 | + const char *const labely=0, const double ymin=0, const double ymax=0, | |
47246 | + const bool exit_on_anykey=false) const { | |
42809 | 47247 | if (is_empty()) |
42810 | 47248 | throw CImgInstanceException(_cimg_instance |
42811 | 47249 | "display_graph(): Empty instance.", |
... | ... | @@ -42831,7 +47269,7 @@ namespace cimg_library_suffixed { |
42831 | 47269 | labelx, |
42832 | 47270 | nxmin + x0*(nxmax - nxmin)/siz1, |
42833 | 47271 | nxmin + x1*(nxmax - nxmin)/siz1, |
42834 | - labely,y0,y1); | |
47272 | + labely,y0,y1,true); | |
42835 | 47273 | const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); |
42836 | 47274 | if (selection[0]>=0) { |
42837 | 47275 | if (selection[2]<0) reset_view = true; |
... | ... | @@ -42860,9 +47298,9 @@ namespace cimg_library_suffixed { |
42860 | 47298 | case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break; |
42861 | 47299 | } |
42862 | 47300 | if (disp.wheel()) { |
42863 | - if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_out = !(go_in = disp.wheel()>0); | |
47301 | + if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_up = !(go_down = disp.wheel()<0); | |
42864 | 47302 | else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0); |
42865 | - else go_up = !(go_down = disp.wheel()<0); | |
47303 | + else go_out = !(go_in = disp.wheel()>0); | |
42866 | 47304 | key = 0; |
42867 | 47305 | } |
42868 | 47306 | |
... | ... | @@ -42915,6 +47353,11 @@ namespace cimg_library_suffixed { |
42915 | 47353 | go_down = false; |
42916 | 47354 | } |
42917 | 47355 | } |
47356 | + if (!exit_on_anykey && key && key!=(int)cimg::keyESC && | |
47357 | + (key!=(int)cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { | |
47358 | + disp.set_key(key,false); | |
47359 | + key = 0; | |
47360 | + } | |
42918 | 47361 | } |
42919 | 47362 | disp._normalization = old_normalization; |
42920 | 47363 | return *this; |
... | ... | @@ -43176,7 +47619,8 @@ namespace cimg_library_suffixed { |
43176 | 47619 | filename?filename:"(FILE*)"); |
43177 | 47620 | |
43178 | 47621 | std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); |
43179 | - unsigned char header[54] = { 0 }, align_buf[4] = { 0 }; | |
47622 | + CImg<ucharT> header(54,1,1,1,0); | |
47623 | + unsigned char align_buf[4] = { 0 }; | |
43180 | 47624 | const unsigned int |
43181 | 47625 | align = (4 - (3*_width)%4)%4, |
43182 | 47626 | buf_size = (3*_width + align)*height(), |
... | ... | @@ -43206,7 +47650,7 @@ namespace cimg_library_suffixed { |
43206 | 47650 | header[0x25] = (buf_size>>24)&0xFF; |
43207 | 47651 | header[0x27] = 0x1; |
43208 | 47652 | header[0x2B] = 0x1; |
43209 | - cimg::fwrite(header,54,nfile); | |
47653 | + cimg::fwrite(header._data,54,nfile); | |
43210 | 47654 | |
43211 | 47655 | const T |
43212 | 47656 | *ptr_r = data(0,_height - 1,0,0), |
... | ... | @@ -43286,7 +47730,7 @@ namespace cimg_library_suffixed { |
43286 | 47730 | unsigned int dimbuf = 0; |
43287 | 47731 | J_COLOR_SPACE colortype = JCS_RGB; |
43288 | 47732 | |
43289 | - switch(_spectrum) { | |
47733 | + switch (_spectrum) { | |
43290 | 47734 | case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break; |
43291 | 47735 | case 2 : dimbuf = 3; colortype = JCS_RGB; break; |
43292 | 47736 | case 3 : dimbuf = 3; colortype = JCS_RGB; break; |
... | ... | @@ -43318,13 +47762,13 @@ namespace cimg_library_suffixed { |
43318 | 47762 | switch (_spectrum) { |
43319 | 47763 | case 1 : { // Greyscale images |
43320 | 47764 | const T *ptr_g = data(0, cinfo.next_scanline); |
43321 | - for(unsigned int b = 0; b < cinfo.image_width; b++) | |
47765 | + for (unsigned int b = 0; b<cinfo.image_width; b++) | |
43322 | 47766 | *(ptrd++) = (unsigned char)*(ptr_g++); |
43323 | 47767 | } break; |
43324 | 47768 | case 2 : { // RG images |
43325 | 47769 | const T *ptr_r = data(0,cinfo.next_scanline,0,0), |
43326 | 47770 | *ptr_g = data(0,cinfo.next_scanline,0,1); |
43327 | - for(unsigned int b = 0; b < cinfo.image_width; ++b) { | |
47771 | + for (unsigned int b = 0; b<cinfo.image_width; ++b) { | |
43328 | 47772 | *(ptrd++) = (unsigned char)*(ptr_r++); |
43329 | 47773 | *(ptrd++) = (unsigned char)*(ptr_g++); |
43330 | 47774 | *(ptrd++) = 0; |
... | ... | @@ -43334,7 +47778,7 @@ namespace cimg_library_suffixed { |
43334 | 47778 | const T *ptr_r = data(0,cinfo.next_scanline,0,0), |
43335 | 47779 | *ptr_g = data(0,cinfo.next_scanline,0,1), |
43336 | 47780 | *ptr_b = data(0,cinfo.next_scanline,0,2); |
43337 | - for(unsigned int b = 0; b < cinfo.image_width; ++b) { | |
47781 | + for (unsigned int b = 0; b<cinfo.image_width; ++b) { | |
43338 | 47782 | *(ptrd++) = (unsigned char)*(ptr_r++); |
43339 | 47783 | *(ptrd++) = (unsigned char)*(ptr_g++); |
43340 | 47784 | *(ptrd++) = (unsigned char)*(ptr_b++); |
... | ... | @@ -43345,7 +47789,7 @@ namespace cimg_library_suffixed { |
43345 | 47789 | *ptr_g = data(0,cinfo.next_scanline,0,1), |
43346 | 47790 | *ptr_b = data(0,cinfo.next_scanline,0,2), |
43347 | 47791 | *ptr_a = data(0,cinfo.next_scanline,0,3); |
43348 | - for(unsigned int b = 0; b < cinfo.image_width; ++b) { | |
47792 | + for (unsigned int b = 0; b<cinfo.image_width; ++b) { | |
43349 | 47793 | *(ptrd++) = (unsigned char)*(ptr_r++); |
43350 | 47794 | *(ptrd++) = (unsigned char)*(ptr_g++); |
43351 | 47795 | *(ptrd++) = (unsigned char)*(ptr_b++); |
... | ... | @@ -44087,11 +48531,12 @@ namespace cimg_library_suffixed { |
44087 | 48531 | - When libtiff is enabled, 2D and 3D (multipage) several |
44088 | 48532 | channel per pixel are supported for |
44089 | 48533 | <tt>char,uchar,short,ushort,float</tt> and \c double pixel types. |
44090 | - - If \c cimg_use_tif is not defined at compilation time the | |
48534 | + - If \c cimg_use_tif is not defined at compile time the | |
44091 | 48535 | function uses CImg<T>&save_other(const char*). |
44092 | 48536 | **/ |
44093 | 48537 | const CImg<T>& save_tiff(const char *const filename, const unsigned int compression_type=0, |
44094 | - const float *const voxel_size=0, const char *const description=0) const { | |
48538 | + const float *const voxel_size=0, const char *const description=0, | |
48539 | + const bool is_bigtiff=true) const { | |
44095 | 48540 | if (!filename) |
44096 | 48541 | throw CImgArgumentException(_cimg_instance |
44097 | 48542 | "save_tiff(): Specified filename is (null).", |
... | ... | @@ -44099,9 +48544,9 @@ namespace cimg_library_suffixed { |
44099 | 48544 | if (is_empty()) { cimg::fempty(0,filename); return *this; } |
44100 | 48545 | |
44101 | 48546 | #ifdef cimg_use_tiff |
44102 | - TIFF *tif = TIFFOpen(filename,"w"); | |
48547 | + TIFF *tif = TIFFOpen(filename,is_bigtiff?"w8":"w4"); | |
44103 | 48548 | if (tif) { |
44104 | - cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z,compression_type,voxel_size,description); | |
48549 | + cimg_forZ(*this,z) _save_tiff(tif,z,z,compression_type,voxel_size,description); | |
44105 | 48550 | TIFFClose(tif); |
44106 | 48551 | } else throw CImgIOException(_cimg_instance |
44107 | 48552 | "save_tiff(): Failed to open file '%s' for writing.", |
... | ... | @@ -44109,7 +48554,7 @@ namespace cimg_library_suffixed { |
44109 | 48554 | filename); |
44110 | 48555 | return *this; |
44111 | 48556 | #else |
44112 | - cimg::unused(compression_type,voxel_size,description); | |
48557 | + cimg::unused(compression_type,voxel_size,description,is_bigtiff); | |
44113 | 48558 | return save_other(filename); |
44114 | 48559 | #endif |
44115 | 48560 | } |
... | ... | @@ -44117,13 +48562,13 @@ namespace cimg_library_suffixed { |
44117 | 48562 | #ifdef cimg_use_tiff |
44118 | 48563 | |
44119 | 48564 | #define _cimg_save_tiff(types,typed,compression_type) if (!std::strcmp(types,pixel_type())) { \ |
44120 | - const typed foo = (typed)0; return _save_tiff(tif,directory,foo,compression_type,voxel_size,description); } | |
48565 | + const typed foo = (typed)0; return _save_tiff(tif,directory,z,foo,compression_type,voxel_size,description); } | |
44121 | 48566 | |
44122 | 48567 | // [internal] Save a plane into a tiff file |
44123 | 48568 | template<typename t> |
44124 | - const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const t& pixel_t, | |
44125 | - const unsigned int compression_type, | |
44126 | - const float *const voxel_size, const char *const description) const { | |
48569 | + const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z, const t& pixel_t, | |
48570 | + const unsigned int compression_type, const float *const voxel_size, | |
48571 | + const char *const description) const { | |
44127 | 48572 | if (is_empty() || !tif || pixel_t) return *this; |
44128 | 48573 | const char *const filename = TIFFFileName(tif); |
44129 | 48574 | uint32 rowsperstrip = (uint32)-1; |
... | ... | @@ -44166,7 +48611,7 @@ namespace cimg_library_suffixed { |
44166 | 48611 | for (unsigned int rr = 0; rr<nrow; ++rr) |
44167 | 48612 | for (unsigned int cc = 0; cc<_width; ++cc) |
44168 | 48613 | for (unsigned int vv = 0; vv<spp; ++vv) |
44169 | - buf[i++] = (t)(*this)(cc,row + rr,0,vv); | |
48614 | + buf[i++] = (t)(*this)(cc,row + rr,z,vv); | |
44170 | 48615 | if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(t))<0) |
44171 | 48616 | throw CImgIOException(_cimg_instance |
44172 | 48617 | "save_tiff(): Invalid strip writing when saving file '%s'.", |
... | ... | @@ -44179,8 +48624,9 @@ namespace cimg_library_suffixed { |
44179 | 48624 | return (*this); |
44180 | 48625 | } |
44181 | 48626 | |
44182 | - const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int compression_type, | |
44183 | - const float *const voxel_size, const char *const description) const { | |
48627 | + const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z, | |
48628 | + const unsigned int compression_type, const float *const voxel_size, | |
48629 | + const char *const description) const { | |
44184 | 48630 | _cimg_save_tiff("bool",unsigned char,compression_type); |
44185 | 48631 | _cimg_save_tiff("char",char,compression_type); |
44186 | 48632 | _cimg_save_tiff("unsigned char",unsigned char,compression_type); |
... | ... | @@ -44255,11 +48701,9 @@ namespace cimg_library_suffixed { |
44255 | 48701 | if (is_empty()) { cimg::fempty(0,filename); return *this; } |
44256 | 48702 | |
44257 | 48703 | std::FILE *file; |
44258 | - char header[348] = { 0 }; | |
44259 | - CImg<charT> hname(1024), iname(1024); | |
48704 | + CImg<charT> header(348,1,1,1,0), hname(1024), iname(1024); | |
44260 | 48705 | const char *const ext = cimg::split_filename(filename); |
44261 | 48706 | short datatype = -1; |
44262 | - std::memset(header,0,348); | |
44263 | 48707 | if (!*ext) { |
44264 | 48708 | cimg_snprintf(hname,hname._width,"%s.hdr",filename); |
44265 | 48709 | cimg_snprintf(iname,iname._width,"%s.img",filename); |
... | ... | @@ -44267,27 +48711,27 @@ namespace cimg_library_suffixed { |
44267 | 48711 | if (!cimg::strncasecmp(ext,"hdr",3)) { |
44268 | 48712 | std::strcpy(hname,filename); |
44269 | 48713 | std::strncpy(iname,filename,iname._width - 1); |
44270 | - std::sprintf(iname._data + std::strlen(iname) - 3,"img"); | |
48714 | + cimg_sprintf(iname._data + std::strlen(iname) - 3,"img"); | |
44271 | 48715 | } |
44272 | 48716 | if (!cimg::strncasecmp(ext,"img",3)) { |
44273 | 48717 | std::strcpy(hname,filename); |
44274 | 48718 | std::strncpy(iname,filename,iname._width - 1); |
44275 | - std::sprintf(hname._data + std::strlen(iname) - 3,"hdr"); | |
48719 | + cimg_sprintf(hname._data + std::strlen(iname) - 3,"hdr"); | |
44276 | 48720 | } |
44277 | 48721 | if (!cimg::strncasecmp(ext,"nii",3)) { |
44278 | 48722 | std::strncpy(hname,filename,hname._width - 1); *iname = 0; |
44279 | 48723 | } |
44280 | - int *const iheader = (int*)header; | |
48724 | + int *const iheader = (int*)header._data; | |
44281 | 48725 | *iheader = 348; |
44282 | - std::strcpy(header + 4,"CImg"); | |
44283 | - std::strcpy(header + 14," "); | |
44284 | - ((short*)(header + 36))[0] = 4096; | |
44285 | - ((char*)(header + 38))[0] = 114; | |
44286 | - ((short*)(header + 40))[0] = 4; | |
44287 | - ((short*)(header + 40))[1] = (short)_width; | |
44288 | - ((short*)(header + 40))[2] = (short)_height; | |
44289 | - ((short*)(header + 40))[3] = (short)_depth; | |
44290 | - ((short*)(header + 40))[4] = (short)_spectrum; | |
48726 | + std::strcpy(header._data + 4,"CImg"); | |
48727 | + std::strcpy(header._data + 14," "); | |
48728 | + ((short*)&(header[36]))[0] = 4096; | |
48729 | + ((char*)&(header[38]))[0] = 114; | |
48730 | + ((short*)&(header[40]))[0] = 4; | |
48731 | + ((short*)&(header[40]))[1] = (short)_width; | |
48732 | + ((short*)&(header[40]))[2] = (short)_height; | |
48733 | + ((short*)&(header[40]))[3] = (short)_depth; | |
48734 | + ((short*)&(header[40]))[4] = (short)_spectrum; | |
44291 | 48735 | if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2; |
44292 | 48736 | if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2; |
44293 | 48737 | if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2; |
... | ... | @@ -44305,17 +48749,17 @@ namespace cimg_library_suffixed { |
44305 | 48749 | cimg_instance, |
44306 | 48750 | pixel_type(),filename); |
44307 | 48751 | |
44308 | - ((short*)(header + 70))[0] = datatype; | |
44309 | - ((short*)(header + 72))[0] = sizeof(T); | |
44310 | - ((float*)(header + 112))[0] = 1; | |
44311 | - ((float*)(header + 76))[0] = 0; | |
48752 | + ((short*)&(header[70]))[0] = datatype; | |
48753 | + ((short*)&(header[72]))[0] = sizeof(T); | |
48754 | + ((float*)&(header[112]))[0] = 1; | |
48755 | + ((float*)&(header[76]))[0] = 0; | |
44312 | 48756 | if (voxel_size) { |
44313 | - ((float*)(header + 76))[1] = voxel_size[0]; | |
44314 | - ((float*)(header + 76))[2] = voxel_size[1]; | |
44315 | - ((float*)(header + 76))[3] = voxel_size[2]; | |
44316 | - } else ((float*)(header + 76))[1] = ((float*)(header + 76))[2] = ((float*)(header + 76))[3] = 1; | |
48757 | + ((float*)&(header[76]))[1] = voxel_size[0]; | |
48758 | + ((float*)&(header[76]))[2] = voxel_size[1]; | |
48759 | + ((float*)&(header[76]))[3] = voxel_size[2]; | |
48760 | + } else ((float*)&(header[76]))[1] = ((float*)&(header[76]))[2] = ((float*)&(header[76]))[3] = 1; | |
44317 | 48761 | file = cimg::fopen(hname,"wb"); |
44318 | - cimg::fwrite(header,348,file); | |
48762 | + cimg::fwrite(header._data,348,file); | |
44319 | 48763 | if (*iname) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); } |
44320 | 48764 | cimg::fwrite(_data,size(),file); |
44321 | 48765 | cimg::fclose(file); |
... | ... | @@ -44446,14 +48890,15 @@ namespace cimg_library_suffixed { |
44446 | 48890 | pixel_type(),filename?filename:"(FILE*)"); |
44447 | 48891 | |
44448 | 48892 | std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); |
44449 | - char header[257] = { 0 }; | |
44450 | - int err = cimg_snprintf(header,sizeof(header),"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n", | |
48893 | + CImg<charT> header(257); | |
48894 | + int err = cimg_snprintf(header,header._width,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n", | |
44451 | 48895 | _width,_height,_depth,_spectrum); |
44452 | - if (voxel_size) err+=std::sprintf(header + err,"VX=%g\nVY=%g\nVZ=%g\n",voxel_size[0],voxel_size[1],voxel_size[2]); | |
44453 | - err+=std::sprintf(header + err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm"); | |
44454 | - std::memset(header + err,'\n',252 - err); | |
44455 | - std::memcpy(header + 252,"##}\n",4); | |
44456 | - cimg::fwrite(header,256,nfile); | |
48896 | + if (voxel_size) err+=cimg_sprintf(header._data + err,"VX=%g\nVY=%g\nVZ=%g\n", | |
48897 | + voxel_size[0],voxel_size[1],voxel_size[2]); | |
48898 | + err+=cimg_sprintf(header._data + err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm"); | |
48899 | + std::memset(header._data + err,'\n',252 - err); | |
48900 | + std::memcpy(header._data + 252,"##}\n",4); | |
48901 | + cimg::fwrite(header._data,256,nfile); | |
44457 | 48902 | cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile); |
44458 | 48903 | if (!file) cimg::fclose(nfile); |
44459 | 48904 | return *this; |
... | ... | @@ -44552,28 +48997,28 @@ namespace cimg_library_suffixed { |
44552 | 48997 | unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const { |
44553 | 48998 | unsigned int nbdims = 0; |
44554 | 48999 | if (id==2 || id==3 || id==4) { |
44555 | - dims[0] = 1; dims[1] = _width; nbdims = 2; | |
49000 | + dims[0] = 1; dims[1] = _width; nbdims = 2; | |
44556 | 49001 | } |
44557 | 49002 | if (id==5 || id==6 || id==7) { |
44558 | - dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3; | |
49003 | + dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3; | |
44559 | 49004 | } |
44560 | 49005 | if (id==8 || id==9 || id==10) { |
44561 | - dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; | |
49006 | + dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; | |
44562 | 49007 | } |
44563 | 49008 | if (id==16 || id==17 || id==18) { |
44564 | - dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4; | |
49009 | + dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4; | |
44565 | 49010 | } |
44566 | 49011 | if (id==19 || id==20 || id==21) { |
44567 | - dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5; | |
49012 | + dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5; | |
44568 | 49013 | } |
44569 | 49014 | if (id==22 || id==23 || id==25) { |
44570 | - dims[0] = _spectrum; dims[1] = _width; nbdims = 2; | |
49015 | + dims[0] = _spectrum; dims[1] = _width; nbdims = 2; | |
44571 | 49016 | } |
44572 | 49017 | if (id==26 || id==27 || id==29) { |
44573 | - dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3; | |
49018 | + dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3; | |
44574 | 49019 | } |
44575 | 49020 | if (id==30 || id==31 || id==33) { |
44576 | - dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; | |
49021 | + dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; | |
44577 | 49022 | } |
44578 | 49023 | return nbdims; |
44579 | 49024 | } |
... | ... | @@ -44597,9 +49042,9 @@ namespace cimg_library_suffixed { |
44597 | 49042 | cimg::fwrite(header,36,nfile); \ |
44598 | 49043 | if (sizeof(unsigned long)==4) { CImg<ulongT> ndims(5); \ |
44599 | 49044 | for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ |
44600 | - else if (sizeof(unsigned int)==4) { CImg<ulongT> ndims(5); \ | |
49045 | + else if (sizeof(unsigned int)==4) { CImg<uintT> ndims(5); \ | |
44601 | 49046 | for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ |
44602 | - else if (sizeof(unsigned short)==4) { CImg<ulongT> ndims(5); \ | |
49047 | + else if (sizeof(unsigned short)==4) { CImg<ushortT> ndims(5); \ | |
44603 | 49048 | for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ |
44604 | 49049 | else throw CImgIOException(_cimg_instance \ |
44605 | 49050 | "save_pandore(): Unsupported datatype for file '%s'.",\ |
... | ... | @@ -44633,8 +49078,9 @@ namespace cimg_library_suffixed { |
44633 | 49078 | if (is_empty()) { cimg::fempty(file,filename); return *this; } |
44634 | 49079 | |
44635 | 49080 | std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); |
44636 | - unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0, | |
44637 | - 0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 }; | |
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 }; | |
44638 | 49084 | unsigned int nbdims, dims[5] = { 0 }; |
44639 | 49085 | bool saved = false; |
44640 | 49086 | _cimg_save_pandore_case(1,1,1,"unsigned char",2); |
... | ... | @@ -45921,8 +50367,7 @@ namespace cimg_library_suffixed { |
45921 | 50367 | \note Can be used to exchange the content of two lists in a fast way. |
45922 | 50368 | **/ |
45923 | 50369 | CImgList<T>& swap(CImgList<T>& list) { |
45924 | - cimg::swap(_width,list._width); | |
45925 | - cimg::swap(_allocated_width,list._allocated_width); | |
50370 | + cimg::swap(_width,list._width,_allocated_width,list._allocated_width); | |
45926 | 50371 | cimg::swap(_data,list._data); |
45927 | 50372 | return list; |
45928 | 50373 | } |
... | ... | @@ -45939,6 +50384,12 @@ namespace cimg_library_suffixed { |
45939 | 50384 | return _empty.assign(); |
45940 | 50385 | } |
45941 | 50386 | |
50387 | + //! Return a reference to an empty list \const. | |
50388 | + static const CImgList<T>& const_empty() { | |
50389 | + static const CImgList<T> _empty; | |
50390 | + return _empty; | |
50391 | + } | |
50392 | + | |
45942 | 50393 | //@} |
45943 | 50394 | //------------------------------------------ |
45944 | 50395 | // |
... | ... | @@ -47480,8 +51931,9 @@ namespace cimg_library_suffixed { |
47480 | 51931 | \return A one-column vector containing the selected image indexes. |
47481 | 51932 | **/ |
47482 | 51933 | CImg<intT> get_select(CImgDisplay &disp, const bool feature_type=true, |
47483 | - const char axis='x', const float align=0) const { | |
47484 | - return _get_select(disp,0,feature_type,axis,align,0,false,false,false); | |
51934 | + const char axis='x', const float align=0, | |
51935 | + const bool exit_on_anykey=false) const { | |
51936 | + return _get_select(disp,0,feature_type,axis,align,exit_on_anykey,0,false,false,false); | |
47485 | 51937 | } |
47486 | 51938 | |
47487 | 51939 | //! Display a simple interactive interface to select images or sublists. |
... | ... | @@ -47493,13 +51945,14 @@ namespace cimg_library_suffixed { |
47493 | 51945 | \return A one-column vector containing the selected image indexes. |
47494 | 51946 | **/ |
47495 | 51947 | CImg<intT> get_select(const char *const title, const bool feature_type=true, |
47496 | - const char axis='x', const float align=0) const { | |
51948 | + const char axis='x', const float align=0, | |
51949 | + const bool exit_on_anykey=false) const { | |
47497 | 51950 | CImgDisplay disp; |
47498 | - return _get_select(disp,title,feature_type,axis,align,0,false,false,false); | |
51951 | + return _get_select(disp,title,feature_type,axis,align,exit_on_anykey,0,false,false,false); | |
47499 | 51952 | } |
47500 | 51953 | |
47501 | 51954 | CImg<intT> _get_select(CImgDisplay &disp, const char *const title, const bool feature_type, |
47502 | - const char axis, const float align, | |
51955 | + const char axis, const float align, const bool exit_on_anykey, | |
47503 | 51956 | const unsigned int orig, const bool resize_disp, |
47504 | 51957 | const bool exit_on_rightbutton, const bool exit_on_wheel) const { |
47505 | 51958 | if (is_empty()) |
... | ... | @@ -47538,7 +51991,7 @@ namespace cimg_library_suffixed { |
47538 | 51991 | bool old_is_resized = disp.is_resized(); |
47539 | 51992 | disp._normalization = 0; |
47540 | 51993 | disp.show().set_key(0); |
47541 | - const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; | |
51994 | + static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; | |
47542 | 51995 | |
47543 | 51996 | // Enter event loop. |
47544 | 51997 | CImg<ucharT> visu0, visu; |
... | ... | @@ -47547,6 +52000,7 @@ namespace cimg_library_suffixed { |
47547 | 52000 | int oindice0 = -1, oindice1 = -1, indice0 = -1, indice1 = -1; |
47548 | 52001 | bool is_clicked = false, is_selected = false, text_down = false, update_display = true; |
47549 | 52002 | unsigned int key = 0; |
52003 | + | |
47550 | 52004 | while (!is_selected && !disp.is_closed() && !key) { |
47551 | 52005 | |
47552 | 52006 | // Create background image. |
... | ... | @@ -47650,6 +52104,7 @@ namespace cimg_library_suffixed { |
47650 | 52104 | if (disp.button()&2 && exit_on_rightbutton) { is_selected = true; indice1 = indice0 = -1; } |
47651 | 52105 | if (disp.wheel() && exit_on_wheel) is_selected = true; |
47652 | 52106 | |
52107 | + CImg<charT> filename(32); | |
47653 | 52108 | switch (key = disp.key()) { |
47654 | 52109 | #if cimg_OS!=2 |
47655 | 52110 | case cimg::keyCTRLRIGHT : |
... | ... | @@ -47679,10 +52134,9 @@ namespace cimg_library_suffixed { |
47679 | 52134 | } break; |
47680 | 52135 | case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { |
47681 | 52136 | static unsigned int snap_number = 0; |
47682 | - char filename[32] = { 0 }; | |
47683 | 52137 | std::FILE *file; |
47684 | 52138 | do { |
47685 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.bmp",snap_number++); | |
52139 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); | |
47686 | 52140 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
47687 | 52141 | } while (file); |
47688 | 52142 | if (visu0) { |
... | ... | @@ -47690,20 +52144,19 @@ namespace cimg_library_suffixed { |
47690 | 52144 | foreground_color,background_color,0.7f,13).display(disp); |
47691 | 52145 | visu0.save(filename); |
47692 | 52146 | (+visu0).draw_text(0,0," Snapshot '%s' saved. ", |
47693 | - foreground_color,background_color,0.7f,13,filename).display(disp); | |
52147 | + foreground_color,background_color,0.7f,13,filename._data).display(disp); | |
47694 | 52148 | } |
47695 | 52149 | disp.set_key(key,false).wait(); key = 0; |
47696 | 52150 | } break; |
47697 | 52151 | case cimg::keyO : |
47698 | 52152 | if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { |
47699 | 52153 | static unsigned int snap_number = 0; |
47700 | - char filename[32] = { 0 }; | |
47701 | 52154 | std::FILE *file; |
47702 | 52155 | do { |
47703 | 52156 | #ifdef cimg_use_zlib |
47704 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimgz",snap_number++); | |
52157 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); | |
47705 | 52158 | #else |
47706 | - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimg",snap_number++); | |
52159 | + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); | |
47707 | 52160 | #endif |
47708 | 52161 | if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); |
47709 | 52162 | } while (file); |
... | ... | @@ -47711,13 +52164,17 @@ namespace cimg_library_suffixed { |
47711 | 52164 | foreground_color,background_color,0.7f,13).display(disp); |
47712 | 52165 | save(filename); |
47713 | 52166 | (+visu0).draw_text(0,0," Instance '%s' saved. ", |
47714 | - foreground_color,background_color,0.7f,13,filename).display(disp); | |
52167 | + foreground_color,background_color,0.7f,13,filename._data).display(disp); | |
47715 | 52168 | disp.set_key(key,false).wait(); key = 0; |
47716 | 52169 | } break; |
47717 | 52170 | } |
47718 | 52171 | if (disp.is_resized()) { disp.resize(false); visu0.assign(); } |
47719 | 52172 | if (ym>=0 && ym<13) { if (!text_down) { visu.assign(); text_down = true; }} |
47720 | 52173 | else if (ym>=visu.height() - 13) { if(text_down) { visu.assign(); text_down = false; }} |
52174 | + if (!exit_on_anykey && key && key!=cimg::keyESC && | |
52175 | + (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { | |
52176 | + key = 0; | |
52177 | + } | |
47721 | 52178 | } |
47722 | 52179 | CImg<intT> res(1,2,1,1,-1); |
47723 | 52180 | if (is_selected) { |
... | ... | @@ -48422,7 +52879,7 @@ namespace cimg_library_suffixed { |
48422 | 52879 | \param first_frame Index of the first frame to read. |
48423 | 52880 | \param last_frame Index of the last frame to read. |
48424 | 52881 | \param step_frame Step value for frame reading. |
48425 | - \note If step_frame==0, the current video stream is open or released without any frames read. | |
52882 | + \note If step_frame==0, the current video stream is forced to be released (without any frames read). | |
48426 | 52883 | **/ |
48427 | 52884 | CImgList<T>& load_video(const char *const filename, |
48428 | 52885 | const unsigned int first_frame=0, const unsigned int last_frame=~0U, |
... | ... | @@ -48465,7 +52922,7 @@ namespace cimg_library_suffixed { |
48465 | 52922 | } else |
48466 | 52923 | if (filename) |
48467 | 52924 | cimg::warn(_cimglist_instance |
48468 | - "load_video() : File '%s', opened video stream associated with filename not found.", | |
52925 | + "load_video() : File '%s', no opened video stream associated with filename found.", | |
48469 | 52926 | cimglist_instance,filename); |
48470 | 52927 | else |
48471 | 52928 | cimg::warn(_cimglist_instance |
... | ... | @@ -48864,10 +53321,10 @@ namespace cimg_library_suffixed { |
48864 | 53321 | cimglist_for(*this,l) msiz+=_data[l].size(); |
48865 | 53322 | msiz*=sizeof(T); |
48866 | 53323 | const unsigned int mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U; |
48867 | - char _title[64] = { 0 }; | |
48868 | - if (!title) cimg_snprintf(_title,sizeof(_title),"CImgList<%s>",pixel_type()); | |
53324 | + CImg<charT> _title(64); | |
53325 | + if (!title) cimg_snprintf(_title,_title._width,"CImgList<%s>",pixel_type()); | |
48869 | 53326 | std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = %u/%u [%u %s], %sdata%s = (CImg<%s>*)%p", |
48870 | - cimg::t_magenta,cimg::t_bold,title?title:_title,cimg::t_normal, | |
53327 | + cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal, | |
48871 | 53328 | cimg::t_bold,cimg::t_normal,(void*)this, |
48872 | 53329 | cimg::t_bold,cimg::t_normal,_width,_allocated_width, |
48873 | 53330 | mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), |
... | ... | @@ -48915,9 +53372,9 @@ namespace cimg_library_suffixed { |
48915 | 53372 | **/ |
48916 | 53373 | const CImgList<T>& display(CImgDisplay &disp, const bool display_info, |
48917 | 53374 | const char axis='x', const float align=0, |
48918 | - unsigned int *const XYZ=0) const { | |
53375 | + unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { | |
48919 | 53376 | bool is_exit = false; |
48920 | - return _display(disp,0,display_info,axis,align,XYZ,0,true,is_exit); | |
53377 | + return _display(disp,0,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit); | |
48921 | 53378 | } |
48922 | 53379 | |
48923 | 53380 | //! Display the current CImgList instance in a new display window. |
... | ... | @@ -48929,15 +53386,16 @@ namespace cimg_library_suffixed { |
48929 | 53386 | **/ |
48930 | 53387 | const CImgList<T>& display(const char *const title=0, const bool display_info=true, |
48931 | 53388 | const char axis='x', const float align=0, |
48932 | - unsigned int *const XYZ=0) const { | |
53389 | + unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { | |
48933 | 53390 | CImgDisplay disp; |
48934 | 53391 | bool is_exit = false; |
48935 | - return _display(disp,title,display_info,axis,align,XYZ,0,true,is_exit); | |
53392 | + return _display(disp,title,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit); | |
48936 | 53393 | } |
48937 | 53394 | |
48938 | 53395 | const CImgList<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info, |
48939 | 53396 | const char axis, const float align, unsigned int *const XYZ, |
48940 | - const unsigned int orig, const bool is_first_call, bool &is_exit) const { | |
53397 | + const bool exit_on_anykey, const unsigned int orig, const bool is_first_call, | |
53398 | + bool &is_exit) const { | |
48941 | 53399 | if (is_empty()) |
48942 | 53400 | throw CImgInstanceException(_cimglist_instance |
48943 | 53401 | "display(): Empty instance.", |
... | ... | @@ -48978,13 +53436,13 @@ namespace cimg_library_suffixed { |
48978 | 53436 | disp.resize(cimg_fitscreen(_data[0]._width,_data[0]._height,_data[0]._depth),false). |
48979 | 53437 | set_title("%s (%ux%ux%ux%u)", |
48980 | 53438 | dtitle.data(),_data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum); |
48981 | - _data[0]._display(disp,0,false,XYZ,!is_first_call); | |
53439 | + _data[0]._display(disp,0,false,XYZ,exit_on_anykey,!is_first_call); | |
48982 | 53440 | if (disp.key()) is_exit = true; |
48983 | 53441 | disp.resize(cimg_fitscreen(dw,dh,1),false).set_title("%s",dtitle.data()); |
48984 | 53442 | } else { |
48985 | 53443 | bool disp_resize = !is_first_call; |
48986 | 53444 | while (!disp.is_closed() && !is_exit) { |
48987 | - const CImg<intT> s = _get_select(disp,0,true,axis,align,orig,disp_resize,!is_first_call,true); | |
53445 | + const CImg<intT> s = _get_select(disp,0,true,axis,align,exit_on_anykey,orig,disp_resize,!is_first_call,true); | |
48988 | 53446 | disp_resize = true; |
48989 | 53447 | if (s[0]<0) { // No selections done. |
48990 | 53448 | if (disp.button()&2) { disp.flush(); break; } |
... | ... | @@ -48999,10 +53457,12 @@ namespace cimg_library_suffixed { |
48999 | 53457 | ind0 = (unsigned int)cimg::max(0,s[0] - (int)delta), |
49000 | 53458 | ind1 = (unsigned int)cimg::min(width() - 1,s[0] + (int)delta); |
49001 | 53459 | if ((ind0!=0 || ind1!=_width - 1) && ind1 - ind0>=3) |
49002 | - get_shared_images(ind0,ind1)._display(disp,0,false,axis,align,XYZ,orig + ind0,false,is_exit); | |
53460 | + get_shared_images(ind0,ind1)._display(disp,0,false,axis,align,XYZ,exit_on_anykey, | |
53461 | + orig + ind0,false,is_exit); | |
49003 | 53462 | } |
49004 | 53463 | } else if (s[0]!=0 || s[1]!=width() - 1) |
49005 | - get_shared_images(s[0],s[1])._display(disp,0,false,axis,align,XYZ,orig + s[0],false,is_exit); | |
53464 | + get_shared_images(s[0],s[1])._display(disp,0,false,axis,align,XYZ,exit_on_anykey, | |
53465 | + orig + s[0],false,is_exit); | |
49006 | 53466 | } |
49007 | 53467 | } |
49008 | 53468 | return *this; |
... | ... | @@ -49136,7 +53596,7 @@ namespace cimg_library_suffixed { |
49136 | 53596 | \param fps Number of desired frames per second. |
49137 | 53597 | \param nb_loops Number of loops (\c 0 for infinite looping). |
49138 | 53598 | **/ |
49139 | - const CImgList<T>& save_gif_external(const char *const filename, const unsigned int fps=25, | |
53599 | + const CImgList<T>& save_gif_external(const char *const filename, const float fps=25, | |
49140 | 53600 | const unsigned int nb_loops=0) { |
49141 | 53601 | CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256); |
49142 | 53602 | CImgList<charT> filenames; |
... | ... | @@ -49162,15 +53622,15 @@ namespace cimg_library_suffixed { |
49162 | 53622 | } |
49163 | 53623 | |
49164 | 53624 | #if cimg_OS!=2 |
49165 | - cimg_snprintf(command,command._width,"%s -delay 1x%u -loop %u", | |
49166 | - cimg::imagemagick_path(),fps,nb_loops); | |
53625 | + cimg_snprintf(command,command._width,"%s -delay %u -loop %u", | |
53626 | + cimg::imagemagick_path(),(unsigned int)cimg::max(0.0f,cimg::round(100/fps)),nb_loops); | |
49167 | 53627 | CImg<ucharT>::string(command).move_to(filenames,0); |
49168 | 53628 | cimg_snprintf(command,command._width,"\"%s\" >/dev/null 2>&1", |
49169 | 53629 | CImg<charT>::string(filename)._system_strescape().data()); |
49170 | 53630 | CImg<ucharT>::string(command).move_to(filenames); |
49171 | 53631 | #else |
49172 | - cimg_snprintf(command,command._width,"\"%s -delay 1x%u -loop %u", | |
49173 | - cimg::imagemagick_path(),fps,nb_loops); | |
53632 | + cimg_snprintf(command,command._width,"\"%s -delay %u -loop %u", | |
53633 | + cimg::imagemagick_path(),(unsigned int)cimg::max(0.0f,cimg::round(100/fps)),nb_loops); | |
49174 | 53634 | CImg<ucharT>::string(command).move_to(filenames,0); |
49175 | 53635 | cimg_snprintf(command,command._width,"\"%s\"\" >NUL 2>&1", |
49176 | 53636 | CImg<charT>::string(filename)._system_strescape().data()); |
... | ... | @@ -49505,7 +53965,8 @@ namespace cimg_library_suffixed { |
49505 | 53965 | \param compression_type Compression mode used to write data. |
49506 | 53966 | **/ |
49507 | 53967 | const CImgList<T>& save_tiff(const char *const filename, const unsigned int compression_type=0, |
49508 | - const float *const voxel_size=0, const char *const description=0) const { | |
53968 | + const float *const voxel_size=0, const char *const description=0, | |
53969 | + const bool is_bigtiff=true) const { | |
49509 | 53970 | if (!filename) |
49510 | 53971 | throw CImgArgumentException(_cimglist_instance |
49511 | 53972 | "save_tiff(): Specified filename is (null).", |
... | ... | @@ -49513,21 +53974,18 @@ namespace cimg_library_suffixed { |
49513 | 53974 | if (is_empty()) { cimg::fempty(0,filename); return *this; } |
49514 | 53975 | |
49515 | 53976 | #ifndef cimg_use_tiff |
49516 | - if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description); | |
53977 | + if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description,is_bigtiff); | |
49517 | 53978 | else cimglist_for(*this,l) { |
49518 | 53979 | CImg<charT> nfilename(1024); |
49519 | 53980 | cimg::number_filename(filename,l,6,nfilename); |
49520 | - _data[l].save_tiff(nfilename,compression_type,voxel_size,description); | |
53981 | + _data[l].save_tiff(nfilename,compression_type,voxel_size,description,is_bigtiff); | |
49521 | 53982 | } |
49522 | 53983 | #else |
49523 | - TIFF *tif = TIFFOpen(filename,"w"); | |
53984 | + TIFF *tif = TIFFOpen(filename,is_bigtiff?"w8":"w4"); | |
49524 | 53985 | if (tif) { |
49525 | 53986 | for (unsigned int dir = 0, l = 0; l<_width; ++l) { |
49526 | 53987 | const CImg<T>& img = (*this)[l]; |
49527 | - if (img) { | |
49528 | - if (img._depth==1) img._save_tiff(tif,dir++,compression_type,voxel_size,description); | |
49529 | - else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++,compression_type,voxel_size,description); | |
49530 | - } | |
53988 | + cimg_forZ(img,z) img._save_tiff(tif,dir++,z,compression_type,voxel_size,description); | |
49531 | 53989 | } |
49532 | 53990 | TIFFClose(tif); |
49533 | 53991 | } else |
... | ... | @@ -49588,7 +54046,7 @@ namespace cimg_library_suffixed { |
49588 | 54046 | CImg<charT> nfilename(1024); |
49589 | 54047 | cimglist_for(*this,l) { |
49590 | 54048 | cimg::number_filename(body,l,6,nfilename); |
49591 | - if (*ext) std::sprintf(nfilename._data + std::strlen(nfilename),".%s",ext); | |
54049 | + if (*ext) cimg_sprintf(nfilename._data + std::strlen(nfilename),".%s",ext); | |
49592 | 54050 | _data[l].save_gzip_external(nfilename); |
49593 | 54051 | } |
49594 | 54052 | } |
... | ... | @@ -49651,7 +54109,7 @@ namespace cimg_library_suffixed { |
49651 | 54109 | |
49652 | 54110 | #define _cimg_docase(x) ((x)>='a'&&(x)<='z'?(x) + 'A' - 'a':(x)) |
49653 | 54111 | const char |
49654 | - *const _codec = codec?codec:"mp4v", | |
54112 | + *const _codec = codec && *codec?codec:"mp4v", | |
49655 | 54113 | codec0 = _cimg_docase(_codec[0]), |
49656 | 54114 | codec1 = _codec[0]?_cimg_docase(_codec[1]):0, |
49657 | 54115 | codec2 = _codec[1]?_cimg_docase(_codec[2]):0, |
... | ... | @@ -49977,13 +54435,13 @@ namespace cimg_library_suffixed { |
49977 | 54435 | \param is_variable_width Decide if the font has a variable (\c true) or fixed (\c false) width. |
49978 | 54436 | **/ |
49979 | 54437 | static const CImgList<ucharT>& font(const unsigned int font_height, const bool is_variable_width=true) { |
49980 | - if (!font_height) return CImgList<ucharT>::empty(); | |
54438 | + if (!font_height) return CImgList<ucharT>::const_empty(); | |
49981 | 54439 | cimg::mutex(11); |
49982 | 54440 | |
49983 | 54441 | // Decompress nearest base font data if needed. |
49984 | - const char *data_fonts[] = { cimg::data_font12x13, cimg::data_font20x23, cimg::data_font47x53, 0 }; | |
49985 | - const unsigned int data_widths[] = { 12,20,47,90 }, data_heights[] = { 13,23,53,103 }, | |
49986 | - data_Ms[] = { 86,79,57,47 }; | |
54442 | + static const char *data_fonts[] = { cimg::data_font12x13, cimg::data_font20x23, cimg::data_font47x53, 0 }; | |
54443 | + static const unsigned int data_widths[] = { 12,20,47,90 }, data_heights[] = { 13,23,53,103 }, | |
54444 | + data_Ms[] = { 86,79,57,47 }; | |
49987 | 54445 | const unsigned int data_ind = font_height<=13U?0U:font_height<=23U?1U:font_height<=53U?2U:3U; |
49988 | 54446 | static CImg<ucharT> base_fonts[4]; |
49989 | 54447 | CImg<ucharT> &base_font = base_fonts[data_ind]; |
... | ... | @@ -50727,7 +55185,7 @@ namespace cimg { |
50727 | 55185 | char *pd = _path; |
50728 | 55186 | for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; } |
50729 | 55187 | *pd = 0; |
50730 | - unsigned int lp = std::strlen(_path); | |
55188 | + unsigned int lp = (unsigned int)std::strlen(_path); | |
50731 | 55189 | if (!_is_pattern && lp && _path[lp - 1]=='/') { |
50732 | 55190 | _path[lp - 1] = 0; --lp; |
50733 | 55191 | #if cimg_OS!=2 |
... | ... | @@ -50747,7 +55205,7 @@ namespace cimg { |
50747 | 55205 | } else { // No path to folder specified, assuming current folder. |
50748 | 55206 | is_current = true; *_path = 0; |
50749 | 55207 | } |
50750 | - lp = std::strlen(_path); | |
55208 | + lp = (unsigned int)std::strlen(_path); | |
50751 | 55209 | } |
50752 | 55210 | |
50753 | 55211 | // Windows version. |
... | ... | @@ -50757,21 +55215,19 @@ namespace cimg { |
50757 | 55215 | std::memcpy(pattern,_path,lp); |
50758 | 55216 | pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0; |
50759 | 55217 | } |
50760 | - | |
50761 | 55218 | WIN32_FIND_DATAA file_data; |
50762 | 55219 | const HANDLE dir = FindFirstFileA(pattern.data(),&file_data); |
50763 | - if (dir==INVALID_HANDLE_VALUE) return CImgList<char>::empty(); | |
55220 | + if (dir==INVALID_HANDLE_VALUE) return CImgList<char>::const_empty(); | |
50764 | 55221 | do { |
50765 | 55222 | const char *const filename = file_data.cFileName; |
50766 | 55223 | if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { |
50767 | - const unsigned int lf = std::strlen(filename); | |
55224 | + const unsigned int lf = (unsigned int)std::strlen(filename); | |
50768 | 55225 | const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0; |
50769 | 55226 | if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) { |
50770 | 55227 | if (include_path) { |
50771 | - CImg<char> full_filename(lp + lf + 2); | |
50772 | - std::memcpy(full_filename,_path,lp); | |
50773 | - full_filename[lp] = '/'; | |
50774 | - std::memcpy(full_filename._data + lp + 1,filename,lf + 1); | |
55228 | + CImg<char> full_filename((lp?lp+1:0) + lf + 1); | |
55229 | + if (lp) { std::memcpy(full_filename,_path,lp); full_filename[lp] = '/'; } | |
55230 | + std::memcpy(full_filename._data + (lp?lp + 1:0),filename,lf + 1); | |
50775 | 55231 | full_filename.move_to(res); |
50776 | 55232 | } else CImg<char>(filename,lf + 1).move_to(res); |
50777 | 55233 | } |
... | ... | @@ -50782,12 +55238,12 @@ namespace cimg { |
50782 | 55238 | // Unix version (posix). |
50783 | 55239 | #else |
50784 | 55240 | DIR *const dir = opendir(is_root?"/":is_current?".":_path.data()); |
50785 | - if (!dir) return CImgList<char>::empty(); | |
55241 | + if (!dir) return CImgList<char>::const_empty(); | |
50786 | 55242 | struct dirent *ent; |
50787 | 55243 | while ((ent=readdir(dir))!=0) { |
50788 | 55244 | const char *const filename = ent->d_name; |
50789 | 55245 | if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { |
50790 | - const unsigned int lf = std::strlen(filename); | |
55246 | + const unsigned int lf = (unsigned int)std::strlen(filename); | |
50791 | 55247 | CImg<char> full_filename(lp + lf + 2); |
50792 | 55248 | |
50793 | 55249 | if (!is_current) { |
... | ... | @@ -50886,7 +55342,8 @@ namespace cimg { |
50886 | 55342 | \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download. |
50887 | 55343 | **/ |
50888 | 55344 | inline char *load_network(const char *const url, char *const filename_local, |
50889 | - const unsigned int timeout, const bool try_fallback) { | |
55345 | + const unsigned int timeout, const bool try_fallback, | |
55346 | + const char *const referer) { | |
50890 | 55347 | if (!url) |
50891 | 55348 | throw CImgArgumentException("cimg::load_network(): Specified URL is (null)."); |
50892 | 55349 | if (!filename_local) |
... | ... | @@ -50921,6 +55378,7 @@ namespace cimg { |
50921 | 55378 | curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L); |
50922 | 55379 | if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout); |
50923 | 55380 | if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L); |
55381 | + if (referer) curl_easy_setopt(curl,CURLOPT_REFERER,referer); | |
50924 | 55382 | res = curl_easy_perform(curl); |
50925 | 55383 | curl_easy_cleanup(curl); |
50926 | 55384 | std::fseek(file,0,SEEK_END); // Check if file size is 0. |
... | ... | @@ -50940,23 +55398,41 @@ namespace cimg { |
50940 | 55398 | cimg::unused(try_fallback); |
50941 | 55399 | |
50942 | 55400 | // Try with 'curl' first. |
50943 | - if (timeout) | |
50944 | - cimg_snprintf(command,command._width,"%s -m %u -f --silent --compressed -o \"%s\" \"%s\"", | |
50945 | - cimg::curl_path(),timeout,filename_local,url); | |
50946 | - else | |
50947 | - cimg_snprintf(command,command._width,"%s -f --silent --compressed -o \"%s\" \"%s\"", | |
50948 | - cimg::curl_path(),filename_local,url); | |
55401 | + if (timeout) { | |
55402 | + if (referer) | |
55403 | + cimg_snprintf(command,command._width,"%s -e %s -m %u -f --silent --compressed -o \"%s\" \"%s\"", | |
55404 | + cimg::curl_path(),referer,timeout,filename_local,url); | |
55405 | + else | |
55406 | + cimg_snprintf(command,command._width,"%s -m %u -f --silent --compressed -o \"%s\" \"%s\"", | |
55407 | + cimg::curl_path(),timeout,filename_local,url); | |
55408 | + } else { | |
55409 | + if (referer) | |
55410 | + cimg_snprintf(command,command._width,"%s -e %s -f --silent --compressed -o \"%s\" \"%s\"", | |
55411 | + cimg::curl_path(),referer,filename_local,url); | |
55412 | + else | |
55413 | + cimg_snprintf(command,command._width,"%s -f --silent --compressed -o \"%s\" \"%s\"", | |
55414 | + cimg::curl_path(),filename_local,url); | |
55415 | + } | |
50949 | 55416 | cimg::system(command); |
50950 | 55417 | |
50951 | 55418 | if (!(file = std::fopen(filename_local,"rb"))) { |
50952 | 55419 | |
50953 | 55420 | // Try with 'wget' otherwise. |
50954 | - if (timeout) | |
50955 | - cimg_snprintf(command,command._width,"%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"", | |
50956 | - cimg::wget_path(),timeout,filename_local,url); | |
50957 | - else | |
50958 | - cimg_snprintf(command,command._width,"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"", | |
50959 | - cimg::wget_path(),filename_local,url); | |
55421 | + if (timeout) { | |
55422 | + if (referer) | |
55423 | + cimg_snprintf(command,command._width,"%s --referer=%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"", | |
55424 | + cimg::wget_path(),referer,timeout,filename_local,url); | |
55425 | + else | |
55426 | + cimg_snprintf(command,command._width,"%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"", | |
55427 | + cimg::wget_path(),timeout,filename_local,url); | |
55428 | + } else { | |
55429 | + if (referer) | |
55430 | + cimg_snprintf(command,command._width,"%s --referer=%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"", | |
55431 | + cimg::wget_path(),referer,filename_local,url); | |
55432 | + else | |
55433 | + cimg_snprintf(command,command._width,"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"", | |
55434 | + cimg::wget_path(),filename_local,url); | |
55435 | + } | |
50960 | 55436 | cimg::system(command); |
50961 | 55437 | |
50962 | 55438 | if (!(file = std::fopen(filename_local,"rb"))) |
... | ... | @@ -51079,7 +55555,7 @@ namespace cimg { |
51079 | 55555 | logo._data,is_centered); |
51080 | 55556 | throw CImgIOException("cimg::dialog(): No display available."); |
51081 | 55557 | #else |
51082 | - const unsigned char | |
55558 | + static const unsigned char | |
51083 | 55559 | black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 }; |
51084 | 55560 | |
51085 | 55561 | // Create buttons and canvas graphics |
... | ... | @@ -51281,6 +55757,9 @@ namespace cil = cimg_library_suffixed; |
51281 | 55757 | #ifdef _cimg_redefine_PI |
51282 | 55758 | #define PI 3.141592653589793238462643383 |
51283 | 55759 | #endif |
55760 | +#ifdef _MSC_VER | |
55761 | +#pragma warning(pop) | |
55762 | +#endif | |
51284 | 55763 | |
51285 | 55764 | #endif |
51286 | 55765 | // Local Variables: | ... | ... |
stim/parser/filename.h
... | ... | @@ -215,7 +215,7 @@ public: |
215 | 215 | hFind = FindFirstFileA((filepath.str().c_str()), &FindFileData); |
216 | 216 | |
217 | 217 | if (hFind == INVALID_HANDLE_VALUE) { |
218 | - printf ("Invalid file handle. Error is %u.\n", GetLastError()); | |
218 | + printf ("Invalid file handle. Error is %u.\n", GetLastError()); | |
219 | 219 | } |
220 | 220 | else { |
221 | 221 | std::string file_name = FindFileData.cFileName; //get the file name |
... | ... | @@ -230,9 +230,8 @@ public: |
230 | 230 | file_list.push_back(current_file); |
231 | 231 | } |
232 | 232 | FindClose(hFind); |
233 | - | |
233 | + } | |
234 | 234 | return file_list; |
235 | - } | |
236 | 235 | |
237 | 236 | } |
238 | 237 | #endif | ... | ... |