| 1 | //#define TEST_MOLLWEIDE
 | 
|---|
| 2 | #include <stdlib.h>
 | 
|---|
| 3 | #include <stdio.h>
 | 
|---|
| 4 | #include <math.h>
 | 
|---|
| 5 | #include "mollweide.h"
 | 
|---|
| 6 | 
 | 
|---|
| 7 | #if defined(TEST_MOLLWEIDE)
 | 
|---|
| 8 | #include "timing.h"
 | 
|---|
| 9 | double _t;
 | 
|---|
| 10 | #endif
 | 
|---|
| 11 | 
 | 
|---|
| 12 | /*! \ingroup XAstroPack
 | 
|---|
| 13 |  \brief La vraie projection Mollweide (longitude,latitude) -> (xmoll,ymoll)
 | 
|---|
| 14 |  \param input: longitude [0,2PI[ en radians
 | 
|---|
| 15 |  \param input: latitude  [-Pi/2,Pi/2] en radians
 | 
|---|
| 16 |  \param output: xmoll dans [-2*sqrt(2),2*sqrt(2)]
 | 
|---|
| 17 |  \param output: ymoll dans [-sqrt(2),sqrt(2)]
 | 
|---|
| 18 |  \warning Probleme de precision pour t pres de Pi/2 (latitude pres de -Pi/2 ou Pi/2)
 | 
|---|
| 19 |  \warning Longitude=Pi=180 au milieu en xmoll=0
 | 
|---|
| 20 |  \return t
 | 
|---|
| 21 |  \verbatim
 | 
|---|
| 22 |  - La vraie MollWeide:
 | 
|---|
| 23 |  Equation implicite en t: 2*t+sin(2*t) = Pi*sin(lat) = a
 | 
|---|
| 24 |      | xmoll = 2*sqrt(2)*(lon-Pi)/Pi*cos(t)
 | 
|---|
| 25 |      | ymoll = sqrt(2)*sin(t)
 | 
|---|
| 26 |  --------------------------------------------------------
 | 
|---|
| 27 |  INPUT: longitude [0,2PI[      en radians
 | 
|---|
| 28 |         latitude  [-Pi/2,Pi/2] en radians
 | 
|---|
| 29 |  OUTPUT: xmoll dans [-2*sqrt(2),2*sqrt(2)]
 | 
|---|
| 30 |          ymoll dans [-sqrt(2),sqrt(2)]
 | 
|---|
| 31 |  RETURN: t
 | 
|---|
| 32 |  --------------------------------------------------------
 | 
|---|
| 33 |  REMARQUES:
 | 
|---|
| 34 |  - xmoll varie [-2*sqrt(2),2*sqrt(2)]
 | 
|---|
| 35 |         centre galactique (longitude=0) au bord,
 | 
|---|
| 36 |         anti-centre (longitude=180) au milieu.
 | 
|---|
| 37 |    pour centre galactique (longitude=0) au milieu,
 | 
|---|
| 38 |         anti-centre (longitude=180) au bord:
 | 
|---|
| 39 |         xmoll' = 2*sqrt(2)*longitude/Pi*cos(t) = xmoll+2*sqrt(2)
 | 
|---|
| 40 |         xmoll' varie [0,4*sqrt(2)]
 | 
|---|
| 41 |  - ymoll varie [-sqrt(2),sqrt(2)] plan gal en 0
 | 
|---|
| 42 |  - t varie [-Pi/2,Pi/2]
 | 
|---|
| 43 |  - a varie [-Pi,Pi]  (a <-> -a  <==> t <-> -t)
 | 
|---|
| 44 |  - Pour latitude --> -latitude alors t --> -t
 | 
|---|
| 45 |         latitude=90   --> t=Pi/2
 | 
|---|
| 46 |         latitude=-90  --> t=-Pi/2
 | 
|---|
| 47 |  RAPIDITE: 10^6 appels a MollWeide_XY en 5.2 seconde (PC Linux 500Mhz)
 | 
|---|
| 48 |  PRECISION: eps=1e-16  -> |t-tvrai|<1e-6 toujours
 | 
|---|
| 49 |                           |t-tvrai|<1e-10 pour t<1.57
 | 
|---|
| 50 |                           |t-tvrai|<1e-10 pour t<1.57
 | 
|---|
| 51 |                           |t-tvrai|<3e-14 pour t<1.50
 | 
|---|
| 52 |                           |t-tvrai|<5e-15 pour t<1.40
 | 
|---|
| 53 |  \endverbatim
 | 
|---|
| 54 | */
 | 
