00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #ifndef PIXEL_ARRAY_H
00032 #define PIXEL_ARRAY_H
00033
00034 #include <vector>
00035 #include <algorithm>
00036 #include <iomanip>
00037 #include <cmath>
00038 #include <cfloat>
00039 #include <iostream>
00040 #include <fstream>
00041 #include "AO_algo.h"
00042 #include "colormap.h"
00043 #include "iofits.h"
00044 #include "fits_header_data.h"
00045 #include "fft_manager.h"
00046
00047 using namespace std;
00048
00049 namespace Arroyo {
00050
00051 using std::string;
00052 using std::vector;
00053 using std::cerr;
00054 using std::endl;
00055 using std::ostream;
00056
00057
00058 template <class T> class pixel_array;
00059 template <class T> pixel_array<T> operator + (const pixel_array<T> &p1,
00060 const pixel_array<T> &p2);
00061 template <class T> pixel_array<T> operator - (const pixel_array<T> &p1,
00062 const pixel_array<T> &p2);
00063 template <class T> pixel_array<T> operator * (const pixel_array<T> &p1,
00064 const pixel_array<T> &p2);
00065 template <class T> pixel_array<T> operator / (const pixel_array<T> &p1,
00066 const pixel_array<T> &p2);
00067 template <class T> pixel_array<T> operator + (const pixel_array<T> &p1,
00068 double & fac);
00069 template <class T> pixel_array<T> operator - (const pixel_array<T> &p1,
00070 double & fac);
00071 template <class T> pixel_array<T> operator * (const pixel_array<T> &p1,
00072 double & fac);
00073 template <class T> pixel_array<T> operator / (const pixel_array<T> &p1,
00074 double & fac);
00075 template <class T> bool operator == (const pixel_array<T> &p1,
00076 const pixel_array<T> &p2);
00077 template <class T> bool operator != (const pixel_array<T> &p1,
00078 const pixel_array<T> &p2);
00079
00084
00085 template<class T>
00086 class pixel_array {
00087
00088 private:
00089
00098 void simple_rotate_and_shift_by_fft(double dx, double dy,
00099 double angle, bool window);
00100
00101 mutable int private_nelem;
00102
00103 protected:
00104
00106 vector<long> axes;
00107
00109 T * pixeldata;
00110
00112 float * pixelwts;
00113
00120 void set_axes(const vector<long> & in_axes);
00121
00126 void allocate_weights(double wt);
00127
00130 void deallocate_weights();
00131
00134 double normalize_by_wts();
00135
00140 void decimate(int nadd);
00141
00144 template<class U>
00145 void flag_zero_wts(const pixel_array<U> & pixarr);
00146
00151 void mask();
00152
00155 template<class U>
00156 void mask(const pixel_array<U> * pixarr);
00157
00160 pixel_array(const iofits & iof);
00161
00162 public:
00163
00166 pixel_array();
00167
00172 pixel_array(const pixel_array<T> & pixarr);
00173
00183 template<class U>
00184 pixel_array(const pixel_array<U> & pixarr,
00185 const vector<long> & pixel_limits);
00186
00192 pixel_array(const vector<long> & in_axes,
00193 const T * data = NULL,
00194 const float * wts = NULL);
00195
00198 ~pixel_array();
00199
00202 pixel_array<T> & operator = (const pixel_array<T> & pixarr);
00203
00206 virtual void read(const iofits & iof);
00207
00210 virtual void write(iofits & iof) const;
00211
00214 void write_to_ppm(double min, double max,
00215 bool logscale,
00216 bool colorbar,
00217 colormap * cmap,
00218 const char * filename,
00219 long min_dimen = -1) const;
00220
00223 inline int total_space() const {
00224
00225 if(this->private_nelem>0){
00226 return(this->private_nelem);
00227 }
00228
00229 int naxes = axes.size();
00230 if(naxes == 0)
00231 this->private_nelem=0;
00232 else {
00233 this->private_nelem = 1;
00234 for(int i=0; i<naxes; i++)
00235 this->private_nelem *= axes[i];
00236 }
00237
00238 return(this->private_nelem);
00239 };
00240
00243 bool weights_allocated() const;
00244
00247 vector<long> get_axes() const {return(axes);};
00248
00253 template<class U>
00254 void copyfrom(const pixel_array<U> & pixarr);
00255
00258 void print_axes(ostream & os) const;
00259
00268 T data(long n) const {
00269 if(n<0 || n>=this->total_space()){
00270 cerr << "pixel_array::data error - element " << n
00271 << " out of range\n";
00272 throw(string("pixel_array::data"));
00273 }
00274 return(pixeldata[n]);
00275 };
00276
00285 void set_data(long n, T val) const {
00286 if(n<0 || n>=this->total_space()){
00287 cerr << "pixel_array::set_data error - element " << n
00288 << " out of range\n";
00289 throw(string("pixel_array::set_data"));
00290 }
00291 pixeldata[n] = val;
00292 };
00293
00296 float wt(long elem) const{
00297 if(pixelwts!=NULL) return(*(pixelwts+elem));
00298 else {
00299 cerr << "pixel_array::wt error - weights not allocated\n";
00300 throw(string("pixel_array::wt"));
00301 }
00302 };
00303
00306 void min_and_max(double & min, double & max) const;
00307
00310 void min_and_max(double & min, vector<int> & minpixel,
00311 double & max, vector<int> & maxpixel) const;
00312
00315 void min_and_max(double & min, vector<int> & minpixel,
00316 double & max, vector<int> & maxpixel,
00317 vector<int> axis_0_limits,
00318 vector<int> axis_1_limits) const;
00319
00322 void flip_x();
00323
00326 void flip_y();
00327
00330 void flip_xy();
00331
00334 void flip_45();
00335
00339 void pad_array(int npad, double value = 0);
00340
00343 void clip_array(int nclip);
00344
00347 void shift_by_fft(double dx, double dy);
00348
00355 void rotate_by_fft(double angle, bool window=true);
00356
00366 void rotate_and_shift_by_fft(double dx,
00367 double dy,
00368 double angle,
00369 bool window=true);
00370
00375 void owen_makedon_rotate_and_shift_by_fft(double dx,
00376 double dy,
00377 double angle);
00378
00382 pixel_array<T> cross_correlate(const pixel_array<T> & pixarr) const;
00383
00390 void offset(const pixel_array<T> & pixarr,
00391 vector<double> & offsets,
00392 long range = -1) const;
00393
00396 template<class U, class V>
00397 friend pixel_array<U> & operator+=(pixel_array<U> & lhs,
00398 const pixel_array<V> & rhs);
00399
00402 template<class U, class V>
00403 friend pixel_array<U> & operator-=(pixel_array<U> & lhs,
00404 const pixel_array<V> & rhs);
00405
00408 template<class U, class V>
00409 friend pixel_array<U> & operator*=(pixel_array<U> & lhs,
00410 const pixel_array<V> & rhs);
00411
00414 template<class U, class V>
00415 friend pixel_array<U> & operator/=(pixel_array<U> & lhs,
00416 const pixel_array<V> & rhs);
00417
00420 virtual pixel_array<T> & operator += (const double & fac);
00421
00424 virtual pixel_array<T> & operator -= (const double & fac);
00425
00428 virtual pixel_array<T> & operator *= (const double & fac);
00429
00432 virtual pixel_array<T> & operator /= (const double & fac);
00433
00436 friend bool operator ==(const pixel_array<T> &p1, const pixel_array<T> &p2){
00437
00438 if(p1.axes.size()!=p2.axes.size()) return(0);
00439
00440 if((p1.pixelwts!=NULL && p2.pixelwts==NULL) ||
00441 (p1.pixelwts==NULL && p2.pixelwts!=NULL)){
00442 return(0);
00443 }
00444
00445 int nelem = 1;
00446 for(int i=0; i<p1.axes.size(); i++){
00447 if(p1.axes[i]!=p2.axes[i])
00448 return(0);
00449 nelem *= p1.axes[i];
00450 }
00451
00452 for(int i=0; i<nelem; i++)
00453 if(p1.pixeldata[i]!=p2.pixeldata[i]) return(0);
00454
00455 if(p1.pixelwts!=NULL)
00456 for(int i=0; i<nelem; i++)
00457 if(p1.pixelwts[i]!=p2.pixelwts[i]) return(0);
00458
00459 return(1);
00460 };
00461
00463 static int verbose_level;
00464
00465 };
00466
00467 template<class T>
00468 int pixel_array<T>::verbose_level = 0;
00469
00470 template<class T>
00471 void pixel_array<T>::set_axes(const vector<long> & in_axes){
00472
00473 int nelem = in_axes.size()==0 ? 0 : 1;
00474 for(int i=0; i<in_axes.size(); i++)
00475 nelem *= in_axes[i];
00476
00477 if(nelem<0){
00478 cerr << "pixel_array::set_axes error - "
00479 << "total number of elements " << nelem
00480 << " less than zero\n";
00481 throw(string("pixel_array::set_axes"));
00482 }
00483
00484 if(pixel_array<T>::verbose_level)
00485 cout << "pixel_array::set_axes - have " << total_space()
00486 << " and need " << nelem << endl;
00487
00488
00489 if(total_space() != nelem){
00490
00491 axes = in_axes;
00492
00493
00494
00495 this->private_nelem = -1;
00496
00497 if(pixel_array<T>::verbose_level)
00498 cout << "pixel_array::set_axes - reallocating memory\n";
00499
00500 bool wts_initialized = this->weights_allocated();
00501
00502 if(pixeldata!=NULL)
00503 delete [] pixeldata;
00504 if(pixelwts!=NULL){
00505 delete [] pixelwts;
00506 pixelwts = NULL;
00507 }
00508
00509 if(nelem==0){
00510 pixeldata=NULL;
00511 pixelwts=NULL;
00512 axes = in_axes;
00513
00514 return;
00515 }
00516
00517 try{
00518 if(pixel_array<T>::verbose_level)
00519 cout << "pixel_array::set_axes - allocating data: nelems "
00520 << nelem << endl;
00521 pixeldata = new T[nelem];
00522 } catch(...){
00523 cerr << "pixel_array::set_axes - error reallocating space for data array\n";
00524 throw(string("pixel_array::set_axes"));
00525 }
00526
00527 for(int i=0; i<nelem; i++)
00528 pixeldata[i] = 0;
00529
00530 if(wts_initialized)
00531 this->allocate_weights(0);
00532 } else {
00533
00534
00535
00536
00537
00538 axes = in_axes;
00539 for(int i=0; i<nelem; i++)
00540 pixeldata[i] = 0;
00541 if(this->weights_allocated())
00542 for(int i=0; i<nelem; i++)
00543 pixelwts[i] = 0;
00544 }
00545 }
00546
00547 template<class T>
00548 void pixel_array<T>::allocate_weights(double wt){
00549
00550 int nelem = total_space();
00551 if(pixeldata==NULL || nelem == 0){
00552 pixelwts=NULL;
00553 return;
00554 }
00555
00556 if(pixelwts!=NULL){
00557 for(int i=0; i<nelem; i++)
00558 pixelwts[i] = wt;
00559 return;
00560 }
00561
00562 try{
00563 if(pixel_array<T>::verbose_level)
00564 cout << "pixel_array::allocate_weights - " << total_space()
00565 << " weights being initialized to " << wt << endl;
00566 pixelwts = new float[nelem];}
00567 catch(...){
00568 cerr << "pixel_array::allocate_weights - could not allocate memory\n";
00569 throw(string("pixel_array::allocate_weights"));
00570 }
00571 for(int i=0; i<nelem; i++) pixelwts[i] = wt;
00572 }
00573
00574 template<class T>
00575 void pixel_array<T>::deallocate_weights(){
00576 if(pixelwts==NULL) return;
00577 delete [] pixelwts;
00578 pixelwts = NULL;
00579 }
00580
00581 template<> double pixel_array<long>::normalize_by_wts();
00582
00583 template<class T>
00584 double pixel_array<T>::normalize_by_wts(){
00585 double maxwt = 0;
00586 if(!weights_allocated())
00587 return(0);
00588 int nelem = total_space();
00589 for(int i=0; i<nelem; i++){
00590 if(pixelwts[i]>maxwt && pixelwts[i]!=0)
00591 maxwt = pixelwts[i];
00592 }
00593 for(int i=0; i<nelem; i++){
00594 if(pixelwts[i]!=maxwt && pixelwts[i]!=0){
00595 pixeldata[i] *= maxwt/(float)pixelwts[i];
00596 pixelwts[i] = maxwt;
00597 } else if(pixelwts[i]==0)
00598 pixeldata[i] = 0;
00599 }
00600 return(maxwt);
00601 }
00602
00603 template<class T>
00604 void pixel_array<T>::decimate(int nadd){
00605 if(axes.size()!=2){
00606 cerr << "pixel_array::decimate - cannot decimate "
00607 << "pixel_array with number of dimensions "
00608 << axes.size() << endl;
00609 throw(string("pixel_array::decimate"));
00610 }
00611
00612 if(nadd<0 || nadd>axes[0] || nadd>axes[1]){
00613 cerr << "pixel_array::decimate - error decimating by a factor of "
00614 << nadd << endl;
00615 throw(string("pixel_array::decimate"));
00616 }
00617
00618 if(nadd==0 || nadd==1) return;
00619
00620 vector<long> newaxes(2);
00621 for(int i=0; i<newaxes.size(); i++)
00622 newaxes[i] = axes[i]/nadd;
00623
00624 T * olddata = pixeldata;
00625 float * oldwts;
00626
00627 pixeldata = new T[newaxes[0]*newaxes[1]];
00628
00629 if(weights_allocated()){
00630 oldwts = pixelwts;
00631 pixelwts = new float[newaxes[0]*newaxes[1]];
00632 }
00633
00634 int wtsum;
00635 for(int i=0; i<newaxes[1]; i++){
00636 for(int j=0; j<newaxes[0]; j++){
00637 pixeldata[i*newaxes[0]+j] = 0;
00638 if(weights_allocated()){
00639 pixelwts[i*newaxes[0]+j] = 0;
00640 wtsum = 0;
00641 }
00642 for(int k=0; k<nadd; k++){
00643 for(int l=0; l<nadd; l++){
00644 if(weights_allocated()){
00645 pixeldata[i*newaxes[0]+j] +=
00646 olddata[(i*nadd+k)*axes[0]+j*nadd+l]*
00647 oldwts[(i*nadd+k)*axes[0]+j*nadd+l];
00648 pixelwts[i*newaxes[0]+j] += oldwts[(i*nadd+k)*axes[0]+j*nadd+l];
00649 } else {
00650 pixeldata[i*newaxes[0]+j] += olddata[(i*nadd+k)*axes[0]+j*nadd+l];
00651 }
00652 }
00653 }
00654 }
00655 }
00656
00657 axes = newaxes;
00658 delete [] olddata;
00659 }
00660
00661
00662 template<class T>
00663 void pixel_array<T>::pad_array(int npad, double value) {
00664 if(npad<0){
00665 cerr << "pixel_array::pad_array error - cannot pad by "
00666 << npad << " pixels\n";
00667 throw(string("pixel_array::pad_array"));
00668 }
00669 if(npad==0 || axes.size()==0) return;
00670
00671 if(axes.size()!=2){
00672 cerr << "pixel_array::pad_array error - cannot pad by "
00673 << axes.size() << " dimensions, "
00674 << " as this generalization has not yet been coded\n";
00675 throw(string("pixel_array::pad_array"));
00676 }
00677
00678 vector<long> new_dimen = axes;
00679 int nelem = 1;
00680 for(int i=0; i<new_dimen.size(); i++){
00681 new_dimen[i] += 2*npad;
00682 nelem *= new_dimen[i];
00683 }
00684
00685
00686 T * newdata = new T[nelem];
00687 float * newwts = NULL;
00688 if(weights_allocated())
00689 newwts = new float[nelem];
00690
00691
00692 for(int i=0; i<new_dimen[1]; i++){
00693 for(int j=0; j<new_dimen[0]; j++){
00694 newdata[i*new_dimen[0]+j] = value;
00695 if(weights_allocated())
00696 newwts[i*new_dimen[0]+j] = 0;
00697 }
00698 }
00699
00700
00701 for(int i=0; i<axes[1]; i++){
00702 for(int j=0; j<axes[0]; j++){
00703 newdata[(i+npad)*new_dimen[0]+npad+j] =
00704 pixeldata[i*axes[0]+j];
00705 if(weights_allocated())
00706 newwts[(i+npad)*new_dimen[0]+npad+j] =
00707 pixelwts[i*axes[0]+j];
00708 }
00709 }
00710
00711 delete [] pixeldata;
00712 pixeldata = newdata;
00713
00714 if(weights_allocated()){
00715 delete pixelwts;
00716 pixelwts = newwts;
00717 }
00718
00719 axes = new_dimen;
00720 }
00721
00722 template<class T>
00723 void pixel_array<T>::clip_array(int nclip) {
00724
00725 if(nclip==0) return;
00726 if(nclip<0){
00727 cerr << "pixel_array::clip_array error - cannot clip by "
00728 << nclip << " pixels\n";
00729 throw(string("pixel_array::clip_array"));
00730 }
00731
00732 vector<long> new_axes = axes;
00733 int nelem = 1;
00734 for(int i=0; i<new_axes.size(); i++){
00735 new_axes[i] -= 2*nclip;
00736 if(new_axes[i]<=0){
00737 cerr << "pixel_array::clip_array error - clipping original array by "
00738 << nclip << " pixels leaves non-positive array size\n";
00739 throw(string("pixel_array::clip_array"));
00740 }
00741 nelem *= new_axes[i];
00742 }
00743
00744
00745 T * newdata = new T[nelem];
00746 float * newwts = NULL;
00747 if(weights_allocated())
00748 newwts = new float[nelem];
00749
00750
00751 for(int i=0; i<new_axes[1]; i++)
00752 for(int j=0; j<new_axes[0]; j++){
00753 newdata[i*new_axes[0]+j] =
00754 pixeldata[(i+nclip)*axes[0]+nclip+j];
00755 if(weights_allocated())
00756 newwts[i*new_axes[0]+j+1] =
00757 pixelwts[(i+nclip)*axes[0]+nclip+j];
00758 }
00759
00760
00761 delete [] pixeldata;
00762 pixeldata = newdata;
00763 if(weights_allocated()){
00764 delete [] pixelwts;
00765 pixelwts = newwts;
00766 }
00767 axes = new_axes;
00768 }
00769
00770 template<class T>
00771 template<class U>
00772 void pixel_array<T>::flag_zero_wts(const pixel_array<U> & pixarr){
00773
00774 if(!pixarr.weights_allocated()){
00775 cerr << "pixel_array::flag_zero_wts error - "
00776 << "reference array has no weights\n";
00777 throw(string("pixel_array::flag_zero_wts"));
00778 }
00779 if(!this->weights_allocated())
00780 this->allocate_weights(1);
00781 int nelem = total_space();
00782 for(int i=0; i<nelem; i++){
00783 if(pixarr.wt(i)==0){
00784 pixeldata[i] = 0;
00785 pixelwts[i] = 0;
00786 }
00787 }
00788 }
00789
00790 template<class T>
00791 void pixel_array<T>::mask(){
00792 if(!this->weights_allocated())
00793 this->allocate_weights(1);
00794 int nelem = total_space();
00795 for(int i=0; i<nelem; i++){
00796 if(pixeldata[i]==0){
00797 pixelwts[i] = 0;
00798 } else {
00799 pixeldata[i] = 1;
00800 pixelwts[i] = 1;
00801 }
00802 }
00803 }
00804
00805 template<class T>
00806 template<class U>
00807 void pixel_array<T>::mask(const pixel_array<U> * pixarr){
00808 if(axes!=pixarr->get_axes()){
00809 cerr << "pixel_array::mask error - mismatched axes\n";
00810 throw(string("pixel_array::mask"));
00811 }
00812 if(this->weights_allocated()==0)
00813 this->allocate_weights(1);
00814 int count = 0;
00815 int nelem = total_space();
00816 for(int i=0; i<nelem; i++){
00817 if(pixarr->data(i)==0){
00818 pixeldata[i] = 0;
00819 pixelwts[i] = 0;
00820 count++;
00821 }
00822 }
00823 }
00824
00825 template<class T>
00826 void pixel_array<T>::read(const iofits & iof){
00827
00828 int ndimen = iof.get_img_dim();
00829 vector<long> tmpaxes = iof.get_img_size();
00830 this->set_axes(tmpaxes);
00831
00832 int nelems = this->total_space();
00833
00834 try{
00835 if(pixel_array<T>::verbose_level)
00836 cout << "pixel_array::pixel_array - reading data\n";
00837 iof.read_image(0, nelems-1, pixeldata);
00838 } catch(...){
00839 cerr << "pixel_array::pixel_array - error reading image\n";
00840 throw(string("pixel_array::pixel_array"));
00841 }
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896 if(!iof.key_exists("WEIGHTS")){
00897 if(iof.get_num_hdus()==2){
00898 if(pixel_array<T>::verbose_level)
00899 cout << "pixel_array::pixel_array - reading weights\n";
00900 this->allocate_weights(0);
00901 iof.movabs_hdu(2);
00902 iof.read_image(0,nelems-1,pixelwts);
00903 } else pixelwts = NULL;
00904 } else {
00905 bool weights;
00906 string comment;
00907 iof.read_key("WEIGHTS", weights, comment);
00908 if(weights){
00909 if(pixel_array<T>::verbose_level)
00910 cout << "pixel_array::pixel_array - reading weights\n";
00911 this->allocate_weights(0);
00912 iof.movrel_hdu(1);
00913 iof.read_image(0, nelems-1, pixelwts);
00914 }
00915
00916 if(iof.get_hdu_num()<iof.get_num_hdus())
00917 iof.movrel_hdu(1);
00918 }
00919 }
00920
00921 template<class T>
00922 void pixel_array<T>::write(iofits & iof) const {
00923
00924 int space = total_space();
00925 if(space!=0) iof.write_image(0,space-1,pixeldata);
00926
00927 string comment = "weights present";
00928 if(pixelwts!=NULL){
00929 iof.write_key("WEIGHTS", true, comment);
00930 Arroyo::fits_header_data<float> fhd(this->get_axes());
00931 fhd.write(iof);
00932 if(space!=0) iof.write_image(0,space-1,pixelwts);
00933 } else
00934 iof.write_key("WEIGHTS", false, comment);
00935
00936 }
00937
00938 template<class T>
00939 void pixel_array<T>::write_to_ppm(double min, double max,
00940 bool logscale,
00941 bool colorbar,
00942 colormap * cmap,
00943 const char * filename,
00944 long min_dimen) const {
00945
00946 if(axes.size()!=2){
00947 cerr << "pixel_array::write_to_ppm error - array has "
00948 << axes.size() << " axes, rather than two\n";
00949 throw(string("pixel_array::write_to_ppm"));
00950 }
00951
00952 if(min>=max){
00953 cerr << "pixel_array::write_to_ppm error - min "
00954 << min << " and max " << max
00955 << " supplied to this function are inconsistent\n";
00956 throw(string("pixel_array::write_to_ppm"));
00957 }
00958
00959 long ppm_dimen;
00960 long ppm_pix_per_elem;
00961 if(min_dimen==-1){
00962 ppm_dimen = axes[0]>axes[1]?axes[0] : axes[1];
00963 ppm_pix_per_elem = 1;
00964 } else {
00965 if(min_dimen<axes[0] || min_dimen<axes[1]){
00966 cerr << "pixel_array::write_to_ppm error - minimum dimension "
00967 << min_dimen << " less than array dimensions "
00968 << axes[0] << "x" << axes[1] << endl;
00969 throw(string("pixel_array::write_to_ppm"));
00970 }
00971 ppm_dimen = min_dimen;
00972 ppm_pix_per_elem = axes[0]>axes[1] ? min_dimen/axes[0] : min_dimen/axes[1];
00973 }
00974 double ppm_min = min;
00975
00976 long axis_zero_min =
00977 axes[0]>axes[1] ? 0 : ((axes[1]-axes[0])*ppm_pix_per_elem)/2;
00978 long axis_zero_max =
00979 axes[0]>axes[1] ? ppm_dimen : axes[0]*ppm_pix_per_elem+axis_zero_min;
00980 long axis_one_min =
00981 axes[1]>axes[0] ? 0 : ((axes[0]-axes[1])*ppm_pix_per_elem)/2;
00982 long axis_one_max =
00983 axes[1]>axes[0] ? ppm_dimen : axes[1]*ppm_pix_per_elem+axis_one_min;
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995 std::ofstream fs;
00996 fs.open(filename);
00997 fs << "P6\n";
00998
00999 long colorbar_padding = 0;
01000 if(colorbar)
01001 colorbar_padding = .1*ppm_dimen>60 ? (long)(.1*ppm_dimen) : 60;
01002 fs << ppm_dimen << " " << ppm_dimen+colorbar_padding << endl;
01003 fs << "255\n";
01004 fs.close();
01005
01006 fs.open(filename,
01007 std::ios::app | std::ios::out | std::ios::binary | std::ios::ate);
01008
01009
01010
01011
01012 int index;
01013 int nelem = axes[0]*axes[1];
01014 for(int i=ppm_dimen-1; i>=0; i--){
01015 for(int j=0; j<ppm_dimen; j++){
01016 if(i<axis_one_min || i>=axis_one_max || j<axis_zero_min || j>=axis_zero_max)
01017 fs << cmap->get_R(ppm_min, min, max, logscale)
01018 << cmap->get_G(ppm_min, min, max, logscale)
01019 << cmap->get_B(ppm_min, min, max, logscale);
01020 else {
01021 index = (((i-axis_one_min)/ppm_pix_per_elem)*axes[0])
01022 +((j-axis_zero_min)/ppm_pix_per_elem);
01023 fs << cmap->get_R(pixeldata[index], min, max, logscale)
01024 << cmap->get_G(pixeldata[index], min, max, logscale)
01025 << cmap->get_B(pixeldata[index], min, max, logscale);
01026 }
01027 }
01028 }
01029
01030 if(colorbar){
01031 int first_limit = (long)(.3*colorbar_padding);
01032 int second_limit = (long)(.5*colorbar_padding);
01033
01034 for(int i=0; i<first_limit; i++)
01035 for(int j=0; j<ppm_dimen; j++)
01036 fs << cmap->get_R(ppm_min, min, max)
01037 << cmap->get_G(ppm_min, min, max)
01038 << cmap->get_B(ppm_min, min, max);
01039
01040 for(int i=first_limit; i<second_limit; i++){
01041 int first = (long)(.1*ppm_dimen);
01042 int second = (long)(.9*ppm_dimen);
01043 for(int j=0; j<first-1; j++)
01044 fs << cmap->get_R(ppm_min, min, max)
01045 << cmap->get_G(ppm_min, min, max)
01046 << cmap->get_B(ppm_min, min, max);
01047
01048 fs << '0' << '0' << '0';
01049
01050 for(int j=first; j<second; j++){
01051 if(i==first_limit || i==second_limit-1)
01052 fs << '0' << '0' << '0';
01053 else
01054 fs << cmap->get_R(min+(j-first)*(max-min)/(double)(second-first), min, max)
01055 << cmap->get_G(min+(j-first)*(max-min)/(double)(second-first), min, max)
01056 << cmap->get_B(min+(j-first)*(max-min)/(double)(second-first), min, max);
01057 }
01058
01059 fs << '0' << '0' << '0';
01060
01061 for(int j=second+1; j<ppm_dimen; j++)
01062 fs << cmap->get_R(ppm_min, min, max)
01063 << cmap->get_G(ppm_min, min, max)
01064 << cmap->get_B(ppm_min, min, max);
01065 }
01066
01067 for(int i=second_limit; i<colorbar_padding; i++)
01068 for(int j=0; j<ppm_dimen; j++)
01069 fs << cmap->get_R(ppm_min, min, max)
01070 << cmap->get_G(ppm_min, min, max)
01071 << cmap->get_B(ppm_min, min, max);
01072 }
01073 }
01074
01075 template<class T>
01076 pixel_array<T>::pixel_array() {
01077 private_nelem = -1;
01078 pixeldata = NULL;
01079 pixelwts = NULL;
01080 }
01081
01082 template<class T>
01083 pixel_array<T>::pixel_array(const pixel_array<T> & pixarr){
01084 private_nelem = -1;
01085 pixeldata = NULL;
01086 pixelwts = NULL;
01087 pixel_array::operator=(pixarr);
01088 }
01089
01090 template<class T>
01091 pixel_array<T>::pixel_array(const iofits & iof){
01092 private_nelem = -1;
01093 pixeldata = NULL;
01094 pixelwts = NULL;
01095 this->read(iof);
01096 }
01097
01098 template<class T>
01099 template<class U>
01100 pixel_array<T>::pixel_array(const pixel_array<U> & pixarr,
01101 const vector<long> & pixel_limits){
01102
01103
01104 private_nelem = -1;
01105 vector<long> paxes = pixarr.get_axes();
01106 if(paxes.size()!=2){
01107 cerr << "pixel_array::pixel_array error - "
01108 << "cannot construct through extraction from "
01109 << axes.size() << " dimensions, "
01110 << " as this generalization has not yet been coded\n";
01111 throw(string("pixel_array::pixel_array"));
01112 }
01113
01114 if(pixel_limits.size()!=2*paxes.size()){
01115 cerr << "pixel_array::pixel_array error - "
01116 << "cannot construct from a pixel array of other than 2 axes\n";
01117 throw(string("pixel_array::pixel_array"));
01118 }
01119
01120 if(pixel_array<T>::verbose_level)
01121 cout << "pixel_array::pixel_array - original axes "
01122 << paxes[0] << "\t" << paxes[1] << endl;
01123
01124 vector<long> tmpaxes(paxes.size());
01125
01126 for(int i=0; i<pixel_limits.size(); i+=2){
01127
01128 if(pixel_limits[i+1] >= paxes[i/2] || pixel_limits[i] < 0){
01129 cerr << "pixel_array::pixel_array - "
01130 << "requested pixels out of ";
01131 if(i==0) cerr << "horizontal";
01132 else cerr << "vertical";
01133 cerr << " range of input pixel_array:\n\t"
01134 << "requested range\t" << pixel_limits[i]
01135 << " - " << pixel_limits[i+1]
01136 << "\n\tinput range\t" << 0 << " - " << paxes[i/2]-1 << endl;
01137 throw(string("pixel_array::pixel_array"));
01138 }
01139
01140 tmpaxes[i/2] = pixel_limits[i+1] - pixel_limits[i] + 1;
01141 if(tmpaxes[i/2]<=0){
01142 cerr << "pixel_array::pixel_array - undefined pixel limits "
01143 << pixel_limits[i+1] << " - " << pixel_limits[i] << endl;
01144 throw(string("pixel_array::pixel_array"));
01145 }
01146 }
01147
01148 pixeldata = NULL;
01149 pixelwts = NULL;
01150 this->set_axes(tmpaxes);
01151 if(pixarr.weights_allocated())
01152 this->allocate_weights(0);
01153
01154
01155
01156 if(pixel_array<T>::verbose_level)
01157 cout << "pixel_array::pixel_array - extracting horizontal "
01158 << pixel_limits[0] << " - " << pixel_limits[1]
01159 << " vertical " << pixel_limits[2] << " - " << pixel_limits[3] << endl;
01160 int tmpa, tmpb;
01161 int axes_one = axes[1];
01162 int axes_zero = axes[0];
01163 int paxes_zero = paxes[0];
01164 long pixel_limits_zero = pixel_limits[0];
01165 long pixel_limits_two = pixel_limits[2];
01166 for(int i=0; i<axes_one; i++){
01167 for(int j=0; j<axes_zero; j++){
01168 tmpa = i*axes_zero+j;
01169 tmpb = (pixel_limits_two+i)*paxes_zero+pixel_limits_zero+j;
01170 pixeldata[tmpa] = pixarr.data(tmpb);
01171 if(pixelwts!=NULL) pixelwts[tmpa] = pixarr.wt(tmpb);
01172 }
01173 }
01174 }
01175
01176 template<class T>
01177 pixel_array<T>::pixel_array(const vector<long> & in_axes,
01178 const T * data,
01179 const float * wts){
01180
01181 if(data == NULL && wts != NULL){
01182 cerr << "pixel_array::pixel_array error - data == NULL, wts != NULL" << endl;
01183 throw(string("pixel_array::pixel_array"));
01184 }
01185
01186 private_nelem = -1;
01187 pixeldata = NULL;
01188 pixelwts = NULL;
01189 this->set_axes(in_axes);
01190
01191 int nelems = total_space();
01192
01193 if(data!=NULL){
01194 for(int i=0; i<nelems; i++)
01195 pixeldata[i] = data[i];
01196
01197 if(wts!=NULL){
01198 this->allocate_weights(0);
01199 for(int i=0; i<nelems; i++)
01200 pixelwts[i] = wts[i];
01201 }
01202 } else
01203 for(int i=0; i<nelems; i++)
01204 pixeldata[i] = 0;
01205 }
01206
01207 template<class T>
01208 pixel_array<T>::~pixel_array(){
01209 if(pixeldata!=NULL)
01210 delete [] pixeldata;
01211 if(pixelwts!=NULL)
01212 delete [] pixelwts;
01213 }
01214
01215 template<class T>
01216 pixel_array<T> & pixel_array<T>::operator = (const pixel_array<T> & pixarr){
01217
01218 if(this == &pixarr){
01219 return(*this);
01220 }
01221 this->copyfrom(pixarr);
01222 return(*this);
01223 }
01224
01225 template<class T>
01226 bool pixel_array<T>::weights_allocated() const {
01227 if(pixelwts == NULL) return(0);
01228 return(1);
01229 }
01230
01231 template<class T>
01232 template<class U>
01233 void pixel_array<T>::copyfrom(const pixel_array<U> & pixarr){
01234
01235 if((void*)this == (void*)&pixarr) return;
01236
01237 this->set_axes(pixarr.get_axes());
01238
01239
01240 int nelem = pixarr.total_space();
01241 for(int i=0; i<nelem; i++)
01242 pixeldata[i] = static_cast<T>(pixarr.data(i));
01243
01244
01245 if(pixarr.weights_allocated()){
01246 if(!this->weights_allocated())
01247 this->allocate_weights(0);
01248 for(int i=0; i<nelem; i++)
01249 pixelwts[i] = pixarr.wt(i);
01250 }
01251 }
01252
01253 template<class T>
01254 void pixel_array<T>::print_axes(ostream & os) const {
01255 os << "pixel_array::print_axes - axes size " << axes.size() << endl;
01256 for(int i=0; i<axes.size(); i++)
01257 os << "pixel_array::print_axes - axis " << i << " size " << axes[i] << endl;
01258 }
01259
01260 template<class T>
01261 void pixel_array<T>::min_and_max(double & min, double & max) const {
01262 vector<int> minpix(2,0), maxpix(2,0);
01263 this->min_and_max(min, minpix, max, maxpix);
01264 }
01265
01266 template<class T>
01267 void pixel_array<T>::min_and_max(double & min, vector<int> & minpixel,
01268 double & max, vector<int> & maxpixel) const {
01269
01270 vector<int> axis_0_limits(2,0);
01271 vector<int> axis_1_limits(2,0);
01272 axis_0_limits[1] = axes[0]-1;
01273 axis_1_limits[1] = axes[1]-1;
01274 this->min_and_max(min, minpixel,
01275 max, maxpixel,
01276 axis_0_limits, axis_1_limits);
01277 }
01278
01279 template<class T>
01280 void pixel_array<T>::min_and_max(double & min, vector<int> & minpixel,
01281 double & max, vector<int> & maxpixel,
01282 vector<int> axis_0_limits,
01283 vector<int> axis_1_limits) const {
01284
01285 if(axis_1_limits.size()!=2 || axis_1_limits.size()!=2){
01286 cerr << "pixel_array<T>::min_and_max error - axis limits wrong dimension\n";
01287 throw(string("pixel_array<T>::min_and_max"));
01288 }
01289
01290 if(axis_0_limits[0] < 0 || axis_0_limits[1] >= this->axes[0]){
01291 cerr << "pixel_array<T>::min_and_max error - axis 0 limits out of range\n";
01292 throw(string("pixel_array<T>::min_and_max"));
01293 }
01294 if(axis_1_limits[0] < 0 || axis_1_limits[1] >= this->axes[1]){
01295 cerr << "pixel_array<T>::min_and_max error - axis 1 limits out of range\n";
01296 throw(string("pixel_array<T>::min_and_max"));
01297 }
01298
01299 if(verbose_level)
01300 cout << "pixel_array<T>::min_and_max - "
01301 << "searching for min and max within limits "
01302 << "(" << axis_0_limits[0] << "," << axis_0_limits[1] << ")"
01303 << "(" << axis_1_limits[0] << "," << axis_1_limits[1] << ")" << endl;
01304
01305 int index;
01306 int axes_0_limits_zero = axis_0_limits[0];
01307 int axes_0_limits_one = axis_0_limits[1];
01308 int axes_1_limits_zero = axis_1_limits[0];
01309 int axes_1_limits_one = axis_1_limits[1];
01310 int axes_zero = axes[0];
01311
01312 minpixel.resize(2);
01313 maxpixel.resize(2);
01314 min = pixeldata[0];
01315 max = pixeldata[0];
01316 if(pixelwts!=NULL){
01317 for(int i=axes_1_limits_zero; i<axes_1_limits_one; i++){
01318 for(int j=axes_0_limits_zero; j<axes_0_limits_one; j++){
01319 index = i*axes_zero+j;
01320 if(min>pixeldata[index] && pixelwts[index]!=0){
01321 min = pixeldata[index];
01322 minpixel[0] = j; minpixel[1] = i;
01323 }
01324 if(max<pixeldata[index] && pixelwts[index]!=0){
01325 max = pixeldata[index];
01326 maxpixel[0] = j; maxpixel[1] = i;
01327 }
01328 }
01329 }
01330 } else {
01331 for(int i=axes_1_limits_zero; i<axes_1_limits_one; i++){
01332 for(int j=axes_0_limits_zero; j<axes_0_limits_one; j++){
01333 index = i*axes_zero+j;
01334 if(min>pixeldata[index]){
01335 min = pixeldata[index];
01336 minpixel[0] = j; minpixel[1] = i;
01337 }
01338 if(max<pixeldata[index]){
01339 max = pixeldata[index];
01340 maxpixel[0] = j; maxpixel[1] = i;
01341 }
01342 }
01343 }
01344 }
01345 }
01346
01347 template<class T>
01348 void pixel_array<T>::flip_x(){
01349 double tmp;
01350 for(int i=0; i<axes[1]; i++){
01351 for(int j=0; j<axes[0]/2; j++){
01352 tmp = pixeldata[i*axes[0]+j];
01353 pixeldata[i*axes[0]+j] = pixeldata[i*axes[0]+axes[0]-j-1];
01354 pixeldata[i*axes[0]+axes[0]-j-1] = tmp;
01355 }
01356 }
01357 }
01358
01359 template<class T>
01360 void pixel_array<T>::flip_y(){
01361 double tmp;
01362 for(int i=0; i<axes[1]/2; i++){
01363 for(int j=0; j<axes[0]; j++){
01364 tmp = pixeldata[i*axes[0]+j];
01365 pixeldata[i*axes[0]+j] = pixeldata[(axes[1]-i-1)*axes[0]+j];
01366 pixeldata[(axes[1]-i-1)*axes[0]+j] = tmp;
01367 }
01368 }
01369 }
01370
01371 template<class T>
01372 void pixel_array<T>::flip_xy(){
01373 double tmp;
01374 for(int i=0; i<axes[1]/2; i++){
01375 for(int j=0; j<axes[0]/2; j++){
01376 tmp = pixeldata[i*axes[0]+j];
01377 pixeldata[i*axes[0]+j] = pixeldata[(axes[1]-i-1)*axes[0] + (axes[0]-j-1)];
01378 pixeldata[(axes[1]-i-1)*axes[0] + (axes[0]-j-1)] = tmp;
01379
01380 tmp = pixeldata[i*axes[0]+(axes[0]-j-1)];
01381 pixeldata[i*axes[0]+(axes[0]-j-1)] = pixeldata[(axes[1]-i-1)*axes[0]+j];
01382 pixeldata[(axes[1]-i-1)*axes[0]+j] = tmp;
01383 }
01384 }
01385 }
01386
01387 template<class T>
01388 void pixel_array<T>::flip_45(){
01389 double tmp;
01390
01391 if(axes[1]!=axes[0]){
01392 cerr << "pixel_array::flip_45 error - cannot flip an array that isn't square\n"
01393 << "dimens "
01394 << axes[0] << "x" << axes[1] << endl;
01395 throw(string("pixel_array::flip_45"));
01396 }
01397
01398 for(int i=0; i<axes[1]; i++){
01399 for(int j=i; j<axes[0]; j++){
01400 tmp = pixeldata[i*axes[0]+j];
01401 pixeldata[i*axes[0]+j] = pixeldata[j*axes[0]+i];
01402 pixeldata[j*axes[0]+i] = tmp;
01403 }
01404 }
01405 }
01406
01407 template<class T>
01408 void pixel_array<T>::shift_by_fft(double dx, double dy){
01409
01410 if(dx==0 && dy==0) return;
01411
01412 if(axes.size()!=2){
01413 cerr << "pixel_array::shift_by_fft error - "
01414 << "array does not have 2 dimensions\n";
01415 throw(string("pixel_array::shift_by_fft"));
01416 }
01417 if(axes[0]<=1 || axes[1]<=1){
01418 cerr << "pixel_array::shift_by_fft error - "
01419 << "array doesn't contain enough elements\n";
01420 throw(string("pixel_array::shift_by_fft"));
01421 }
01422
01423 if(fabs(dx)>=1 || fabs(dy)>=1){
01424 cerr << "pixel_array::shift_by_fft error - "
01425 << "cannot shift by more than 1 pixel\n";
01426 throw(string("pixel_array::shift_by_fft"));
01427 }
01428
01429 if(pixel_array<T>::verbose_level)
01430 cout << "pixel_array::shift_by_fft - shifting " << dx << " pixels in x, "
01431 << dy << " pixels in y\n";
01432
01433
01434
01435 int nelem = axes[1]*2*(axes[0]/2+1);
01436
01437 T * thisarr;
01438 T * shiftarr;
01439 try{
01440 thisarr = new T[nelem];
01441 shiftarr = new T[2*axes[0]*axes[1]];
01442 } catch(...) {
01443 cerr << "pixel_array::shift_by_fft error - error allocating memory\n";
01444 throw(string("pixel_array::shift_by_fft"));
01445 }
01446 Arroyo::rfft_manager<T> rfft_mgr;
01447 Arroyo::fft_manager<T> fft_mgr;
01448
01449 int axes_zero = axes[0];
01450 int axes_one = axes[1];
01451 for(int i=0; i<axes_one; i++)
01452 for(int j=0; j<axes_zero; j++)
01453 thisarr[i*2*(axes_zero/2+1)+j] = pixeldata[i*axes_zero+j];
01454
01455 if(pixel_array<T>::verbose_level)
01456 cout << "pixel_array::shift_by_fft - performing forward fft\n";
01457
01458
01459
01460
01461 bool fftw_estimate = true;
01462 bool fftw_in_place = true;
01463 vector<long> flipped_axes(2);
01464 flipped_axes[0] = axes[1];
01465 flipped_axes[1] = axes[0];
01466 rfft_mgr.real_to_complex_fft(flipped_axes,
01467 fftw_estimate, fftw_in_place,
01468 thisarr);
01469
01470 double dxs = 2*M_PI*dx/(float)axes[0];
01471 double dys = 2*M_PI*dy/(float)axes[1];
01472 double phase, tmp, cp, sp;
01473
01474 int index, indexa, indexb;
01475 for(int i=0; i<axes_one; i++){
01476 for(int j=0; j<axes_zero/2+1; j++){
01477 indexa = i*axes_zero + j;
01478 indexb = i*(axes_zero/2+1) + j;
01479 shiftarr[2*indexa] = thisarr[2*indexb];
01480 shiftarr[2*indexa+1] = thisarr[2*indexb+1];
01481 }
01482 }
01483
01484
01485 for(int j=axes_zero/2+1; j<axes_zero; j++){
01486 indexa = j;
01487 indexb = axes_zero-j;
01488 shiftarr[2*indexa] = thisarr[2*indexb];
01489 shiftarr[2*indexa+1] = -thisarr[2*indexb+1];
01490 }
01491
01492 for(int i=1; i<axes_one; i++){
01493 for(int j=axes_zero/2+1; j<axes_zero; j++){
01494 indexa = i*axes_zero + j;
01495 indexb = (axes_one-i)*(axes_zero/2+1) + axes_zero - j;
01496 shiftarr[2*indexa] = thisarr[2*indexb];
01497 shiftarr[2*indexa+1] = -thisarr[2*indexb+1];
01498 }
01499 }
01500
01501 for(int i=0; i<axes_one; i++){
01502 for(int j=0; j<axes_zero; j++){
01503 if(j<axes_zero/2) phase = dxs*j;
01504 else phase = -dxs*(axes_zero-j);
01505 if(i<axes_one/2) phase += dys*i;
01506 else phase -= dys*(axes_one-i);
01507 cp = cos(-phase);
01508 sp = sin(-phase);
01509 index = 2*(i*axes_zero+j);
01510 tmp = shiftarr[index]*cp-shiftarr[index+1]*sp;
01511 shiftarr[index+1] = shiftarr[index]*sp + shiftarr[index+1]*cp;
01512 shiftarr[index] = tmp;
01513 }
01514 }
01515
01516 if(pixel_array<T>::verbose_level)
01517 cout << "pixel_array::shift_by_fft - performing backwards fft\n";
01518
01519
01520
01521 fft_mgr.backward_fft(flipped_axes, fftw_estimate, fftw_in_place, shiftarr);
01522
01523 double scale = 1/(double)(axes[0]*axes[1]);
01524 for(int i=0; i<axes_one; i++)
01525 for(int j=0; j<axes_zero; j++){
01526 pixeldata[i*axes_zero+j] =
01527 static_cast<T>(shiftarr[2*(i*axes_zero+j)]*scale);
01528 }
01529
01530 delete [] thisarr;
01531 delete [] shiftarr;
01532 }
01533
01534 template<class T>
01535 void pixel_array<T>::rotate_by_fft(double angle, bool window){
01536 if(angle==0) return;
01537 this->rotate_and_shift_by_fft(0, 0, angle, window);
01538 }
01539
01540 template<class T>
01541 void pixel_array<T>::rotate_and_shift_by_fft(
01542 double dx, double dy, double angle, bool window){
01543 this->simple_rotate_and_shift_by_fft(dx, dy, angle, window);
01544 }
01545
01546 template<class T>
01547 void pixel_array<T>::simple_rotate_and_shift_by_fft(
01548 double dx, double dy, double angle, bool window){
01549
01550
01551 if(dx!=0 || dy!=0){
01552 cerr << "pixel_array::simple_rotate_and_shift_by_fft error - "
01553 << "shifting by fft not yet supported by this function\n";
01554 throw(string("pixel_array::simple_rotate_and_shift_by_fft"));
01555 }
01556
01557
01558 if(this->weights_allocated()){
01559 cerr << "pixel_array::simple_rotate_and_shift_by_fft error - "
01560 << "this member function does not support rotation of "
01561 << "arrays with weights defined\n";
01562 throw(string("pixel_array::simple_rotate_and_shift_by_fft"));
01563 }
01564
01565 angle = fmod(angle, 2*M_PI);
01566 if(angle<0) angle += 2*M_PI;
01567
01568 if(pixel_array<T>::verbose_level)
01569 cout << "pixel_array::simple_rotate_and_shift_by_fft - "
01570 << "rotating through angle "
01571 << angle << endl;
01572
01573
01574 if(angle>=3*M_PI_2){
01575
01576
01577 int nelem = axes[0]*axes[1];
01578 T * tmparray = new T[nelem];
01579 for(int i=0; i<axes[1]; i++)
01580 for(int j=0; j<axes[0]; j++)
01581 tmparray[(axes[0]-j-1)*axes[1]+i] = this->pixeldata[i*axes[0]+j];
01582 long tmp = axes[0];
01583 axes[0] = axes[1];
01584 axes[1] = tmp;
01585 for(int i=0; i<nelem; i++)
01586 this->pixeldata[i] = tmparray[i];
01587 delete [] tmparray;
01588 angle -= 3*M_PI_2;
01589 } else if(angle>=M_PI) {
01590 this->flip_xy();
01591 angle -= M_PI;
01592 } else if(angle>=M_PI_2) {
01593
01594 int nelem = axes[0]*axes[1];
01595 T * tmparray = new T[nelem];
01596 for(int i=0; i<axes[1]; i++)
01597 for(int j=0; j<axes[0]; j++)
01598 tmparray[j*axes[1]+(axes[1]-i-1)] = this->pixeldata[i*axes[0]+j];
01599 long tmp = axes[0];
01600 axes[0] = axes[1];
01601 axes[1] = tmp;
01602 for(int i=0; i<nelem; i++)
01603 this->pixeldata[i] = tmparray[i];
01604 delete [] tmparray;
01605 angle -= M_PI_2;
01606 }
01607
01608
01609 if(dx==0 && dy==0 && angle==0) return;
01610
01611 if(pixel_array<T>::verbose_level)
01612 cout << "pixel_array::simple_rotate_and_shift_by_fft - "
01613 << "performing rotation by fft through angle " << angle << endl;
01614
01615
01616 vector<long> new_axes(2);
01617 new_axes[0] = (int)(ceil(axes[0] + axes[1]*tan(angle/2.0)));
01618 new_axes[1] = (int)(2*(ceil(axes[1] + axes[0]*sin(angle))/2));
01619
01620
01621 new_axes[0] = (int)(2*(ceil(new_axes[0] + axes[1]*tan(angle/2.0))/2));
01622
01623 if(pixel_array<T>::verbose_level)
01624 cout << "pixel_array::simple_rotate_and_shift_by_fft - "
01625 << "old axes " << axes[0] << "\t" << axes[1]
01626 << " new axes " << new_axes[0] << "\t" << new_axes[1] << endl;
01627
01628 int row_pad = new_axes[0]-axes[0];
01629 int column_pad = new_axes[1]-axes[1];
01630
01631 int nelem = 2*(new_axes[0]/2+1)*new_axes[1];
01632 int column_stride = 2*(new_axes[0]/2+1);
01633
01634 double * tmparr;
01635 try{tmparr = new double[nelem];}
01636 catch(...) {
01637 cerr << "pixel_array::simple_rotate_and_shift_by_fft error - "
01638 << "could not allocate memory\n";
01639 throw(string("pixel_array::simple_rotate_and_shift_by_fft"));
01640 }
01641
01642
01643 for(int i=0; i<nelem; i++)
01644 tmparr[i] = 0;
01645
01646 for(int i=0; i<axes[1]; i++)
01647 for(int j=0; j<axes[0]; j++)
01648 tmparr[(i+column_pad/2)*column_stride + j + row_pad/2]
01649 = pixeldata[i*axes[0]+j];
01650
01651 bool fftw_estimate = false;
01652 bool fftw_in_place = true;
01653
01654 Arroyo::rfft_manager<double> rfft_row_mgr;
01655
01656 int index;
01657 double dyslope, shear, phase, cp, sp, tmp;
01658 double amp, tphase;
01659 for(int i=0; i<new_axes[1]; i++){
01660 rfft_row_mgr.real_to_complex_fft(vector<long>(1,new_axes[0]),
01661 fftw_estimate, fftw_in_place,
01662 &(tmparr[i*column_stride]));
01663
01664 shear = tan(angle/2.0)*(i-new_axes[1]/2);
01665 dyslope = 2*M_PI*shear/(float)new_axes[0];
01666 for(int j=0; j<column_stride/2; j++){
01667 phase = dyslope*j;
01668 if(window){
01669 cp = (1-(j/(double)(column_stride/2+1)))*cos(phase)/(double)column_stride;
01670 sp = (1-(j/(double)(column_stride/2+1)))*sin(phase)/(double)column_stride;
01671 } else {
01672 cp = cos(phase)/(double)column_stride;
01673 sp = sin(phase)/(double)column_stride;
01674 }
01675 index = i*column_stride+2*j;
01676 tmp = tmparr[index]*cp-tmparr[index+1]*sp;
01677 tmparr[index+1] = tmparr[index]*sp + tmparr[index+1]*cp;
01678 tmparr[index] = tmp;
01679 }
01680 rfft_row_mgr.complex_to_real_fft(vector<long>(1,new_axes[0]),
01681 fftw_estimate, fftw_in_place,
01682 &(tmparr[i*column_stride]));
01683 }
01684
01685 Arroyo::rfft_manager<double> rfft_column_mgr;
01686
01687 double * tmp_1d_array = new double[2*(new_axes[1]/2+1)];
01688 for(int i=0; i<new_axes[0]; i++){
01689 for(int j=0; j<new_axes[1]; j++)
01690 tmp_1d_array[j] = tmparr[j*column_stride+i];
01691 rfft_column_mgr.real_to_complex_fft(vector<long>(1,new_axes[1]),
01692 fftw_estimate, fftw_in_place,
01693 tmp_1d_array);
01694
01695
01696 shear = -sin(angle)*(i-new_axes[0]/2);
01697 dyslope = 2*M_PI*shear/(float)new_axes[1];
01698 for(int j=0; j<new_axes[1]/2+1; j++){
01699 phase = dyslope*j;
01700 if(window){
01701 cp = (1-(j/(double)(new_axes[1]/2+1)))*cos(phase)/(double)new_axes[1];
01702 sp = (1-(j/(double)(new_axes[1]/2+1)))*sin(phase)/(double)new_axes[1];
01703 } else {
01704 cp = cos(phase)/(double)new_axes[1];
01705 sp = sin(phase)/(double)new_axes[1];
01706 }
01707 tmp = tmp_1d_array[2*j]*cp-tmp_1d_array[2*j+1]*sp;
01708 tmp_1d_array[2*j+1] = tmp_1d_array[2*j]*sp + tmp_1d_array[2*j+1]*cp;
01709 tmp_1d_array[2*j] = tmp;
01710 }
01711
01712 rfft_column_mgr.complex_to_real_fft(vector<long>(1,new_axes[1]),
01713 fftw_estimate, fftw_in_place,
01714 tmp_1d_array);
01715 for(int j=0; j<new_axes[1]; j++)
01716 tmparr[j*column_stride+i] = tmp_1d_array[j];
01717 }
01718 delete [] tmp_1d_array;
01719
01720 for(int i=0; i<new_axes[1]; i++){
01721 rfft_row_mgr.real_to_complex_fft(vector<long>(1,new_axes[0]),
01722 fftw_estimate, fftw_in_place,
01723 &(tmparr[i*column_stride]));
01724
01725 shear = tan(angle/2.0)*(i-new_axes[1]/2);
01726 dyslope = 2*M_PI*shear/(float)new_axes[0];
01727 for(int j=0; j<column_stride/2; j++){
01728 phase = dyslope*j;
01729 if(window){
01730 cp = (1-(j/(double)(column_stride/2+1)))*cos(phase)/(double)column_stride;
01731 sp = (1-(j/(double)(column_stride/2+1)))*sin(phase)/(double)column_stride;
01732 } else {
01733 cp = cos(phase)/(double)column_stride;
01734 sp = sin(phase)/(double)column_stride;
01735 }
01736 index = i*column_stride+2*j;
01737 tmp = tmparr[index]*cp-tmparr[index+1]*sp;
01738 tmparr[index+1] = tmparr[index]*sp + tmparr[index+1]*cp;
01739 tmparr[index] = tmp;
01740 }
01741 rfft_row_mgr.complex_to_real_fft(vector<long>(1,new_axes[0]),
01742 fftw_estimate, fftw_in_place,
01743 &(tmparr[i*column_stride]));
01744 }
01745
01746 this->set_axes(new_axes);
01747 for(int i=0; i<new_axes[1]; i++)
01748 for(int j=0; j<new_axes[0]; j++){
01749 this->pixeldata[i*new_axes[0]+j] = tmparr[i*column_stride+j];
01750 }
01751 delete [] tmparr;
01752 }
01753
01754 template<class T>
01755 void pixel_array<T>::owen_makedon_rotate_and_shift_by_fft(
01756 double dx, double dy, double angle){
01757
01758
01759 if(angle < -M_PI_2 || angle > M_PI_2){
01760 cerr << "pixel_array::owen_makedon_rotate_and_shift_by_fft error - "
01761 << "requested rotation angle "
01762 << angle << " outside the range -PI/2 < angle < PI/2\n";
01763 throw(string("pixel_array::rotate"));
01764 }
01765
01766
01767 double ta = tan(angle/2.0);
01768 long max_shear = (long)(ceil(axes[1]*ta));
01769 if(max_shear%1!=0) max_shear++;
01770
01771 cout << "pixel_array::owen_makedon_rotate_and_shift_by_fft - max shear "
01772 << max_shear
01773 << " for angle " << angle << " axes * tan angle / 2 "
01774 << axes[1]*ta << endl;
01775
01776
01777 vector<long> new_axes(2);
01778 new_axes[0] = (axes[0]+2*max_shear);
01779 new_axes[1] = 2*axes[1];
01780
01781 cout << "pixel_array::owen_makedon_rotate_and_shift_by_fft - new axes "
01782 << new_axes[0] << "\t" << new_axes[1] << endl;
01783
01784 int nelem = 2*(new_axes[0]/2+1)*new_axes[1];
01785 int column_stride = 2*(new_axes[0]/2+1);
01786
01787 cout << "pixel_array::owen_makedon_rotate_and_shift_by_fft - allocating "
01788 << nelem << " elements\n";
01789
01790 double * tmparr;
01791 try{tmparr = new double[nelem];}
01792 catch(...) {
01793 cerr << "pixel_array::owen_makedon_rotate_and_shift_by_fft error - "
01794 << "could not allocate memory\n";
01795 throw(string("pixel_array::owen_makedon_rotate_and_shift_by_fft"));
01796 }
01797
01798
01799 for(int i=0; i<nelem; i++)
01800 tmparr[i] = 0;
01801
01802 for(int i=0; i<axes[1]; i++)
01803 for(int j=0; j<axes[0]; j++)
01804 tmparr[(i+axes[1]/2)*column_stride+j+max_shear] = pixeldata[i*axes[0]+j];
01805
01806 Arroyo::rfft_manager<double> rfft_row_mgr;
01807 bool fftw_estimate = false;
01808 bool fftw_in_place = true;
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820 int index;
01821 double dyslope, shear, phase, cp, sp, tmp;
01822 double amp, tphase;
01823 for(int i=axes[1]/2; i<3*axes[1]/2; i++){
01824 rfft_row_mgr.real_to_complex_fft(vector<long>(1,new_axes[0]),
01825 fftw_estimate, fftw_in_place,
01826 &(tmparr[i*column_stride]));
01827 shear = -tan(angle/2.0)*(i-axes[1]);
01828 dyslope = 2*M_PI*shear/(float)new_axes[0];
01829 for(int j=0; j<column_stride/2; j++){
01830 phase = dyslope*j;
01831 cp = cos(phase);
01832 sp = sin(phase);
01833 index = i*column_stride+2*j;
01834 tmp = tmparr[index]*cp-tmparr[index+1]*sp;
01835 tmparr[index+1] = tmparr[index]*sp + tmparr[index+1]*cp;
01836 tmparr[index] = tmp;
01837 }
01838
01839
01840
01841
01842
01843 }
01844
01845 Arroyo::fft_manager<double> fft_column_mgr;
01846
01847
01848
01849 double * tmp_1d_array = new double[2*new_axes[1]];
01850 for(int i=0; i<2*axes[1]; i++)
01851 tmp_1d_array[i] = 0;
01852
01853 for(int i=0; i<new_axes[0]/2; i++){
01854 for(int j=0; j<axes[1]; j++){
01855 tmp_1d_array[2*j] = tmparr[(axes[1]/2+j)*column_stride+2*i];
01856 tmp_1d_array[2*j+1] = tmparr[(axes[1]/2+j)*column_stride+2*i+1];
01857 }
01858 fft_column_mgr.forward_fft(vector<long>(1,axes[1]), false, true, tmp_1d_array);
01859 for(int j=0; j<axes[1]; j++){
01860 tmparr[(axes[1]/2+j)*column_stride+2*i] = tmp_1d_array[2*j];
01861 tmparr[(axes[1]/2+j)*column_stride+2*i+1] = tmp_1d_array[2*j+1];
01862 }
01863 }
01864
01865
01866
01867
01868
01869 for(int i=0; i<axes[1]/2; i++)
01870 for(int j=0; j<2*(new_axes[0]/2+1); j++){
01871 tmparr[i*column_stride+j] =
01872 tmparr[(axes[1]+i)*column_stride+j];
01873 tmparr[(3*axes[1]/2+i)*column_stride+j] =
01874 tmparr[(axes[1]/2+i)*column_stride+j];
01875 }
01876
01877
01878
01879
01880 for(int i=0; i<new_axes[1]; i++){
01881 rfft_row_mgr.complex_to_real_fft(vector<long>(1,new_axes[0]),
01882 fftw_estimate, fftw_in_place,
01883 &(tmparr[i*column_stride]));
01884 shear = -2*sin(angle/2.0)*(i-new_axes[1]/2);
01885 dyslope = 2*M_PI*shear/(float)new_axes[0];
01886 for(int j=0; j<column_stride/2; j++){
01887 phase = dyslope*j;
01888 cp = cos(phase);
01889 sp = sin(phase);
01890 index = i*column_stride+2*j;
01891 tmp = tmparr[index]*cp-tmparr[index+1]*sp;
01892 tmparr[index+1] = tmparr[index]*sp + tmparr[index+1]*cp;
01893 tmparr[index] = tmp;
01894 }
01895 rfft_row_mgr.real_to_complex_fft(vector<long>(1,new_axes[0]),
01896 fftw_estimate, fftw_in_place,
01897 &(tmparr[i*column_stride]));
01898 }
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914 double x_halfpix=0, y_halfpix=0;
01915 int x_extrapix=1, y_extrapix=1;
01916 if(axes[1]%2==0){
01917 x_halfpix = .5;
01918 x_extrapix = 0;
01919 }
01920 if(axes[0]%2==0){
01921 y_halfpix = .5;
01922 y_extrapix = 0;
01923 }
01924 for(int i=-new_axes[1]/2; i<new_axes[1]/2+x_extrapix; i++){
01925 for(int j=0; j<new_axes[0]/2+y_extrapix; j++){
01926 index = (i+new_axes[1]/2)*column_stride+2*j;
01927 cout << i << "\t" << j << "\t";
01928 if(fabs( (i+x_halfpix) + 2*sin(angle)*(j+y_halfpix) )>axes[1]/2)
01929 tmparr[index] = tmparr[index+1] = 0;
01930 if(fabs( -tan(angle/2.0) * (i+x_halfpix)
01931 + (1-2*sin(angle)*tan(angle/2.0))*(j+y_halfpix) )>axes[0]/2)
01932 tmparr[index] = tmparr[index+1] = 0;
01933 cout << fabs( (i+x_halfpix) + 2*sin(angle)*(j+y_halfpix))
01934 << "\t"
01935 << fabs( -tan(angle/2.0) * (i+x_halfpix)
01936 + (1-2*sin(angle)*tan(angle/2.0))*(j+y_halfpix))
01937 << "\t";
01938 cout << tmparr[index] << "\t" << tmparr[index+1] << endl;
01939 }
01940 }
01941
01942
01943
01944
01945 Arroyo::fft_manager<double> new_column_mgr;
01946
01947 for(int i=0; i<new_axes[0]/2; i++){
01948 for(int j=0; j<new_axes[1]; j++){
01949 tmp_1d_array[2*j] = tmparr[j*column_stride+2*i];
01950 tmp_1d_array[2*j+1] = tmparr[j*column_stride+2*i+1];
01951 }
01952
01953 new_column_mgr.backward_fft(vector<long>(1,new_axes[1]),
01954 fftw_estimate, fftw_in_place,
01955 tmp_1d_array);
01956
01957 shear = .5*tan(angle/2.0)*i;
01958 dyslope = 2*M_PI*shear/(float)new_axes[1];
01959 for(int j=0; j<new_axes[1]; j++){
01960 phase = dyslope*(j-new_axes[1]/2);
01961 cp = cos(phase);
01962 sp = sin(phase);
01963 index = 2*j;
01964 tmp = tmp_1d_array[index]*cp-tmp_1d_array[index+1]*sp;
01965 tmp_1d_array[index+1] = tmp_1d_array[index]*sp + tmp_1d_array[index+1]*cp;
01966 tmp_1d_array[index] = tmp;
01967 }
01968
01969 for(int j=0; j<new_axes[1]; j++){
01970 tmparr[j*column_stride+2*i] = tmp_1d_array[2*j];
01971 tmparr[j*column_stride+2*i+1] = tmp_1d_array[2*j+1];
01972 }
01973 }
01974
01975
01976
01977 for(int i=0; i<new_axes[1]; i++)
01978 rfft_row_mgr.complex_to_real_fft(vector<long>(1,new_axes[0]),
01979 fftw_estimate, fftw_in_place,
01980 &(tmparr[i*column_stride]));
01981
01982 delete [] tmp_1d_array;
01983
01984 this->set_axes(new_axes);
01985 for(int i=0; i<new_axes[1]; i++)
01986 for(int j=0; j<new_axes[0]; j++){
01987 this->pixeldata[i*new_axes[0]+j] = tmparr[i*2*(new_axes[0]/2+1)+j];
01988 }
01989 delete [] tmparr;
01990
01991 }
01992
01993 template<class T>
01994 pixel_array<T> pixel_array<T>::cross_correlate(
01995 const pixel_array<T> & pixarr) const {
01996 if(pixarr.axes.size()!=2 || axes.size()!=2
01997 || axes[0]!=pixarr.axes[0] || axes[1]!=pixarr.axes[1]){
01998 cerr << "pixel_array::cross_correlate error - array mismatch\n";
01999 throw(string("pixel_array::cross_correlate"));
02000 }
02001 if(axes[0]<=1 || axes[1]<=1 || pixarr.axes[0]<=1 || pixarr.axes[1]<=1){
02002 cerr << "pixel_array::cross_correlate error - "
02003 << "array doesn't contain enough elements\n";
02004 throw(string("pixel_array::cross_correlate"));
02005 }
02006
02007
02008
02009 int nelem = axes[1]*2*(axes[0]/2+1);
02010
02011 T * fft_xcorr;
02012 T * xcorr;
02013 T * thisarr;
02014 T * inarr;
02015 try{
02016 if(pixel_array<T>::verbose_level)
02017 cout << "pixel_array::cross_correlate - allocating data nelem "
02018 << nelem << endl;
02019 thisarr = new T[nelem];
02020 inarr = new T[nelem];
02021 fft_xcorr = new T[nelem];
02022 if(pixel_array<T>::verbose_level)
02023 cout << "pixel_array::cross_correlate - allocating data nelem "
02024 << axes[0]*axes[1] << endl;
02025 xcorr = new T[axes[0]*axes[1]];
02026 } catch(...) {
02027 cerr << "pixel_array::cross_correlate error - error allocating memory\n";
02028 throw(string("pixel_array::cross_correlate"));
02029 }
02030 Arroyo::rfft_manager<T> rfft_mgr;
02031
02032 int axes_one = axes[1];
02033 int axes_zero = axes[0];
02034 for(int i=0; i<axes_one; i++){
02035 for(int j=0; j<axes_zero; j++){
02036 thisarr[i*2*(axes_zero/2+1)+j] = this->pixeldata[i*axes_zero+j];
02037 inarr[i*2*(axes_zero/2+1)+j] = pixarr.pixeldata[i*axes_zero+j];
02038 }
02039 }
02040
02041
02042
02043
02044 bool fftw_estimate = true;
02045 bool fftw_in_place = true;
02046 vector<long> flipped_axes(2);
02047 flipped_axes[0] = axes[1];
02048 flipped_axes[1] = axes[0];
02049 if(pixel_array<T>::verbose_level)
02050 cout << "pixel_array::cross_correlate - transforming this pixel_array\n";
02051 rfft_mgr.real_to_complex_fft(flipped_axes,
02052 fftw_estimate, fftw_in_place,
02053 thisarr);
02054 if(pixel_array<T>::verbose_level)
02055 cout << "pixel_array::cross_correlate - transforming arg pixel_array\n";
02056 rfft_mgr.real_to_complex_fft(flipped_axes,
02057 fftw_estimate, fftw_in_place,
02058 inarr);
02059
02060 int indexa, indexb;
02061 double scale = 1.0/(double)(axes[0]*axes[1]);
02062 for(int i=0; i<axes_one; i++){
02063 for(int j=0; j<axes_zero/2+1; j++){
02064 indexa = i*2*(axes_zero/2+1) + j;
02065 indexb = i*2*(axes_zero/2+1) + 2*j;
02066 fft_xcorr[indexb] = (thisarr[indexb]*inarr[indexb] +
02067 thisarr[indexb+1]*inarr[indexb+1])*scale;
02068 fft_xcorr[indexb+1] = (thisarr[indexb]*inarr[indexb+1] -
02069 thisarr[indexb+1]*inarr[indexb])*scale;
02070 }
02071 }
02072 delete [] thisarr;
02073 delete [] inarr;
02074
02075
02076
02077
02078 fftw_in_place = false;
02079 if(pixel_array<T>::verbose_level)
02080 cout << "pixel_array::cross_correlate - "
02081 << "back-transforming to retrieve cross-correlated array\n";
02082 rfft_mgr.complex_to_real_fft(flipped_axes,
02083 fftw_estimate, fftw_in_place,
02084 fft_xcorr, xcorr);
02085
02086 delete [] fft_xcorr;
02087
02088 pixel_array<T> xcorr_pixarr = pixel_array<T>(axes, xcorr);
02089 delete [] xcorr;
02090 return(xcorr_pixarr);
02091 }
02092
02093 template<class T>
02094 void pixel_array<T>::offset(const pixel_array<T> & pixarr,
02095 vector<double> & offsets,
02096 long range) const {
02097
02098 if(pixarr.axes.size()!=2 || axes.size()!=2
02099 || axes[0]!=pixarr.axes[0] || axes[1]!=pixarr.axes[1]){
02100 cerr << "pixel_array::offset error - array mismatch\n";
02101 throw(string("pixel_array::offset"));
02102 }
02103 if(axes[0]<=1 || axes[1]<=1 || pixarr.axes[0]<=1 || pixarr.axes[1]<=1){
02104 cerr << "pixel_array::offset error - "
02105 << "array doesn't contain enough elements\n";
02106 throw(string("pixel_array::offset"));
02107 }
02108
02109 if(pixel_array<T>::verbose_level)
02110 cout << "pixel_array::offset - seeking offset between arrays of size\n"
02111 << "\t(" << this->axes[0] << ", " << this->axes[1]
02112 << ") and (" << pixarr.axes[0] << "," << pixarr.axes[1]
02113 << ")" << endl;
02114
02115 pixel_array<T> xcorr_pixarr = this->cross_correlate(pixarr);
02116 vector<int> xcorr_minpixel(2,0), xcorr_maxpixel(2,0);
02117
02118 double min, max;
02119 xcorr_pixarr.min_and_max(min, xcorr_minpixel, max, xcorr_maxpixel);
02120
02121
02122 for(int i=0; i<2; i++){
02123 if(xcorr_maxpixel[i]>axes[i]/2){
02124 if(pixel_array<T>::verbose_level)
02125 cout << "pixel_array<T>::offset - correcting dec " << i << endl;
02126 xcorr_maxpixel[i] -= axes[i];
02127 }
02128 if(xcorr_maxpixel[i]<-axes[i]/2){
02129 if(pixel_array<T>::verbose_level)
02130 cout << "pixel_array<T>::offset - correcting axis " << i << endl;
02131 xcorr_maxpixel[i] += axes[i];
02132 }
02133 }
02134
02135
02136
02137
02138
02139 vector<int> tmp_minpixel, tmp_maxpixel;
02140 if(range!=-1){
02141 vector<int> axis_0_range(2,range), axis_1_range(2,range);
02142 axis_0_range[1] = axes[0]-range-1;
02143 axis_1_range[1] = axes[1]-range-1;
02144
02145 this->min_and_max(min, tmp_minpixel, max, tmp_maxpixel, axis_0_range, axis_1_range);
02146 } else
02147 this->min_and_max(min, tmp_minpixel, max, tmp_maxpixel);
02148
02149
02150 for(int i=0; i<2; i++){
02151 if(tmp_maxpixel[i]+xcorr_maxpixel[i]>axes[i])
02152 xcorr_maxpixel[i] -= axes[i];
02153 if(tmp_maxpixel[i]-xcorr_maxpixel[i]<0)
02154 xcorr_maxpixel[i] += axes[i];
02155 }
02156
02157 if(pixel_array<T>::verbose_level) {
02158 cout << "pixel_array<T>::offset - xcorr max " << xcorr_maxpixel[0] << "\t"
02159 << xcorr_maxpixel[1] << "\t" << max << endl;
02160 cout << "pixel_array<T>::offset - this max " << max << " at "
02161 << tmp_maxpixel[0] << "," << tmp_maxpixel[1] << endl;
02162 }
02163
02164 pixel_array<T> tpix, apix;
02165 if(range!=-1){
02166
02167
02168
02169 long maxrange = range;
02170 vector<long> this_pixlimits(4), arg_pixlimits(4);
02171
02172 this_pixlimits[0] = tmp_maxpixel[0] - maxrange;
02173 this_pixlimits[1] = tmp_maxpixel[0] + maxrange-1;
02174 this_pixlimits[2] = tmp_maxpixel[1] - maxrange;
02175 this_pixlimits[3] = tmp_maxpixel[1] + maxrange-1;
02176
02177 if(pixel_array<T>::verbose_level)
02178 cout << "pixel_array<T>::offset - extracting pixels "
02179 << this_pixlimits[0] << " - " << this_pixlimits[1] << " in x "
02180 << this_pixlimits[2] << " - " << this_pixlimits[3] << " in y "
02181 << this_pixlimits[1] - this_pixlimits[0] + 1 << " x "
02182 << this_pixlimits[3] - this_pixlimits[2] + 1 << endl;
02183 tpix = pixel_array<T>(*this, this_pixlimits);
02184
02185
02186
02187
02188
02189
02190
02191
02192
02193
02194 arg_pixlimits[0] = this_pixlimits[0]+xcorr_maxpixel[0];
02195 arg_pixlimits[1] = this_pixlimits[1]+xcorr_maxpixel[0];
02196 arg_pixlimits[2] = this_pixlimits[2]+xcorr_maxpixel[1];
02197 arg_pixlimits[3] = this_pixlimits[3]+xcorr_maxpixel[1];
02198
02199 if(pixel_array<T>::verbose_level)
02200 cout << "pixel_array<T>::offset - extracting pixels "
02201 << arg_pixlimits[0] << " - " << arg_pixlimits[1] << " in x "
02202 << arg_pixlimits[2] << " - " << arg_pixlimits[3] << " in y "
02203 << arg_pixlimits[1] - arg_pixlimits[0] + 1 << " x "
02204 << arg_pixlimits[3] - arg_pixlimits[2] + 1 << endl;
02205 apix = pixel_array<T>(pixarr, arg_pixlimits);
02206 } else {
02207 tpix = *this;
02208 apix = pixarr;
02209 }
02210
02211 tpix.min_and_max(min, tmp_minpixel, max, tmp_maxpixel);
02212
02213 if(pixel_array<T>::verbose_level)
02214 cout << "pixel_array<T>::offset - tpix max " << max << " at "
02215 << tmp_maxpixel[0] << "," << tmp_maxpixel[1] << endl;
02216 apix.min_and_max(min, tmp_minpixel, max, tmp_maxpixel);
02217 if(pixel_array<T>::verbose_level)
02218 cout << "pixel_array<T>::offset - apix max " << max << " at "
02219 << tmp_maxpixel[0] << "," << tmp_maxpixel[1] << endl;
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241 int nelem = tpix.axes[1]*2*(tpix.axes[0]/2+1);
02242
02243 T * tarr;
02244 T * aarr;
02245 T * product_amps;
02246 T * phase_difference;
02247 try{
02248 if(pixel_array<T>::verbose_level)
02249 cout << "pixel_array::offset - allocating data nelem " << nelem << endl;
02250 tarr = new T[nelem];
02251 aarr = new T[nelem];
02252 product_amps = new T[nelem];
02253 phase_difference = new T[nelem];
02254 } catch(...) {
02255 cerr << "pixel_array::offset error - error allocating memory\n";
02256 throw(string("pixel_array::offset"));
02257 }
02258 Arroyo::rfft_manager<T> rfft_mgr;
02259
02260 int scale = tpix.axes[0]*tpix.axes[1];
02261 int tpix_axes_one = tpix.axes[1];
02262 int tpix_axes_zero = tpix.axes[0];
02263 for(int i=0; i<tpix_axes_one; i++){
02264 for(int j=0; j<tpix_axes_zero; j++){
02265 tarr[i*2*(tpix_axes_zero/2+1)+j] = tpix.pixeldata[i*tpix_axes_zero+j];
02266 aarr[i*2*(tpix_axes_zero/2+1)+j] = apix.pixeldata[i*tpix_axes_zero+j];
02267 }
02268 }
02269
02270
02271
02272
02273 bool fftw_estimate = true;
02274 bool fftw_in_place = true;
02275 vector<long> flipped_axes(2);
02276 flipped_axes[0] = tpix.axes[1];
02277 flipped_axes[1] = tpix.axes[0];
02278 rfft_mgr.real_to_complex_fft(flipped_axes,
02279 fftw_estimate, fftw_in_place,
02280 tarr);
02281 rfft_mgr.real_to_complex_fft(flipped_axes,
02282 fftw_estimate, fftw_in_place,
02283 aarr);
02284
02285 double tmpamp, tmpphase;
02286 int indexa, indexb;
02287
02288 for(int i=0; i<tpix_axes_one; i++){
02289 for(int j=0; j<tpix_axes_zero/2+1; j++){
02290 indexa = i*2*(tpix_axes_zero/2+1) + j;
02291 indexb = i*2*(tpix_axes_zero/2+1) + 2*j;
02292 product_amps[indexa] =
02293 sqrt(tarr[indexb]*tarr[indexb] + tarr[indexb+1]*tarr[indexb+1])*
02294 sqrt(aarr[indexb]*aarr[indexb] + aarr[indexb+1]*aarr[indexb+1]);
02295 phase_difference[indexa] =
02296 atan2(tarr[indexb+1],tarr[indexb]) -
02297 atan2(aarr[indexb+1],aarr[indexb]);
02298 }
02299 }
02300 delete [] tarr;
02301 delete [] aarr;
02302
02303
02304 for(int j=tpix_axes_zero/2+1; j<tpix_axes_zero; j++){
02305 indexa = j;
02306 indexb = tpix_axes_zero - j;
02307 product_amps[indexa] = product_amps[indexb];
02308 phase_difference[indexa] = -phase_difference[indexb];
02309 }
02310
02311 for(int i=1; i<tpix_axes_one; i++){
02312 for(int j=tpix_axes_zero/2+1; j<tpix_axes_zero; j++){
02313 indexa = i*2*(tpix_axes_zero/2+1) + j;
02314 indexb = (tpix_axes_one-i)*2*(tpix_axes_zero/2+1) + tpix_axes_zero - j;
02315 product_amps[indexa] = product_amps[indexb];
02316 phase_difference[indexa] = -phase_difference[indexb];
02317 }
02318 }
02319
02320
02321 double faca = 2*M_PI/tpix.axes[0];
02322 double facb = 2*M_PI/tpix.axes[1];
02323 double tmp, tmpa, tmpb;
02324 double fa, fb, b, chisq;
02325 double dfa_du, dfa_dv, dfb_du, dfb_dv;
02326 double min_chisq = 0, min_fa, min_fb;
02327 double iindex, jindex;
02328 double last_chisq = 0;
02329 double frac_axis_0=0, frac_axis_1=0;
02330 int index;
02331
02332
02333 while(1){
02334 fa=fb=dfa_du=dfa_dv=dfb_dv=chisq=0;
02335 for(int i=0; i<tpix_axes_one; i++){
02336 for(int j=0; j<tpix_axes_zero; j++){
02337 index = 2*i*(tpix_axes_zero/2+1)+j;
02338 if(i<=tpix_axes_one/2) iindex = i;
02339 else iindex = i-tpix_axes_one;
02340 if(j<=tpix_axes_zero/2) jindex = j;
02341 else jindex = j-tpix_axes_zero;
02342
02343 tmpa = product_amps[index]*sin(phase_difference[index] -
02344 iindex*frac_axis_1*facb -
02345 jindex*frac_axis_0*faca);
02346 fa += iindex*tmpa;
02347 fb += jindex*tmpa;
02348 tmpb = product_amps[index]*cos(phase_difference[index] -
02349 iindex*frac_axis_1*facb -
02350 jindex*frac_axis_0*faca);
02351
02352 dfa_du += iindex*iindex*tmpb;
02353 dfb_dv += jindex*jindex*tmpb;
02354 dfa_dv += iindex*jindex*tmpb;
02355 chisq -= tmpb;
02356 }
02357 }
02358
02359 dfb_du = dfa_dv;
02360 tmpa = (fa*dfb_dv - fb*dfa_dv)/(dfa_du*dfb_dv-dfa_dv*dfb_du);
02361 tmpb = (-fa*dfb_du + fb*dfa_du)/(dfa_du*dfb_dv-dfa_dv*dfb_du);
02362 frac_axis_0+=tmpb;
02363 frac_axis_1+=tmpa;
02364
02365 if(fabs(tmpa)<1e-6 && fabs(tmpb)<1e-6)
02366 break;
02367 last_chisq = chisq;
02368 }
02369 if(pixel_array<T>::verbose_level)
02370 cout << "pixel_array<T>::offset - " << endl
02371 << " dfa_du " << dfa_du << " dfa_dv " << dfa_dv
02372 << " dfb_du " << dfb_du << " dfb_dv " << dfb_dv << endl
02373 << " fa " << setw(10) << setprecision(3) << fa
02374 << " fb " << setw(10) << setprecision(3) << fb << endl
02375 << " tmpa " << tmpa << " tmpb " << tmpb << endl
02376 << " chisq " << setw(10) << setprecision(6) << chisq
02377 << setprecision(3) << endl
02378 << " dra " << setw(10) << frac_axis_0 << endl
02379 << " ddec " << setw(10) << frac_axis_1 << endl
02380 << " axis 0 " << setw(10) << setprecision(6)
02381 << xcorr_maxpixel[0] + frac_axis_0 << endl
02382 << " axis 1 " << setw(10) << xcorr_maxpixel[1] + frac_axis_1 << endl;
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395 offsets.resize(2);
02396 offsets[0] = xcorr_maxpixel[0] + frac_axis_0;
02397 offsets[1] = xcorr_maxpixel[1] + frac_axis_1;
02398
02399 if(pixel_array<T>::verbose_level)
02400 cout << "pixel_array<T>::offset - final offsets "
02401 << offsets[0] << "\t" << offsets[1] << endl;
02402
02403
02404 delete [] product_amps;
02405 delete [] phase_difference;
02406 }
02407
02408 template <> pixel_array<long> & operator+=<long, float>(
02409 pixel_array<long> & lhs, const pixel_array<float> & rhs);
02410 template <> pixel_array<long> & operator+=<long, double>(
02411 pixel_array<long> & lhs, const pixel_array<double> & rhs);
02412
02413 template<class T, class U>
02414 pixel_array<T> & operator += (pixel_array<T> & lhs,
02415 const pixel_array<U> & rhs){
02416 if(lhs.get_axes()!=rhs.get_axes()){
02417 cerr << "pixel_array::operator+= error - "
02418 << "mismatched array sizes\n";
02419 for(int i=0; i<lhs.get_axes().size(); i++){
02420 cerr << setw(8) << lhs.get_axes()[i];
02421 }
02422 cerr << endl;
02423 for(int i=0; i<rhs.get_axes().size(); i++){
02424 cerr << setw(8) << rhs.get_axes()[i];
02425 }
02426 cerr << endl;
02427 throw(string("pixel_array::operator+="));
02428 }
02429
02430 if((lhs.pixelwts!=NULL && rhs.weights_allocated()==0) ||
02431 (lhs.pixelwts==NULL && rhs.weights_allocated()!=0)){
02432 cerr << "pixel_array<T> & operator += error - "
02433 << "weights not defined for both objects\n";
02434 throw(string("pixel_array<T> & operator +="));
02435 }
02436
02437 int nelem = lhs.total_space();
02438 if(pixel_array<T>::verbose_level)
02439 cout << "pixel_array::operator+= - adding data\n";
02440 for(int i=0; i<nelem; i++){
02441 if(lhs.pixelwts!=NULL && lhs.pixelwts[i] == 0 && rhs.wt(i) == 0){
02442 lhs.pixeldata[i] = 0;
02443 lhs.pixelwts[i] = 0;
02444 } else if(lhs.pixelwts!=NULL && lhs.pixelwts[i] == 0 && rhs.wt(i) != 0){
02445 lhs.pixeldata[i] = rhs.pixeldata[i];
02446 lhs.pixelwts[i] = rhs.pixelwts[i];
02447 } else if(lhs.pixelwts!=NULL){
02448 lhs.pixeldata[i] += rhs.pixeldata[i];
02449 lhs.pixelwts[i] += rhs.pixelwts[i];
02450 } else {
02451 lhs.pixeldata[i] += rhs.pixeldata[i];
02452 }
02453 }
02454 return(lhs);
02455 }
02456
02457 template <> pixel_array<long> & operator-=<long, float>(
02458 pixel_array<long> & lhs, const pixel_array<float> & rhs);
02459 template <> pixel_array<long> & operator-=<long, double>(
02460 pixel_array<long> & lhs, const pixel_array<double> & rhs);
02461
02462 template<class T, class U>
02463 pixel_array<T> & operator -= (
02464 pixel_array<T> & lhs,
02465 const pixel_array<U> & rhs){
02466 if(lhs.get_axes()!=rhs.get_axes()){
02467 cerr << "pixel_array::operator-= error - "
02468 << "mismatched array sizes\n";
02469 for(int i=0; i<lhs.get_axes().size(); i++){
02470 cerr << setw(8) << lhs.get_axes()[i];
02471 }
02472 cerr << endl;
02473 for(int i=0; i<rhs.get_axes().size(); i++){
02474 cerr << setw(8) << rhs.get_axes()[i];
02475 }
02476 cerr << endl;
02477 throw(string("pixel_array::operator-="));
02478 }
02479
02480 if((lhs.pixelwts!=NULL && rhs.weights_allocated()==0) ||
02481 (lhs.pixelwts==NULL && rhs.weights_allocated()!=0)){
02482 cerr << "pixel_array<T> & operator-= error - "
02483 << "weights not defined for both objects\n";
02484 throw(string("pixel_array<T> & operator-="));
02485 }
02486
02487 int nelem = lhs.total_space();
02488 if(pixel_array<T>::verbose_level)
02489 cout << "pixel_array::operator-= - subtracting data\n";
02490 for(int i=0; i<nelem; i++){
02491 if(lhs.pixelwts!=NULL && lhs.pixelwts[i] == 0 && rhs.pixelwts[i] == 0){
02492 lhs.pixeldata[i] = 0;
02493 lhs.pixelwts[i] = 0;
02494 } else if(lhs.pixelwts!=NULL && lhs.pixelwts[i] == 0 && rhs.pixelwts[i] != 0){
02495 lhs.pixeldata[i] = -rhs.pixeldata[i];
02496 lhs.pixelwts[i] = rhs.pixelwts[i];
02497 } else if(lhs.pixelwts!=NULL){
02498 lhs.pixeldata[i] -= rhs.pixeldata[i];
02499 lhs.pixelwts[i] += rhs.pixelwts[i];
02500 } else {
02501 lhs.pixeldata[i] -= rhs.pixeldata[i];
02502 }
02503 }
02504 return(lhs);
02505 }
02506
02507 template <> pixel_array<long> & operator*=<long, float>(
02508 pixel_array<long> & lhs, const pixel_array<float> & rhs);
02509 template <> pixel_array<long> & operator*=<long, double>(
02510 pixel_array<long> & lhs, const pixel_array<double> & rhs);
02511
02512 template<class T, class U>
02513 pixel_array<T> & operator *= (
02514 pixel_array<T> & lhs,
02515 const pixel_array<U> & rhs){
02516 if(lhs.get_axes()!=rhs.get_axes()){
02517 cerr << "pixel_array::operator*= error - "
02518 << "mismatched array sizes\n";
02519 for(int i=0; i<lhs.get_axes().size(); i++){
02520 cerr << setw(8) << lhs.get_axes()[i];
02521 }
02522 cerr << endl;
02523 for(int i=0; i<rhs.get_axes().size(); i++){
02524 cerr << setw(8) << rhs.get_axes()[i];
02525 }
02526 cerr << endl;
02527 throw(string("pixel_array::operator*="));
02528 }
02529
02530 if((lhs.pixelwts!=NULL && rhs.weights_allocated()==0) ||
02531 (lhs.pixelwts==NULL && rhs.weights_allocated()!=0)){
02532 cerr << "pixel_array<T> & operator*= error - "
02533 << "weights not defined for both objects\n";
02534 throw(string("pixel_array<T> & operator*="));
02535 }
02536
02537 int nelem = lhs.total_space();
02538 if(pixel_array<T>::verbose_level)
02539 cout << "pixel_array::operator*= - multiplying data\n";
02540 for(int i=0; i<nelem; i++){
02541 if(lhs.pixelwts!=NULL && lhs.pixelwts[i] == 0 && rhs.pixelwts[i] == 0){
02542 lhs.pixeldata[i] = 0;
02543 lhs.pixelwts[i] = 0;
02544 } else if(lhs.pixelwts!=NULL && lhs.pixelwts[i] == 0
02545 && rhs.pixelwts[i] != 0){
02546 lhs.pixeldata[i] = rhs.pixeldata[i];
02547 lhs.pixelwts[i] = rhs.pixelwts[i];
02548 } else if(lhs.pixelwts!=NULL){
02549 lhs.pixeldata[i] *= rhs.pixeldata[i];
02550 lhs.pixelwts[i] = sqrt(1/((rhs.pixeldata[i]*rhs.pixeldata[i])/
02551 (lhs.pixelwts[i]*lhs.pixelwts[i])
02552 + (lhs.pixeldata[i]*lhs.pixeldata[i])/
02553 (rhs.pixelwts[i]*rhs.pixelwts[i])));
02554 } else {
02555 lhs.pixeldata[i] *= rhs.pixeldata[i];
02556 }
02557 }
02558 return(lhs);
02559 }
02560
02561 template <> pixel_array<long> & operator/=<long, float>(
02562 pixel_array<long> & lhs, const pixel_array<float> & rhs);
02563 template <> pixel_array<long> & operator/=<long, double>(
02564 pixel_array<long> & lhs, const pixel_array<double> & rhs);
02565
02566 template<class T, class U>
02567 pixel_array<T> & operator /= (
02568 pixel_array<T> & lhs,
02569 const pixel_array<U> & rhs){
02570 if(lhs.get_axes()!=rhs.get_axes()){
02571 cerr << "pixel_array::operator/= error - "
02572 << "mismatched array sizes\n";
02573 for(int i=0; i<lhs.get_axes().size(); i++){
02574 cerr << setw(8) << lhs.get_axes()[i];
02575 }
02576 cerr << endl;
02577 for(int i=0; i<rhs.get_axes().size(); i++){
02578 cerr << setw(8) << rhs.get_axes()[i];
02579 }
02580 cerr << endl;
02581 throw(string("pixel_array::operator/="));
02582 }
02583
02584 if((lhs.pixelwts!=NULL && rhs.weights_allocated()==0) ||
02585 (lhs.pixelwts==NULL && rhs.weights_allocated()!=0)){
02586 cerr << "pixel_array<T> & operator/= error - "
02587 << "weights not defined for both objects\n";
02588 throw(string("pixel_array<T> & operator/="));
02589 }
02590
02591 int nelem = lhs.total_space();
02592 if(pixel_array<T>::verbose_level)
02593 cout << "pixel_array::operator/= - dividing data\n";
02594 for(int i=0; i<nelem; i++){
02595 if(rhs.pixeldata[i]==0){
02596 lhs.pixeldata[i] = 0;
02597 if(lhs.pixelwts!=NULL)
02598 lhs.pixelwts[i] = 0;
02599 } else if(lhs.pixelwts!=NULL){
02600 lhs.pixeldata[i] /= rhs.pixeldata[i];
02601 lhs.pixelwts[i] =
02602 sqrt(1/(1/(lhs.pixelwts[i]*lhs.pixelwts[i]*
02603 rhs.pixeldata[i]*rhs.pixeldata[i]) +
02604 (lhs.pixeldata[i]*lhs.pixeldata[i])/
02605 (rhs.pixeldata[i]*rhs.pixeldata[i]*
02606 rhs.pixeldata[i]*rhs.pixeldata[i]
02607 *lhs.pixelwts[i]*lhs.pixelwts[i])));
02608 } else lhs.pixeldata[i] /= rhs.pixeldata[i];
02609 }
02610 return(lhs);
02611 }
02612
02613 template <> pixel_array<long> & pixel_array<long>::operator += (
02614 const double & fac);
02615
02616 template<class T>
02617 pixel_array<T> & pixel_array<T>::operator += (const double & fac){
02618 if(fac==0) return(*this);
02619 int nelem = total_space();
02620 for(int i=0; i<nelem; i++)
02621 this->pixeldata[i] += fac;
02622 return(*this);
02623 }
02624
02625 template <> pixel_array<long> & pixel_array<long>::operator -= (
02626 const double & fac);
02627
02628 template<class T>
02629 pixel_array<T> & pixel_array<T>::operator -= (const double & fac){
02630 if(fac==0) return(*this);
02631 int nelem = total_space();
02632 for(int i=0; i<nelem; i++)
02633 this->pixeldata[i] -= fac;
02634 return(*this);
02635 }
02636
02637 template <> pixel_array<long> & pixel_array<long>::operator *= (
02638 const double & fac);
02639
02640 template<class T>
02641 pixel_array<T> & pixel_array<T>::operator *= (const double & fac){
02642 if(fac==1) return(*this);
02643 int nelem = total_space();
02644 for(int i=0; i<nelem; i++){
02645 this->pixeldata[i] *= fac;
02646 }
02647 if(pixelwts!=NULL)
02648 for(int i=0; i<nelem; i++)
02649 this->pixelwts[i] *= fac;
02650 return(*this);
02651 }
02652
02653 template <> pixel_array<long> & pixel_array<long>::operator /= (
02654 const double & fac);
02655
02656 template<class T>
02657 pixel_array<T> & pixel_array<T>::operator /= (const double & fac){
02658 if(fac==1) return(*this);
02659 if(fac==0){
02660 cerr << "pixel_array::operator /= division by zero error\n";
02661 throw(string("pixel_array::operator /="));
02662 }
02663 int nelem = total_space();
02664 for(int i=0; i<nelem; i++)
02665 this->pixeldata[i] /= fac;
02666 if(pixelwts!=NULL)
02667 for(int i=0; i<nelem; i++)
02668 this->pixelwts[i] /= fac;
02669
02670 return(*this);
02671 }
02672
02673 template<class T>
02674 pixel_array<T> operator + (const pixel_array<T> &p1,
02675 const pixel_array<T> &p2){
02676 if(p1.get_axes()!=p2.get_axes()){
02677 cerr << "pixel_array::operator+ error - "
02678 << "mismatched array sizes\n";
02679 for(int i=0; i<p1.get_axes().size(); i++){
02680 cerr << setw(8) << p1.get_axes()[i];
02681 }
02682 cerr << endl;
02683 for(int i=0; i<p2.get_axes().size(); i++){
02684 cerr << setw(8) << p2.get_axes()[i];
02685 }
02686 cerr << endl;
02687 throw(string("pixel_array::operator+"));
02688 }
02689 pixel_array<T> pixarr(p1);
02690 pixarr += p2;
02691 return(pixarr);
02692 }
02693
02694 template <class T>
02695 pixel_array<T> operator - (const pixel_array<T> &p1,
02696 const pixel_array<T> &p2){
02697 if(p1.get_axes()!=p2.get_axes()){
02698 cerr << "pixel_array::operator- error - "
02699 << "mismatched array sizes\n";
02700 for(int i=0; i<p1.get_axes().size(); i++){
02701 cerr << setw(8) << p1.get_axes()[i];
02702 }
02703 cerr << endl;
02704 for(int i=0; i<p2.get_axes().size(); i++){
02705 cerr << setw(8) << p2.get_axes()[i];
02706 }
02707 cerr << endl;
02708 throw(string("pixel_array::operator-"));
02709 }
02710 pixel_array<T> pixarr(p1);
02711 pixarr -= p2;
02712 return(pixarr);
02713 }
02714
02715 template <class T>
02716 pixel_array<T> operator * (const pixel_array<T> &p1,
02717 const pixel_array<T> &p2){
02718 if(p1.get_axes()!=p2.get_axes()){
02719 cerr << "pixel_array::operator* error - "
02720 << "mismatched array sizes\n";
02721 for(int i=0; i<p1.get_axes().size(); i++){
02722 cerr << setw(8) << p1.get_axes()[i];
02723 }
02724 cerr << endl;
02725 for(int i=0; i<p2.get_axes().size(); i++){
02726 cerr << setw(8) << p2.get_axes()[i];
02727 }
02728 cerr << endl;
02729 throw(string("pixel_array::operator/"));
02730 }
02731 pixel_array<T> pixarr(p1);
02732 pixarr *= p2;
02733 return(pixarr);
02734 }
02735
02736 template <class T>
02737 pixel_array<T> operator / (const pixel_array<T> &p1,
02738 const pixel_array<T> &p2){
02739 if(p1.get_axes()!=p2.get_axes()){
02740 cerr << "pixel_array::operator/ error - "
02741 << "mismatched array sizes\n";
02742 for(int i=0; i<p1.get_axes().size(); i++){
02743 cerr << setw(8) << p1.get_axes()[i];
02744 }
02745 cerr << endl;
02746 for(int i=0; i<p2.get_axes().size(); i++){
02747 cerr << setw(8) << p2.get_axes()[i];
02748 }
02749 cerr << endl;
02750 throw(string("pixel_array::operator/"));
02751 }
02752 pixel_array<T> pixarr(p1);
02753 pixarr /= p2;
02754 return(pixarr);
02755 }
02756
02757 template <class T>
02758 pixel_array<T> operator + (const pixel_array<T> &p1, double & fac){
02759 pixel_array<T> pixarr(p1);
02760 pixarr += fac;
02761 return(pixarr);
02762 }
02763
02764 template <class T>
02765 pixel_array<T> operator - (const pixel_array<T> &p1, double & fac){
02766 pixel_array<T> pixarr(p1);
02767 pixarr -= fac;
02768 return(pixarr);
02769 }
02770
02771 template <class T>
02772 pixel_array<T> operator * (const pixel_array<T> &p1, double & fac){
02773 pixel_array<T> pixarr(p1);
02774 pixarr *= fac;
02775 return(pixarr);
02776 }
02777
02778 template <class T>
02779 pixel_array<T> operator / (const pixel_array<T> &p1, double & fac){
02780 pixel_array<T> pixarr(p1);
02781 pixarr /= fac;
02782 return(pixarr);
02783 }
02784
02787 template <class T>
02788 bool operator != (const pixel_array<T> &p1, const pixel_array<T> &p2){
02789 return(!(p1==p2));
02790 }
02791 }
02792
02793 #endif