|---|
| 55 | double MollWeide_XY(double longitude,double latitude,double* xmoll,double*ymoll)
 | 
|---|
| 56 | {
 | 
|---|
| 57 |  int i,niter=2;
 | 
|---|
| 58 |  double tini,t0,f0,f1,f2,e1,e2,dt,a,asgn,eps=1.e-16;
 | 
|---|
| 59 |  
 | 
|---|
| 60 |  a = M_PI*sin(latitude);
 | 
|---|
| 61 |  if(a<0.) {a*=-1.; asgn=-1.;} else asgn=1.;
 | 
|---|
| 62 |  // premier guess t1 ok pour t->0 (droite)
 | 
|---|
| 63 |  f1 = a/4.;
 | 
|---|
| 64 |  // second guess t2 ok pour t->Pi/2 (DL en Pi/2, type a+b*x^3)
 | 
|---|
| 65 |  f2 = 0.75*(M_PI-a);
 | 
|---|
| 66 |  if(f2>0.) f2=M_PI_2-pow(f2,0.33333333333333333); else f2=M_PI_2;
 | 
|---|
| 67 |  e1 = 2.*f1+sin(2.*f1)-a; if(e1<0.) e1 *= -1.;
 | 
|---|
| 68 |  e2 = 2.*f2+sin(2.*f2)-a; if(e2<0.) e2 *= -1.;
 | 
|---|
| 69 |  tini = (f1*e2+f2*e1)/(e1+e2);
 | 
|---|
| 70 |  //printf("---> a=%e tini=%e f1=%e f2=%e\n",a,tini,f1,f2);
 | 
|---|
| 71 |  if(tini<0) tini=0.; else if(tini>M_PI_2) tini=M_PI_2;
 | 
|---|
| 72 |  // L'approximation par le DL au 2sd ordre, on resoud:
 | 
|---|
| 73 |  // a = f(x0) + f'(x0)*(x-x0) + f''(x0)*(x-x0)^2/2
 | 
|---|
| 74 |  t0 = tini;
 | 
|---|
| 75 |  for(i=0;i<niter;i++) {
 | 
|---|
| 76 |    e1 = sin(2.*t0);
 | 
|---|
| 77 |    f0 = 2.*t0+e1;           // (f(x0))     >=0 sur 0<t<Pi/2
 | 
|---|
| 78 |    //printf(".%d    a-f0=%e\n",i,a-f0);
 | 
|---|
| 79 |    if(a-f0<eps && a-f0>-eps) break;
 | 
|---|
| 80 |    f1 = 2.*(1.+cos(2.*t0)); // (f'(x0))    >=0 sur 0<t<Pi/2
 | 
|---|
| 81 |    f2 = -2.*e1;             // (f''(x0)/2) <=0 sur 0<t<Pi/2
 | 
|---|
| 82 |    dt = f1*f1 - 4.*(f0-a)*f2;
 | 
|---|
| 83 |    //printf(".%d    f0=%e f1=%e f2=%e disc=%e\n",i,f0,f1,f2,dt);
 | 
|---|
| 84 |    if(dt>=0.) dt=-f1+sqrt(dt); else dt=0.;
 | 
|---|
| 85 |    ////printf(".%d    -b+sqrt(disc)=%e\n",i,dt);
 | 
|---|
| 86 |    if(f2<-eps && (dt>eps || dt<-eps)) { // approx parabolique
 | 
|---|
| 87 |      t0 += dt/(2.*f2);
 | 
|---|
| 88 |      //printf(".%d  parab  t0=%e\n",i,t0);
 | 
|---|
| 89 |    } else if(f1>eps) {
 | 
|---|
| 90 |      t0 += (a-f0)/f1; // approx lineaire
 | 
|---|
| 91 |      //printf(".%d  lin  t0=%e\n",i,t0);
 | 
|---|
| 92 |    }
 | 
|---|
| 93 |    if(t0<0) t0=0.; else if(t0>M_PI_2) t0=M_PI_2;
 | 
|---|
| 94 |  }
 | 
|---|
| 95 | 
 | 
|---|
| 96 |  t0 *= asgn;
 | 
|---|
| 97 |  *xmoll = 2.*M_SQRT2*(longitude-M_PI)/M_PI*cos(t0);
 | 
|---|
| 98 |  *ymoll = M_SQRT2*sin(t0);
 | 
|---|
| 99 | 
 | 
|---|
| 100 |  #if defined(TEST_MOLLWEIDE)
 | 
|---|
| 101 |  _t = tini;
 | 
|---|
| 102 |  #endif
 | 
|---|
| 103 | 
 | 
|---|
| 104 |  return t0;
 | 
|---|
| 105 | }
 | 
|---|
| 106 | 
 | 
|---|
| 107 | /*! \ingroup XAstroPack
 | 
|---|
| 108 |  \brief La vraie projection Mollweide (xmoll,ymoll) -> (longitude,latitude)
 | 
|---|
| 109 |  \param input: xmoll dans [-2*sqrt(2),2*sqrt(2)]
 | 
|---|
| 110 |  \param input: ymoll dans [-sqrt(2),sqrt(2)]
 | 
|---|
| 111 |  \param output: longitude [0,2PI[ en radians
 | 
|---|
| 112 |  \param output: latitude  [-Pi/2,Pi/2] en radians
 | 
|---|
| 113 |  \return t
 | 
|---|
| 114 |  \warning Probleme de precision pour t pres de Pi/2 (latitude pres de -Pi/2 ou Pi/2)
 | 
|---|
| 115 |  \warning Longitude=Pi=180 au milieu en xmoll=0
 | 
|---|
| 116 |  \verbatim
 | 
|---|
| 117 |  --------------------------------------------------------
 | 
|---|
| 118 |  INPUT: xmoll dans [-2*sqrt(2),2*sqrt(2)]
 | 
|---|
| 119 |         ymoll dans [-sqrt(2),sqrt(2)]
 | 
|---|
| 120 |  OUTPUT: longitude [0,2PI[      en radians
 | 
|---|
| 121 |          latitude  [-Pi/2,Pi/2] en radians
 | 
|---|
| 122 |  RETURN: t if OK
 | 
|---|
| 123 |          -991 : xmoll hors limites
 | 
|---|
| 124 |          -992 : ymoll hors limites
 | 
|---|
| 125 |          -993 : non inversible (poles de la sphere)
 | 
|---|
| 126 |  --------------------------------------------------------
 | 
|---|
| 127 |  \endverbatim
 | 
|---|
| 128 | */
 | 
|---|
| 129 | double MollWeide_LL(double xmoll,double ymoll,double* longitude,double* latitude)
 | 
|---|
| 130 | {
 | 
|---|
| 131 |  double t,a,eps=1.e-20;
 | 
|---|
| 132 | 
 | 
|---|
| 133 |  *longitude = *latitude = -999.;
 | 
|---|
| 134 |  if(xmoll<-2*M_SQRT2 || xmoll>2*M_SQRT2) return(-901.);
 | 
|---|
| 135 |  if(ymoll<-M_SQRT2 || ymoll>M_SQRT2) return(-902.);
 | 
|---|
| 136 | 
 | 
|---|
| 137 |  t = ymoll/M_SQRT2; if(t<-1.) t=-1.; else if(t>1.) t=1.;
 | 
|---|
| 138 |  t = asin(t);
 | 
|---|
| 139 | 
 | 
|---|
| 140 |  a = (2.*t+sin(2.*t))/M_PI; if(a<-1.) a=-1.; else if(a>1.) a=1.;
 | 
|---|
| 141 |  *latitude = asin(a);
 | 
|---|
| 142 | 
 | 
|---|
| 143 |  a= cos(t);
 | 
|---|
| 144 |  if(fabs(a)<eps) return(-903.);
 | 
|---|
| 145 |  *longitude = M_PI*(xmoll/(2.*M_SQRT2*a)+1.);
 | 
|---|
| 146 | 
 | 
|---|
| 147 |  return(t);
 | 
|---|
| 148 | }
 | 
|---|
| 149 | 
 | 
|---|
| 150 | ///////////////////////////////////////
 | 
|---|
| 151 | ////////// Programme de test //////////
 | 
|---|
| 152 | ///////////////////////////////////////
 | 
|---|
| 153 | #if defined(TEST_MOLLWEIDE)
 | 
|---|
| 154 | int main()
 | 
|---|
| 155 | {
 | 
|---|
| 156 |  FILE *file  = fopen("mollw.data","w");
 | 
|---|
| 157 |  FILE *file2 = fopen("mollw2.data","w");
 | 
|---|
| 158 |  int i,npoints=250000;
 | 
|---|
| 159 |  double tvrai,lon,lat,x,y,tcalc,a;
 | 
|---|
| 160 |  double longitude,latitude,tll,txy;
 | 
|---|
| 161 |  InitTim();
 | 
|---|
| 162 | 
 | 
|---|
| 163 |  tll=txy=0.;
 | 
|---|
| 164 |  for(i=0;i<=npoints;i++) {
 | 
|---|
| 165 |    //tvrai = 1.57078;
 | 
|---|
| 166 |    tvrai = (double)i*(M_PI_2) /(double)npoints;
 | 
|---|
| 167 |    a = 2.*tvrai+sin(2.*tvrai);
 | 
|---|
| 168 |    lat = asin(a/M_PI);
 | 
|---|
| 169 |    tcalc = MollWeide_XY(0.,lat,&x,&y);
 | 
|---|
| 170 |    if(fabs(tcalc-tvrai)>tll) {tll = fabs(tcalc-tvrai); txy=tvrai;}
 | 
|---|
| 171 |    if(file) fprintf(file,"%e %e %e %e %e\n",tvrai,tcalc,_t,a,tcalc-tvrai);
 | 
|---|
| 172 |  }
 | 
|---|
| 173 |  printf("Maximum difference: %e for t=%.10e=Pi/2-%.10e\n",tll,txy,M_PI_2-txy);
 | 
|---|
| 174 |  if(file) fclose(file);
 | 
|---|
| 175 |  PrtTim("--- End of first testing ---");
 | 
|---|
| 176 | 
 | 
|---|
| 177 |  for(lon=0.;lon<360.;lon+=2.5) for(lat=-90.;lat<=90.1;lat+=2.5) {
 | 
|---|
| 178 |    txy = MollWeide_XY(lon*M_PI/180.,lat*M_PI/180.,&x,&y);
 | 
|---|
| 179 |    tll = MollWeide_LL(x,y,&longitude,&latitude);
 | 
|---|
| 180 |    longitude *= 180./M_PI;
 | 
|---|
| 181 |    latitude  *= 180./M_PI;
 | 
|---|
| 182 |    if(file2) fprintf(file2,"%e %e %e %e %e %e %e %e %e %e\n"
 | 
|---|
| 183 |      ,lon,lat,x,y,longitude,latitude,txy,tll,longitude-lon,latitude-lat);
 | 
|---|
| 184 |  }
 | 
|---|
| 185 |  if(file2) fclose(file2);
 | 
|---|
| 186 |  PrtTim("--- End of second testing ---");
 | 
|---|
| 187 |  return 0;
 | 
|---|
| 188 | }
 | 
|---|
| 189 | #endif
 | 
|---|