1 /*============================================================================
2   WCSLIB 7.7 - an implementation of the FITS WCS standard.
3   Copyright (C) 1995-2021, Mark Calabretta
4 
5   This file is part of WCSLIB.
6 
7   WCSLIB is free software: you can redistribute it and/or modify it under the
8   terms of the GNU Lesser General Public License as published by the Free
9   Software Foundation, either version 3 of the License, or (at your option)
10   any later version.
11 
12   WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15   more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with WCSLIB.  If not, see http://www.gnu.org/licenses.
19 
20   Author: Mark Calabretta, Australia Telescope National Facility, CSIRO.
21   http://www.atnf.csiro.au/people/Mark.Calabretta
22   $Id: prj.c,v 7.7 2021/07/12 06:36:49 mcalabre Exp $
23 *===========================================================================*/
24 
25 #include <math.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "wcserr.h"
31 #include "wcsmath.h"
32 #include "wcsprintf.h"
33 #include "wcstrig.h"
34 #include "wcsutil.h"
35 #include "prj.h"
36 
37 
38 // Projection categories.
39 const int ZENITHAL          = 1;
40 const int CYLINDRICAL       = 2;
41 const int PSEUDOCYLINDRICAL = 3;
42 const int CONVENTIONAL      = 4;
43 const int CONIC             = 5;
44 const int POLYCONIC         = 6;
45 const int QUADCUBE          = 7;
46 const int HEALPIX           = 8;
47 
48 const char prj_categories[9][32] =
49   {"undefined", "zenithal", "cylindrical", "pseudocylindrical",
50   "conventional", "conic", "polyconic", "quadcube", "HEALPix"};
51 
52 
53 // Projection codes.
54 const int  prj_ncode = 28;
55 const char prj_codes[28][4] =
56   {"AZP", "SZP", "TAN", "STG", "SIN", "ARC", "ZPN", "ZEA", "AIR", "CYP",
57    "CEA", "CAR", "MER", "COP", "COE", "COD", "COO", "SFL", "PAR", "MOL",
58    "AIT", "BON", "PCO", "TSC", "CSC", "QSC", "HPX", "XPH"};
59 
60 const int AZP = 101;
61 const int SZP = 102;
62 const int TAN = 103;
63 const int STG = 104;
64 const int SIN = 105;
65 const int ARC = 106;
66 const int ZPN = 107;
67 const int ZEA = 108;
68 const int AIR = 109;
69 const int CYP = 201;
70 const int CEA = 202;
71 const int CAR = 203;
72 const int MER = 204;
73 const int SFL = 301;
74 const int PAR = 302;
75 const int MOL = 303;
76 const int AIT = 401;
77 const int COP = 501;
78 const int COE = 502;
79 const int COD = 503;
80 const int COO = 504;
81 const int BON = 601;
82 const int PCO = 602;
83 const int TSC = 701;
84 const int CSC = 702;
85 const int QSC = 703;
86 const int HPX = 801;
87 const int XPH = 802;
88 
89 
90 // Map status return value to message.
91 const char *prj_errmsg[] = {
92   "Success",
93   "Null prjprm pointer passed",
94   "Invalid projection parameters",
95   "One or more of the (x,y) coordinates were invalid",
96   "One or more of the (phi,theta) coordinates were invalid"};
97 
98 // Convenience macros for generating common error messages.
99 #define PRJERR_BAD_PARAM_SET(function) \
100   wcserr_set(&(prj->err), PRJERR_BAD_PARAM, function, __FILE__, __LINE__, \
101     "Invalid parameters for %s projection", prj->name);
102 
103 #define PRJERR_BAD_PIX_SET(function) \
104   wcserr_set(&(prj->err), PRJERR_BAD_PIX, function, __FILE__, __LINE__, \
105     "One or more of the (x, y) coordinates were invalid for %s projection", \
106     prj->name);
107 
108 #define PRJERR_BAD_WORLD_SET(function) \
109   wcserr_set(&(prj->err), PRJERR_BAD_WORLD, function, __FILE__, __LINE__, \
110     "One or more of the (lat, lng) coordinates were invalid for " \
111     "%s projection", prj->name);
112 
113 #define copysign(X, Y) ((Y) < 0.0 ? -fabs(X) : fabs(X))
114 
115 
116 /*============================================================================
117 * Generic routines:
118 *
119 * prjini initializes a prjprm struct to default values.
120 *
121 * prjfree frees any memory that may have been allocated to store an error
122 *        message in the prjprm struct.
123 *
124 * prjsize computed the size of a prjprm struct.
125 *
126 * prjprt prints the contents of a prjprm struct.
127 *
128 * prjbchk performs bounds checking on the native coordinates returned by the
129 *        *x2s() routines.
130 *
131 * prjset invokes the specific initialization routine based on the projection
132 *        code in the prjprm struct.
133 *
134 * prjx2s invokes the specific deprojection routine based on the pointer-to-
135 *        function stored in the prjprm struct.
136 *
137 * prjs2x invokes the specific projection routine based on the pointer-to-
138 *        function stored in the prjprm struct.
139 *
140 *---------------------------------------------------------------------------*/
141 
prjini(struct prjprm * prj)142 int prjini(struct prjprm *prj)
143 
144 {
145   register int k;
146 
147   if (prj == 0x0) return PRJERR_NULL_POINTER;
148 
149   prj->flag = 0;
150 
151   strcpy(prj->code, "   ");
152   prj->pv[0]  = 0.0;
153   prj->pv[1]  = UNDEFINED;
154   prj->pv[2]  = UNDEFINED;
155   prj->pv[3]  = UNDEFINED;
156   for (k = 4; k < PVN; prj->pv[k++] = 0.0);
157   prj->r0     = 0.0;
158   prj->phi0   = UNDEFINED;
159   prj->theta0 = UNDEFINED;
160   prj->bounds = 7;
161 
162   strcpy(prj->name, "undefined");
163   for (k = 9; k < 40; prj->name[k++] = '\0');
164   prj->category  = 0;
165   prj->pvrange   = 0;
166   prj->simplezen = 0;
167   prj->equiareal = 0;
168   prj->conformal = 0;
169   prj->global    = 0;
170   prj->divergent = 0;
171   prj->x0 = 0.0;
172   prj->y0 = 0.0;
173 
174   prj->err = 0x0;
175 
176   prj->padding = 0x0;
177   for (k = 0; k < 10; prj->w[k++] = 0.0);
178   prj->m = 0;
179   prj->n = 0;
180   prj->prjx2s = 0x0;
181   prj->prjs2x = 0x0;
182 
183   return 0;
184 }
185 
186 //----------------------------------------------------------------------------
187 
prjfree(struct prjprm * prj)188 int prjfree(struct prjprm *prj)
189 
190 {
191   if (prj == 0x0) return PRJERR_NULL_POINTER;
192 
193   wcserr_clear(&(prj->err));
194 
195   return 0;
196 }
197 
198 //----------------------------------------------------------------------------
199 
prjsize(const struct prjprm * prj,int sizes[2])200 int prjsize(const struct prjprm *prj, int sizes[2])
201 
202 {
203   if (prj == 0x0) {
204     sizes[0] = sizes[1] = 0;
205     return PRJERR_SUCCESS;
206   }
207 
208   // Base size, in bytes.
209   sizes[0] = sizeof(struct prjprm);
210 
211   // Total size of allocated memory, in bytes.
212   sizes[1] = 0;
213 
214   int exsizes[2];
215 
216   // prjprm::err.
217   wcserr_size(prj->err, exsizes);
218   sizes[1] += exsizes[0] + exsizes[1];
219 
220   return PRJERR_SUCCESS;
221 }
222 
223 //----------------------------------------------------------------------------
224 
prjprt(const struct prjprm * prj)225 int prjprt(const struct prjprm *prj)
226 
227 {
228   char hext[32];
229   int  i, n;
230 
231   if (prj == 0x0) return PRJERR_NULL_POINTER;
232 
233   wcsprintf("       flag: %d\n",  prj->flag);
234   wcsprintf("       code: \"%s\"\n",  prj->code);
235   wcsprintf("         r0: %9f\n", prj->r0);
236   wcsprintf("         pv:");
237   if (prj->pvrange) {
238     n = (prj->pvrange)%100;
239 
240     if (prj->pvrange/100) {
241       wcsprintf(" (0)");
242     } else {
243       wcsprintf(" %#- 11.5g", prj->pv[0]);
244       n--;
245     }
246 
247     for (i = 1; i <= n; i++) {
248       if (i%5 == 1) {
249         wcsprintf("\n           ");
250       }
251 
252       if (undefined(prj->pv[i])) {
253         wcsprintf("  UNDEFINED   ");
254       } else {
255         wcsprintf("  %#- 11.5g", prj->pv[i]);
256       }
257     }
258     wcsprintf("\n");
259   } else {
260     wcsprintf(" (not used)\n");
261   }
262   if (undefined(prj->phi0)) {
263     wcsprintf("       phi0: UNDEFINED\n");
264   } else {
265     wcsprintf("       phi0: %9f\n", prj->phi0);
266   }
267   if (undefined(prj->theta0)) {
268     wcsprintf("     theta0: UNDEFINED\n");
269   } else {
270     wcsprintf("     theta0: %9f\n", prj->theta0);
271   }
272   wcsprintf("     bounds: %d\n",  prj->bounds);
273 
274   wcsprintf("\n");
275   wcsprintf("       name: \"%s\"\n", prj->name);
276   wcsprintf("   category: %d (%s)\n", prj->category,
277                                       prj_categories[prj->category]);
278   wcsprintf("    pvrange: %d\n", prj->pvrange);
279   wcsprintf("  simplezen: %d\n", prj->simplezen);
280   wcsprintf("  equiareal: %d\n", prj->equiareal);
281   wcsprintf("  conformal: %d\n", prj->conformal);
282   wcsprintf("     global: %d\n", prj->global);
283   wcsprintf("  divergent: %d\n", prj->divergent);
284   wcsprintf("         x0: %f\n", prj->x0);
285   wcsprintf("         y0: %f\n", prj->y0);
286 
287   WCSPRINTF_PTR("        err: ", prj->err, "\n");
288   if (prj->err) {
289     wcserr_prt(prj->err, "             ");
290   }
291 
292   wcsprintf("        w[]:");
293   for (i = 0; i < 5; i++) {
294     wcsprintf("  %#- 11.5g", prj->w[i]);
295   }
296   wcsprintf("\n            ");
297   for (i = 5; i < 10; i++) {
298     wcsprintf("  %#- 11.5g", prj->w[i]);
299   }
300   wcsprintf("\n");
301   wcsprintf("          m: %d\n", prj->m);
302   wcsprintf("          n: %d\n", prj->n);
303   wcsprintf("     prjx2s: %s\n",
304     wcsutil_fptr2str((void (*)(void))prj->prjx2s, hext));
305   wcsprintf("     prjs2x: %s\n",
306     wcsutil_fptr2str((void (*)(void))prj->prjs2x, hext));
307 
308   return 0;
309 }
310 
311 //----------------------------------------------------------------------------
312 
prjperr(const struct prjprm * prj,const char * prefix)313 int prjperr(const struct prjprm *prj, const char *prefix)
314 
315 {
316   if (prj == 0x0) return PRJERR_NULL_POINTER;
317 
318   if (prj->err) {
319     wcserr_prt(prj->err, prefix);
320   }
321 
322   return 0;
323 }
324 
325 //----------------------------------------------------------------------------
326 
prjbchk(double tol,int nphi,int ntheta,int spt,double phi[],double theta[],int stat[])327 int prjbchk(
328   double tol,
329   int nphi,
330   int ntheta,
331   int spt,
332   double phi[],
333   double theta[],
334   int stat[])
335 
336 {
337   int status = 0;
338   register int iphi, itheta, *statp;
339   register double *phip, *thetap;
340 
341   phip   = phi;
342   thetap = theta;
343   statp  = stat;
344   for (itheta = 0; itheta < ntheta; itheta++) {
345     for (iphi = 0; iphi < nphi; iphi++, phip += spt, thetap += spt, statp++) {
346       // Skip values already marked as illegal.
347       if (*statp == 0) {
348         if (*phip < -180.0) {
349           if (*phip < -180.0-tol) {
350             *statp = 1;
351             status = 1;
352           } else {
353             *phip = -180.0;
354           }
355         } else if (180.0 < *phip) {
356           if (180.0+tol < *phip) {
357             *statp = 1;
358             status = 1;
359           } else {
360             *phip = 180.0;
361           }
362         }
363 
364         if (*thetap < -90.0) {
365           if (*thetap < -90.0-tol) {
366             *statp = 1;
367             status = 1;
368           } else {
369             *thetap = -90.0;
370           }
371         } else if (90.0 < *thetap) {
372           if (90.0+tol < *thetap) {
373             *statp = 1;
374             status = 1;
375           } else {
376             *thetap = 90.0;
377           }
378         }
379       }
380     }
381   }
382 
383   return status;
384 }
385 
386 //----------------------------------------------------------------------------
387 
prjset(struct prjprm * prj)388 int prjset(struct prjprm *prj)
389 
390 {
391   static const char *function = "prjset";
392 
393   int status;
394   struct wcserr **err;
395 
396   if (prj == 0x0) return PRJERR_NULL_POINTER;
397   err = &(prj->err);
398 
399   // Invoke the relevant initialization routine.
400   prj->code[3] = '\0';
401   if (strcmp(prj->code, "AZP") == 0) {
402     status = azpset(prj);
403   } else if (strcmp(prj->code, "SZP") == 0) {
404     status = szpset(prj);
405   } else if (strcmp(prj->code, "TAN") == 0) {
406     status = tanset(prj);
407   } else if (strcmp(prj->code, "STG") == 0) {
408     status = stgset(prj);
409   } else if (strcmp(prj->code, "SIN") == 0) {
410     status = sinset(prj);
411   } else if (strcmp(prj->code, "ARC") == 0) {
412     status = arcset(prj);
413   } else if (strcmp(prj->code, "ZPN") == 0) {
414     status = zpnset(prj);
415   } else if (strcmp(prj->code, "ZEA") == 0) {
416     status = zeaset(prj);
417   } else if (strcmp(prj->code, "AIR") == 0) {
418     status = airset(prj);
419   } else if (strcmp(prj->code, "CYP") == 0) {
420     status = cypset(prj);
421   } else if (strcmp(prj->code, "CEA") == 0) {
422     status = ceaset(prj);
423   } else if (strcmp(prj->code, "CAR") == 0) {
424     status = carset(prj);
425   } else if (strcmp(prj->code, "MER") == 0) {
426     status = merset(prj);
427   } else if (strcmp(prj->code, "SFL") == 0) {
428     status = sflset(prj);
429   } else if (strcmp(prj->code, "PAR") == 0) {
430     status = parset(prj);
431   } else if (strcmp(prj->code, "MOL") == 0) {
432     status = molset(prj);
433   } else if (strcmp(prj->code, "AIT") == 0) {
434     status = aitset(prj);
435   } else if (strcmp(prj->code, "COP") == 0) {
436     status = copset(prj);
437   } else if (strcmp(prj->code, "COE") == 0) {
438     status = coeset(prj);
439   } else if (strcmp(prj->code, "COD") == 0) {
440     status = codset(prj);
441   } else if (strcmp(prj->code, "COO") == 0) {
442     status = cooset(prj);
443   } else if (strcmp(prj->code, "BON") == 0) {
444     status = bonset(prj);
445   } else if (strcmp(prj->code, "PCO") == 0) {
446     status = pcoset(prj);
447   } else if (strcmp(prj->code, "TSC") == 0) {
448     status = tscset(prj);
449   } else if (strcmp(prj->code, "CSC") == 0) {
450     status = cscset(prj);
451   } else if (strcmp(prj->code, "QSC") == 0) {
452     status = qscset(prj);
453   } else if (strcmp(prj->code, "HPX") == 0) {
454     status = hpxset(prj);
455   } else if (strcmp(prj->code, "XPH") == 0) {
456     status = xphset(prj);
457   } else {
458     // Unrecognized projection code.
459     status = wcserr_set(WCSERR_SET(PRJERR_BAD_PARAM),
460                "Unrecognized projection code '%s'", prj->code);
461   }
462 
463   return status;
464 }
465 
466 //----------------------------------------------------------------------------
467 
prjx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])468 int prjx2s(
469   struct prjprm *prj,
470   int nx,
471   int ny,
472   int sxy,
473   int spt,
474   const double x[],
475   const double y[],
476   double phi[],
477   double theta[],
478   int stat[])
479 
480 {
481   int status;
482 
483   // Initialize.
484   if (prj == 0x0) return PRJERR_NULL_POINTER;
485   if (prj->flag == 0) {
486     if ((status = prjset(prj))) return status;
487   }
488 
489   return prj->prjx2s(prj, nx, ny, sxy, spt, x, y, phi, theta, stat);
490 }
491 
492 //----------------------------------------------------------------------------
493 
prjs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])494 int prjs2x(
495   struct prjprm *prj,
496   int nphi,
497   int ntheta,
498   int spt,
499   int sxy,
500   const double phi[],
501   const double theta[],
502   double x[],
503   double y[],
504   int stat[])
505 
506 {
507   int status;
508 
509   // Initialize.
510   if (prj == 0x0) return PRJERR_NULL_POINTER;
511   if (prj->flag == 0) {
512     if ((status = prjset(prj))) return status;
513   }
514 
515   return prj->prjs2x(prj, nphi, ntheta, spt, sxy, phi, theta, x, y, stat);
516 }
517 
518 /*============================================================================
519 * Internal helper routine used by the *set() routines - not intended for
520 * outside use.  It forces (x,y) = (0,0) at (phi0,theta0).
521 *---------------------------------------------------------------------------*/
522 
prjoff(struct prjprm * prj,const double phi0,const double theta0)523 int prjoff(
524   struct prjprm *prj,
525   const double phi0,
526   const double theta0)
527 
528 {
529   int    stat;
530   double x0, y0;
531 
532   if (prj == 0x0) return PRJERR_NULL_POINTER;
533 
534   prj->x0 = 0.0;
535   prj->y0 = 0.0;
536 
537   if (undefined(prj->phi0) || undefined(prj->theta0)) {
538     // Set both to the projection-specific default if either undefined.
539     prj->phi0   = phi0;
540     prj->theta0 = theta0;
541 
542   } else {
543     if (prj->prjs2x(prj, 1, 1, 1, 1, &(prj->phi0), &(prj->theta0), &x0, &y0,
544                     &stat)) {
545       return PRJERR_BAD_PARAM_SET("prjoff");
546     }
547 
548     prj->x0 = x0;
549     prj->y0 = y0;
550   }
551 
552   return 0;
553 }
554 
555 /*============================================================================
556 *   AZP: zenithal/azimuthal perspective projection.
557 *
558 *   Given:
559 *      prj->pv[1]   Distance parameter, mu in units of r0.
560 *      prj->pv[2]   Tilt angle, gamma in degrees.
561 *
562 *   Given and/or returned:
563 *      prj->r0      Reset to 180/pi if 0.
564 *      prj->phi0    Reset to  0.0 if undefined.
565 *      prj->theta0  Reset to 90.0 if undefined.
566 *
567 *   Returned:
568 *      prj->flag     AZP
569 *      prj->code    "AZP"
570 *      prj->x0      Offset in x.
571 *      prj->y0      Offset in y.
572 *      prj->w[0]    r0*(mu+1)
573 *      prj->w[1]    tan(gamma)
574 *      prj->w[2]    sec(gamma)
575 *      prj->w[3]    cos(gamma)
576 *      prj->w[4]    sin(gamma)
577 *      prj->w[5]    asin(-1/mu) for |mu| >= 1, -90 otherwise
578 *      prj->w[6]    mu*cos(gamma)
579 *      prj->w[7]    1 if |mu*cos(gamma)| < 1, 0 otherwise
580 *      prj->prjx2s  Pointer to azpx2s().
581 *      prj->prjs2x  Pointer to azps2x().
582 *===========================================================================*/
583 
azpset(struct prjprm * prj)584 int azpset(struct prjprm *prj)
585 
586 {
587   if (prj == 0x0) return PRJERR_NULL_POINTER;
588 
589   prj->flag = AZP;
590   strcpy(prj->code, "AZP");
591 
592   if (undefined(prj->pv[1])) prj->pv[1] = 0.0;
593   if (undefined(prj->pv[2])) prj->pv[2] = 0.0;
594   if (prj->r0 == 0.0) prj->r0 = R2D;
595 
596   strcpy(prj->name, "zenithal/azimuthal perspective");
597   prj->category  = ZENITHAL;
598   prj->pvrange   = 102;
599   prj->simplezen = prj->pv[2] == 0.0;
600   prj->equiareal = 0;
601   prj->conformal = 0;
602   prj->global    = 0;
603   prj->divergent = prj->pv[1] <= 1.0;
604 
605   prj->w[0] = prj->r0*(prj->pv[1] + 1.0);
606   if (prj->w[0] == 0.0) {
607     return PRJERR_BAD_PARAM_SET("azpset");
608   }
609 
610   prj->w[3] = cosd(prj->pv[2]);
611   if (prj->w[3] == 0.0) {
612     return PRJERR_BAD_PARAM_SET("azpset");
613   }
614 
615   prj->w[2] = 1.0/prj->w[3];
616   prj->w[4] = sind(prj->pv[2]);
617   prj->w[1] = prj->w[4] / prj->w[3];
618 
619   if (fabs(prj->pv[1]) > 1.0) {
620     prj->w[5] = asind(-1.0/prj->pv[1]);
621   } else {
622     prj->w[5] = -90.0;
623   }
624 
625   prj->w[6] = prj->pv[1] * prj->w[3];
626   prj->w[7] = (fabs(prj->w[6]) < 1.0) ? 1.0 : 0.0;
627 
628   prj->prjx2s = azpx2s;
629   prj->prjs2x = azps2x;
630 
631   return prjoff(prj, 0.0, 90.0);
632 }
633 
634 //----------------------------------------------------------------------------
635 
azpx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])636 int azpx2s(
637   struct prjprm *prj,
638   int nx,
639   int ny,
640   int sxy,
641   int spt,
642   const double x[],
643   const double y[],
644   double phi[],
645   double theta[],
646   int stat[])
647 
648 {
649   int mx, my, rowlen, rowoff, status;
650   double a, b, q, r, s, t, xj, yj, yc, yc2;
651   const double tol = 1.0e-13;
652   register int ix, iy, *statp;
653   register const double *xp, *yp;
654   register double *phip, *thetap;
655 
656 
657   // Initialize.
658   if (prj == 0x0) return PRJERR_NULL_POINTER;
659   if (prj->flag != AZP) {
660     if ((status = azpset(prj))) return status;
661   }
662 
663   if (ny > 0) {
664     mx = nx;
665     my = ny;
666   } else {
667     mx = 1;
668     my = 1;
669     ny = nx;
670   }
671 
672   status = 0;
673 
674 
675   // Do x dependence.
676   xp = x;
677   rowoff = 0;
678   rowlen = nx*spt;
679   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
680     xj = *xp + prj->x0;
681 
682     phip = phi + rowoff;
683     for (iy = 0; iy < my; iy++) {
684       *phip = xj;
685       phip += rowlen;
686     }
687   }
688 
689 
690   // Do y dependence.
691   yp = y;
692   phip   = phi;
693   thetap = theta;
694   statp  = stat;
695   for (iy = 0; iy < ny; iy++, yp += sxy) {
696     yj = *yp + prj->y0;
697 
698     yc  = yj*prj->w[3];
699     yc2 = yc*yc;
700 
701     q = prj->w[0] + yj*prj->w[4];
702 
703     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
704       xj = *phip;
705 
706       r = sqrt(xj*xj + yc2);
707       if (r == 0.0) {
708         *phip = 0.0;
709         *thetap = 90.0;
710         *(statp++) = 0;
711 
712       } else {
713         *phip = atan2d(xj, -yc);
714 
715         s = r / q;
716         t = s*prj->pv[1]/sqrt(s*s + 1.0);
717 
718         s = atan2d(1.0, s);
719 
720         if (fabs(t) > 1.0) {
721           if (fabs(t) > 1.0+tol) {
722             *thetap = 0.0;
723             *(statp++) = 1;
724             if (!status) status = PRJERR_BAD_PIX_SET("azpx2s");
725             continue;
726           }
727           t = copysign(90.0, t);
728         } else {
729           t = asind(t);
730         }
731 
732         a = s - t;
733         b = s + t + 180.0;
734 
735         if (a > 90.0) a -= 360.0;
736         if (b > 90.0) b -= 360.0;
737 
738         *thetap = (a > b) ? a : b;
739         *(statp++) = 0;
740       }
741     }
742   }
743 
744 
745   // Do bounds checking on the native coordinates.
746   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
747     if (!status) status = PRJERR_BAD_PIX_SET("azpx2s");
748   }
749 
750   return status;
751 }
752 
753 //----------------------------------------------------------------------------
754 
azps2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])755 int azps2x(
756   struct prjprm *prj,
757   int nphi,
758   int ntheta,
759   int spt,
760   int sxy,
761   const double phi[],
762   const double theta[],
763   double x[],
764   double y[],
765   int stat[])
766 
767 {
768   int mphi, mtheta, rowlen, rowoff, status;
769   double a, b, cosphi, costhe, r, s, sinphi, sinthe, t;
770   register int iphi, itheta, istat, *statp;
771   register const double *phip, *thetap;
772   register double *xp, *yp;
773 
774 
775   // Initialize.
776   if (prj == 0x0) return PRJERR_NULL_POINTER;
777   if (prj->flag != AZP) {
778     if ((status = azpset(prj))) return status;
779   }
780 
781   if (ntheta > 0) {
782     mphi   = nphi;
783     mtheta = ntheta;
784   } else {
785     mphi   = 1;
786     mtheta = 1;
787     ntheta = nphi;
788   }
789 
790   status = 0;
791 
792 
793   // Do phi dependence.
794   phip = phi;
795   rowoff = 0;
796   rowlen = nphi*sxy;
797   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
798     sincosd(*phip, &sinphi, &cosphi);
799 
800     xp = x + rowoff;
801     yp = y + rowoff;
802     for (itheta = 0; itheta < mtheta; itheta++) {
803       *xp = sinphi;
804       *yp = cosphi;
805       xp += rowlen;
806       yp += rowlen;
807     }
808   }
809 
810 
811   // Do theta dependence.
812   thetap = theta;
813   xp = x;
814   yp = y;
815   statp = stat;
816   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
817     sincosd(*thetap, &sinthe, &costhe);
818 
819     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
820       s = prj->w[1]*(*yp);
821       t = (prj->pv[1] + sinthe) + costhe*s;
822 
823       if (t == 0.0) {
824         *xp = 0.0;
825         *yp = 0.0;
826         *(statp++) = 1;
827         if (!status) status = PRJERR_BAD_WORLD_SET("azps2x");
828 
829       } else {
830         r = prj->w[0]*costhe/t;
831 
832         // Bounds checking.
833         istat = 0;
834         if (prj->bounds&1) {
835           if (*thetap < prj->w[5]) {
836             // Overlap.
837             istat = 1;
838             if (!status) status = PRJERR_BAD_WORLD_SET("azps2x");
839 
840           } else if (prj->w[7] > 0.0) {
841             // Divergence.
842             t = prj->pv[1] / sqrt(1.0 + s*s);
843 
844             if (fabs(t) <= 1.0) {
845               s = atand(-s);
846               t = asind(t);
847               a = s - t;
848               b = s + t + 180.0;
849 
850               if (a > 90.0) a -= 360.0;
851               if (b > 90.0) b -= 360.0;
852 
853               if (*thetap < ((a > b) ? a : b)) {
854                 istat = 1;
855                 if (!status) status = PRJERR_BAD_WORLD_SET("azps2x");
856               }
857             }
858           }
859         }
860 
861         *xp =  r*(*xp) - prj->x0;
862         *yp = -r*(*yp)*prj->w[2] - prj->y0;
863         *(statp++) = istat;
864       }
865     }
866   }
867 
868   return status;
869 }
870 
871 /*============================================================================
872 *   SZP: slant zenithal perspective projection.
873 *
874 *   Given:
875 *      prj->pv[1]   Distance of the point of projection from the centre of the
876 *                   generating sphere, mu in units of r0.
877 *      prj->pv[2]   Native longitude, phi_c, and ...
878 *      prj->pv[3]   Native latitude, theta_c, on the planewards side of the
879 *                   intersection of the line through the point of projection
880 *                   and the centre of the generating sphere, phi_c in degrees.
881 *
882 *   Given and/or returned:
883 *      prj->r0      Reset to 180/pi if 0.
884 *      prj->phi0    Reset to  0.0 if undefined.
885 *      prj->theta0  Reset to 90.0 if undefined.
886 *
887 *   Returned:
888 *      prj->flag     SZP
889 *      prj->code    "SZP"
890 *      prj->x0      Fiducial offset in x.
891 *      prj->y0      Fiducial offset in y.
892 *      prj->w[0]    1/r0
893 *      prj->w[1]    xp = -mu*cos(theta_c)*sin(phi_c)
894 *      prj->w[2]    yp =  mu*cos(theta_c)*cos(phi_c)
895 *      prj->w[3]    zp =  mu*sin(theta_c) + 1
896 *      prj->w[4]    r0*xp
897 *      prj->w[5]    r0*yp
898 *      prj->w[6]    r0*zp
899 *      prj->w[7]    (zp - 1)^2
900 *      prj->w[8]    asin(1-zp) if |1 - zp| < 1, -90 otherwise
901 *      prj->prjx2s  Pointer to szpx2s().
902 *      prj->prjs2x  Pointer to szps2x().
903 *===========================================================================*/
904 
szpset(struct prjprm * prj)905 int szpset(struct prjprm *prj)
906 
907 {
908   if (prj == 0x0) return PRJERR_NULL_POINTER;
909 
910   prj->flag = SZP;
911   strcpy(prj->code, "SZP");
912 
913   if (undefined(prj->pv[1])) prj->pv[1] =  0.0;
914   if (undefined(prj->pv[2])) prj->pv[2] =  0.0;
915   if (undefined(prj->pv[3])) prj->pv[3] = 90.0;
916   if (prj->r0 == 0.0) prj->r0 = R2D;
917 
918   strcpy(prj->name, "slant zenithal perspective");
919   prj->category  = ZENITHAL;
920   prj->pvrange   = 103;
921   prj->simplezen = prj->pv[3] == 90.0;
922   prj->equiareal = 0;
923   prj->conformal = 0;
924   prj->global    = 0;
925   prj->divergent = prj->pv[1] <= 1.0;
926 
927   prj->w[0] = 1.0/prj->r0;
928 
929   prj->w[3] = prj->pv[1] * sind(prj->pv[3]) + 1.0;
930   if (prj->w[3] == 0.0) {
931     return PRJERR_BAD_PARAM_SET("szpset");
932   }
933 
934   prj->w[1] = -prj->pv[1] * cosd(prj->pv[3]) * sind(prj->pv[2]);
935   prj->w[2] =  prj->pv[1] * cosd(prj->pv[3]) * cosd(prj->pv[2]);
936   prj->w[4] =  prj->r0 * prj->w[1];
937   prj->w[5] =  prj->r0 * prj->w[2];
938   prj->w[6] =  prj->r0 * prj->w[3];
939   prj->w[7] =  (prj->w[3] - 1.0) * prj->w[3] - 1.0;
940 
941   if (fabs(prj->w[3] - 1.0) < 1.0) {
942     prj->w[8] = asind(1.0 - prj->w[3]);
943   } else {
944     prj->w[8] = -90.0;
945   }
946 
947   prj->prjx2s = szpx2s;
948   prj->prjs2x = szps2x;
949 
950   return prjoff(prj, 0.0, 90.0);
951 }
952 
953 //----------------------------------------------------------------------------
954 
szpx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])955 int szpx2s(
956   struct prjprm *prj,
957   int nx,
958   int ny,
959   int sxy,
960   int spt,
961   const double x[],
962   const double y[],
963   double phi[],
964   double theta[],
965   int stat[])
966 
967 {
968   int mx, my, rowlen, rowoff, status;
969   double a, b, c, d, r2, sinth1, sinth2, sinthe, t, x1, xr, xy, y1, yr, z;
970   const double tol = 1.0e-13;
971   register int ix, iy, *statp;
972   register const double *xp, *yp;
973   register double *phip, *thetap;
974 
975 
976   // Initialize.
977   if (prj == 0x0) return PRJERR_NULL_POINTER;
978   if (prj->flag != SZP) {
979     if ((status = szpset(prj))) return status;
980   }
981 
982   if (ny > 0) {
983     mx = nx;
984     my = ny;
985   } else {
986     mx = 1;
987     my = 1;
988     ny = nx;
989   }
990 
991   status = 0;
992 
993 
994   // Do x dependence.
995   xp = x;
996   rowoff = 0;
997   rowlen = nx*spt;
998   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
999     xr = (*xp + prj->x0)*prj->w[0];
1000 
1001     phip = phi + rowoff;
1002     for (iy = 0; iy < my; iy++) {
1003       *phip = xr;
1004       phip += rowlen;
1005     }
1006   }
1007 
1008 
1009   // Do y dependence.
1010   yp = y;
1011   phip   = phi;
1012   thetap = theta;
1013   statp  = stat;
1014   for (iy = 0; iy < ny; iy++, yp += sxy) {
1015     yr = (*yp + prj->y0)*prj->w[0];
1016 
1017     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
1018       xr = *phip;
1019       r2 = xr*xr + yr*yr;
1020 
1021       x1 = (xr - prj->w[1])/prj->w[3];
1022       y1 = (yr - prj->w[2])/prj->w[3];
1023       xy = xr*x1 + yr*y1;
1024 
1025       if (r2 < 1.0e-10) {
1026         // Use small angle formula.
1027         z = r2/2.0;
1028         *thetap = 90.0 - R2D*sqrt(r2/(1.0 + xy));
1029 
1030       } else {
1031         t = x1*x1 + y1*y1;
1032         a = t + 1.0;
1033         b = xy - t;
1034         c = r2 - xy - xy + t - 1.0;
1035         d = b*b - a*c;
1036 
1037         // Check for a solution.
1038         if (d < 0.0) {
1039           *phip = 0.0;
1040           *thetap = 0.0;
1041           *(statp++) = 1;
1042           if (!status) status = PRJERR_BAD_PIX_SET("szpx2s");
1043           continue;
1044         }
1045         d = sqrt(d);
1046 
1047         // Choose solution closest to pole.
1048         sinth1 = (-b + d)/a;
1049         sinth2 = (-b - d)/a;
1050         sinthe = (sinth1 > sinth2) ? sinth1 : sinth2;
1051         if (sinthe > 1.0) {
1052           if (sinthe-1.0 < tol) {
1053             sinthe = 1.0;
1054           } else {
1055             sinthe = (sinth1 < sinth2) ? sinth1 : sinth2;
1056           }
1057         }
1058 
1059         if (sinthe < -1.0) {
1060           if (sinthe+1.0 > -tol) {
1061             sinthe = -1.0;
1062           }
1063         }
1064 
1065         if (sinthe > 1.0 || sinthe < -1.0) {
1066           *phip   = 0.0;
1067           *thetap = 0.0;
1068           *(statp++) = 1;
1069           if (!status) status = PRJERR_BAD_PIX_SET("szpx2s");
1070           continue;
1071         }
1072 
1073         *thetap = asind(sinthe);
1074 
1075         z = 1.0 - sinthe;
1076       }
1077 
1078       *phip = atan2d(xr - x1*z, -(yr - y1*z));
1079       *(statp++) = 0;
1080     }
1081   }
1082 
1083 
1084   // Do bounds checking on the native coordinates.
1085   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
1086     if (!status) status = PRJERR_BAD_PIX_SET("szpx2s");
1087   }
1088 
1089   return status;
1090 }
1091 
1092 //----------------------------------------------------------------------------
1093 
szps2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])1094 int szps2x(
1095   struct prjprm *prj,
1096   int nphi,
1097   int ntheta,
1098   int spt,
1099   int sxy,
1100   const double phi[],
1101   const double theta[],
1102   double x[],
1103   double y[],
1104   int stat[])
1105 
1106 {
1107   int mphi, mtheta, rowlen, rowoff, status;
1108   double a, b, cosphi, r, s, sinphi, t, u, v;
1109   register int iphi, itheta, istat, *statp;
1110   register const double *phip, *thetap;
1111   register double *xp, *yp;
1112 
1113 
1114   // Initialize.
1115   if (prj == 0x0) return PRJERR_NULL_POINTER;
1116   if (prj->flag != SZP) {
1117     if ((status = szpset(prj))) return status;
1118   }
1119 
1120   if (ntheta > 0) {
1121     mphi   = nphi;
1122     mtheta = ntheta;
1123   } else {
1124     mphi   = 1;
1125     mtheta = 1;
1126     ntheta = nphi;
1127   }
1128 
1129   status = 0;
1130 
1131 
1132   // Do phi dependence.
1133   phip = phi;
1134   rowoff = 0;
1135   rowlen = nphi*sxy;
1136   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
1137     sincosd(*phip, &sinphi, &cosphi);
1138 
1139     xp = x + rowoff;
1140     yp = y + rowoff;
1141     for (itheta = 0; itheta < mtheta; itheta++) {
1142       *xp = sinphi;
1143       *yp = cosphi;
1144       xp += rowlen;
1145       yp += rowlen;
1146     }
1147   }
1148 
1149 
1150   // Do theta dependence.
1151   thetap = theta;
1152   xp = x;
1153   yp = y;
1154   statp = stat;
1155   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
1156     s = 1.0 - sind(*thetap);
1157     t = prj->w[3] - s;
1158 
1159     if (t == 0.0) {
1160       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
1161         *xp = 0.0;
1162         *yp = 0.0;
1163         *(statp++) = 1;
1164       }
1165 
1166       if (!status) status = PRJERR_BAD_WORLD_SET("szps2x");
1167 
1168     } else {
1169       r = prj->w[6]*cosd(*thetap)/t;
1170       u = prj->w[4]*s/t + prj->x0;
1171       v = prj->w[5]*s/t + prj->y0;
1172 
1173       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
1174         // Bounds checking.
1175         istat = 0;
1176         if (prj->bounds&1) {
1177           if (*thetap < prj->w[8]) {
1178             // Divergence.
1179             istat = 1;
1180             if (!status) status = PRJERR_BAD_WORLD_SET("szps2x");
1181 
1182           } else if (fabs(prj->pv[1]) > 1.0) {
1183             // Overlap.
1184             s = prj->w[1]*(*xp) - prj->w[2]*(*yp);
1185             t = 1.0/sqrt(prj->w[7] + s*s);
1186 
1187             if (fabs(t) <= 1.0) {
1188               s = atan2d(s, prj->w[3] - 1.0);
1189               t = asind(t);
1190               a = s - t;
1191               b = s + t + 180.0;
1192 
1193               if (a > 90.0) a -= 360.0;
1194               if (b > 90.0) b -= 360.0;
1195 
1196               if (*thetap < ((a > b) ? a : b)) {
1197                 istat = 1;
1198                 if (!status) status = PRJERR_BAD_WORLD_SET("szps2x");
1199               }
1200             }
1201           }
1202         }
1203 
1204         *xp =  r*(*xp) - u;
1205         *yp = -r*(*yp) - v;
1206         *(statp++) = istat;
1207       }
1208     }
1209   }
1210 
1211   return status;
1212 }
1213 
1214 
1215 /*============================================================================
1216 *   TAN: gnomonic projection.
1217 *
1218 *   Given and/or returned:
1219 *      prj->r0      Reset to 180/pi if 0.
1220 *      prj->phi0    Reset to  0.0 if undefined.
1221 *      prj->theta0  Reset to 90.0 if undefined.
1222 *
1223 *   Returned:
1224 *      prj->flag     TAN
1225 *      prj->code    "TAN"
1226 *      prj->x0      Fiducial offset in x.
1227 *      prj->y0      Fiducial offset in y.
1228 *      prj->prjx2s  Pointer to tanx2s().
1229 *      prj->prjs2x  Pointer to tans2x().
1230 *===========================================================================*/
1231 
tanset(struct prjprm * prj)1232 int tanset(struct prjprm *prj)
1233 
1234 {
1235   if (prj == 0x0) return PRJERR_NULL_POINTER;
1236 
1237   prj->flag = TAN;
1238   strcpy(prj->code, "TAN");
1239 
1240   if (prj->r0 == 0.0) prj->r0 = R2D;
1241 
1242   strcpy(prj->name, "gnomonic");
1243   prj->category  = ZENITHAL;
1244   prj->pvrange   = 0;
1245   prj->simplezen = 1;
1246   prj->equiareal = 0;
1247   prj->conformal = 0;
1248   prj->global    = 0;
1249   prj->divergent = 1;
1250 
1251   prj->prjx2s = tanx2s;
1252   prj->prjs2x = tans2x;
1253 
1254   return prjoff(prj, 0.0, 90.0);
1255 }
1256 
1257 //----------------------------------------------------------------------------
1258 
tanx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])1259 int tanx2s(
1260   struct prjprm *prj,
1261   int nx,
1262   int ny,
1263   int sxy,
1264   int spt,
1265   const double x[],
1266   const double y[],
1267   double phi[],
1268   double theta[],
1269   int stat[])
1270 
1271 {
1272   int mx, my, rowlen, rowoff, status;
1273   double r, xj, yj, yj2;
1274   register int ix, iy, *statp;
1275   register const double *xp, *yp;
1276   register double *phip, *thetap;
1277 
1278 
1279   // Initialize.
1280   if (prj == 0x0) return PRJERR_NULL_POINTER;
1281   if (prj->flag != TAN) {
1282     if ((status = tanset(prj))) return status;
1283   }
1284 
1285   if (ny > 0) {
1286     mx = nx;
1287     my = ny;
1288   } else {
1289     mx = 1;
1290     my = 1;
1291     ny = nx;
1292   }
1293 
1294   status = 0;
1295 
1296 
1297   // Do x dependence.
1298   xp = x;
1299   rowoff = 0;
1300   rowlen = nx*spt;
1301   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
1302     xj = *xp + prj->x0;
1303 
1304     phip = phi + rowoff;
1305     for (iy = 0; iy < my; iy++) {
1306       *phip = xj;
1307       phip += rowlen;
1308     }
1309   }
1310 
1311 
1312   // Do y dependence.
1313   yp = y;
1314   phip   = phi;
1315   thetap = theta;
1316   statp  = stat;
1317   for (iy = 0; iy < ny; iy++, yp += sxy) {
1318     yj  = *yp + prj->y0;
1319     yj2 = yj*yj;
1320 
1321     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
1322       xj = *phip;
1323 
1324       r = sqrt(xj*xj + yj2);
1325       if (r == 0.0) {
1326         *phip = 0.0;
1327       } else {
1328         *phip = atan2d(xj, -yj);
1329       }
1330 
1331       *thetap = atan2d(prj->r0, r);
1332       *(statp++) = 0;
1333     }
1334   }
1335 
1336 
1337   // Do bounds checking on the native coordinates.
1338   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
1339     if (!status) status = PRJERR_BAD_PIX_SET("tanx2s");
1340   }
1341 
1342   return status;
1343 }
1344 
1345 //----------------------------------------------------------------------------
1346 
tans2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])1347 int tans2x(
1348   struct prjprm *prj,
1349   int nphi,
1350   int ntheta,
1351   int spt,
1352   int sxy,
1353   const double phi[],
1354   const double theta[],
1355   double x[],
1356   double y[],
1357   int stat[])
1358 
1359 {
1360   int mphi, mtheta, rowlen, rowoff, status;
1361   double cosphi, r, s, sinphi;
1362   register int iphi, itheta, istat, *statp;
1363   register const double *phip, *thetap;
1364   register double *xp, *yp;
1365 
1366 
1367   // Initialize.
1368   if (prj == 0x0) return PRJERR_NULL_POINTER;
1369   if (prj->flag != TAN) {
1370     if ((status = tanset(prj))) return status;
1371   }
1372 
1373   if (ntheta > 0) {
1374     mphi   = nphi;
1375     mtheta = ntheta;
1376   } else {
1377     mphi   = 1;
1378     mtheta = 1;
1379     ntheta = nphi;
1380   }
1381 
1382   status = 0;
1383 
1384 
1385   // Do phi dependence.
1386   phip = phi;
1387   rowoff = 0;
1388   rowlen = nphi*sxy;
1389   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
1390     sincosd(*phip, &sinphi, &cosphi);
1391 
1392     xp = x + rowoff;
1393     yp = y + rowoff;
1394     for (itheta = 0; itheta < mtheta; itheta++) {
1395       *xp = sinphi;
1396       *yp = cosphi;
1397       xp += rowlen;
1398       yp += rowlen;
1399     }
1400   }
1401 
1402 
1403   // Do theta dependence.
1404   thetap = theta;
1405   xp = x;
1406   yp = y;
1407   statp = stat;
1408   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
1409     s = sind(*thetap);
1410     if (s == 0.0) {
1411       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
1412         *xp = 0.0;
1413         *yp = 0.0;
1414         *(statp++) = 1;
1415       }
1416       if (!status) status = PRJERR_BAD_WORLD_SET("tans2x");
1417 
1418     } else {
1419       r =  prj->r0*cosd(*thetap)/s;
1420 
1421       // Bounds checking.
1422       istat = 0;
1423       if (prj->bounds&1) {
1424         if (s < 0.0) {
1425           istat = 1;
1426           if (!status) status = PRJERR_BAD_WORLD_SET("tans2x");
1427         }
1428       }
1429 
1430       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
1431         *xp =  r*(*xp) - prj->x0;
1432         *yp = -r*(*yp) - prj->y0;
1433         *(statp++) = istat;
1434       }
1435     }
1436   }
1437 
1438   return status;
1439 }
1440 
1441 /*============================================================================
1442 *   STG: stereographic projection.
1443 *
1444 *   Given and/or returned:
1445 *      prj->r0      Reset to 180/pi if 0.
1446 *      prj->phi0    Reset to  0.0 if undefined.
1447 *      prj->theta0  Reset to 90.0 if undefined.
1448 *
1449 *   Returned:
1450 *      prj->flag     STG
1451 *      prj->code    "STG"
1452 *      prj->x0      Fiducial offset in x.
1453 *      prj->y0      Fiducial offset in y.
1454 *      prj->w[0]    2*r0
1455 *      prj->w[1]    1/(2*r0)
1456 *      prj->prjx2s  Pointer to stgx2s().
1457 *      prj->prjs2x  Pointer to stgs2x().
1458 *===========================================================================*/
1459 
stgset(struct prjprm * prj)1460 int stgset(struct prjprm *prj)
1461 
1462 {
1463   if (prj == 0x0) return PRJERR_NULL_POINTER;
1464 
1465   prj->flag = STG;
1466   strcpy(prj->code, "STG");
1467 
1468   strcpy(prj->name, "stereographic");
1469   prj->category  = ZENITHAL;
1470   prj->pvrange   = 0;
1471   prj->simplezen = 1;
1472   prj->equiareal = 0;
1473   prj->conformal = 1;
1474   prj->global    = 0;
1475   prj->divergent = 1;
1476 
1477   if (prj->r0 == 0.0) {
1478     prj->r0 = R2D;
1479     prj->w[0] = 360.0/PI;
1480     prj->w[1] = PI/360.0;
1481   } else {
1482     prj->w[0] = 2.0*prj->r0;
1483     prj->w[1] = 1.0/prj->w[0];
1484   }
1485 
1486   prj->prjx2s = stgx2s;
1487   prj->prjs2x = stgs2x;
1488 
1489   return prjoff(prj, 0.0, 90.0);
1490 }
1491 
1492 //----------------------------------------------------------------------------
1493 
stgx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])1494 int stgx2s(
1495   struct prjprm *prj,
1496   int nx,
1497   int ny,
1498   int sxy,
1499   int spt,
1500   const double x[],
1501   const double y[],
1502   double phi[],
1503   double theta[],
1504   int stat[])
1505 
1506 {
1507   int mx, my, rowlen, rowoff, status;
1508   double r, xj, yj, yj2;
1509   register int ix, iy, *statp;
1510   register const double *xp, *yp;
1511   register double *phip, *thetap;
1512 
1513 
1514   // Initialize.
1515   if (prj == 0x0) return PRJERR_NULL_POINTER;
1516   if (prj->flag != STG) {
1517     if ((status = stgset(prj))) return status;
1518   }
1519 
1520   if (ny > 0) {
1521     mx = nx;
1522     my = ny;
1523   } else {
1524     mx = 1;
1525     my = 1;
1526     ny = nx;
1527   }
1528 
1529 
1530   // Do x dependence.
1531   xp = x;
1532   rowoff = 0;
1533   rowlen = nx*spt;
1534   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
1535     xj = *xp + prj->x0;
1536 
1537     phip = phi + rowoff;
1538     for (iy = 0; iy < my; iy++) {
1539       *phip = xj;
1540       phip += rowlen;
1541     }
1542   }
1543 
1544 
1545   // Do y dependence.
1546   yp = y;
1547   phip   = phi;
1548   thetap = theta;
1549   statp  = stat;
1550   for (iy = 0; iy < ny; iy++, yp += sxy) {
1551     yj  = *yp + prj->y0;
1552     yj2 = yj*yj;
1553 
1554     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
1555       xj  = *phip;
1556 
1557       r = sqrt(xj*xj + yj2);
1558       if (r == 0.0) {
1559         *phip = 0.0;
1560       } else {
1561         *phip = atan2d(xj, -yj);
1562       }
1563 
1564       *thetap = 90.0 - 2.0*atand(r*prj->w[1]);
1565       *(statp++) = 0;
1566     }
1567   }
1568 
1569   return 0;
1570 }
1571 
1572 //----------------------------------------------------------------------------
1573 
stgs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])1574 int stgs2x(
1575   struct prjprm *prj,
1576   int nphi,
1577   int ntheta,
1578   int spt,
1579   int sxy,
1580   const double phi[],
1581   const double theta[],
1582   double x[],
1583   double y[],
1584   int stat[])
1585 
1586 {
1587   int mphi, mtheta, rowlen, rowoff, status;
1588   double cosphi, r, s, sinphi;
1589   register int iphi, itheta, *statp;
1590   register const double *phip, *thetap;
1591   register double *xp, *yp;
1592 
1593 
1594   // Initialize.
1595   if (prj == 0x0) return PRJERR_NULL_POINTER;
1596   if (prj->flag != STG) {
1597     if ((status = stgset(prj))) return status;
1598   }
1599 
1600   if (ntheta > 0) {
1601     mphi   = nphi;
1602     mtheta = ntheta;
1603   } else {
1604     mphi   = 1;
1605     mtheta = 1;
1606     ntheta = nphi;
1607   }
1608 
1609   status = 0;
1610 
1611 
1612   // Do phi dependence.
1613   phip = phi;
1614   rowoff = 0;
1615   rowlen = nphi*sxy;
1616   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
1617     sincosd(*phip, &sinphi, &cosphi);
1618 
1619     xp = x + rowoff;
1620     yp = y + rowoff;
1621     for (itheta = 0; itheta < mtheta; itheta++) {
1622       *xp = sinphi;
1623       *yp = cosphi;
1624       xp += rowlen;
1625       yp += rowlen;
1626     }
1627   }
1628 
1629 
1630   // Do theta dependence.
1631   thetap = theta;
1632   xp = x;
1633   yp = y;
1634   statp = stat;
1635   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
1636     s = 1.0 + sind(*thetap);
1637     if (s == 0.0) {
1638       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
1639         *xp = 0.0;
1640         *yp = 0.0;
1641         *(statp++) = 1;
1642       }
1643       if (!status) status = PRJERR_BAD_WORLD_SET("stgs2x");
1644 
1645     } else {
1646       r = prj->w[0]*cosd(*thetap)/s;
1647 
1648       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
1649         *xp =  r*(*xp) - prj->x0;
1650         *yp = -r*(*yp) - prj->y0;
1651         *(statp++) = 0;
1652       }
1653     }
1654   }
1655 
1656   return status;
1657 }
1658 
1659 /*============================================================================
1660 *   SIN: orthographic/synthesis projection.
1661 *
1662 *   Given:
1663 *      prj->pv[1:2] Obliqueness parameters, xi and eta.
1664 *
1665 *   Given and/or returned:
1666 *      prj->r0      Reset to 180/pi if 0.
1667 *      prj->phi0    Reset to  0.0 if undefined.
1668 *      prj->theta0  Reset to 90.0 if undefined.
1669 *
1670 *   Returned:
1671 *      prj->flag     SIN
1672 *      prj->code    "SIN"
1673 *      prj->x0      Fiducial offset in x.
1674 *      prj->y0      Fiducial offset in y.
1675 *      prj->w[0]    1/r0
1676 *      prj->w[1]    xi**2 + eta**2
1677 *      prj->w[2]    xi**2 + eta**2 + 1
1678 *      prj->w[3]    xi**2 + eta**2 - 1
1679 *      prj->prjx2s  Pointer to sinx2s().
1680 *      prj->prjs2x  Pointer to sins2x().
1681 *===========================================================================*/
1682 
sinset(struct prjprm * prj)1683 int sinset(struct prjprm *prj)
1684 
1685 {
1686   if (prj == 0x0) return PRJERR_NULL_POINTER;
1687 
1688   prj->flag = SIN;
1689   strcpy(prj->code, "SIN");
1690 
1691   if (undefined(prj->pv[1])) prj->pv[1] = 0.0;
1692   if (undefined(prj->pv[2])) prj->pv[2] = 0.0;
1693   if (prj->r0 == 0.0) prj->r0 = R2D;
1694 
1695   strcpy(prj->name, "orthographic/synthesis");
1696   prj->category  = ZENITHAL;
1697   prj->pvrange   = 102;
1698   prj->simplezen = (prj->pv[1] == 0.0 && prj->pv[2] == 0.0);
1699   prj->equiareal = 0;
1700   prj->conformal = 0;
1701   prj->global    = 0;
1702   prj->divergent = 0;
1703 
1704   prj->w[0] = 1.0/prj->r0;
1705   prj->w[1] = prj->pv[1]*prj->pv[1] + prj->pv[2]*prj->pv[2];
1706   prj->w[2] = prj->w[1] + 1.0;
1707   prj->w[3] = prj->w[1] - 1.0;
1708 
1709   prj->prjx2s = sinx2s;
1710   prj->prjs2x = sins2x;
1711 
1712   return prjoff(prj, 0.0, 90.0);
1713 }
1714 
1715 //----------------------------------------------------------------------------
1716 
sinx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])1717 int sinx2s(
1718   struct prjprm *prj,
1719   int nx,
1720   int ny,
1721   int sxy,
1722   int spt,
1723   const double x[],
1724   const double y[],
1725   double phi[],
1726   double theta[],
1727   int stat[])
1728 
1729 {
1730   int mx, my, rowlen, rowoff, status;
1731   const double tol = 1.0e-13;
1732   double a, b, c, d, eta, r2, sinth1, sinth2, sinthe, x0, xi, x1, xy, y0, y02,
1733          y1, z;
1734   register int ix, iy, *statp;
1735   register const double *xp, *yp;
1736   register double *phip, *thetap;
1737 
1738 
1739   // Initialize.
1740   if (prj == 0x0) return PRJERR_NULL_POINTER;
1741   if (prj->flag != SIN) {
1742     if ((status = sinset(prj))) return status;
1743   }
1744 
1745   xi  = prj->pv[1];
1746   eta = prj->pv[2];
1747 
1748   if (ny > 0) {
1749     mx = nx;
1750     my = ny;
1751   } else {
1752     mx = 1;
1753     my = 1;
1754     ny = nx;
1755   }
1756 
1757   status = 0;
1758 
1759 
1760   // Do x dependence.
1761   xp = x;
1762   rowoff = 0;
1763   rowlen = nx*spt;
1764   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
1765     x0 = (*xp + prj->x0)*prj->w[0];
1766 
1767     phip = phi + rowoff;
1768     for (iy = 0; iy < my; iy++) {
1769       *phip = x0;
1770       phip += rowlen;
1771     }
1772   }
1773 
1774 
1775   // Do y dependence.
1776   yp = y;
1777   phip   = phi;
1778   thetap = theta;
1779   statp  = stat;
1780   for (iy = 0; iy < ny; iy++, yp += sxy) {
1781     y0 = (*yp + prj->y0)*prj->w[0];
1782     y02 = y0*y0;
1783 
1784     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
1785       // Compute intermediaries.
1786       x0 = *phip;
1787       r2 = x0*x0 + y02;
1788 
1789       if (prj->w[1] == 0.0) {
1790         // Orthographic projection.
1791         if (r2 != 0.0) {
1792           *phip = atan2d(x0, -y0);
1793         } else {
1794           *phip = 0.0;
1795         }
1796 
1797         if (r2 < 0.5) {
1798           *thetap = acosd(sqrt(r2));
1799         } else if (r2 <= 1.0) {
1800           *thetap = asind(sqrt(1.0 - r2));
1801         } else {
1802           *(statp++) = 1;
1803           if (!status) status = PRJERR_BAD_PIX_SET("sinx2s")
1804           continue;
1805         }
1806 
1807       } else {
1808         // "Synthesis" projection.
1809         xy = x0*xi + y0*eta;
1810 
1811         if (r2 < 1.0e-10) {
1812           // Use small angle formula.
1813           z = r2/2.0;
1814           *thetap = 90.0 - R2D*sqrt(r2/(1.0 + xy));
1815 
1816         } else {
1817           a = prj->w[2];
1818           b = xy - prj->w[1];
1819           c = r2 - xy - xy + prj->w[3];
1820           d = b*b - a*c;
1821 
1822           // Check for a solution.
1823           if (d < 0.0) {
1824             *phip = 0.0;
1825             *thetap = 0.0;
1826             *(statp++) = 1;
1827             if (!status) status = PRJERR_BAD_PIX_SET("sinx2s")
1828             continue;
1829           }
1830           d = sqrt(d);
1831 
1832           // Choose solution closest to pole.
1833           sinth1 = (-b + d)/a;
1834           sinth2 = (-b - d)/a;
1835           sinthe = (sinth1 > sinth2) ? sinth1 : sinth2;
1836           if (sinthe > 1.0) {
1837             if (sinthe-1.0 < tol) {
1838               sinthe = 1.0;
1839             } else {
1840               sinthe = (sinth1 < sinth2) ? sinth1 : sinth2;
1841             }
1842           }
1843 
1844           if (sinthe < -1.0) {
1845             if (sinthe+1.0 > -tol) {
1846               sinthe = -1.0;
1847             }
1848           }
1849 
1850           if (sinthe > 1.0 || sinthe < -1.0) {
1851             *phip = 0.0;
1852             *thetap = 0.0;
1853             *(statp++) = 1;
1854             if (!status) status = PRJERR_BAD_PIX_SET("sinx2s")
1855             continue;
1856           }
1857 
1858           *thetap = asind(sinthe);
1859           z = 1.0 - sinthe;
1860         }
1861 
1862         x1 = -y0 + eta*z;
1863         y1 =  x0 -  xi*z;
1864         if (x1 == 0.0 && y1 == 0.0) {
1865           *phip = 0.0;
1866         } else {
1867           *phip = atan2d(y1,x1);
1868         }
1869       }
1870 
1871       *(statp++) = 0;
1872     }
1873   }
1874 
1875 
1876   // Do bounds checking on the native coordinates.
1877   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
1878     if (!status) status = PRJERR_BAD_PIX_SET("sinx2s");
1879   }
1880 
1881   return status;
1882 }
1883 
1884 //----------------------------------------------------------------------------
1885 
sins2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])1886 int sins2x(
1887   struct prjprm *prj,
1888   int nphi,
1889   int ntheta,
1890   int spt,
1891   int sxy,
1892   const double phi[],
1893   const double theta[],
1894   double x[],
1895   double y[],
1896   int stat[])
1897 
1898 {
1899   int mphi, mtheta, rowlen, rowoff, status;
1900   double cosphi, costhe, sinphi, r, t, z, z1, z2;
1901   register int iphi, itheta, istat, *statp;
1902   register const double *phip, *thetap;
1903   register double *xp, *yp;
1904 
1905 
1906   // Initialize.
1907   if (prj == 0x0) return PRJERR_NULL_POINTER;
1908   if (prj->flag != SIN) {
1909     if ((status = sinset(prj))) return status;
1910   }
1911 
1912   if (ntheta > 0) {
1913     mphi   = nphi;
1914     mtheta = ntheta;
1915   } else {
1916     mphi   = 1;
1917     mtheta = 1;
1918     ntheta = nphi;
1919   }
1920 
1921   status = 0;
1922 
1923 
1924   // Do phi dependence.
1925   phip = phi;
1926   rowoff = 0;
1927   rowlen = nphi*sxy;
1928   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
1929     sincosd(*phip, &sinphi, &cosphi);
1930 
1931     xp = x + rowoff;
1932     yp = y + rowoff;
1933     for (itheta = 0; itheta < mtheta; itheta++) {
1934       *xp = sinphi;
1935       *yp = cosphi;
1936       xp += rowlen;
1937       yp += rowlen;
1938     }
1939   }
1940 
1941 
1942   // Do theta dependence.
1943   thetap = theta;
1944   xp = x;
1945   yp = y;
1946   statp = stat;
1947   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
1948     t = (90.0 - fabs(*thetap))*D2R;
1949     if (t < 1.0e-5) {
1950       if (*thetap > 0.0) {
1951          z = t*t/2.0;
1952       } else {
1953          z = 2.0 - t*t/2.0;
1954       }
1955       costhe = t;
1956     } else {
1957       z = 1.0 - sind(*thetap);
1958       costhe = cosd(*thetap);
1959     }
1960     r = prj->r0*costhe;
1961 
1962     if (prj->w[1] == 0.0) {
1963       // Orthographic projection.
1964       istat = 0;
1965       if (prj->bounds&1) {
1966         if (*thetap < 0.0) {
1967           istat = 1;
1968           if (!status) status = PRJERR_BAD_WORLD_SET("sins2x");
1969         }
1970       }
1971 
1972       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
1973         *xp =  r*(*xp) - prj->x0;
1974         *yp = -r*(*yp) - prj->y0;
1975         *(statp++) = istat;
1976       }
1977 
1978     } else {
1979       // "Synthesis" projection.
1980       z *= prj->r0;
1981       z1 = prj->pv[1]*z - prj->x0;
1982       z2 = prj->pv[2]*z - prj->y0;
1983 
1984       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
1985         istat = 0;
1986         if (prj->bounds&1) {
1987           t = -atand(prj->pv[1]*(*xp) - prj->pv[2]*(*yp));
1988           if (*thetap < t) {
1989             istat = 1;
1990             if (!status) status = PRJERR_BAD_WORLD_SET("sins2x");
1991           }
1992         }
1993 
1994         *xp =  r*(*xp) + z1;
1995         *yp = -r*(*yp) + z2;
1996         *(statp++) = istat;
1997       }
1998     }
1999   }
2000 
2001   return status;
2002 }
2003 
2004 /*============================================================================
2005 *   ARC: zenithal/azimuthal equidistant projection.
2006 *
2007 *   Given and/or returned:
2008 *      prj->r0      Reset to 180/pi if 0.
2009 *      prj->phi0    Reset to  0.0 if undefined.
2010 *      prj->theta0  Reset to 90.0 if undefined.
2011 *
2012 *   Returned:
2013 *      prj->flag     ARC
2014 *      prj->code    "ARC"
2015 *      prj->x0      Fiducial offset in x.
2016 *      prj->y0      Fiducial offset in y.
2017 *      prj->w[0]    r0*(pi/180)
2018 *      prj->w[1]    (180/pi)/r0
2019 *      prj->prjx2s  Pointer to arcx2s().
2020 *      prj->prjs2x  Pointer to arcs2x().
2021 *===========================================================================*/
2022 
arcset(struct prjprm * prj)2023 int arcset(struct prjprm *prj)
2024 
2025 {
2026   if (prj == 0x0) return PRJERR_NULL_POINTER;
2027 
2028   prj->flag = ARC;
2029   strcpy(prj->code, "ARC");
2030 
2031   strcpy(prj->name, "zenithal/azimuthal equidistant");
2032   prj->category  = ZENITHAL;
2033   prj->pvrange   = 0;
2034   prj->simplezen = 1;
2035   prj->equiareal = 0;
2036   prj->conformal = 0;
2037   prj->global    = 1;
2038   prj->divergent = 0;
2039 
2040   if (prj->r0 == 0.0) {
2041     prj->r0 = R2D;
2042     prj->w[0] = 1.0;
2043     prj->w[1] = 1.0;
2044   } else {
2045     prj->w[0] = prj->r0*D2R;
2046     prj->w[1] = 1.0/prj->w[0];
2047   }
2048 
2049   prj->prjx2s = arcx2s;
2050   prj->prjs2x = arcs2x;
2051 
2052   return prjoff(prj, 0.0, 90.0);
2053 }
2054 
2055 //----------------------------------------------------------------------------
2056 
arcx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])2057 int arcx2s(
2058   struct prjprm *prj,
2059   int nx,
2060   int ny,
2061   int sxy,
2062   int spt,
2063   const double x[],
2064   const double y[],
2065   double phi[],
2066   double theta[],
2067   int stat[])
2068 
2069 {
2070   int mx, my, rowlen, rowoff, status;
2071   double r, xj, yj, yj2;
2072   register int ix, iy, *statp;
2073   register const double *xp, *yp;
2074   register double *phip, *thetap;
2075 
2076 
2077   // Initialize.
2078   if (prj == 0x0) return PRJERR_NULL_POINTER;
2079   if (prj->flag != ARC) {
2080     if ((status = arcset(prj))) return status;
2081   }
2082 
2083   if (ny > 0) {
2084     mx = nx;
2085     my = ny;
2086   } else {
2087     mx = 1;
2088     my = 1;
2089     ny = nx;
2090   }
2091 
2092   status = 0;
2093 
2094 
2095   // Do x dependence.
2096   xp = x;
2097   rowoff = 0;
2098   rowlen = nx*spt;
2099   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
2100     xj = *xp + prj->x0;
2101 
2102     phip = phi + rowoff;
2103     for (iy = 0; iy < my; iy++) {
2104       *phip = xj;
2105       phip += rowlen;
2106     }
2107   }
2108 
2109 
2110   // Do y dependence.
2111   yp = y;
2112   phip   = phi;
2113   thetap = theta;
2114   statp  = stat;
2115   for (iy = 0; iy < ny; iy++, yp += sxy) {
2116     yj  = *yp + prj->y0;
2117     yj2 = yj*yj;
2118 
2119     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
2120       xj = *phip;
2121 
2122       r = sqrt(xj*xj + yj2);
2123       if (r == 0.0) {
2124         *phip = 0.0;
2125         *thetap = 90.0;
2126       } else {
2127         *phip = atan2d(xj, -yj);
2128         *thetap = 90.0 - r*prj->w[1];
2129       }
2130 
2131       *(statp++) = 0;
2132     }
2133   }
2134 
2135 
2136   // Do bounds checking on the native coordinates.
2137   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
2138     if (!status) status = PRJERR_BAD_PIX_SET("arcx2s");
2139   }
2140 
2141   return status;
2142 }
2143 
2144 //----------------------------------------------------------------------------
2145 
arcs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])2146 int arcs2x(
2147   struct prjprm *prj,
2148   int nphi,
2149   int ntheta,
2150   int spt,
2151   int sxy,
2152   const double phi[],
2153   const double theta[],
2154   double x[],
2155   double y[],
2156   int stat[])
2157 
2158 {
2159   int mphi, mtheta, rowlen, rowoff, status;
2160   double cosphi, r, sinphi;
2161   register int iphi, itheta, *statp;
2162   register const double *phip, *thetap;
2163   register double *xp, *yp;
2164 
2165 
2166   // Initialize.
2167   if (prj == 0x0) return PRJERR_NULL_POINTER;
2168   if (prj->flag != ARC) {
2169     if ((status = arcset(prj))) return status;
2170   }
2171 
2172   if (ntheta > 0) {
2173     mphi   = nphi;
2174     mtheta = ntheta;
2175   } else {
2176     mphi   = 1;
2177     mtheta = 1;
2178     ntheta = nphi;
2179   }
2180 
2181 
2182   // Do phi dependence.
2183   phip = phi;
2184   rowoff = 0;
2185   rowlen = nphi*sxy;
2186   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
2187     sincosd(*phip, &sinphi, &cosphi);
2188 
2189     xp = x + rowoff;
2190     yp = y + rowoff;
2191     for (itheta = 0; itheta < mtheta; itheta++) {
2192       *xp = sinphi;
2193       *yp = cosphi;
2194       xp += rowlen;
2195       yp += rowlen;
2196     }
2197   }
2198 
2199 
2200   // Do theta dependence.
2201   thetap = theta;
2202   xp = x;
2203   yp = y;
2204   statp = stat;
2205   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
2206     r =  prj->w[0]*(90.0 - *thetap);
2207 
2208     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
2209       *xp =  r*(*xp) - prj->x0;
2210       *yp = -r*(*yp) - prj->y0;
2211       *(statp++) = 0;
2212     }
2213   }
2214 
2215   return 0;
2216 }
2217 
2218 /*============================================================================
2219 *   ZPN: zenithal/azimuthal polynomial projection.
2220 *
2221 *   Given:
2222 *      prj->pv[]    Polynomial coefficients.
2223 *
2224 *   Given and/or returned:
2225 *      prj->r0      Reset to 180/pi if 0.
2226 *      prj->phi0    Reset to  0.0 if undefined.
2227 *      prj->theta0  Reset to 90.0 if undefined.
2228 *
2229 *   Returned:
2230 *      prj->flag     ZPN
2231 *      prj->code    "ZPN"
2232 *      prj->x0      Fiducial offset in x.
2233 *      prj->y0      Fiducial offset in y.
2234 *      prj->n       Degree of the polynomial, N.
2235 *      prj->w[0]    Co-latitude of the first point of inflection, radian.
2236 *      prj->w[1]    Radius of the first point of inflection (N > 1), radian.
2237 *      prj->prjx2s  Pointer to zpnx2s().
2238 *      prj->prjs2x  Pointer to zpns2x().
2239 *===========================================================================*/
2240 
zpnset(struct prjprm * prj)2241 int zpnset(struct prjprm *prj)
2242 
2243 {
2244   int j, k, m;
2245   double d, d1, d2, r, zd, zd1, zd2;
2246   const double tol = 1.0e-13;
2247 
2248   if (prj == 0x0) return PRJERR_NULL_POINTER;
2249 
2250   strcpy(prj->code, "ZPN");
2251   prj->flag = ZPN;
2252 
2253   if (undefined(prj->pv[1])) prj->pv[1] = 0.0;
2254   if (undefined(prj->pv[2])) prj->pv[2] = 0.0;
2255   if (undefined(prj->pv[3])) prj->pv[3] = 0.0;
2256   if (prj->r0 == 0.0) prj->r0 = R2D;
2257 
2258   strcpy(prj->name, "zenithal/azimuthal polynomial");
2259   prj->category  = ZENITHAL;
2260   prj->pvrange   = 30;
2261   prj->simplezen = 1;
2262   prj->equiareal = 0;
2263   prj->conformal = 0;
2264   prj->global    = 0;
2265   prj->divergent = 0;
2266 
2267   // Find the highest non-zero coefficient.
2268   for (k = PVN-1; k >= 0 && prj->pv[k] == 0.0; k--);
2269   if (k < 0) {
2270     return PRJERR_BAD_PARAM_SET("zpnset");
2271   }
2272 
2273   prj->n = k;
2274 
2275   if (k < 2) {
2276     // No point of inflection.
2277     prj->w[0] = PI;
2278 
2279   } else {
2280     // Find the point of inflection closest to the pole.
2281     zd1 = 0.0;
2282     d1  = prj->pv[1];
2283     if (d1 <= 0.0) {
2284       return PRJERR_BAD_PARAM_SET("zpnset");
2285     }
2286 
2287     // Find the point where the derivative first goes negative.
2288     for (j = 0; j < 180; j++) {
2289       zd2 = j*D2R;
2290       d2  = 0.0;
2291       for (m = k; m > 0; m--) {
2292         d2 = d2*zd2 + m*prj->pv[m];
2293       }
2294 
2295       if (d2 <= 0.0) break;
2296       zd1 = zd2;
2297       d1  = d2;
2298     }
2299 
2300     if (j == 180) {
2301       // No negative derivative -> no point of inflection.
2302       zd = PI;
2303       prj->global = 1;
2304     } else {
2305       // Find where the derivative is zero.
2306       for (j = 1; j <= 10; j++) {
2307         zd = zd1 - d1*(zd2-zd1)/(d2-d1);
2308 
2309         d = 0.0;
2310         for (m = k; m > 0; m--) {
2311           d = d*zd + m*prj->pv[m];
2312         }
2313 
2314         if (fabs(d) < tol) break;
2315 
2316         if (d < 0.0) {
2317           zd2 = zd;
2318           d2  = d;
2319         } else {
2320           zd1 = zd;
2321           d1  = d;
2322         }
2323       }
2324     }
2325 
2326     r = 0.0;
2327     for (m = k; m >= 0; m--) {
2328       r = r*zd + prj->pv[m];
2329     }
2330     prj->w[0] = zd;
2331     prj->w[1] = r;
2332   }
2333 
2334   prj->prjx2s = zpnx2s;
2335   prj->prjs2x = zpns2x;
2336 
2337   return prjoff(prj, 0.0, 90.0);
2338 }
2339 
2340 //----------------------------------------------------------------------------
2341 
zpnx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])2342 int zpnx2s(
2343   struct prjprm *prj,
2344   int nx,
2345   int ny,
2346   int sxy,
2347   int spt,
2348   const double x[],
2349   const double y[],
2350   double phi[],
2351   double theta[],
2352   int stat[])
2353 
2354 {
2355   int j, k, m, mx, my, rowlen, rowoff, status;
2356   double a, b, c, d, lambda, r, r1, r2, rt, xj, yj, yj2, zd, zd1, zd2;
2357   const double tol = 1.0e-13;
2358   register int ix, iy, *statp;
2359   register const double *xp, *yp;
2360   register double *phip, *thetap;
2361 
2362 
2363   // Initialize.
2364   if (prj == 0x0) return PRJERR_NULL_POINTER;
2365   if (prj->flag != ZPN) {
2366     if ((status = zpnset(prj))) return status;
2367   }
2368 
2369   k = prj->n;
2370 
2371   if (ny > 0) {
2372     mx = nx;
2373     my = ny;
2374   } else {
2375     mx = 1;
2376     my = 1;
2377     ny = nx;
2378   }
2379 
2380   status = 0;
2381 
2382 
2383   // Do x dependence.
2384   xp = x;
2385   rowoff = 0;
2386   rowlen = nx*spt;
2387   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
2388     xj = *xp + prj->x0;
2389 
2390     phip = phi + rowoff;
2391     for (iy = 0; iy < my; iy++) {
2392       *phip = xj;
2393       phip += rowlen;
2394     }
2395   }
2396 
2397 
2398   // Do y dependence.
2399   yp = y;
2400   phip   = phi;
2401   thetap = theta;
2402   statp  = stat;
2403   for (iy = 0; iy < ny; iy++, yp += sxy) {
2404     yj  = *yp + prj->y0;
2405     yj2 = yj*yj;
2406 
2407     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
2408       xj = *phip;
2409 
2410       r = sqrt(xj*xj + yj2)/prj->r0;
2411       if (r == 0.0) {
2412         *phip = 0.0;
2413       } else {
2414         *phip = atan2d(xj, -yj);
2415       }
2416 
2417       if (k < 1) {
2418         // Constant - no solution.
2419         return PRJERR_BAD_PARAM_SET("zpnx2s");
2420 
2421       } else if (k == 1) {
2422         // Linear.
2423         zd = (r - prj->pv[0])/prj->pv[1];
2424 
2425       } else if (k == 2) {
2426         // Quadratic.
2427         a = prj->pv[2];
2428         b = prj->pv[1];
2429         c = prj->pv[0] - r;
2430 
2431         d = b*b - 4.0*a*c;
2432         if (d < 0.0) {
2433           *thetap = 0.0;
2434           *(statp++) = 1;
2435           if (!status) status = PRJERR_BAD_PIX_SET("zpnx2s");
2436           continue;
2437         }
2438         d = sqrt(d);
2439 
2440         // Choose solution closest to pole.
2441         zd1 = (-b + d)/(2.0*a);
2442         zd2 = (-b - d)/(2.0*a);
2443         zd  = (zd1<zd2) ? zd1 : zd2;
2444         if (zd < -tol) zd = (zd1>zd2) ? zd1 : zd2;
2445         if (zd < 0.0) {
2446           if (zd < -tol) {
2447             *thetap = 0.0;
2448             *(statp++) = 1;
2449             if (!status) status = PRJERR_BAD_PIX_SET("zpnx2s");
2450             continue;
2451           }
2452           zd = 0.0;
2453         } else if (zd > PI) {
2454           if (zd > PI+tol) {
2455             *thetap = 0.0;
2456             *(statp++) = 1;
2457             if (!status) status = PRJERR_BAD_PIX_SET("zpnx2s");
2458             continue;
2459           }
2460           zd = PI;
2461         }
2462       } else {
2463         // Higher order - solve iteratively.
2464         zd1 = 0.0;
2465         r1  = prj->pv[0];
2466         zd2 = prj->w[0];
2467         r2  = prj->w[1];
2468 
2469         if (r < r1) {
2470           if (r < r1-tol) {
2471             *thetap = 0.0;
2472             *(statp++) = 1;
2473             if (!status) status = PRJERR_BAD_PIX_SET("zpnx2s");
2474             continue;
2475           }
2476           zd = zd1;
2477         } else if (r > r2) {
2478           if (r > r2+tol) {
2479             *thetap = 0.0;
2480             *(statp++) = 1;
2481             if (!status) status = PRJERR_BAD_PIX_SET("zpnx2s");
2482             continue;
2483           }
2484           zd = zd2;
2485         } else {
2486           // Dissect the interval.
2487           for (j = 0; j < 100; j++) {
2488             lambda = (r2 - r)/(r2 - r1);
2489             if (lambda < 0.1) {
2490               lambda = 0.1;
2491             } else if (lambda > 0.9) {
2492               lambda = 0.9;
2493             }
2494 
2495             zd = zd2 - lambda*(zd2 - zd1);
2496 
2497             rt = 0.0;
2498             for (m = k; m >= 0; m--) {
2499               rt = (rt * zd) + prj->pv[m];
2500             }
2501 
2502             if (rt < r) {
2503               if (r-rt < tol) break;
2504               r1 = rt;
2505               zd1 = zd;
2506             } else {
2507               if (rt-r < tol) break;
2508               r2 = rt;
2509               zd2 = zd;
2510             }
2511 
2512             if (fabs(zd2-zd1) < tol) break;
2513           }
2514         }
2515       }
2516 
2517       *thetap = 90.0 - zd*R2D;
2518       *(statp++) = 0;
2519     }
2520   }
2521 
2522 
2523   // Do bounds checking on the native coordinates.
2524   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
2525     if (!status) status = PRJERR_BAD_PIX_SET("zpnx2s");
2526   }
2527 
2528   return status;
2529 }
2530 
2531 //----------------------------------------------------------------------------
2532 
zpns2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])2533 int zpns2x(
2534   struct prjprm *prj,
2535   int nphi,
2536   int ntheta,
2537   int spt,
2538   int sxy,
2539   const double phi[],
2540   const double theta[],
2541   double x[],
2542   double y[],
2543   int stat[])
2544 
2545 {
2546   int m, mphi, mtheta, rowlen, rowoff, status;
2547   double cosphi, r, s, sinphi;
2548   register int iphi, itheta, istat, *statp;
2549   register const double *phip, *thetap;
2550   register double *xp, *yp;
2551 
2552 
2553   // Initialize.
2554   if (prj == 0x0) return PRJERR_NULL_POINTER;
2555   if (prj->flag != ZPN) {
2556     if ((status = zpnset(prj))) return status;
2557   }
2558 
2559   if (ntheta > 0) {
2560     mphi   = nphi;
2561     mtheta = ntheta;
2562   } else {
2563     mphi   = 1;
2564     mtheta = 1;
2565     ntheta = nphi;
2566   }
2567 
2568   status = 0;
2569 
2570 
2571   // Do phi dependence.
2572   phip = phi;
2573   rowoff = 0;
2574   rowlen = nphi*sxy;
2575   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
2576     sincosd(*phip, &sinphi, &cosphi);
2577 
2578     xp = x + rowoff;
2579     yp = y + rowoff;
2580     for (itheta = 0; itheta < mtheta; itheta++) {
2581       *xp = sinphi;
2582       *yp = cosphi;
2583       xp += rowlen;
2584       yp += rowlen;
2585     }
2586   }
2587 
2588 
2589   // Do theta dependence.
2590   thetap = theta;
2591   xp = x;
2592   yp = y;
2593   statp = stat;
2594   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
2595     s = (90.0 - *thetap)*D2R;
2596 
2597     r = 0.0;
2598     for (m = prj->n; m >= 0; m--) {
2599       r = r*s + prj->pv[m];
2600     }
2601     r *= prj->r0;
2602 
2603     // Bounds checking.
2604     istat = 0;
2605     if (prj->bounds&1) {
2606       if (s > prj->w[0]) {
2607         istat = 1;
2608         if (!status) status = PRJERR_BAD_WORLD_SET("zpns2x");
2609       }
2610     }
2611 
2612     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
2613       *xp =  r*(*xp) - prj->x0;
2614       *yp = -r*(*yp) - prj->y0;
2615       *(statp++) = istat;
2616     }
2617   }
2618 
2619   return status;
2620 }
2621 
2622 /*============================================================================
2623 *   ZEA: zenithal/azimuthal equal area projection.
2624 *
2625 *   Given and/or returned:
2626 *      prj->r0      Reset to 180/pi if 0.
2627 *      prj->phi0    Reset to  0.0 if undefined.
2628 *      prj->theta0  Reset to 90.0 if undefined.
2629 *
2630 *   Returned:
2631 *      prj->flag     ZEA
2632 *      prj->code    "ZEA"
2633 *      prj->x0      Fiducial offset in x.
2634 *      prj->y0      Fiducial offset in y.
2635 *      prj->w[0]    2*r0
2636 *      prj->w[1]    1/(2*r0)
2637 *      prj->prjx2s  Pointer to zeax2s().
2638 *      prj->prjs2x  Pointer to zeas2x().
2639 *===========================================================================*/
2640 
zeaset(struct prjprm * prj)2641 int zeaset(struct prjprm *prj)
2642 
2643 {
2644   if (prj == 0x0) return PRJERR_NULL_POINTER;
2645 
2646   prj->flag = ZEA;
2647   strcpy(prj->code, "ZEA");
2648 
2649   strcpy(prj->name, "zenithal/azimuthal equal area");
2650   prj->category  = ZENITHAL;
2651   prj->pvrange   = 0;
2652   prj->simplezen = 1;
2653   prj->equiareal = 1;
2654   prj->conformal = 0;
2655   prj->global    = 1;
2656   prj->divergent = 0;
2657 
2658   if (prj->r0 == 0.0) {
2659     prj->r0 = R2D;
2660     prj->w[0] = 360.0/PI;
2661     prj->w[1] = PI/360.0;
2662   } else {
2663     prj->w[0] = 2.0*prj->r0;
2664     prj->w[1] = 1.0/prj->w[0];
2665   }
2666 
2667   prj->prjx2s = zeax2s;
2668   prj->prjs2x = zeas2x;
2669 
2670   return prjoff(prj, 0.0, 90.0);
2671 }
2672 
2673 //----------------------------------------------------------------------------
2674 
zeax2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])2675 int zeax2s(
2676   struct prjprm *prj,
2677   int nx,
2678   int ny,
2679   int sxy,
2680   int spt,
2681   const double x[],
2682   const double y[],
2683   double phi[],
2684   double theta[],
2685   int stat[])
2686 
2687 {
2688   int mx, my, rowlen, rowoff, status;
2689   double r, s, xj, yj, yj2;
2690   const double tol = 1.0e-12;
2691   register int ix, iy, *statp;
2692   register const double *xp, *yp;
2693   register double *phip, *thetap;
2694 
2695 
2696   // Initialize.
2697   if (prj == 0x0) return PRJERR_NULL_POINTER;
2698   if (prj->flag != ZEA) {
2699     if ((status = zeaset(prj))) return status;
2700   }
2701 
2702   if (ny > 0) {
2703     mx = nx;
2704     my = ny;
2705   } else {
2706     mx = 1;
2707     my = 1;
2708     ny = nx;
2709   }
2710 
2711   status = 0;
2712 
2713 
2714   // Do x dependence.
2715   xp = x;
2716   rowoff = 0;
2717   rowlen = nx*spt;
2718   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
2719     xj = *xp + prj->x0;
2720 
2721     phip = phi + rowoff;
2722     for (iy = 0; iy < my; iy++) {
2723       *phip = xj;
2724       phip += rowlen;
2725     }
2726   }
2727 
2728 
2729   // Do y dependence.
2730   yp = y;
2731   phip   = phi;
2732   thetap = theta;
2733   statp  = stat;
2734   for (iy = 0; iy < ny; iy++, yp += sxy) {
2735     yj  = *yp + prj->y0;
2736     yj2 = yj*yj;
2737 
2738     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
2739       xj  = *phip;
2740 
2741       r = sqrt(xj*xj + yj2);
2742       if (r == 0.0) {
2743         *phip = 0.0;
2744       } else {
2745         *phip = atan2d(xj, -yj);
2746       }
2747 
2748       s = r*prj->w[1];
2749       if (fabs(s) > 1.0) {
2750         if (fabs(r - prj->w[0]) < tol) {
2751           *thetap = -90.0;
2752         } else {
2753           *thetap = 0.0;
2754           *(statp++) = 1;
2755           if (!status) status = PRJERR_BAD_PIX_SET("zeax2s");
2756           continue;
2757         }
2758       } else {
2759         *thetap = 90.0 - 2.0*asind(s);
2760       }
2761 
2762       *(statp++) = 0;
2763     }
2764   }
2765 
2766 
2767   // Do bounds checking on the native coordinates.
2768   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
2769     if (!status) status = PRJERR_BAD_PIX_SET("zeax2s");
2770   }
2771 
2772   return status;
2773 }
2774 
2775 //----------------------------------------------------------------------------
2776 
zeas2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])2777 int zeas2x(
2778   struct prjprm *prj,
2779   int nphi,
2780   int ntheta,
2781   int spt,
2782   int sxy,
2783   const double phi[],
2784   const double theta[],
2785   double x[],
2786   double y[],
2787   int stat[])
2788 
2789 {
2790   int mphi, mtheta, rowlen, rowoff, status;
2791   double cosphi, r, sinphi;
2792   register int iphi, itheta, *statp;
2793   register const double *phip, *thetap;
2794   register double *xp, *yp;
2795 
2796 
2797   // Initialize.
2798   if (prj == 0x0) return PRJERR_NULL_POINTER;
2799   if (prj->flag != ZEA) {
2800     if ((status = zeaset(prj))) return status;
2801   }
2802 
2803   if (ntheta > 0) {
2804     mphi   = nphi;
2805     mtheta = ntheta;
2806   } else {
2807     mphi   = 1;
2808     mtheta = 1;
2809     ntheta = nphi;
2810   }
2811 
2812 
2813   // Do phi dependence.
2814   phip = phi;
2815   rowoff = 0;
2816   rowlen = nphi*sxy;
2817   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
2818     sincosd(*phip, &sinphi, &cosphi);
2819 
2820     xp = x + rowoff;
2821     yp = y + rowoff;
2822     for (itheta = 0; itheta < mtheta; itheta++) {
2823       *xp = sinphi;
2824       *yp = cosphi;
2825       xp += rowlen;
2826       yp += rowlen;
2827     }
2828   }
2829 
2830 
2831   // Do theta dependence.
2832   thetap = theta;
2833   xp = x;
2834   yp = y;
2835   statp = stat;
2836   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
2837     r =  prj->w[0]*sind((90.0 - *thetap)/2.0);
2838 
2839     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
2840       *xp =  r*(*xp) - prj->x0;
2841       *yp = -r*(*yp) - prj->y0;
2842       *(statp++) = 0;
2843     }
2844   }
2845 
2846   return 0;
2847 }
2848 
2849 /*============================================================================
2850 *   AIR: Airy's projection.
2851 *
2852 *   Given:
2853 *      prj->pv[1]   Latitude theta_b within which the error is minimized, in
2854 *                   degrees.
2855 *
2856 *   Given and/or returned:
2857 *      prj->r0      Reset to 180/pi if 0.
2858 *      prj->phi0    Reset to  0.0 if undefined.
2859 *      prj->theta0  Reset to 90.0 if undefined.
2860 *
2861 *   Returned:
2862 *      prj->flag     AIR
2863 *      prj->code    "AIR"
2864 *      prj->x0      Fiducial offset in x.
2865 *      prj->y0      Fiducial offset in y.
2866 *      prj->w[0]    2*r0
2867 *      prj->w[1]    ln(cos(xi_b))/tan(xi_b)**2, where xi_b = (90-theta_b)/2
2868 *      prj->w[2]    1/2 - prj->w[1]
2869 *      prj->w[3]    2*r0*prj->w[2]
2870 *      prj->w[4]    tol, cutoff for using small angle approximation, in
2871 *                   radians.
2872 *      prj->w[5]    prj->w[2]*tol
2873 *      prj->w[6]    (180/pi)/prj->w[2]
2874 *      prj->prjx2s  Pointer to airx2s().
2875 *      prj->prjs2x  Pointer to airs2x().
2876 *===========================================================================*/
2877 
airset(struct prjprm * prj)2878 int airset(struct prjprm *prj)
2879 
2880 {
2881   const double tol = 1.0e-4;
2882   double cosxi;
2883 
2884   if (prj == 0x0) return PRJERR_NULL_POINTER;
2885 
2886   prj->flag = AIR;
2887   strcpy(prj->code, "AIR");
2888 
2889   if (undefined(prj->pv[1])) prj->pv[1] = 90.0;
2890   if (prj->r0 == 0.0) prj->r0 = R2D;
2891 
2892   strcpy(prj->name, "Airy's zenithal");
2893   prj->category  = ZENITHAL;
2894   prj->pvrange   = 101;
2895   prj->simplezen = 1;
2896   prj->equiareal = 0;
2897   prj->conformal = 0;
2898   prj->global    = 0;
2899   prj->divergent = 1;
2900 
2901   prj->w[0] = 2.0*prj->r0;
2902   if (prj->pv[1] == 90.0) {
2903     prj->w[1] = -0.5;
2904     prj->w[2] =  1.0;
2905   } else if (prj->pv[1] > -90.0) {
2906     cosxi = cosd((90.0 - prj->pv[1])/2.0);
2907     prj->w[1] = log(cosxi)*(cosxi*cosxi)/(1.0-cosxi*cosxi);
2908     prj->w[2] = 0.5 - prj->w[1];
2909   } else {
2910     return PRJERR_BAD_PARAM_SET("airset");
2911   }
2912 
2913   prj->w[3] = prj->w[0] * prj->w[2];
2914   prj->w[4] = tol;
2915   prj->w[5] = prj->w[2]*tol;
2916   prj->w[6] = R2D/prj->w[2];
2917 
2918   prj->prjx2s = airx2s;
2919   prj->prjs2x = airs2x;
2920 
2921   return prjoff(prj, 0.0, 90.0);
2922 }
2923 
2924 //----------------------------------------------------------------------------
2925 
airx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])2926 int airx2s(
2927   struct prjprm *prj,
2928   int nx,
2929   int ny,
2930   int sxy,
2931   int spt,
2932   const double x[],
2933   const double y[],
2934   double phi[],
2935   double theta[],
2936   int stat[])
2937 
2938 {
2939   int k, mx, my, rowlen, rowoff, status;
2940   double cosxi, lambda, r, r1, r2, rt, tanxi, x1, x2, xi, xj, yj, yj2;
2941   const double tol = 1.0e-12;
2942   register int ix, iy, *statp;
2943   register const double *xp, *yp;
2944   register double *phip, *thetap;
2945 
2946 
2947   // Initialize.
2948   if (prj == 0x0) return PRJERR_NULL_POINTER;
2949   if (prj->flag != AIR) {
2950     if ((status = airset(prj))) return status;
2951   }
2952 
2953   if (ny > 0) {
2954     mx = nx;
2955     my = ny;
2956   } else {
2957     mx = 1;
2958     my = 1;
2959     ny = nx;
2960   }
2961 
2962   status = 0;
2963 
2964 
2965   // Do x dependence.
2966   xp = x;
2967   rowoff = 0;
2968   rowlen = nx*spt;
2969   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
2970     xj = *xp + prj->x0;
2971 
2972     phip = phi + rowoff;
2973     for (iy = 0; iy < my; iy++) {
2974       *phip = xj;
2975       phip += rowlen;
2976     }
2977   }
2978 
2979 
2980   // Do y dependence.
2981   yp = y;
2982   phip   = phi;
2983   thetap = theta;
2984   statp  = stat;
2985   for (iy = 0; iy < ny; iy++, yp += sxy) {
2986     yj  = *yp + prj->y0;
2987     yj2 = yj*yj;
2988 
2989     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
2990       xj = *phip;
2991 
2992       r = sqrt(xj*xj + yj2)/prj->w[0];
2993       if (r == 0.0) {
2994         *phip = 0.0;
2995       } else {
2996         *phip = atan2d(xj, -yj);
2997       }
2998 
2999 
3000       if (r == 0.0) {
3001         xi = 0.0;
3002       } else if (r < prj->w[5]) {
3003         xi = r*prj->w[6];
3004       } else {
3005         // Find a solution interval.
3006         x1 = x2 = 1.0;
3007         r1 = r2 = 0.0;
3008         for (k = 0; k < 30; k++) {
3009           x2 = x1/2.0;
3010           tanxi = sqrt(1.0-x2*x2)/x2;
3011           r2 = -(log(x2)/tanxi + prj->w[1]*tanxi);
3012 
3013           if (r2 >= r) break;
3014           x1 = x2;
3015           r1 = r2;
3016         }
3017         if (k == 30) {
3018           *thetap = 0.0;
3019           *(statp++) = 1;
3020           if (!status) status = PRJERR_BAD_PIX_SET("airx2s");
3021           continue;
3022         }
3023 
3024         for (k = 0; k < 100; k++) {
3025           // Weighted division of the interval.
3026           lambda = (r2-r)/(r2-r1);
3027           if (lambda < 0.1) {
3028             lambda = 0.1;
3029           } else if (lambda > 0.9) {
3030             lambda = 0.9;
3031           }
3032           cosxi = x2 - lambda*(x2-x1);
3033 
3034           tanxi = sqrt(1.0-cosxi*cosxi)/cosxi;
3035           rt = -(log(cosxi)/tanxi + prj->w[1]*tanxi);
3036 
3037           if (rt < r) {
3038             if (r-rt < tol) break;
3039             r1 = rt;
3040             x1 = cosxi;
3041           } else {
3042             if (rt-r < tol) break;
3043             r2 = rt;
3044             x2 = cosxi;
3045           }
3046         }
3047         if (k == 100) {
3048           *thetap = 0.0;
3049           *(statp++) = 1;
3050           if (!status) status = PRJERR_BAD_PIX_SET("airx2s");
3051           continue;
3052         }
3053 
3054         xi = acosd(cosxi);
3055       }
3056 
3057       *thetap = 90.0 - 2.0*xi;
3058       *(statp++) = 0;
3059     }
3060   }
3061 
3062 
3063   // Do bounds checking on the native coordinates.
3064   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
3065     if (!status) status = PRJERR_BAD_PIX_SET("airx2s");
3066   }
3067 
3068   return status;
3069 }
3070 
3071 //----------------------------------------------------------------------------
3072 
airs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])3073 int airs2x(
3074   struct prjprm *prj,
3075   int nphi,
3076   int ntheta,
3077   int spt,
3078   int sxy,
3079   const double phi[],
3080   const double theta[],
3081   double x[],
3082   double y[],
3083   int stat[])
3084 
3085 {
3086   int mphi, mtheta, rowlen, rowoff, status;
3087   double cosphi, cosxi, r, tanxi, xi, sinphi;
3088   register int iphi, itheta, istat, *statp;
3089   register const double *phip, *thetap;
3090   register double *xp, *yp;
3091 
3092 
3093   // Initialize.
3094   if (prj == 0x0) return PRJERR_NULL_POINTER;
3095   if (prj->flag != AIR) {
3096     if ((status = airset(prj))) return status;
3097   }
3098 
3099   if (ntheta > 0) {
3100     mphi   = nphi;
3101     mtheta = ntheta;
3102   } else {
3103     mphi   = 1;
3104     mtheta = 1;
3105     ntheta = nphi;
3106   }
3107 
3108   status = 0;
3109 
3110 
3111   // Do phi dependence.
3112   phip = phi;
3113   rowoff = 0;
3114   rowlen = nphi*sxy;
3115   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
3116     sincosd(*phip, &sinphi, &cosphi);
3117 
3118     xp = x + rowoff;
3119     yp = y + rowoff;
3120     for (itheta = 0; itheta < mtheta; itheta++) {
3121       *xp = sinphi;
3122       *yp = cosphi;
3123       xp += rowlen;
3124       yp += rowlen;
3125     }
3126   }
3127 
3128 
3129   // Do theta dependence.
3130   thetap = theta;
3131   xp = x;
3132   yp = y;
3133   statp = stat;
3134   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
3135     istat = 0;
3136 
3137     if (*thetap == 90.0) {
3138       r = 0.0;
3139     } else if (*thetap > -90.0) {
3140       xi = D2R*(90.0 - *thetap)/2.0;
3141       if (xi < prj->w[4]) {
3142         r = xi*prj->w[3];
3143       } else {
3144         cosxi = cosd((90.0 - *thetap)/2.0);
3145         tanxi = sqrt(1.0 - cosxi*cosxi)/cosxi;
3146         r = -prj->w[0]*(log(cosxi)/tanxi + prj->w[1]*tanxi);
3147       }
3148     } else {
3149       r = 0.0;
3150       istat = 1;
3151       if (!status) status = PRJERR_BAD_WORLD_SET("airs2x");
3152     }
3153 
3154     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
3155       *xp =  r*(*xp) - prj->x0;
3156       *yp = -r*(*yp) - prj->y0;
3157       *(statp++) = istat;
3158     }
3159   }
3160 
3161   return status;
3162 }
3163 
3164 /*============================================================================
3165 *   CYP: cylindrical perspective projection.
3166 *
3167 *   Given:
3168 *      prj->pv[1]   Distance of point of projection from the centre of the
3169 *                   generating sphere, mu, in units of r0.
3170 *      prj->pv[2]   Radius of the cylinder of projection, lambda, in units of
3171 *                   r0.
3172 *
3173 *   Given and/or returned:
3174 *      prj->r0      Reset to 180/pi if 0.
3175 *      prj->phi0    Reset to 0.0 if undefined.
3176 *      prj->theta0  Reset to 0.0 if undefined.
3177 *
3178 *   Returned:
3179 *      prj->flag     CYP
3180 *      prj->code    "CYP"
3181 *      prj->x0      Fiducial offset in x.
3182 *      prj->y0      Fiducial offset in y.
3183 *      prj->w[0]    r0*lambda*(pi/180)
3184 *      prj->w[1]    (180/pi)/(r0*lambda)
3185 *      prj->w[2]    r0*(mu + lambda)
3186 *      prj->w[3]    1/(r0*(mu + lambda))
3187 *      prj->prjx2s  Pointer to cypx2s().
3188 *      prj->prjs2x  Pointer to cyps2x().
3189 *===========================================================================*/
3190 
cypset(struct prjprm * prj)3191 int cypset(struct prjprm *prj)
3192 
3193 {
3194   if (prj == 0x0) return PRJERR_NULL_POINTER;
3195 
3196   prj->flag = CYP;
3197   strcpy(prj->code, "CYP");
3198 
3199   if (undefined(prj->pv[1])) prj->pv[1] = 1.0;
3200   if (undefined(prj->pv[2])) prj->pv[2] = 1.0;
3201 
3202   strcpy(prj->name, "cylindrical perspective");
3203   prj->category  = CYLINDRICAL;
3204   prj->pvrange   = 102;
3205   prj->simplezen = 0;
3206   prj->equiareal = 0;
3207   prj->conformal = 0;
3208   prj->global    = prj->pv[1] < -1.0 || 0.0 < prj->pv[1];
3209   prj->divergent = !prj->global;
3210 
3211   if (prj->r0 == 0.0) {
3212     prj->r0 = R2D;
3213 
3214     prj->w[0] = prj->pv[2];
3215     if (prj->w[0] == 0.0) {
3216       return PRJERR_BAD_PARAM_SET("cypset");
3217     }
3218 
3219     prj->w[1] = 1.0/prj->w[0];
3220 
3221     prj->w[2] = R2D*(prj->pv[1] + prj->pv[2]);
3222     if (prj->w[2] == 0.0) {
3223       return PRJERR_BAD_PARAM_SET("cypset");
3224     }
3225 
3226     prj->w[3] = 1.0/prj->w[2];
3227   } else {
3228     prj->w[0] = prj->r0*prj->pv[2]*D2R;
3229     if (prj->w[0] == 0.0) {
3230       return PRJERR_BAD_PARAM_SET("cypset");
3231     }
3232 
3233     prj->w[1] = 1.0/prj->w[0];
3234 
3235     prj->w[2] = prj->r0*(prj->pv[1] + prj->pv[2]);
3236     if (prj->w[2] == 0.0) {
3237       return PRJERR_BAD_PARAM_SET("cypset");
3238     }
3239 
3240     prj->w[3] = 1.0/prj->w[2];
3241   }
3242 
3243   prj->prjx2s = cypx2s;
3244   prj->prjs2x = cyps2x;
3245 
3246   return prjoff(prj, 0.0, 0.0);
3247 }
3248 
3249 //----------------------------------------------------------------------------
3250 
cypx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])3251 int cypx2s(
3252   struct prjprm *prj,
3253   int nx,
3254   int ny,
3255   int sxy,
3256   int spt,
3257   const double x[],
3258   const double y[],
3259   double phi[],
3260   double theta[],
3261   int stat[])
3262 
3263 {
3264   int mx, my, rowlen, rowoff, status;
3265   double eta, s, t;
3266   register int ix, iy, *statp;
3267   register const double *xp, *yp;
3268   register double *phip, *thetap;
3269 
3270 
3271   // Initialize.
3272   if (prj == 0x0) return PRJERR_NULL_POINTER;
3273   if (prj->flag != CYP) {
3274     if ((status = cypset(prj))) return status;
3275   }
3276 
3277   if (ny > 0) {
3278     mx = nx;
3279     my = ny;
3280   } else {
3281     mx = 1;
3282     my = 1;
3283     ny = nx;
3284   }
3285 
3286   status = 0;
3287 
3288 
3289   // Do x dependence.
3290   xp = x;
3291   rowoff = 0;
3292   rowlen = nx*spt;
3293   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
3294     s = prj->w[1]*(*xp + prj->x0);
3295 
3296     phip = phi + rowoff;
3297     for (iy = 0; iy < my; iy++) {
3298       *phip = s;
3299       phip += rowlen;
3300     }
3301   }
3302 
3303 
3304   // Do y dependence.
3305   yp = y;
3306   thetap = theta;
3307   statp = stat;
3308   for (iy = 0; iy < ny; iy++, yp += sxy) {
3309     eta = prj->w[3]*(*yp + prj->y0);
3310     t = atan2d(eta,1.0) + asind(eta*prj->pv[1]/sqrt(eta*eta+1.0));
3311 
3312     for (ix = 0; ix < mx; ix++, thetap += spt) {
3313       *thetap = t;
3314       *(statp++) = 0;
3315     }
3316   }
3317 
3318 
3319   // Do bounds checking on the native coordinates.
3320   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
3321     if (!status) status = PRJERR_BAD_PIX_SET("cypx2s");
3322   }
3323 
3324   return status;
3325 }
3326 
3327 //----------------------------------------------------------------------------
3328 
cyps2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])3329 int cyps2x(
3330   struct prjprm *prj,
3331   int nphi,
3332   int ntheta,
3333   int spt,
3334   int sxy,
3335   const double phi[],
3336   const double theta[],
3337   double x[],
3338   double y[],
3339   int stat[])
3340 
3341 {
3342   int mphi, mtheta, rowlen, rowoff, status;
3343   double eta, xi;
3344   register int iphi, itheta, istat, *statp;
3345   register const double *phip, *thetap;
3346   register double *xp, *yp;
3347 
3348 
3349   // Initialize.
3350   if (prj == 0x0) return PRJERR_NULL_POINTER;
3351   if (prj->flag != CYP) {
3352     if ((status = cypset(prj))) return status;
3353   }
3354 
3355   if (ntheta > 0) {
3356     mphi   = nphi;
3357     mtheta = ntheta;
3358   } else {
3359     mphi   = 1;
3360     mtheta = 1;
3361     ntheta = nphi;
3362   }
3363 
3364   status = 0;
3365 
3366 
3367   // Do phi dependence.
3368   phip = phi;
3369   rowoff = 0;
3370   rowlen = nphi*sxy;
3371   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
3372     xi = prj->w[0]*(*phip) - prj->x0;
3373 
3374     xp = x + rowoff;
3375     for (itheta = 0; itheta < mtheta; itheta++) {
3376       *xp = xi;
3377       xp += rowlen;
3378     }
3379   }
3380 
3381 
3382   // Do theta dependence.
3383   thetap = theta;
3384   yp = y;
3385   statp = stat;
3386   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
3387     eta = prj->pv[1] + cosd(*thetap);
3388 
3389     istat = 0;
3390     if (eta == 0.0) {
3391       istat = 1;
3392       if (!status) status = PRJERR_BAD_WORLD_SET("cyps2x");
3393 
3394     } else {
3395       eta = prj->w[2]*sind(*thetap)/eta;
3396     }
3397 
3398     eta -= prj->y0;
3399     for (iphi = 0; iphi < mphi; iphi++, yp += sxy) {
3400       *yp = eta;
3401       *(statp++) = istat;
3402     }
3403   }
3404 
3405   return status;
3406 }
3407 
3408 /*============================================================================
3409 *   CEA: cylindrical equal area projection.
3410 *
3411 *   Given:
3412 *      prj->pv[1]   Square of the cosine of the latitude at which the
3413 *                   projection is conformal, lambda.
3414 *
3415 *   Given and/or returned:
3416 *      prj->r0      Reset to 180/pi if 0.
3417 *      prj->phi0    Reset to 0.0 if undefined.
3418 *      prj->theta0  Reset to 0.0 if undefined.
3419 *
3420 *   Returned:
3421 *      prj->flag     CEA
3422 *      prj->code    "CEA"
3423 *      prj->x0      Fiducial offset in x.
3424 *      prj->y0      Fiducial offset in y.
3425 *      prj->w[0]    r0*(pi/180)
3426 *      prj->w[1]    (180/pi)/r0
3427 *      prj->w[2]    r0/lambda
3428 *      prj->w[3]    lambda/r0
3429 *      prj->prjx2s  Pointer to ceax2s().
3430 *      prj->prjs2x  Pointer to ceas2x().
3431 *===========================================================================*/
3432 
ceaset(struct prjprm * prj)3433 int ceaset(struct prjprm *prj)
3434 
3435 {
3436   if (prj == 0x0) return PRJERR_NULL_POINTER;
3437 
3438   prj->flag = CEA;
3439   strcpy(prj->code, "CEA");
3440 
3441   if (undefined(prj->pv[1])) prj->pv[1] = 1.0;
3442 
3443   strcpy(prj->name, "cylindrical equal area");
3444   prj->category  = CYLINDRICAL;
3445   prj->pvrange   = 101;
3446   prj->simplezen = 0;
3447   prj->equiareal = 1;
3448   prj->conformal = 0;
3449   prj->global    = 1;
3450   prj->divergent = 0;
3451 
3452   if (prj->r0 == 0.0) {
3453     prj->r0 = R2D;
3454     prj->w[0] = 1.0;
3455     prj->w[1] = 1.0;
3456     if (prj->pv[1] <= 0.0 || prj->pv[1] > 1.0) {
3457       return PRJERR_BAD_PARAM_SET("ceaset");
3458     }
3459     prj->w[2] = prj->r0/prj->pv[1];
3460     prj->w[3] = prj->pv[1]/prj->r0;
3461   } else {
3462     prj->w[0] = prj->r0*D2R;
3463     prj->w[1] = R2D/prj->r0;
3464     if (prj->pv[1] <= 0.0 || prj->pv[1] > 1.0) {
3465       return PRJERR_BAD_PARAM_SET("ceaset");
3466     }
3467     prj->w[2] = prj->r0/prj->pv[1];
3468     prj->w[3] = prj->pv[1]/prj->r0;
3469   }
3470 
3471   prj->prjx2s = ceax2s;
3472   prj->prjs2x = ceas2x;
3473 
3474   return prjoff(prj, 0.0, 0.0);
3475 }
3476 
3477 //----------------------------------------------------------------------------
3478 
ceax2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])3479 int ceax2s(
3480   struct prjprm *prj,
3481   int nx,
3482   int ny,
3483   int sxy,
3484   int spt,
3485   const double x[],
3486   const double y[],
3487   double phi[],
3488   double theta[],
3489   int stat[])
3490 
3491 {
3492   int mx, my, rowlen, rowoff, status;
3493   double s;
3494   const double tol = 1.0e-13;
3495   register int istat, ix, iy, *statp;
3496   register const double *xp, *yp;
3497   register double *phip, *thetap;
3498 
3499 
3500   // Initialize.
3501   if (prj == 0x0) return PRJERR_NULL_POINTER;
3502   if (prj->flag != CEA) {
3503     if ((status = ceaset(prj))) return status;
3504   }
3505 
3506   if (ny > 0) {
3507     mx = nx;
3508     my = ny;
3509   } else {
3510     mx = 1;
3511     my = 1;
3512     ny = nx;
3513   }
3514 
3515   status = 0;
3516 
3517 
3518   // Do x dependence.
3519   xp = x;
3520   rowoff = 0;
3521   rowlen = nx*spt;
3522   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
3523     s = prj->w[1]*(*xp + prj->x0);
3524 
3525     phip = phi + rowoff;
3526     for (iy = 0; iy < my; iy++) {
3527       *phip = s;
3528       phip += rowlen;
3529     }
3530   }
3531 
3532 
3533   // Do y dependence.
3534   yp = y;
3535   thetap = theta;
3536   statp = stat;
3537   for (iy = 0; iy < ny; iy++, yp += sxy) {
3538     s = prj->w[3]*(*yp + prj->y0);
3539 
3540     istat = 0;
3541     if (fabs(s) > 1.0) {
3542       if (fabs(s) > 1.0+tol) {
3543         s = 0.0;
3544         istat = 1;
3545         if (!status) status = PRJERR_BAD_PIX_SET("ceax2s");
3546       } else {
3547         s = copysign(90.0, s);
3548       }
3549     } else {
3550       s = asind(s);
3551     }
3552 
3553     for (ix = 0; ix < mx; ix++, thetap += spt) {
3554       *thetap = s;
3555       *(statp++) = istat;
3556     }
3557   }
3558 
3559 
3560   // Do bounds checking on the native coordinates.
3561   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
3562     if (!status) status = PRJERR_BAD_PIX_SET("ceax2s");
3563   }
3564 
3565   return status;
3566 }
3567 
3568 //----------------------------------------------------------------------------
3569 
ceas2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])3570 int ceas2x(
3571   struct prjprm *prj,
3572   int nphi,
3573   int ntheta,
3574   int spt,
3575   int sxy,
3576   const double phi[],
3577   const double theta[],
3578   double x[],
3579   double y[],
3580   int stat[])
3581 
3582 {
3583   int mphi, mtheta, rowlen, rowoff, status;
3584   double eta, xi;
3585   register int iphi, itheta, *statp;
3586   register const double *phip, *thetap;
3587   register double *xp, *yp;
3588 
3589 
3590   // Initialize.
3591   if (prj == 0x0) return PRJERR_NULL_POINTER;
3592   if (prj->flag != CEA) {
3593     if ((status = ceaset(prj))) return status;
3594   }
3595 
3596   if (ntheta > 0) {
3597     mphi   = nphi;
3598     mtheta = ntheta;
3599   } else {
3600     mphi   = 1;
3601     mtheta = 1;
3602     ntheta = nphi;
3603   }
3604 
3605 
3606   // Do phi dependence.
3607   phip = phi;
3608   rowoff = 0;
3609   rowlen = nphi*sxy;
3610   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
3611     xi = prj->w[0]*(*phip) - prj->x0;
3612 
3613     xp = x + rowoff;
3614     for (itheta = 0; itheta < mtheta; itheta++) {
3615       *xp = xi;
3616       xp += rowlen;
3617     }
3618   }
3619 
3620 
3621   // Do theta dependence.
3622   thetap = theta;
3623   yp = y;
3624   statp = stat;
3625   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
3626     eta = prj->w[2]*sind(*thetap) - prj->y0;
3627 
3628     for (iphi = 0; iphi < mphi; iphi++, yp += sxy) {
3629       *yp = eta;
3630       *(statp++) = 0;
3631     }
3632   }
3633 
3634   return 0;
3635 }
3636 
3637 /*============================================================================
3638 *   CAR: Plate carree projection.
3639 *
3640 *   Given and/or returned:
3641 *      prj->r0      Reset to 180/pi if 0.
3642 *      prj->phi0    Reset to 0.0 if undefined.
3643 *      prj->theta0  Reset to 0.0 if undefined.
3644 *
3645 *   Returned:
3646 *      prj->flag     CAR
3647 *      prj->code    "CAR"
3648 *      prj->x0      Fiducial offset in x.
3649 *      prj->y0      Fiducial offset in y.
3650 *      prj->w[0]    r0*(pi/180)
3651 *      prj->w[1]    (180/pi)/r0
3652 *      prj->prjx2s  Pointer to carx2s().
3653 *      prj->prjs2x  Pointer to cars2x().
3654 *===========================================================================*/
3655 
carset(struct prjprm * prj)3656 int carset(struct prjprm *prj)
3657 
3658 {
3659   if (prj == 0x0) return PRJERR_NULL_POINTER;
3660 
3661   prj->flag = CAR;
3662   strcpy(prj->code, "CAR");
3663 
3664   strcpy(prj->name, "plate caree");
3665   prj->category  = CYLINDRICAL;
3666   prj->pvrange   = 0;
3667   prj->simplezen = 0;
3668   prj->equiareal = 0;
3669   prj->conformal = 0;
3670   prj->global    = 1;
3671   prj->divergent = 0;
3672 
3673   if (prj->r0 == 0.0) {
3674     prj->r0 = R2D;
3675     prj->w[0] = 1.0;
3676     prj->w[1] = 1.0;
3677   } else {
3678     prj->w[0] = prj->r0*D2R;
3679     prj->w[1] = 1.0/prj->w[0];
3680   }
3681 
3682   prj->prjx2s = carx2s;
3683   prj->prjs2x = cars2x;
3684 
3685   return prjoff(prj, 0.0, 0.0);
3686 }
3687 
3688 //----------------------------------------------------------------------------
3689 
carx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])3690 int carx2s(
3691   struct prjprm *prj,
3692   int nx,
3693   int ny,
3694   int sxy,
3695   int spt,
3696   const double x[],
3697   const double y[],
3698   double phi[],
3699   double theta[],
3700   int stat[])
3701 
3702 {
3703   int mx, my, rowlen, rowoff, status;
3704   double s, t;
3705   register int ix, iy, *statp;
3706   register const double *xp, *yp;
3707   register double *phip, *thetap;
3708 
3709 
3710   // Initialize.
3711   if (prj == 0x0) return PRJERR_NULL_POINTER;
3712   if (prj->flag != CAR) {
3713     if ((status = carset(prj))) return status;
3714   }
3715 
3716   if (ny > 0) {
3717     mx = nx;
3718     my = ny;
3719   } else {
3720     mx = 1;
3721     my = 1;
3722     ny = nx;
3723   }
3724 
3725   status = 0;
3726 
3727 
3728   // Do x dependence.
3729   xp = x;
3730   rowoff = 0;
3731   rowlen = nx*spt;
3732   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
3733     s = prj->w[1]*(*xp + prj->x0);
3734 
3735     phip = phi + rowoff;
3736     for (iy = 0; iy < my; iy++) {
3737       *phip = s;
3738       phip += rowlen;
3739     }
3740   }
3741 
3742 
3743   // Do y dependence.
3744   yp = y;
3745   thetap = theta;
3746   statp = stat;
3747   for (iy = 0; iy < ny; iy++, yp += sxy) {
3748     t = prj->w[1]*(*yp + prj->y0);
3749 
3750     for (ix = 0; ix < mx; ix++, thetap += spt) {
3751       *thetap = t;
3752       *(statp++) = 0;
3753     }
3754   }
3755 
3756 
3757   // Do bounds checking on the native coordinates.
3758   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
3759     if (!status) status = PRJERR_BAD_PIX_SET("carx2s");
3760   }
3761 
3762   return status;
3763 }
3764 
3765 //----------------------------------------------------------------------------
3766 
cars2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])3767 int cars2x(
3768   struct prjprm *prj,
3769   int nphi,
3770   int ntheta,
3771   int spt,
3772   int sxy,
3773   const double phi[],
3774   const double theta[],
3775   double x[],
3776   double y[],
3777   int stat[])
3778 
3779 {
3780   int mphi, mtheta, rowlen, rowoff, status;
3781   double eta, xi;
3782   register int iphi, itheta, *statp;
3783   register const double *phip, *thetap;
3784   register double *xp, *yp;
3785 
3786 
3787   // Initialize.
3788   if (prj == 0x0) return PRJERR_NULL_POINTER;
3789   if (prj->flag != CAR) {
3790     if ((status = carset(prj))) return status;
3791   }
3792 
3793   if (ntheta > 0) {
3794     mphi   = nphi;
3795     mtheta = ntheta;
3796   } else {
3797     mphi   = 1;
3798     mtheta = 1;
3799     ntheta = nphi;
3800   }
3801 
3802 
3803   // Do phi dependence.
3804   phip = phi;
3805   rowoff = 0;
3806   rowlen = nphi*sxy;
3807   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
3808     xi = prj->w[0]*(*phip) - prj->x0;
3809 
3810     xp = x + rowoff;
3811     for (itheta = 0; itheta < mtheta; itheta++) {
3812       *xp = xi;
3813       xp += rowlen;
3814     }
3815   }
3816 
3817 
3818   // Do theta dependence.
3819   thetap = theta;
3820   yp = y;
3821   statp = stat;
3822   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
3823     eta = prj->w[0]*(*thetap) - prj->y0;
3824 
3825     for (iphi = 0; iphi < mphi; iphi++, yp += sxy) {
3826       *yp = eta;
3827       *(statp++) = 0;
3828     }
3829   }
3830 
3831   return 0;
3832 }
3833 
3834 /*============================================================================
3835 *   MER: Mercator's projection.
3836 *
3837 *   Given and/or returned:
3838 *      prj->r0      Reset to 180/pi if 0.
3839 *      prj->phi0    Reset to 0.0 if undefined.
3840 *      prj->theta0  Reset to 0.0 if undefined.
3841 *
3842 *   Returned:
3843 *      prj->flag     MER
3844 *      prj->code    "MER"
3845 *      prj->x0      Fiducial offset in x.
3846 *      prj->y0      Fiducial offset in y.
3847 *      prj->w[0]    r0*(pi/180)
3848 *      prj->w[1]    (180/pi)/r0
3849 *      prj->prjx2s  Pointer to merx2s().
3850 *      prj->prjs2x  Pointer to mers2x().
3851 *===========================================================================*/
3852 
merset(struct prjprm * prj)3853 int merset(struct prjprm *prj)
3854 
3855 {
3856   if (prj == 0x0) return PRJERR_NULL_POINTER;
3857 
3858   prj->flag = MER;
3859   strcpy(prj->code, "MER");
3860 
3861   strcpy(prj->name, "Mercator's");
3862   prj->category  = CYLINDRICAL;
3863   prj->pvrange   = 0;
3864   prj->simplezen = 0;
3865   prj->equiareal = 0;
3866   prj->conformal = 1;
3867   prj->global    = 0;
3868   prj->divergent = 1;
3869 
3870   if (prj->r0 == 0.0) {
3871     prj->r0 = R2D;
3872     prj->w[0] = 1.0;
3873     prj->w[1] = 1.0;
3874   } else {
3875     prj->w[0] = prj->r0*D2R;
3876     prj->w[1] = 1.0/prj->w[0];
3877   }
3878 
3879   prj->prjx2s = merx2s;
3880   prj->prjs2x = mers2x;
3881 
3882   return prjoff(prj, 0.0, 0.0);
3883 }
3884 
3885 //----------------------------------------------------------------------------
3886 
merx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])3887 int merx2s(
3888   struct prjprm *prj,
3889   int nx,
3890   int ny,
3891   int sxy,
3892   int spt,
3893   const double x[],
3894   const double y[],
3895   double phi[],
3896   double theta[],
3897   int stat[])
3898 
3899 {
3900   int mx, my, rowlen, rowoff, status;
3901   double s, t;
3902   register int ix, iy, *statp;
3903   register const double *xp, *yp;
3904   register double *phip, *thetap;
3905 
3906 
3907   // Initialize.
3908   if (prj == 0x0) return PRJERR_NULL_POINTER;
3909   if (prj->flag != MER) {
3910     if ((status = merset(prj))) return status;
3911   }
3912 
3913   if (ny > 0) {
3914     mx = nx;
3915     my = ny;
3916   } else {
3917     mx = 1;
3918     my = 1;
3919     ny = nx;
3920   }
3921 
3922   status = 0;
3923 
3924 
3925   // Do x dependence.
3926   xp = x;
3927   rowoff = 0;
3928   rowlen = nx*spt;
3929   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
3930     s = prj->w[1]*(*xp + prj->x0);
3931 
3932     phip = phi + rowoff;
3933     for (iy = 0; iy < my; iy++) {
3934       *phip = s;
3935       phip += rowlen;
3936     }
3937   }
3938 
3939 
3940   // Do y dependence.
3941   yp = y;
3942   thetap = theta;
3943   statp  = stat;
3944   for (iy = 0; iy < ny; iy++, yp += sxy) {
3945     t = 2.0*atand(exp((*yp + prj->y0)/prj->r0)) - 90.0;
3946 
3947     for (ix = 0; ix < mx; ix++, thetap += spt) {
3948       *thetap = t;
3949       *(statp++) = 0;
3950     }
3951   }
3952 
3953 
3954   // Do bounds checking on the native coordinates.
3955   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
3956     if (!status) status = PRJERR_BAD_PIX_SET("merx2s");
3957   }
3958 
3959   return status;
3960 }
3961 
3962 //----------------------------------------------------------------------------
3963 
mers2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])3964 int mers2x(
3965   struct prjprm *prj,
3966   int nphi,
3967   int ntheta,
3968   int spt,
3969   int sxy,
3970   const double phi[],
3971   const double theta[],
3972   double x[],
3973   double y[],
3974   int stat[])
3975 
3976 {
3977   int mphi, mtheta, rowlen, rowoff, status;
3978   double eta, xi;
3979   register int iphi, itheta, istat, *statp;
3980   register const double *phip, *thetap;
3981   register double *xp, *yp;
3982 
3983 
3984   // Initialize.
3985   if (prj == 0x0) return PRJERR_NULL_POINTER;
3986   if (prj->flag != MER) {
3987     if ((status = merset(prj))) return status;
3988   }
3989 
3990   if (ntheta > 0) {
3991     mphi   = nphi;
3992     mtheta = ntheta;
3993   } else {
3994     mphi   = 1;
3995     mtheta = 1;
3996     ntheta = nphi;
3997   }
3998 
3999   status = 0;
4000 
4001 
4002   // Do phi dependence.
4003   phip = phi;
4004   rowoff = 0;
4005   rowlen = nphi*sxy;
4006   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
4007     xi  = prj->w[0]*(*phip) - prj->x0;
4008 
4009     xp = x + rowoff;
4010     for (itheta = 0; itheta < mtheta; itheta++) {
4011       *xp = xi;
4012       xp += rowlen;
4013     }
4014   }
4015 
4016 
4017   // Do theta dependence.
4018   thetap = theta;
4019   yp = y;
4020   statp = stat;
4021   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
4022     istat = 0;
4023 
4024     if (*thetap <= -90.0 || *thetap >= 90.0) {
4025       eta = 0.0;
4026       istat = 1;
4027       if (!status) status = PRJERR_BAD_WORLD_SET("mers2x");
4028     } else {
4029       eta = prj->r0*log(tand((*thetap+90.0)/2.0)) - prj->y0;
4030     }
4031 
4032     for (iphi = 0; iphi < mphi; iphi++, yp += sxy) {
4033       *yp = eta;
4034       *(statp++) = istat;
4035     }
4036   }
4037 
4038   return status;
4039 }
4040 
4041 /*============================================================================
4042 *   SFL: Sanson-Flamsteed ("global sinusoid") projection.
4043 *
4044 *   Given and/or returned:
4045 *      prj->r0      Reset to 180/pi if 0.
4046 *      prj->phi0    Reset to 0.0 if undefined.
4047 *      prj->theta0  Reset to 0.0 if undefined.
4048 *
4049 *   Returned:
4050 *      prj->flag     SFL
4051 *      prj->code    "SFL"
4052 *      prj->x0      Fiducial offset in x.
4053 *      prj->y0      Fiducial offset in y.
4054 *      prj->w[0]    r0*(pi/180)
4055 *      prj->w[1]    (180/pi)/r0
4056 *      prj->prjx2s  Pointer to sflx2s().
4057 *      prj->prjs2x  Pointer to sfls2x().
4058 *===========================================================================*/
4059 
sflset(struct prjprm * prj)4060 int sflset(struct prjprm *prj)
4061 
4062 {
4063   if (prj == 0x0) return PRJERR_NULL_POINTER;
4064 
4065   prj->flag = SFL;
4066   strcpy(prj->code, "SFL");
4067 
4068   strcpy(prj->name, "Sanson-Flamsteed");
4069   prj->category  = PSEUDOCYLINDRICAL;
4070   prj->pvrange   = 0;
4071   prj->simplezen = 0;
4072   prj->equiareal = 1;
4073   prj->conformal = 0;
4074   prj->global    = 1;
4075   prj->divergent = 0;
4076 
4077   if (prj->r0 == 0.0) {
4078     prj->r0 = R2D;
4079     prj->w[0] = 1.0;
4080     prj->w[1] = 1.0;
4081   } else {
4082     prj->w[0] = prj->r0*D2R;
4083     prj->w[1] = 1.0/prj->w[0];
4084   }
4085 
4086   prj->prjx2s = sflx2s;
4087   prj->prjs2x = sfls2x;
4088 
4089   return prjoff(prj, 0.0, 0.0);
4090 }
4091 
4092 //----------------------------------------------------------------------------
4093 
sflx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])4094 int sflx2s(
4095   struct prjprm *prj,
4096   int nx,
4097   int ny,
4098   int sxy,
4099   int spt,
4100   const double x[],
4101   const double y[],
4102   double phi[],
4103   double theta[],
4104   int stat[])
4105 
4106 {
4107   int mx, my, rowlen, rowoff, status;
4108   double s, t, yj;
4109   register int istat, ix, iy, *statp;
4110   register const double *xp, *yp;
4111   register double *phip, *thetap;
4112 
4113 
4114   // Initialize.
4115   if (prj == 0x0) return PRJERR_NULL_POINTER;
4116   if (prj->flag != SFL) {
4117     if ((status = sflset(prj))) return status;
4118   }
4119 
4120   if (ny > 0) {
4121     mx = nx;
4122     my = ny;
4123   } else {
4124     mx = 1;
4125     my = 1;
4126     ny = nx;
4127   }
4128 
4129   status = 0;
4130 
4131 
4132   // Do x dependence.
4133   xp = x;
4134   rowoff = 0;
4135   rowlen = nx*spt;
4136   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
4137     s = prj->w[1]*(*xp + prj->x0);
4138 
4139     phip = phi + rowoff;
4140     for (iy = 0; iy < my; iy++) {
4141       *phip = s;
4142       phip += rowlen;
4143     }
4144   }
4145 
4146 
4147   // Do y dependence.
4148   yp = y;
4149   phip   = phi;
4150   thetap = theta;
4151   statp  = stat;
4152   for (iy = 0; iy < ny; iy++, yp += sxy) {
4153     yj = *yp + prj->y0;
4154     s = cos(yj/prj->r0);
4155 
4156     istat = 0;
4157     if (s == 0.0) {
4158       istat = 1;
4159       if (!status) status = PRJERR_BAD_PIX_SET("sflx2s");
4160     } else {
4161       s = 1.0/s;
4162     }
4163 
4164     t = prj->w[1]*yj;
4165 
4166     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
4167       *phip  *= s;
4168       *thetap = t;
4169       *(statp++) = istat;
4170     }
4171   }
4172 
4173 
4174   // Do bounds checking on the native coordinates.
4175   if (prj->bounds&4 && prjbchk(1.0e-12, nx, my, spt, phi, theta, stat)) {
4176     if (!status) status = PRJERR_BAD_PIX_SET("sflx2s");
4177   }
4178 
4179   return status;
4180 }
4181 
4182 //----------------------------------------------------------------------------
4183 
sfls2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])4184 int sfls2x(
4185   struct prjprm *prj,
4186   int nphi,
4187   int ntheta,
4188   int spt,
4189   int sxy,
4190   const double phi[],
4191   const double theta[],
4192   double x[],
4193   double y[],
4194   int stat[])
4195 
4196 {
4197   int mphi, mtheta, rowlen, rowoff, status;
4198   double eta, xi;
4199   register int iphi, itheta, *statp;
4200   register const double *phip, *thetap;
4201   register double *xp, *yp;
4202 
4203 
4204   // Initialize.
4205   if (prj == 0x0) return PRJERR_NULL_POINTER;
4206   if (prj->flag != SFL) {
4207     if ((status = sflset(prj))) return status;
4208   }
4209 
4210   if (ntheta > 0) {
4211     mphi   = nphi;
4212     mtheta = ntheta;
4213   } else {
4214     mphi   = 1;
4215     mtheta = 1;
4216     ntheta = nphi;
4217   }
4218 
4219 
4220   // Do phi dependence.
4221   phip = phi;
4222   rowoff = 0;
4223   rowlen = nphi*sxy;
4224   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
4225     xi = prj->w[0]*(*phip);
4226 
4227     xp = x + rowoff;
4228     for (itheta = 0; itheta < mtheta; itheta++) {
4229       *xp = xi;
4230       xp += rowlen;
4231     }
4232   }
4233 
4234 
4235   // Do theta dependence.
4236   thetap = theta;
4237   xp = x;
4238   yp = y;
4239   statp = stat;
4240   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
4241     xi  = cosd(*thetap);
4242     eta = prj->w[0]*(*thetap) - prj->y0;
4243 
4244     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
4245       *xp = xi*(*xp) - prj->x0;
4246       *yp = eta;
4247       *(statp++) = 0;
4248     }
4249   }
4250 
4251   return 0;
4252 }
4253 
4254 /*============================================================================
4255 *   PAR: parabolic projection.
4256 *
4257 *   Given and/or returned:
4258 *      prj->r0      Reset to 180/pi if 0.
4259 *      prj->phi0    Reset to 0.0 if undefined.
4260 *      prj->theta0  Reset to 0.0 if undefined.
4261 *
4262 *   Returned:
4263 *      prj->flag     PAR
4264 *      prj->code    "PAR"
4265 *      prj->x0      Fiducial offset in x.
4266 *      prj->y0      Fiducial offset in y.
4267 *      prj->w[0]    r0*(pi/180)
4268 *      prj->w[1]    (180/pi)/r0
4269 *      prj->w[2]    pi*r0
4270 *      prj->w[3]    1/(pi*r0)
4271 *      prj->prjx2s  Pointer to parx2s().
4272 *      prj->prjs2x  Pointer to pars2x().
4273 *===========================================================================*/
4274 
parset(struct prjprm * prj)4275 int parset(struct prjprm *prj)
4276 
4277 {
4278   if (prj == 0x0) return PRJERR_NULL_POINTER;
4279 
4280   prj->flag = PAR;
4281   strcpy(prj->code, "PAR");
4282 
4283   strcpy(prj->name, "parabolic");
4284   prj->category  = PSEUDOCYLINDRICAL;
4285   prj->pvrange   = 0;
4286   prj->simplezen = 0;
4287   prj->equiareal = 1;
4288   prj->conformal = 0;
4289   prj->global    = 1;
4290   prj->divergent = 0;
4291 
4292   if (prj->r0 == 0.0) {
4293     prj->r0 = R2D;
4294     prj->w[0] = 1.0;
4295     prj->w[1] = 1.0;
4296     prj->w[2] = 180.0;
4297     prj->w[3] = 1.0/prj->w[2];
4298   } else {
4299     prj->w[0] = prj->r0*D2R;
4300     prj->w[1] = 1.0/prj->w[0];
4301     prj->w[2] = PI*prj->r0;
4302     prj->w[3] = 1.0/prj->w[2];
4303   }
4304 
4305   prj->prjx2s = parx2s;
4306   prj->prjs2x = pars2x;
4307 
4308   return prjoff(prj, 0.0, 0.0);
4309 }
4310 
4311 //----------------------------------------------------------------------------
4312 
parx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])4313 int parx2s(
4314   struct prjprm *prj,
4315   int nx,
4316   int ny,
4317   int sxy,
4318   int spt,
4319   const double x[],
4320   const double y[],
4321   double phi[],
4322   double theta[],
4323   int stat[])
4324 
4325 {
4326   int mx, my, rowlen, rowoff, status;
4327   double r, s, t, xj;
4328   const double tol = 1.0e-13;
4329   register int istat, ix, iy, *statp;
4330   register const double *xp, *yp;
4331   register double *phip, *thetap;
4332 
4333 
4334   // Initialize.
4335   if (prj == 0x0) return PRJERR_NULL_POINTER;
4336   if (prj->flag != PAR) {
4337     if ((status = parset(prj))) return status;
4338   }
4339 
4340   if (ny > 0) {
4341     mx = nx;
4342     my = ny;
4343   } else {
4344     mx = 1;
4345     my = 1;
4346     ny = nx;
4347   }
4348 
4349   status = 0;
4350 
4351 
4352   // Do x dependence.
4353   xp = x;
4354   rowoff = 0;
4355   rowlen = nx*spt;
4356   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
4357     xj = *xp + prj->x0;
4358     s = prj->w[1]*xj;
4359     t = fabs(xj) - tol;
4360 
4361     phip   = phi   + rowoff;
4362     thetap = theta + rowoff;
4363     for (iy = 0; iy < my; iy++) {
4364       *phip   = s;
4365       *thetap = t;
4366       phip   += rowlen;
4367       thetap += rowlen;
4368     }
4369   }
4370 
4371 
4372   // Do y dependence.
4373   yp = y;
4374   phip   = phi;
4375   thetap = theta;
4376   statp  = stat;
4377   for (iy = 0; iy < ny; iy++, yp += sxy) {
4378     r = prj->w[3]*(*yp + prj->y0);
4379 
4380     istat = 0;
4381     if (r > 1.0 || r < -1.0) {
4382       s = 0.0;
4383       t = 0.0;
4384       istat = 1;
4385       if (!status) status = PRJERR_BAD_PIX_SET("parx2s");
4386 
4387     } else {
4388       s = 1.0 - 4.0*r*r;
4389       if (s == 0.0) {
4390         // Deferred test.
4391         istat = -1;
4392       } else {
4393         s = 1.0/s;
4394       }
4395 
4396       t = 3.0*asind(r);
4397     }
4398 
4399     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
4400       if (istat < 0) {
4401         if (*thetap < 0.0) {
4402           *(statp++) = 0;
4403         } else {
4404           *(statp++) = 1;
4405           if (!status) status = PRJERR_BAD_PIX_SET("parx2s");
4406         }
4407       } else {
4408         *(statp++) = istat;
4409       }
4410 
4411       *phip  *= s;
4412       *thetap = t;
4413     }
4414   }
4415 
4416 
4417   // Do bounds checking on the native coordinates.
4418   if (prj->bounds&4 && prjbchk(1.0e-12, nx, my, spt, phi, theta, stat)) {
4419     if (!status) status = PRJERR_BAD_PIX_SET("parx2s");
4420   }
4421 
4422   return status;
4423 }
4424 
4425 //----------------------------------------------------------------------------
4426 
pars2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])4427 int pars2x(
4428   struct prjprm *prj,
4429   int nphi,
4430   int ntheta,
4431   int spt,
4432   int sxy,
4433   const double phi[],
4434   const double theta[],
4435   double x[],
4436   double y[],
4437   int stat[])
4438 
4439 {
4440   int mphi, mtheta, rowlen, rowoff, status;
4441   double eta, s, xi;
4442   register int iphi, itheta, *statp;
4443   register const double *phip, *thetap;
4444   register double *xp, *yp;
4445 
4446 
4447   // Initialize.
4448   if (prj == 0x0) return PRJERR_NULL_POINTER;
4449   if (prj->flag != PAR) {
4450     if ((status = parset(prj))) return status;
4451   }
4452 
4453   if (ntheta > 0) {
4454     mphi   = nphi;
4455     mtheta = ntheta;
4456   } else {
4457     mphi   = 1;
4458     mtheta = 1;
4459     ntheta = nphi;
4460   }
4461 
4462 
4463   // Do phi dependence.
4464   phip = phi;
4465   rowoff = 0;
4466   rowlen = nphi*sxy;
4467   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
4468     xi = prj->w[0]*(*phip);
4469 
4470     xp = x + rowoff;
4471     for (itheta = 0; itheta < mtheta; itheta++) {
4472       *xp = xi;
4473       xp += rowlen;
4474     }
4475   }
4476 
4477 
4478   // Do theta dependence.
4479   thetap = theta;
4480   xp = x;
4481   yp = y;
4482   statp = stat;
4483   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
4484     s = sind((*thetap)/3.0);
4485     xi = (1.0 - 4.0*s*s);
4486     eta = prj->w[2]*s - prj->y0;
4487 
4488     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
4489       *xp = xi*(*xp) - prj->x0;
4490       *yp = eta;
4491       *(statp++) = 0;
4492     }
4493   }
4494 
4495   return 0;
4496 }
4497 
4498 /*============================================================================
4499 *   MOL: Mollweide's projection.
4500 *
4501 *   Given and/or returned:
4502 *      prj->r0      Reset to 180/pi if 0.
4503 *      prj->phi0    Reset to 0.0 if undefined.
4504 *      prj->theta0  Reset to 0.0 if undefined.
4505 *
4506 *   Returned:
4507 *      prj->flag     MOL
4508 *      prj->code    "MOL"
4509 *      prj->x0      Fiducial offset in x.
4510 *      prj->y0      Fiducial offset in y.
4511 *      prj->w[0]    sqrt(2)*r0
4512 *      prj->w[1]    sqrt(2)*r0/90
4513 *      prj->w[2]    1/(sqrt(2)*r0)
4514 *      prj->w[3]    90/r0
4515 *      prj->prjx2s  Pointer to molx2s().
4516 *      prj->prjs2x  Pointer to mols2x().
4517 *===========================================================================*/
4518 
molset(struct prjprm * prj)4519 int molset(struct prjprm *prj)
4520 
4521 {
4522   if (prj == 0x0) return PRJERR_NULL_POINTER;
4523 
4524   prj->flag = MOL;
4525   strcpy(prj->code, "MOL");
4526 
4527   if (prj->r0 == 0.0) prj->r0 = R2D;
4528 
4529   strcpy(prj->name, "Mollweide's");
4530   prj->category  = PSEUDOCYLINDRICAL;
4531   prj->pvrange   = 0;
4532   prj->simplezen = 0;
4533   prj->equiareal = 1;
4534   prj->conformal = 0;
4535   prj->global    = 1;
4536   prj->divergent = 0;
4537 
4538   prj->w[0] = SQRT2*prj->r0;
4539   prj->w[1] = prj->w[0]/90.0;
4540   prj->w[2] = 1.0/prj->w[0];
4541   prj->w[3] = 90.0/prj->r0;
4542   prj->w[4] = 2.0/PI;
4543 
4544   prj->prjx2s = molx2s;
4545   prj->prjs2x = mols2x;
4546 
4547   return prjoff(prj, 0.0, 0.0);
4548 }
4549 
4550 //----------------------------------------------------------------------------
4551 
molx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])4552 int molx2s(
4553   struct prjprm *prj,
4554   int nx,
4555   int ny,
4556   int sxy,
4557   int spt,
4558   const double x[],
4559   const double y[],
4560   double phi[],
4561   double theta[],
4562   int stat[])
4563 
4564 {
4565   int mx, my, rowlen, rowoff, status;
4566   double r, s, t, xj, y0, yj, z;
4567   const double tol = 1.0e-12;
4568   register int istat, ix, iy, *statp;
4569   register const double *xp, *yp;
4570   register double *phip, *thetap;
4571 
4572 
4573   // Initialize.
4574   if (prj == 0x0) return PRJERR_NULL_POINTER;
4575   if (prj->flag != MOL) {
4576     if ((status = molset(prj))) return status;
4577   }
4578 
4579   if (ny > 0) {
4580     mx = nx;
4581     my = ny;
4582   } else {
4583     mx = 1;
4584     my = 1;
4585     ny = nx;
4586   }
4587 
4588   status = 0;
4589 
4590 
4591   // Do x dependence.
4592   xp = x;
4593   rowoff = 0;
4594   rowlen = nx*spt;
4595   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
4596     xj = *xp + prj->x0;
4597     s = prj->w[3]*xj;
4598     t = fabs(xj) - tol;
4599 
4600     phip   = phi   + rowoff;
4601     thetap = theta + rowoff;
4602     for (iy = 0; iy < my; iy++) {
4603       *phip   = s;
4604       *thetap = t;
4605       phip   += rowlen;
4606       thetap += rowlen;
4607     }
4608   }
4609 
4610 
4611   // Do y dependence.
4612   yp = y;
4613   phip   = phi;
4614   thetap = theta;
4615   statp  = stat;
4616   for (iy = 0; iy < ny; iy++, yp += sxy) {
4617     yj = *yp + prj->y0;
4618     y0 = yj/prj->r0;
4619     r  = 2.0 - y0*y0;
4620 
4621     istat = 0;
4622     if (r <= tol) {
4623       if (r < -tol) {
4624         istat = 1;
4625         if (!status) status = PRJERR_BAD_PIX_SET("molx2s");
4626       } else {
4627         // OK if fabs(x) < tol whence phi = 0.0.
4628         istat = -1;
4629       }
4630 
4631       r = 0.0;
4632       s = 0.0;
4633 
4634     } else {
4635       r = sqrt(r);
4636       s = 1.0/r;
4637     }
4638 
4639     z = yj*prj->w[2];
4640     if (fabs(z) > 1.0) {
4641       if (fabs(z) > 1.0+tol) {
4642         z = 0.0;
4643         istat = 1;
4644         if (!status) status = PRJERR_BAD_PIX_SET("molx2s");
4645       } else {
4646         z = copysign(1.0, z) + y0*r/PI;
4647       }
4648     } else {
4649       z = asin(z)*prj->w[4] + y0*r/PI;
4650     }
4651 
4652     if (fabs(z) > 1.0) {
4653       if (fabs(z) > 1.0+tol) {
4654         z = 0.0;
4655         istat = 1;
4656         if (!status) status = PRJERR_BAD_PIX_SET("molx2s");
4657       } else {
4658         z = copysign(1.0, z);
4659       }
4660     }
4661 
4662     t = asind(z);
4663 
4664     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
4665       if (istat < 0) {
4666         if (*thetap < 0.0) {
4667           *(statp++) = 0;
4668         } else {
4669           *(statp++) = 1;
4670           if (!status) status = PRJERR_BAD_PIX_SET("molx2s");
4671         }
4672       } else {
4673         *(statp++) = istat;
4674       }
4675 
4676       *phip  *= s;
4677       *thetap = t;
4678     }
4679   }
4680 
4681 
4682   // Do bounds checking on the native coordinates.
4683   if (prj->bounds&4 && prjbchk(1.0e-11, nx, my, spt, phi, theta, stat)) {
4684     if (!status) status = PRJERR_BAD_PIX_SET("molx2s");
4685   }
4686 
4687   return status;
4688 }
4689 
4690 //----------------------------------------------------------------------------
4691 
mols2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])4692 int mols2x(
4693   struct prjprm *prj,
4694   int nphi,
4695   int ntheta,
4696   int spt,
4697   int sxy,
4698   const double phi[],
4699   const double theta[],
4700   double x[],
4701   double y[],
4702   int stat[])
4703 
4704 {
4705   int k, mphi, mtheta, rowlen, rowoff, status;
4706   double eta, gamma, resid, u, v, v0, v1, xi;
4707   const double tol = 1.0e-13;
4708   register int iphi, itheta, *statp;
4709   register const double *phip, *thetap;
4710   register double *xp, *yp;
4711 
4712 
4713   // Initialize.
4714   if (prj == 0x0) return PRJERR_NULL_POINTER;
4715   if (prj->flag != MOL) {
4716     if ((status = molset(prj))) return status;
4717   }
4718 
4719   if (ntheta > 0) {
4720     mphi   = nphi;
4721     mtheta = ntheta;
4722   } else {
4723     mphi   = 1;
4724     mtheta = 1;
4725     ntheta = nphi;
4726   }
4727 
4728 
4729   // Do phi dependence.
4730   phip = phi;
4731   rowoff = 0;
4732   rowlen = nphi*sxy;
4733   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
4734     xi = prj->w[1]*(*phip);
4735 
4736     xp = x + rowoff;
4737     for (itheta = 0; itheta < mtheta; itheta++) {
4738       *xp = xi;
4739       xp += rowlen;
4740     }
4741   }
4742 
4743 
4744   // Do theta dependence.
4745   thetap = theta;
4746   xp = x;
4747   yp = y;
4748   statp = stat;
4749   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
4750     if (fabs(*thetap) == 90.0) {
4751       xi  = 0.0;
4752       eta = copysign(prj->w[0], *thetap);
4753 
4754     } else if (*thetap == 0.0) {
4755       xi  = 1.0;
4756       eta = 0.0;
4757 
4758     } else {
4759       u  = PI*sind(*thetap);
4760       v0 = -PI;
4761       v1 =  PI;
4762       v  = u;
4763       for (k = 0; k < 100; k++) {
4764         resid = (v - u) + sin(v);
4765         if (resid < 0.0) {
4766           if (resid > -tol) break;
4767           v0 = v;
4768         } else {
4769           if (resid < tol) break;
4770           v1 = v;
4771         }
4772         v = (v0 + v1)/2.0;
4773       }
4774 
4775       gamma = v/2.0;
4776       xi  = cos(gamma);
4777       eta = prj->w[0]*sin(gamma);
4778     }
4779 
4780     eta -= prj->y0;
4781     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
4782       *xp = xi*(*xp) - prj->x0;
4783       *yp = eta;
4784       *(statp++) = 0;
4785     }
4786   }
4787 
4788   return 0;
4789 }
4790 
4791 /*============================================================================
4792 *   AIT: Hammer-Aitoff projection.
4793 *
4794 *   Given and/or returned:
4795 *      prj->r0      Reset to 180/pi if 0.
4796 *      prj->phi0    Reset to 0.0 if undefined.
4797 *      prj->theta0  Reset to 0.0 if undefined.
4798 *
4799 *   Returned:
4800 *      prj->flag     AIT
4801 *      prj->code    "AIT"
4802 *      prj->x0      Fiducial offset in x.
4803 *      prj->y0      Fiducial offset in y.
4804 *      prj->w[0]    2*r0**2
4805 *      prj->w[1]    1/(2*r0)**2
4806 *      prj->w[2]    1/(4*r0)**2
4807 *      prj->w[3]    1/(2*r0)
4808 *      prj->prjx2s  Pointer to aitx2s().
4809 *      prj->prjs2x  Pointer to aits2x().
4810 *===========================================================================*/
4811 
aitset(struct prjprm * prj)4812 int aitset(struct prjprm *prj)
4813 
4814 {
4815   if (prj == 0x0) return PRJERR_NULL_POINTER;
4816 
4817   prj->flag = AIT;
4818   strcpy(prj->code, "AIT");
4819 
4820   if (prj->r0 == 0.0) prj->r0 = R2D;
4821 
4822   strcpy(prj->name, "Hammer-Aitoff");
4823   prj->category  = CONVENTIONAL;
4824   prj->pvrange   = 0;
4825   prj->simplezen = 0;
4826   prj->equiareal = 1;
4827   prj->conformal = 0;
4828   prj->global    = 1;
4829   prj->divergent = 0;
4830 
4831   prj->w[0] = 2.0*prj->r0*prj->r0;
4832   prj->w[1] = 1.0/(2.0*prj->w[0]);
4833   prj->w[2] = prj->w[1]/4.0;
4834   prj->w[3] = 1.0/(2.0*prj->r0);
4835 
4836   prj->prjx2s = aitx2s;
4837   prj->prjs2x = aits2x;
4838 
4839   return prjoff(prj, 0.0, 0.0);
4840 }
4841 
4842 //----------------------------------------------------------------------------
4843 
aitx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])4844 int aitx2s(
4845   struct prjprm *prj,
4846   int nx,
4847   int ny,
4848   int sxy,
4849   int spt,
4850   const double x[],
4851   const double y[],
4852   double phi[],
4853   double theta[],
4854   int stat[])
4855 
4856 {
4857   int mx, my, rowlen, rowoff, status;
4858   double s, t, x0, xj, y0, yj, yj2, z;
4859   const double tol = 1.0e-13;
4860   register int ix, iy, istat, *statp;
4861   register const double *xp, *yp;
4862   register double *phip, *thetap;
4863 
4864 
4865   // Initialize.
4866   if (prj == 0x0) return PRJERR_NULL_POINTER;
4867   if (prj->flag != AIT) {
4868     if ((status = aitset(prj))) return status;
4869   }
4870 
4871   if (ny > 0) {
4872     mx = nx;
4873     my = ny;
4874   } else {
4875     mx = 1;
4876     my = 1;
4877     ny = nx;
4878   }
4879 
4880   status = 0;
4881 
4882 
4883   // Do x dependence.
4884   xp = x;
4885   rowoff = 0;
4886   rowlen = nx*spt;
4887   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
4888     xj = *xp + prj->x0;
4889     s  = 1.0 - xj*xj*prj->w[2];
4890     t  = xj*prj->w[3];
4891 
4892     phip   = phi   + rowoff;
4893     thetap = theta + rowoff;
4894     for (iy = 0; iy < my; iy++) {
4895       *phip   = s;
4896       *thetap = t;
4897       phip   += rowlen;
4898       thetap += rowlen;
4899     }
4900   }
4901 
4902 
4903   // Do y dependence.
4904   yp = y;
4905   phip   = phi;
4906   thetap = theta;
4907   statp  = stat;
4908   for (iy = 0; iy < ny; iy++, yp += sxy) {
4909     yj  = *yp + prj->y0;
4910     yj2 = yj*yj*prj->w[1];
4911 
4912     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
4913       s = *phip - yj2;
4914 
4915       istat = 0;
4916       if (s < 0.5) {
4917         if (s < 0.5-tol) {
4918           istat = 1;
4919           if (!status) status = PRJERR_BAD_PIX_SET("aitx2s");
4920         }
4921 
4922         s = 0.5;
4923       }
4924 
4925       z = sqrt(s);
4926       x0 = 2.0*z*z - 1.0;
4927       y0 = z*(*thetap);
4928       if (x0 == 0.0 && y0 == 0.0) {
4929         *phip = 0.0;
4930       } else {
4931         *phip = 2.0*atan2d(y0, x0);
4932       }
4933 
4934       t = z*yj/prj->r0;
4935       if (fabs(t) > 1.0) {
4936         if (fabs(t) > 1.0+tol) {
4937           istat = 1;
4938           if (!status) status = PRJERR_BAD_PIX_SET("aitx2s");
4939         }
4940         t = copysign(90.0, t);
4941 
4942       } else {
4943         t = asind(t);
4944       }
4945 
4946       *thetap = t;
4947       *(statp++) = istat;
4948     }
4949   }
4950 
4951 
4952   // Do bounds checking on the native coordinates.
4953   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
4954     if (!status) status = PRJERR_BAD_PIX_SET("aitx2s");
4955   }
4956 
4957   return status;
4958 }
4959 
4960 //----------------------------------------------------------------------------
4961 
aits2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])4962 int aits2x(
4963   struct prjprm *prj,
4964   int nphi,
4965   int ntheta,
4966   int spt,
4967   int sxy,
4968   const double phi[],
4969   const double theta[],
4970   double x[],
4971   double y[],
4972   int stat[])
4973 
4974 {
4975   int mphi, mtheta, rowlen, rowoff, status;
4976   double cosphi, costhe, sinphi, sinthe, w;
4977   register int iphi, itheta, *statp;
4978   register const double *phip, *thetap;
4979   register double *xp, *yp;
4980 
4981 
4982   // Initialize.
4983   if (prj == 0x0) return PRJERR_NULL_POINTER;
4984   if (prj->flag != AIT) {
4985     if ((status = aitset(prj))) return status;
4986   }
4987 
4988   if (ntheta > 0) {
4989     mphi   = nphi;
4990     mtheta = ntheta;
4991   } else {
4992     mphi   = 1;
4993     mtheta = 1;
4994     ntheta = nphi;
4995   }
4996 
4997 
4998   // Do phi dependence.
4999   phip = phi;
5000   rowoff = 0;
5001   rowlen = nphi*sxy;
5002   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
5003     w = (*phip)/2.0;
5004     sincosd(w, &sinphi, &cosphi);
5005 
5006     xp = x + rowoff;
5007     yp = y + rowoff;
5008     for (itheta = 0; itheta < mtheta; itheta++) {
5009       *xp = sinphi;
5010       *yp = cosphi;
5011       xp += rowlen;
5012       yp += rowlen;
5013     }
5014   }
5015 
5016 
5017   // Do theta dependence.
5018   thetap = theta;
5019   xp = x;
5020   yp = y;
5021   statp = stat;
5022   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
5023     sincosd(*thetap, &sinthe, &costhe);
5024 
5025     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
5026       w = sqrt(prj->w[0]/(1.0 + costhe*(*yp)));
5027       *xp = 2.0*w*costhe*(*xp) - prj->x0;
5028       *yp = w*sinthe - prj->y0;
5029       *(statp++) = 0;
5030     }
5031   }
5032 
5033   return 0;
5034 }
5035 
5036 /*============================================================================
5037 *   COP: conic perspective projection.
5038 *
5039 *   Given:
5040 *      prj->pv[1]   sigma = (theta2+theta1)/2
5041 *      prj->pv[2]   delta = (theta2-theta1)/2, where theta1 and theta2 are the
5042 *                   latitudes of the standard parallels, in degrees.
5043 *
5044 *   Given and/or returned:
5045 *      prj->r0      Reset to 180/pi if 0.
5046 *      prj->phi0    Reset to sigma if undefined.
5047 *      prj->theta0  Reset to sigma if undefined.
5048 *
5049 *   Returned:
5050 *      prj->flag     COP
5051 *      prj->code    "COP"
5052 *      prj->x0      Fiducial offset in x.
5053 *      prj->y0      Fiducial offset in y.
5054 *      prj->w[0]    C  = sin(sigma)
5055 *      prj->w[1]    1/C
5056 *      prj->w[2]    Y0 = r0*cos(delta)*cot(sigma)
5057 *      prj->w[3]    r0*cos(delta)
5058 *      prj->w[4]    1/(r0*cos(delta)
5059 *      prj->w[5]    cot(sigma)
5060 *      prj->prjx2s  Pointer to copx2s().
5061 *      prj->prjs2x  Pointer to cops2x().
5062 *===========================================================================*/
5063 
copset(struct prjprm * prj)5064 int copset(struct prjprm *prj)
5065 
5066 {
5067   if (prj == 0x0) return PRJERR_NULL_POINTER;
5068 
5069   prj->flag = COP;
5070   strcpy(prj->code, "COP");
5071   strcpy(prj->name, "conic perspective");
5072 
5073   if (undefined(prj->pv[1])) {
5074     return PRJERR_BAD_PARAM_SET("copset");
5075   }
5076   if (undefined(prj->pv[2])) prj->pv[2] = 0.0;
5077   if (prj->r0 == 0.0) prj->r0 = R2D;
5078 
5079   prj->category  = CONIC;
5080   prj->pvrange   = 102;
5081   prj->simplezen = 0;
5082   prj->equiareal = 0;
5083   prj->conformal = 0;
5084   prj->global    = 0;
5085   prj->divergent = 1;
5086 
5087   prj->w[0] = sind(prj->pv[1]);
5088   if (prj->w[0] == 0.0) {
5089     return PRJERR_BAD_PARAM_SET("copset");
5090   }
5091 
5092   prj->w[1] = 1.0/prj->w[0];
5093 
5094   prj->w[3] = prj->r0*cosd(prj->pv[2]);
5095   if (prj->w[3] == 0.0) {
5096     return PRJERR_BAD_PARAM_SET("copset");
5097   }
5098 
5099   prj->w[4] = 1.0/prj->w[3];
5100   prj->w[5] = 1.0/tand(prj->pv[1]);
5101 
5102   prj->w[2] = prj->w[3]*prj->w[5];
5103 
5104   prj->prjx2s = copx2s;
5105   prj->prjs2x = cops2x;
5106 
5107   return prjoff(prj, 0.0, prj->pv[1]);
5108 }
5109 
5110 //----------------------------------------------------------------------------
5111 
copx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])5112 int copx2s(
5113   struct prjprm *prj,
5114   int nx,
5115   int ny,
5116   int sxy,
5117   int spt,
5118   const double x[],
5119   const double y[],
5120   double phi[],
5121   double theta[],
5122   int stat[])
5123 
5124 {
5125   int mx, my, rowlen, rowoff, status;
5126   double alpha, dy, dy2, r, xj;
5127   register int ix, iy, *statp;
5128   register const double *xp, *yp;
5129   register double *phip, *thetap;
5130 
5131   // Initialize.
5132   if (prj == 0x0) return PRJERR_NULL_POINTER;
5133   if (prj->flag != COP) {
5134     if ((status = copset(prj))) return status;
5135   }
5136 
5137   if (ny > 0) {
5138     mx = nx;
5139     my = ny;
5140   } else {
5141     mx = 1;
5142     my = 1;
5143     ny = nx;
5144   }
5145 
5146   status = 0;
5147 
5148 
5149   // Do x dependence.
5150   xp = x;
5151   rowoff = 0;
5152   rowlen = nx*spt;
5153   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
5154     xj = *xp + prj->x0;
5155 
5156     phip = phi + rowoff;
5157     for (iy = 0; iy < my; iy++) {
5158       *phip = xj;
5159       phip += rowlen;
5160     }
5161   }
5162 
5163 
5164   // Do y dependence.
5165   yp = y;
5166   phip   = phi;
5167   thetap = theta;
5168   statp  = stat;
5169   for (iy = 0; iy < ny; iy++, yp += sxy) {
5170     dy  = prj->w[2] - (*yp + prj->y0);
5171     dy2 = dy*dy;
5172 
5173     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
5174       xj = *phip;
5175 
5176       r = sqrt(xj*xj + dy2);
5177       if (prj->pv[1] < 0.0) r = -r;
5178 
5179       if (r == 0.0) {
5180         alpha = 0.0;
5181       } else {
5182         alpha = atan2d(xj/r, dy/r);
5183       }
5184 
5185       *phip = alpha*prj->w[1];
5186       *thetap = prj->pv[1] + atand(prj->w[5] - r*prj->w[4]);
5187       *(statp++) = 0;
5188     }
5189   }
5190 
5191 
5192   // Do bounds checking on the native coordinates.
5193   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
5194     if (!status) status = PRJERR_BAD_PIX_SET("copx2s");
5195   }
5196 
5197   return status;
5198 }
5199 
5200 //----------------------------------------------------------------------------
5201 
cops2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])5202 int cops2x(
5203   struct prjprm *prj,
5204   int nphi,
5205   int ntheta,
5206   int spt,
5207   int sxy,
5208   const double phi[],
5209   const double theta[],
5210   double x[],
5211   double y[],
5212   int stat[])
5213 
5214 {
5215   int mphi, mtheta, rowlen, rowoff, status;
5216   double alpha, cosalpha, r, s, t, sinalpha, y0;
5217   register int iphi, itheta, istat, *statp;
5218   register const double *phip, *thetap;
5219   register double *xp, *yp;
5220 
5221   // Initialize.
5222   if (prj == 0x0) return PRJERR_NULL_POINTER;
5223   if (prj->flag != COP) {
5224     if ((status = copset(prj))) return status;
5225   }
5226 
5227   if (ntheta > 0) {
5228     mphi   = nphi;
5229     mtheta = ntheta;
5230   } else {
5231     mphi   = 1;
5232     mtheta = 1;
5233     ntheta = nphi;
5234   }
5235 
5236   status = 0;
5237 
5238 
5239   // Do phi dependence.
5240   phip = phi;
5241   rowoff = 0;
5242   rowlen = nphi*sxy;
5243   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
5244     alpha = prj->w[0]*(*phip);
5245     sincosd(alpha, &sinalpha, &cosalpha);
5246 
5247     xp = x + rowoff;
5248     yp = y + rowoff;
5249     for (itheta = 0; itheta < mtheta; itheta++) {
5250       *xp = sinalpha;
5251       *yp = cosalpha;
5252       xp += rowlen;
5253       yp += rowlen;
5254     }
5255   }
5256 
5257 
5258   // Do theta dependence.
5259   thetap = theta;
5260   xp = x;
5261   yp = y;
5262   statp = stat;
5263   y0 = prj->y0 - prj->w[2];
5264   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
5265     t = *thetap - prj->pv[1];
5266     s = cosd(t);
5267 
5268     istat = 0;
5269     if (s == 0.0) {
5270       // Latitude of divergence.
5271       r = 0.0;
5272       istat = 1;
5273       if (!status) status = PRJERR_BAD_WORLD_SET("cops2x");
5274 
5275     } else if (fabs(*thetap) == 90.0) {
5276       // Return an exact value at the poles.
5277       r = 0.0;
5278 
5279       // Bounds checking.
5280       if (prj->bounds&1) {
5281         if ((*thetap < 0.0) != (prj->pv[1] < 0.0)) {
5282           istat = 1;
5283           if (!status) status = PRJERR_BAD_WORLD_SET("cops2x");
5284         }
5285       }
5286 
5287     } else {
5288       r = prj->w[2] - prj->w[3]*sind(t)/s;
5289 
5290       // Bounds checking.
5291       if (prj->bounds&1) {
5292         if (r*prj->w[0] < 0.0) {
5293           istat = 1;
5294           if (!status) status = PRJERR_BAD_WORLD_SET("cops2x");
5295         }
5296       }
5297     }
5298 
5299     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
5300       *xp =  r*(*xp) - prj->x0;
5301       *yp = -r*(*yp) - y0;
5302       *(statp++) = istat;
5303     }
5304   }
5305 
5306   return status;
5307 }
5308 
5309 /*============================================================================
5310 *   COE: conic equal area projection.
5311 *
5312 *   Given:
5313 *      prj->pv[1]   sigma = (theta2+theta1)/2
5314 *      prj->pv[2]   delta = (theta2-theta1)/2, where theta1 and theta2 are the
5315 *                   latitudes of the standard parallels, in degrees.
5316 *
5317 *   Given and/or returned:
5318 *      prj->r0      Reset to 180/pi if 0.
5319 *      prj->phi0    Reset to sigma if undefined.
5320 *      prj->theta0  Reset to sigma if undefined.
5321 *
5322 *   Returned:
5323 *      prj->flag     COE
5324 *      prj->code    "COE"
5325 *      prj->x0      Fiducial offset in x.
5326 *      prj->y0      Fiducial offset in y.
5327 *      prj->w[0]    C = (sin(theta1) + sin(theta2))/2
5328 *      prj->w[1]    1/C
5329 *      prj->w[2]    Y0 = chi*sqrt(psi - 2C*sind(sigma))
5330 *      prj->w[3]    chi = r0/C
5331 *      prj->w[4]    psi = 1 + sin(theta1)*sin(theta2)
5332 *      prj->w[5]    2C
5333 *      prj->w[6]    (1 + sin(theta1)*sin(theta2))*(r0/C)**2
5334 *      prj->w[7]    C/(2*r0**2)
5335 *      prj->w[8]    chi*sqrt(psi + 2C)
5336 *      prj->prjx2s  Pointer to coex2s().
5337 *      prj->prjs2x  Pointer to coes2x().
5338 *===========================================================================*/
5339 
coeset(struct prjprm * prj)5340 int coeset(struct prjprm *prj)
5341 
5342 {
5343   double theta1, theta2;
5344 
5345   if (prj == 0x0) return PRJERR_NULL_POINTER;
5346 
5347   prj->flag = COE;
5348   strcpy(prj->code, "COE");
5349   strcpy(prj->name, "conic equal area");
5350 
5351   if (undefined(prj->pv[1])) {
5352     return PRJERR_BAD_PARAM_SET("coeset");
5353   }
5354   if (undefined(prj->pv[2])) prj->pv[2] = 0.0;
5355   if (prj->r0 == 0.0) prj->r0 = R2D;
5356 
5357   prj->category  = CONIC;
5358   prj->pvrange   = 102;
5359   prj->simplezen = 0;
5360   prj->equiareal = 1;
5361   prj->conformal = 0;
5362   prj->global    = 1;
5363   prj->divergent = 0;
5364 
5365   theta1 = prj->pv[1] - prj->pv[2];
5366   theta2 = prj->pv[1] + prj->pv[2];
5367 
5368   prj->w[0] = (sind(theta1) + sind(theta2))/2.0;
5369   if (prj->w[0] == 0.0) {
5370     return PRJERR_BAD_PARAM_SET("coeset");
5371   }
5372 
5373   prj->w[1] = 1.0/prj->w[0];
5374 
5375   prj->w[3] = prj->r0/prj->w[0];
5376   prj->w[4] = 1.0 + sind(theta1)*sind(theta2);
5377   prj->w[5] = 2.0*prj->w[0];
5378   prj->w[6] = prj->w[3]*prj->w[3]*prj->w[4];
5379   prj->w[7] = 1.0/(2.0*prj->r0*prj->w[3]);
5380   prj->w[8] = prj->w[3]*sqrt(prj->w[4] + prj->w[5]);
5381 
5382   prj->w[2] = prj->w[3]*sqrt(prj->w[4] - prj->w[5]*sind(prj->pv[1]));
5383 
5384   prj->prjx2s = coex2s;
5385   prj->prjs2x = coes2x;
5386 
5387   return prjoff(prj, 0.0, prj->pv[1]);
5388 }
5389 
5390 //----------------------------------------------------------------------------
5391 
coex2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])5392 int coex2s(
5393   struct prjprm *prj,
5394   int nx,
5395   int ny,
5396   int sxy,
5397   int spt,
5398   const double x[],
5399   const double y[],
5400   double phi[],
5401   double theta[],
5402   int stat[])
5403 
5404 {
5405   int mx, my, rowlen, rowoff, status;
5406   double alpha, dy, dy2, r, t, w, xj;
5407   const double tol = 1.0e-12;
5408   register int ix, iy, istat, *statp;
5409   register const double *xp, *yp;
5410   register double *phip, *thetap;
5411 
5412   // Initialize.
5413   if (prj == 0x0) return PRJERR_NULL_POINTER;
5414   if (prj->flag != COE) {
5415     if ((status = coeset(prj))) return status;
5416   }
5417 
5418   if (ny > 0) {
5419     mx = nx;
5420     my = ny;
5421   } else {
5422     mx = 1;
5423     my = 1;
5424     ny = nx;
5425   }
5426 
5427   status = 0;
5428 
5429 
5430   // Do x dependence.
5431   xp = x;
5432   rowoff = 0;
5433   rowlen = nx*spt;
5434   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
5435     xj = *xp + prj->x0;
5436 
5437     phip = phi + rowoff;
5438     for (iy = 0; iy < my; iy++) {
5439       *phip = xj;
5440       phip += rowlen;
5441     }
5442   }
5443 
5444 
5445   // Do y dependence.
5446   yp = y;
5447   phip   = phi;
5448   thetap = theta;
5449   statp  = stat;
5450   for (iy = 0; iy < ny; iy++, yp += sxy) {
5451     dy  = prj->w[2] - (*yp + prj->y0);
5452     dy2 = dy*dy;
5453 
5454     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
5455       xj = *phip;
5456 
5457       r = sqrt(xj*xj + dy2);
5458       if (prj->pv[1] < 0.0) r = -r;
5459 
5460       if (r == 0.0) {
5461         alpha = 0.0;
5462       } else {
5463         alpha = atan2d(xj/r, dy/r);
5464       }
5465 
5466       istat = 0;
5467       if (fabs(r - prj->w[8]) < tol) {
5468         t = -90.0;
5469       } else {
5470         w = (prj->w[6] - r*r)*prj->w[7];
5471         if (fabs(w) > 1.0) {
5472           if (fabs(w-1.0) < tol) {
5473             t = 90.0;
5474           } else if (fabs(w+1.0) < tol) {
5475             t = -90.0;
5476           } else {
5477             t = 0.0;
5478             istat = 1;
5479             if (!status) status = PRJERR_BAD_PIX_SET("coex2s");
5480           }
5481         } else {
5482           t = asind(w);
5483         }
5484       }
5485 
5486       *phip = alpha*prj->w[1];
5487       *thetap = t;
5488       *(statp++) = istat;
5489     }
5490   }
5491 
5492 
5493   // Do bounds checking on the native coordinates.
5494   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
5495     if (!status) status = PRJERR_BAD_PIX_SET("coex2s");
5496   }
5497 
5498   return status;
5499 }
5500 
5501 //----------------------------------------------------------------------------
5502 
coes2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])5503 int coes2x(
5504   struct prjprm *prj,
5505   int nphi,
5506   int ntheta,
5507   int spt,
5508   int sxy,
5509   const double phi[],
5510   const double theta[],
5511   double x[],
5512   double y[],
5513   int stat[])
5514 
5515 {
5516   int mphi, mtheta, rowlen, rowoff, status;
5517   double alpha, cosalpha, r, sinalpha, y0;
5518   register int iphi, itheta, *statp;
5519   register const double *phip, *thetap;
5520   register double *xp, *yp;
5521 
5522   // Initialize.
5523   if (prj == 0x0) return PRJERR_NULL_POINTER;
5524   if (prj->flag != COE) {
5525     if ((status = coeset(prj))) return status;
5526   }
5527 
5528   if (ntheta > 0) {
5529     mphi   = nphi;
5530     mtheta = ntheta;
5531   } else {
5532     mphi   = 1;
5533     mtheta = 1;
5534     ntheta = nphi;
5535   }
5536 
5537 
5538   // Do phi dependence.
5539   phip = phi;
5540   rowoff = 0;
5541   rowlen = nphi*sxy;
5542   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
5543     alpha = prj->w[0]*(*phip);
5544     sincosd(alpha, &sinalpha, &cosalpha);
5545 
5546     xp = x + rowoff;
5547     yp = y + rowoff;
5548     for (itheta = 0; itheta < mtheta; itheta++) {
5549       *xp = sinalpha;
5550       *yp = cosalpha;
5551       xp += rowlen;
5552       yp += rowlen;
5553     }
5554   }
5555 
5556 
5557   // Do theta dependence.
5558   thetap = theta;
5559   xp = x;
5560   yp = y;
5561   statp = stat;
5562   y0 = prj->y0 - prj->w[2];
5563   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
5564     if (*thetap == -90.0) {
5565       r = prj->w[8];
5566     } else {
5567       r = prj->w[3]*sqrt(prj->w[4] - prj->w[5]*sind(*thetap));
5568     }
5569 
5570     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
5571       *xp =  r*(*xp) - prj->x0;
5572       *yp = -r*(*yp) - y0;
5573       *(statp++) = 0;
5574     }
5575   }
5576 
5577   return 0;
5578 }
5579 
5580 /*============================================================================
5581 *   COD: conic equidistant projection.
5582 *
5583 *   Given:
5584 *      prj->pv[1]   sigma = (theta2+theta1)/2
5585 *      prj->pv[2]   delta = (theta2-theta1)/2, where theta1 and theta2 are the
5586 *                   latitudes of the standard parallels, in degrees.
5587 *
5588 *   Given and/or returned:
5589 *      prj->r0      Reset to 180/pi if 0.
5590 *      prj->phi0    Reset to sigma if undefined.
5591 *      prj->theta0  Reset to sigma if undefined.
5592 *
5593 *   Returned:
5594 *      prj->flag     COD
5595 *      prj->code    "COD"
5596 *      prj->x0      Fiducial offset in x.
5597 *      prj->y0      Fiducial offset in y.
5598 *      prj->w[0]    C = r0*sin(sigma)*sin(delta)/delta
5599 *      prj->w[1]    1/C
5600 *      prj->w[2]    Y0 = delta*cot(delta)*cot(sigma)
5601 *      prj->w[3]    Y0 + sigma
5602 *      prj->prjx2s  Pointer to codx2s().
5603 *      prj->prjs2x  Pointer to cods2x().
5604 *===========================================================================*/
5605 
codset(struct prjprm * prj)5606 int codset(struct prjprm *prj)
5607 
5608 {
5609   if (prj == 0x0) return PRJERR_NULL_POINTER;
5610 
5611   prj->flag = COD;
5612   strcpy(prj->code, "COD");
5613   strcpy(prj->name, "conic equidistant");
5614 
5615   if (undefined(prj->pv[1])) {
5616     return PRJERR_BAD_PARAM_SET("codset");
5617   }
5618   if (undefined(prj->pv[2])) prj->pv[2] = 0.0;
5619   if (prj->r0 == 0.0) prj->r0 = R2D;
5620 
5621   prj->category  = CONIC;
5622   prj->pvrange   = 102;
5623   prj->simplezen = 0;
5624   prj->equiareal = 0;
5625   prj->conformal = 0;
5626   prj->global    = 1;
5627   prj->divergent = 0;
5628 
5629   if (prj->pv[2] == 0.0) {
5630     prj->w[0] = prj->r0*sind(prj->pv[1])*D2R;
5631   } else {
5632     prj->w[0] = prj->r0*sind(prj->pv[1])*sind(prj->pv[2])/prj->pv[2];
5633   }
5634 
5635   if (prj->w[0] == 0.0) {
5636     return PRJERR_BAD_PARAM_SET("codset");
5637   }
5638 
5639   prj->w[1] = 1.0/prj->w[0];
5640   prj->w[2] = prj->r0*cosd(prj->pv[2])*cosd(prj->pv[1])/prj->w[0];
5641   prj->w[3] = prj->w[2] + prj->pv[1];
5642 
5643   prj->prjx2s = codx2s;
5644   prj->prjs2x = cods2x;
5645 
5646   return prjoff(prj, 0.0, prj->pv[1]);
5647 }
5648 
5649 //----------------------------------------------------------------------------
5650 
codx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])5651 int codx2s(
5652   struct prjprm *prj,
5653   int nx,
5654   int ny,
5655   int sxy,
5656   int spt,
5657   const double x[],
5658   const double y[],
5659   double phi[],
5660   double theta[],
5661   int stat[])
5662 
5663 {
5664   int mx, my, rowlen, rowoff, status;
5665   double alpha, dy, dy2, r, xj;
5666   register int ix, iy, *statp;
5667   register const double *xp, *yp;
5668   register double *phip, *thetap;
5669 
5670   // Initialize.
5671   if (prj == 0x0) return PRJERR_NULL_POINTER;
5672   if (prj->flag != COD) {
5673     if ((status = codset(prj))) return status;
5674   }
5675 
5676   if (ny > 0) {
5677     mx = nx;
5678     my = ny;
5679   } else {
5680     mx = 1;
5681     my = 1;
5682     ny = nx;
5683   }
5684 
5685   status = 0;
5686 
5687 
5688   // Do x dependence.
5689   xp = x;
5690   rowoff = 0;
5691   rowlen = nx*spt;
5692   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
5693     xj = *xp + prj->x0;
5694 
5695     phip = phi + rowoff;
5696     for (iy = 0; iy < my; iy++) {
5697       *phip = xj;
5698       phip += rowlen;
5699     }
5700   }
5701 
5702 
5703   // Do y dependence.
5704   yp = y;
5705   phip   = phi;
5706   thetap = theta;
5707   statp  = stat;
5708   for (iy = 0; iy < ny; iy++, yp += sxy) {
5709     dy  = prj->w[2] - (*yp + prj->y0);
5710     dy2 = dy*dy;
5711 
5712     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
5713       xj = *phip;
5714 
5715       r = sqrt(xj*xj + dy2);
5716       if (prj->pv[1] < 0.0) r = -r;
5717 
5718       if (r == 0.0) {
5719         alpha = 0.0;
5720       } else {
5721         alpha = atan2d(xj/r, dy/r);
5722       }
5723 
5724       *phip = alpha*prj->w[1];
5725       *thetap = prj->w[3] - r;
5726       *(statp++) = 0;
5727     }
5728   }
5729 
5730 
5731   // Do bounds checking on the native coordinates.
5732   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
5733     if (!status) status = PRJERR_BAD_PIX_SET("codx2s");
5734   }
5735 
5736   return status;
5737 }
5738 
5739 //----------------------------------------------------------------------------
5740 
cods2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])5741 int cods2x(
5742   struct prjprm *prj,
5743   int nphi,
5744   int ntheta,
5745   int spt,
5746   int sxy,
5747   const double phi[],
5748   const double theta[],
5749   double x[],
5750   double y[],
5751   int stat[])
5752 
5753 {
5754   int mphi, mtheta, rowlen, rowoff, status;
5755   double alpha, cosalpha, r, sinalpha, y0;
5756   register int iphi, itheta, *statp;
5757   register const double *phip, *thetap;
5758   register double *xp, *yp;
5759 
5760   // Initialize.
5761   if (prj == 0x0) return PRJERR_NULL_POINTER;
5762   if (prj->flag != COD) {
5763     if ((status = codset(prj))) return status;
5764   }
5765 
5766   if (ntheta > 0) {
5767     mphi   = nphi;
5768     mtheta = ntheta;
5769   } else {
5770     mphi   = 1;
5771     mtheta = 1;
5772     ntheta = nphi;
5773   }
5774 
5775 
5776   // Do phi dependence.
5777   phip = phi;
5778   rowoff = 0;
5779   rowlen = nphi*sxy;
5780   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
5781     alpha = prj->w[0]*(*phip);
5782     sincosd(alpha, &sinalpha, &cosalpha);
5783 
5784     xp = x + rowoff;
5785     yp = y + rowoff;
5786     for (itheta = 0; itheta < mtheta; itheta++) {
5787       *xp = sinalpha;
5788       *yp = cosalpha;
5789       xp += rowlen;
5790       yp += rowlen;
5791     }
5792   }
5793 
5794 
5795   // Do theta dependence.
5796   thetap = theta;
5797   xp = x;
5798   yp = y;
5799   statp = stat;
5800   y0 = prj->y0 - prj->w[2];
5801   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
5802     r = prj->w[3] - *thetap;
5803 
5804     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
5805       *xp =  r*(*xp) - prj->x0;
5806       *yp = -r*(*yp) - y0;
5807       *(statp++) = 0;
5808     }
5809   }
5810 
5811   return 0;
5812 }
5813 
5814 /*============================================================================
5815 *   COO: conic orthomorphic projection.
5816 *
5817 *   Given:
5818 *      prj->pv[1]   sigma = (theta2+theta1)/2
5819 *      prj->pv[2]   delta = (theta2-theta1)/2, where theta1 and theta2 are the
5820 *                   latitudes of the standard parallels, in degrees.
5821 *
5822 *   Given and/or returned:
5823 *      prj->r0      Reset to 180/pi if 0.
5824 *      prj->phi0    Reset to sigma if undefined.
5825 *      prj->theta0  Reset to sigma if undefined.
5826 *
5827 *   Returned:
5828 *      prj->flag     COO
5829 *      prj->code    "COO"
5830 *      prj->x0      Fiducial offset in x.
5831 *      prj->y0      Fiducial offset in y.
5832 *      prj->w[0]    C = ln(cos(theta2)/cos(theta1))/ln(tan(tau2)/tan(tau1))
5833 *                       where tau1 = (90 - theta1)/2
5834 *                             tau2 = (90 - theta2)/2
5835 *      prj->w[1]    1/C
5836 *      prj->w[2]    Y0 = psi*tan((90-sigma)/2)**C
5837 *      prj->w[3]    psi = (r0*cos(theta1)/C)/tan(tau1)**C
5838 *      prj->w[4]    1/psi
5839 *      prj->prjx2s  Pointer to coox2s().
5840 *      prj->prjs2x  Pointer to coos2x().
5841 *===========================================================================*/
5842 
cooset(struct prjprm * prj)5843 int cooset(struct prjprm *prj)
5844 
5845 {
5846   double cos1, cos2, tan1, tan2, theta1, theta2;
5847 
5848   if (prj == 0x0) return PRJERR_NULL_POINTER;
5849 
5850   prj->flag = COO;
5851   strcpy(prj->code, "COO");
5852   strcpy(prj->name, "conic orthomorphic");
5853 
5854   if (undefined(prj->pv[1])) {
5855     return PRJERR_BAD_PARAM_SET("cooset");
5856   }
5857   if (undefined(prj->pv[2])) prj->pv[2] = 0.0;
5858   if (prj->r0 == 0.0) prj->r0 = R2D;
5859 
5860   prj->category  = CONIC;
5861   prj->pvrange   = 102;
5862   prj->simplezen = 0;
5863   prj->equiareal = 0;
5864   prj->conformal = 1;
5865   prj->global    = 0;
5866   prj->divergent = 1;
5867 
5868   theta1 = prj->pv[1] - prj->pv[2];
5869   theta2 = prj->pv[1] + prj->pv[2];
5870 
5871   tan1 = tand((90.0 - theta1)/2.0);
5872   cos1 = cosd(theta1);
5873 
5874   if (theta1 == theta2) {
5875     prj->w[0] = sind(theta1);
5876   } else {
5877     tan2 = tand((90.0 - theta2)/2.0);
5878     cos2 = cosd(theta2);
5879     prj->w[0] = log(cos2/cos1)/log(tan2/tan1);
5880   }
5881   if (prj->w[0] == 0.0) {
5882     return PRJERR_BAD_PARAM_SET("cooset");
5883   }
5884 
5885   prj->w[1] = 1.0/prj->w[0];
5886 
5887   prj->w[3] = prj->r0*(cos1/prj->w[0])/pow(tan1,prj->w[0]);
5888   if (prj->w[3] == 0.0) {
5889     return PRJERR_BAD_PARAM_SET("cooset");
5890   }
5891   prj->w[2] = prj->w[3]*pow(tand((90.0 - prj->pv[1])/2.0),prj->w[0]);
5892   prj->w[4] = 1.0/prj->w[3];
5893 
5894   prj->prjx2s = coox2s;
5895   prj->prjs2x = coos2x;
5896 
5897   return prjoff(prj, 0.0, prj->pv[1]);
5898 }
5899 
5900 //----------------------------------------------------------------------------
5901 
coox2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])5902 int coox2s(
5903   struct prjprm *prj,
5904   int nx,
5905   int ny,
5906   int sxy,
5907   int spt,
5908   const double x[],
5909   const double y[],
5910   double phi[],
5911   double theta[],
5912   int stat[])
5913 
5914 {
5915   int mx, my, rowlen, rowoff, status;
5916   double alpha, dy, dy2, r, t, xj;
5917   register int ix, iy, istat, *statp;
5918   register const double *xp, *yp;
5919   register double *phip, *thetap;
5920 
5921   // Initialize.
5922   if (prj == 0x0) return PRJERR_NULL_POINTER;
5923   if (prj->flag != COO) {
5924     if ((status = cooset(prj))) return status;
5925   }
5926 
5927   if (ny > 0) {
5928     mx = nx;
5929     my = ny;
5930   } else {
5931     mx = 1;
5932     my = 1;
5933     ny = nx;
5934   }
5935 
5936   status = 0;
5937 
5938 
5939   // Do x dependence.
5940   xp = x;
5941   rowoff = 0;
5942   rowlen = nx*spt;
5943   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
5944     xj = *xp + prj->x0;
5945 
5946     phip = phi + rowoff;
5947     for (iy = 0; iy < my; iy++) {
5948       *phip = xj;
5949       phip += rowlen;
5950     }
5951   }
5952 
5953 
5954   // Do y dependence.
5955   yp = y;
5956   phip   = phi;
5957   thetap = theta;
5958   statp  = stat;
5959   for (iy = 0; iy < ny; iy++, yp += sxy) {
5960     dy  = prj->w[2] - (*yp + prj->y0);
5961     dy2 = dy*dy;
5962 
5963     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
5964       xj = *phip;
5965 
5966       r = sqrt(xj*xj + dy2);
5967       if (prj->pv[1] < 0.0) r = -r;
5968 
5969       if (r == 0.0) {
5970         alpha = 0.0;
5971       } else {
5972         alpha = atan2d(xj/r, dy/r);
5973       }
5974 
5975       istat = 0;
5976       if (r == 0.0) {
5977         if (prj->w[0] < 0.0) {
5978           t = -90.0;
5979         } else {
5980           t = 0.0;
5981           istat = 1;
5982           if (!status) status = PRJERR_BAD_PIX_SET("coox2s");
5983         }
5984       } else {
5985         t = 90.0 - 2.0*atand(pow(r*prj->w[4],prj->w[1]));
5986       }
5987 
5988       *phip = alpha*prj->w[1];
5989       *thetap = t;
5990       *(statp++) = istat;
5991     }
5992   }
5993 
5994 
5995   // Do bounds checking on the native coordinates.
5996   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
5997     if (!status) status = PRJERR_BAD_PIX_SET("coox2s");
5998   }
5999 
6000   return status;
6001 }
6002 
6003 //----------------------------------------------------------------------------
6004 
coos2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])6005 int coos2x(
6006   struct prjprm *prj,
6007   int nphi,
6008   int ntheta,
6009   int spt,
6010   int sxy,
6011   const double phi[],
6012   const double theta[],
6013   double x[],
6014   double y[],
6015   int stat[])
6016 
6017 {
6018   int mphi, mtheta, rowlen, rowoff, status;
6019   double alpha, cosalpha, r, sinalpha, y0;
6020   register int iphi, itheta, istat, *statp;
6021   register const double *phip, *thetap;
6022   register double *xp, *yp;
6023 
6024   // Initialize.
6025   if (prj == 0x0) return PRJERR_NULL_POINTER;
6026   if (prj->flag != COO) {
6027     if ((status = cooset(prj))) return status;
6028   }
6029 
6030   if (ntheta > 0) {
6031     mphi   = nphi;
6032     mtheta = ntheta;
6033   } else {
6034     mphi   = 1;
6035     mtheta = 1;
6036     ntheta = nphi;
6037   }
6038 
6039   status = 0;
6040 
6041 
6042   // Do phi dependence.
6043   phip = phi;
6044   rowoff = 0;
6045   rowlen = nphi*sxy;
6046   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
6047     alpha = prj->w[0]*(*phip);
6048     sincosd(alpha, &sinalpha, &cosalpha);
6049 
6050     xp = x + rowoff;
6051     yp = y + rowoff;
6052     for (itheta = 0; itheta < mtheta; itheta++) {
6053       *xp = sinalpha;
6054       *yp = cosalpha;
6055       xp += rowlen;
6056       yp += rowlen;
6057     }
6058   }
6059 
6060 
6061   // Do theta dependence.
6062   thetap = theta;
6063   xp = x;
6064   yp = y;
6065   statp = stat;
6066   y0 = prj->y0 - prj->w[2];
6067   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
6068     istat = 0;
6069 
6070     if (*thetap == -90.0) {
6071       r = 0.0;
6072       if (prj->w[0] >= 0.0) {
6073         istat = 1;
6074         if (!status) status = PRJERR_BAD_WORLD_SET("coos2x");
6075       }
6076     } else {
6077       r = prj->w[3]*pow(tand((90.0 - *thetap)/2.0),prj->w[0]);
6078     }
6079 
6080     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
6081       *xp =  r*(*xp) - prj->x0;
6082       *yp = -r*(*yp) - y0;
6083       *(statp++) = istat;
6084     }
6085   }
6086 
6087   return status;
6088 }
6089 
6090 /*============================================================================
6091 *   BON: Bonne's projection.
6092 *
6093 *   Given:
6094 *      prj->pv[1]   Bonne conformal latitude, theta1, in degrees.
6095 *
6096 *   Given and/or returned:
6097 *      prj->r0      Reset to 180/pi if 0.
6098 *      prj->phi0    Reset to 0.0 if undefined.
6099 *      prj->theta0  Reset to 0.0 if undefined.
6100 *
6101 *   Returned:
6102 *      prj->flag     BON
6103 *      prj->code    "BON"
6104 *      prj->x0      Fiducial offset in x.
6105 *      prj->y0      Fiducial offset in y.
6106 *      prj->w[1]    r0*pi/180
6107 *      prj->w[2]    Y0 = r0*(cot(theta1) + theta1*pi/180)
6108 *      prj->prjx2s  Pointer to bonx2s().
6109 *      prj->prjs2x  Pointer to bons2x().
6110 *===========================================================================*/
6111 
bonset(struct prjprm * prj)6112 int bonset(struct prjprm *prj)
6113 
6114 {
6115   if (prj == 0x0) return PRJERR_NULL_POINTER;
6116 
6117   prj->flag = BON;
6118   strcpy(prj->code, "BON");
6119   strcpy(prj->name, "Bonne's");
6120 
6121   if (undefined(prj->pv[1])) {
6122     return PRJERR_BAD_PARAM_SET("bonset");
6123   }
6124 
6125   if (prj->pv[1] == 0.0) {
6126     // Sanson-Flamsteed.
6127     return sflset(prj);
6128   }
6129 
6130   prj->category  = POLYCONIC;
6131   prj->pvrange   = 101;
6132   prj->simplezen = 0;
6133   prj->equiareal = 1;
6134   prj->conformal = 0;
6135   prj->global    = 1;
6136   prj->divergent = 0;
6137 
6138   if (prj->r0 == 0.0) {
6139     prj->r0 = R2D;
6140     prj->w[1] = 1.0;
6141     prj->w[2] = prj->r0*cosd(prj->pv[1])/sind(prj->pv[1]) + prj->pv[1];
6142   } else {
6143     prj->w[1] = prj->r0*D2R;
6144     prj->w[2] = prj->r0*(cosd(prj->pv[1])/sind(prj->pv[1]) + prj->pv[1]*D2R);
6145   }
6146 
6147   prj->prjx2s = bonx2s;
6148   prj->prjs2x = bons2x;
6149 
6150   return prjoff(prj, 0.0, 0.0);
6151 }
6152 
6153 //----------------------------------------------------------------------------
6154 
bonx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])6155 int bonx2s(
6156   struct prjprm *prj,
6157   int nx,
6158   int ny,
6159   int sxy,
6160   int spt,
6161   const double x[],
6162   const double y[],
6163   double phi[],
6164   double theta[],
6165   int stat[])
6166 
6167 {
6168   int mx, my, rowlen, rowoff, status;
6169   double alpha, dy, dy2, costhe, r, s, t, xj;
6170   register int ix, iy, *statp;
6171   register const double *xp, *yp;
6172   register double *phip, *thetap;
6173 
6174 
6175   // Initialize.
6176   if (prj == 0x0) return PRJERR_NULL_POINTER;
6177   if (prj->pv[1] == 0.0) {
6178     // Sanson-Flamsteed.
6179     return sflx2s(prj, nx, ny, sxy, spt, x, y, phi, theta, stat);
6180   }
6181 
6182   if (prj->flag != BON) {
6183     if ((status = bonset(prj))) return status;
6184   }
6185 
6186   if (ny > 0) {
6187     mx = nx;
6188     my = ny;
6189   } else {
6190     mx = 1;
6191     my = 1;
6192     ny = nx;
6193   }
6194 
6195   status = 0;
6196 
6197 
6198   // Do x dependence.
6199   xp = x;
6200   rowoff = 0;
6201   rowlen = nx*spt;
6202   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
6203     xj = *xp + prj->x0;
6204 
6205     phip = phi + rowoff;
6206     for (iy = 0; iy < my; iy++) {
6207       *phip = xj;
6208       phip += rowlen;
6209     }
6210   }
6211 
6212 
6213   // Do y dependence.
6214   yp = y;
6215   phip   = phi;
6216   thetap = theta;
6217   statp  = stat;
6218   for (iy = 0; iy < ny; iy++, yp += sxy) {
6219     dy  = prj->w[2] - (*yp + prj->y0);
6220     dy2 = dy*dy;
6221 
6222     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
6223       xj = *phip;
6224 
6225       r = sqrt(xj*xj + dy2);
6226       if (prj->pv[1] < 0.0) r = -r;
6227 
6228       if (r == 0.0) {
6229         alpha = 0.0;
6230       } else {
6231         alpha = atan2d(xj/r, dy/r);
6232       }
6233 
6234       t = (prj->w[2] - r)/prj->w[1];
6235       costhe = cosd(t);
6236       if (costhe == 0.0) {
6237         s = 0.0;
6238       } else {
6239         s = alpha*(r/prj->r0)/costhe;
6240       }
6241 
6242       *phip = s;
6243       *thetap = t;
6244       *(statp++) = 0;
6245     }
6246   }
6247 
6248 
6249   // Do bounds checking on the native coordinates.
6250   if (prj->bounds&4 && prjbchk(1.0e-11, nx, my, spt, phi, theta, stat)) {
6251     if (!status) status = PRJERR_BAD_PIX_SET("bonx2s");
6252   }
6253 
6254   return status;
6255 }
6256 
6257 //----------------------------------------------------------------------------
6258 
bons2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])6259 int bons2x(
6260   struct prjprm *prj,
6261   int nphi,
6262   int ntheta,
6263   int spt,
6264   int sxy,
6265   const double phi[],
6266   const double theta[],
6267   double x[],
6268   double y[],
6269   int stat[])
6270 
6271 {
6272   int mphi, mtheta, rowlen, rowoff, status;
6273   double alpha, cosalpha, r, s, sinalpha, y0;
6274   register int iphi, itheta, *statp;
6275   register const double *phip, *thetap;
6276   register double *xp, *yp;
6277 
6278   // Initialize.
6279   if (prj == 0x0) return PRJERR_NULL_POINTER;
6280   if (prj->pv[1] == 0.0) {
6281     // Sanson-Flamsteed.
6282     return sfls2x(prj, nphi, ntheta, spt, sxy, phi, theta, x, y, stat);
6283   }
6284 
6285   if (prj->flag != BON) {
6286     if ((status = bonset(prj))) return status;
6287   }
6288 
6289   if (ntheta > 0) {
6290     mphi   = nphi;
6291     mtheta = ntheta;
6292   } else {
6293     mphi   = 1;
6294     mtheta = 1;
6295     ntheta = nphi;
6296   }
6297 
6298   y0 = prj->y0 - prj->w[2];
6299 
6300 
6301   // Do phi dependence.
6302   phip = phi;
6303   rowoff = 0;
6304   rowlen = nphi*sxy;
6305   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
6306     s = prj->r0*(*phip);
6307 
6308     xp = x + rowoff;
6309     for (itheta = 0; itheta < mtheta; itheta++) {
6310       *xp = s;
6311       xp += rowlen;
6312     }
6313   }
6314 
6315 
6316   // Do theta dependence.
6317   thetap = theta;
6318   xp = x;
6319   yp = y;
6320   statp = stat;
6321   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
6322     r = prj->w[2] - prj->w[1]*(*thetap);
6323     s = cosd(*thetap)/r;
6324 
6325     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
6326       alpha = s*(*xp);
6327       sincosd(alpha, &sinalpha, &cosalpha);
6328       *xp =  r*sinalpha - prj->x0;
6329       *yp = -r*cosalpha - y0;
6330       *(statp++) = 0;
6331     }
6332   }
6333 
6334   return 0;
6335 }
6336 
6337 /*============================================================================
6338 *   PCO: polyconic projection.
6339 *
6340 *   Given and/or returned:
6341 *      prj->r0      Reset to 180/pi if 0.
6342 *      prj->phi0    Reset to 0.0 if undefined.
6343 *      prj->theta0  Reset to 0.0 if undefined.
6344 *
6345 *   Returned:
6346 *      prj->flag     PCO
6347 *      prj->code    "PCO"
6348 *      prj->x0      Fiducial offset in x.
6349 *      prj->y0      Fiducial offset in y.
6350 *      prj->w[0]    r0*(pi/180)
6351 *      prj->w[1]    (180/pi)/r0
6352 *      prj->w[2]    2*r0
6353 *      prj->w[3]    (pi/180)/(2*r0)
6354 *      prj->prjx2s  Pointer to pcox2s().
6355 *      prj->prjs2x  Pointer to pcos2x().
6356 *===========================================================================*/
6357 
pcoset(struct prjprm * prj)6358 int pcoset(struct prjprm *prj)
6359 
6360 {
6361   if (prj == 0x0) return PRJERR_NULL_POINTER;
6362 
6363   prj->flag = PCO;
6364   strcpy(prj->code, "PCO");
6365 
6366   strcpy(prj->name, "polyconic");
6367   prj->category  = POLYCONIC;
6368   prj->pvrange   = 0;
6369   prj->simplezen = 0;
6370   prj->equiareal = 0;
6371   prj->conformal = 0;
6372   prj->global    = 1;
6373   prj->divergent = 0;
6374 
6375   if (prj->r0 == 0.0) {
6376     prj->r0 = R2D;
6377     prj->w[0] = 1.0;
6378     prj->w[1] = 1.0;
6379     prj->w[2] = 360.0/PI;
6380   } else {
6381     prj->w[0] = prj->r0*D2R;
6382     prj->w[1] = 1.0/prj->w[0];
6383     prj->w[2] = 2.0*prj->r0;
6384   }
6385   prj->w[3] = D2R/prj->w[2];
6386 
6387   prj->prjx2s = pcox2s;
6388   prj->prjs2x = pcos2x;
6389 
6390   return prjoff(prj, 0.0, 0.0);
6391 }
6392 
6393 //----------------------------------------------------------------------------
6394 
pcox2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])6395 int pcox2s(
6396   struct prjprm *prj,
6397   int nx,
6398   int ny,
6399   int sxy,
6400   int spt,
6401   const double x[],
6402   const double y[],
6403   double phi[],
6404   double theta[],
6405   int stat[])
6406 
6407 {
6408   int mx, my, rowlen, rowoff, status;
6409   double f, fneg, fpos, lambda, tanthe, the, theneg, thepos, w, x1, xj, xx,
6410          yj, ymthe, y1;
6411   const double tol = 1.0e-12;
6412   register int ix, iy, k, *statp;
6413   register const double *xp, *yp;
6414   register double *phip, *thetap;
6415 
6416 
6417   // Initialize.
6418   if (prj == 0x0) return PRJERR_NULL_POINTER;
6419   if (prj->flag != PCO) {
6420     if ((status = pcoset(prj))) return status;
6421   }
6422 
6423   if (ny > 0) {
6424     mx = nx;
6425     my = ny;
6426   } else {
6427     mx = 1;
6428     my = 1;
6429     ny = nx;
6430   }
6431 
6432   status = 0;
6433 
6434 
6435   // Do x dependence.
6436   xp = x;
6437   rowoff = 0;
6438   rowlen = nx*spt;
6439   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
6440     xj = *xp + prj->x0;
6441 
6442     phip = phi + rowoff;
6443     for (iy = 0; iy < my; iy++) {
6444       *phip = xj;
6445       phip += rowlen;
6446     }
6447   }
6448 
6449 
6450   // Do y dependence.
6451   yp = y;
6452   phip   = phi;
6453   thetap = theta;
6454   statp  = stat;
6455   for (iy = 0; iy < ny; iy++, yp += sxy) {
6456     yj = *yp + prj->y0;
6457     w  = fabs(yj*prj->w[1]);
6458 
6459     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
6460       xj = *phip;
6461 
6462       if (w < tol) {
6463         *phip = xj*prj->w[1];
6464         *thetap = 0.0;
6465 
6466       } else if (fabs(w-90.0) < tol) {
6467         *phip = 0.0;
6468         *thetap = copysign(90.0, yj);
6469 
6470       } else {
6471         if (w < 1.0e-4) {
6472           // To avoid cot(theta) blowing up near theta == 0.
6473           the    = yj / (prj->w[0] + prj->w[3]*xj*xj);
6474           ymthe  = yj - prj->w[0]*the;
6475           tanthe = tand(the);
6476 
6477         } else {
6478           // Iterative solution using weighted division of the interval.
6479           thepos = yj / prj->w[0];
6480           theneg = 0.0;
6481 
6482           // Setting fneg = -fpos halves the interval in the first iter.
6483           xx = xj*xj;
6484           fpos  =  xx;
6485           fneg  = -xx;
6486 
6487           for (k = 0; k < 64; k++) {
6488             // Weighted division of the interval.
6489             lambda = fpos/(fpos-fneg);
6490             if (lambda < 0.1) {
6491               lambda = 0.1;
6492             } else if (lambda > 0.9) {
6493               lambda = 0.9;
6494             }
6495             the = thepos - lambda*(thepos-theneg);
6496 
6497             // Compute the residue.
6498             ymthe  = yj - prj->w[0]*the;
6499             tanthe = tand(the);
6500             f = xx + ymthe*(ymthe - prj->w[2]/tanthe);
6501 
6502             // Check for convergence.
6503             if (fabs(f) < tol) break;
6504             if (fabs(thepos-theneg) < tol) break;
6505 
6506             // Redefine the interval.
6507             if (f > 0.0) {
6508               thepos = the;
6509               fpos = f;
6510             } else {
6511               theneg = the;
6512               fneg = f;
6513             }
6514           }
6515         }
6516 
6517         x1 = prj->r0 - ymthe*tanthe;
6518         y1 = xj*tanthe;
6519         if (x1 == 0.0 && y1 == 0.0) {
6520           *phip = 0.0;
6521         } else {
6522           *phip = atan2d(y1, x1)/sind(the);
6523         }
6524 
6525         *thetap = the;
6526       }
6527 
6528       *(statp++) = 0;
6529     }
6530   }
6531 
6532 
6533   // Do bounds checking on the native coordinates.
6534   if (prj->bounds&4 && prjbchk(1.0e-12, nx, my, spt, phi, theta, stat)) {
6535     if (!status) status = PRJERR_BAD_PIX_SET("pcox2s");
6536   }
6537 
6538   return status;
6539 }
6540 
6541 //----------------------------------------------------------------------------
6542 
pcos2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])6543 int pcos2x(
6544   struct prjprm *prj,
6545   int nphi,
6546   int ntheta,
6547   int spt,
6548   int sxy,
6549   const double phi[],
6550   const double theta[],
6551   double x[],
6552   double y[],
6553   int stat[])
6554 
6555 {
6556   int mphi, mtheta, rowlen, rowoff, status;
6557   double cospsi, costhe, cotthe, sinpsi, sinthe, therad;
6558   register int iphi, itheta, *statp;
6559   register const double *phip, *thetap;
6560   register double *xp, *yp;
6561 
6562   // Initialize.
6563   if (prj == 0x0) return PRJERR_NULL_POINTER;
6564   if (prj->flag != PCO) {
6565     if ((status = pcoset(prj))) return status;
6566   }
6567 
6568   if (ntheta > 0) {
6569     mphi   = nphi;
6570     mtheta = ntheta;
6571   } else {
6572     mphi   = 1;
6573     mtheta = 1;
6574     ntheta = nphi;
6575   }
6576 
6577 
6578   // Do phi dependence.
6579   phip = phi;
6580   rowoff = 0;
6581   rowlen = nphi*sxy;
6582   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
6583     xp = x + rowoff;
6584     for (itheta = 0; itheta < mtheta; itheta++) {
6585       *xp = *phip;
6586       xp += rowlen;
6587     }
6588   }
6589 
6590 
6591   // Do theta dependence.
6592   thetap = theta;
6593   xp = x;
6594   yp = y;
6595   statp = stat;
6596   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
6597     if (*thetap == 0.0) {
6598       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
6599         *xp =  prj->w[0]*(*xp) - prj->x0;
6600         *yp = -prj->y0;
6601         *(statp++) = 0;
6602       }
6603 
6604     } else if (fabs(*thetap) < 1.0e-4) {
6605       // To avoid cot(theta) blowing up near theta == 0.
6606       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
6607         *xp = prj->w[0]*(*xp)*cosd(*thetap) - prj->x0;
6608         *yp = (prj->w[0] + prj->w[3]*(*xp)*(*xp))*(*thetap) - prj->y0;
6609         *(statp++) = 0;
6610       }
6611 
6612     } else {
6613       therad = (*thetap)*D2R;
6614       sincosd(*thetap, &sinthe, &costhe);
6615 
6616       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
6617         sincosd((*xp)*sinthe, &sinpsi, &cospsi);
6618         cotthe = costhe/sinthe;
6619         *xp = prj->r0*cotthe*sinpsi - prj->x0;
6620         *yp = prj->r0*(cotthe*(1.0 - cospsi) + therad) - prj->y0;
6621         *(statp++) = 0;
6622       }
6623     }
6624   }
6625 
6626   return 0;
6627 }
6628 
6629 /*============================================================================
6630 *   TSC: tangential spherical cube projection.
6631 *
6632 *   Given and/or returned:
6633 *      prj->r0      Reset to 180/pi if 0.
6634 *      prj->phi0    Reset to 0.0 if undefined.
6635 *      prj->theta0  Reset to 0.0 if undefined.
6636 *
6637 *   Returned:
6638 *      prj->flag     TSC
6639 *      prj->code    "TSC"
6640 *      prj->x0      Fiducial offset in x.
6641 *      prj->y0      Fiducial offset in y.
6642 *      prj->w[0]    r0*(pi/4)
6643 *      prj->w[1]    (4/pi)/r0
6644 *      prj->prjx2s  Pointer to tscx2s().
6645 *      prj->prjs2x  Pointer to tscs2x().
6646 *===========================================================================*/
6647 
tscset(struct prjprm * prj)6648 int tscset(struct prjprm *prj)
6649 
6650 {
6651   if (prj == 0x0) return PRJERR_NULL_POINTER;
6652 
6653   prj->flag = TSC;
6654   strcpy(prj->code, "TSC");
6655 
6656   strcpy(prj->name, "tangential spherical cube");
6657   prj->category  = QUADCUBE;
6658   prj->pvrange   = 0;
6659   prj->simplezen = 0;
6660   prj->equiareal = 0;
6661   prj->conformal = 0;
6662   prj->global    = 1;
6663   prj->divergent = 0;
6664 
6665   if (prj->r0 == 0.0) {
6666     prj->r0 = R2D;
6667     prj->w[0] = 45.0;
6668     prj->w[1] = 1.0/45.0;
6669   } else {
6670     prj->w[0] = prj->r0*PI/4.0;
6671     prj->w[1] = 1.0/prj->w[0];
6672   }
6673 
6674   prj->prjx2s = tscx2s;
6675   prj->prjs2x = tscs2x;
6676 
6677   return prjoff(prj, 0.0, 0.0);
6678 }
6679 
6680 //----------------------------------------------------------------------------
6681 
tscx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])6682 int tscx2s(
6683   struct prjprm *prj,
6684   int nx,
6685   int ny,
6686   int sxy,
6687   int spt,
6688   const double x[],
6689   const double y[],
6690   double phi[],
6691   double theta[],
6692   int stat[])
6693 
6694 {
6695   int mx, my, rowlen, rowoff, status;
6696   double l, m, n, xf, yf;
6697   register int ix, iy, *statp;
6698   register const double *xp, *yp;
6699   register double *phip, *thetap;
6700 
6701 
6702   // Initialize.
6703   if (prj == 0x0) return PRJERR_NULL_POINTER;
6704   if (prj->flag != TSC) {
6705     if ((status = tscset(prj))) return status;
6706   }
6707 
6708   if (ny > 0) {
6709     mx = nx;
6710     my = ny;
6711   } else {
6712     mx = 1;
6713     my = 1;
6714     ny = nx;
6715   }
6716 
6717   status = 0;
6718 
6719 
6720   // Do x dependence.
6721   xp = x;
6722   rowoff = 0;
6723   rowlen = nx*spt;
6724   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
6725     xf = (*xp + prj->x0)*prj->w[1];
6726 
6727     phip = phi + rowoff;
6728     for (iy = 0; iy < my; iy++) {
6729       *phip = xf;
6730       phip += rowlen;
6731     }
6732   }
6733 
6734 
6735   // Do y dependence.
6736   yp = y;
6737   phip   = phi;
6738   thetap = theta;
6739   statp  = stat;
6740   for (iy = 0; iy < ny; iy++, yp += sxy) {
6741     yf = (*yp + prj->y0)*prj->w[1];
6742 
6743     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
6744       xf = *phip;
6745 
6746       // Bounds checking.
6747       if (fabs(xf) <= 1.0) {
6748         if (fabs(yf) > 3.0) {
6749           *phip = 0.0;
6750           *thetap = 0.0;
6751           *(statp++) = 1;
6752           if (!status) status = PRJERR_BAD_PIX_SET("tscx2s");
6753           continue;
6754         }
6755       } else {
6756         if (fabs(xf) > 7.0 || fabs(yf) > 1.0) {
6757           *phip = 0.0;
6758           *thetap = 0.0;
6759           *(statp++) = 1;
6760           if (!status) status = PRJERR_BAD_PIX_SET("tscx2s");
6761           continue;
6762         }
6763       }
6764 
6765       // Map negative faces to the other side.
6766       if (xf < -1.0) xf += 8.0;
6767 
6768       // Determine the face.
6769       if (xf > 5.0) {
6770         // face = 4
6771         xf = xf - 6.0;
6772         m  = -1.0/sqrt(1.0 + xf*xf + yf*yf);
6773         l  = -m*xf;
6774         n  = -m*yf;
6775       } else if (xf > 3.0) {
6776         // face = 3
6777         xf = xf - 4.0;
6778         l  = -1.0/sqrt(1.0 + xf*xf + yf*yf);
6779         m  =  l*xf;
6780         n  = -l*yf;
6781       } else if (xf > 1.0) {
6782         // face = 2
6783         xf = xf - 2.0;
6784         m  =  1.0/sqrt(1.0 + xf*xf + yf*yf);
6785         l  = -m*xf;
6786         n  =  m*yf;
6787       } else if (yf > 1.0) {
6788         // face = 0
6789         yf = yf - 2.0;
6790         n  = 1.0/sqrt(1.0 + xf*xf + yf*yf);
6791         l  = -n*yf;
6792         m  =  n*xf;
6793       } else if (yf < -1.0) {
6794         // face = 5
6795         yf = yf + 2.0;
6796         n  = -1.0/sqrt(1.0 + xf*xf + yf*yf);
6797         l  = -n*yf;
6798         m  = -n*xf;
6799       } else {
6800         // face = 1
6801         l  =  1.0/sqrt(1.0 + xf*xf + yf*yf);
6802         m  =  l*xf;
6803         n  =  l*yf;
6804       }
6805 
6806       if (l == 0.0 && m == 0.0) {
6807         *phip = 0.0;
6808       } else {
6809         *phip = atan2d(m, l);
6810       }
6811 
6812       *thetap = asind(n);
6813       *(statp++) = 0;
6814     }
6815   }
6816 
6817 
6818   // Do bounds checking on the native coordinates.
6819   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
6820     if (!status) status = PRJERR_BAD_PIX_SET("tscx2s");
6821   }
6822 
6823   return status;
6824 }
6825 
6826 //----------------------------------------------------------------------------
6827 
tscs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])6828 int tscs2x(
6829   struct prjprm *prj,
6830   int nphi,
6831   int ntheta,
6832   int spt,
6833   int sxy,
6834   const double phi[],
6835   const double theta[],
6836   double x[],
6837   double y[],
6838   int stat[])
6839 
6840 {
6841   int face, mphi, mtheta, rowlen, rowoff, status;
6842   double cosphi, costhe, l, m, n, sinphi, sinthe, x0, xf, y0, yf, zeta;
6843   const double tol = 1.0e-12;
6844   register int iphi, istat, itheta, *statp;
6845   register const double *phip, *thetap;
6846   register double *xp, *yp;
6847 
6848   // Initialize.
6849   if (prj == 0x0) return PRJERR_NULL_POINTER;
6850   if (prj->flag != TSC) {
6851     if ((status = tscset(prj))) return status;
6852   }
6853 
6854   if (ntheta > 0) {
6855     mphi   = nphi;
6856     mtheta = ntheta;
6857   } else {
6858     mphi   = 1;
6859     mtheta = 1;
6860     ntheta = nphi;
6861   }
6862 
6863   status = 0;
6864 
6865 
6866   // Do phi dependence.
6867   phip = phi;
6868   rowoff = 0;
6869   rowlen = nphi*sxy;
6870   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
6871     sincosd(*phip, &sinphi, &cosphi);
6872 
6873     xp = x + rowoff;
6874     yp = y + rowoff;
6875     for (itheta = 0; itheta < mtheta; itheta++) {
6876       *xp = cosphi;
6877       *yp = sinphi;
6878       xp += rowlen;
6879       yp += rowlen;
6880     }
6881   }
6882 
6883 
6884   // Do theta dependence.
6885   thetap = theta;
6886   xp = x;
6887   yp = y;
6888   statp = stat;
6889   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
6890     sincosd(*thetap, &sinthe, &costhe);
6891 
6892     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
6893       l = costhe*(*xp);
6894       m = costhe*(*yp);
6895       n = sinthe;
6896 
6897       face = 0;
6898       zeta = n;
6899       if (l > zeta) {
6900         face = 1;
6901         zeta = l;
6902       }
6903       if (m > zeta) {
6904         face = 2;
6905         zeta = m;
6906       }
6907       if (-l > zeta) {
6908         face = 3;
6909         zeta = -l;
6910       }
6911       if (-m > zeta) {
6912         face = 4;
6913         zeta = -m;
6914       }
6915       if (-n > zeta) {
6916         face = 5;
6917         zeta = -n;
6918       }
6919 
6920       switch (face) {
6921       case 1:
6922         xf =  m/zeta;
6923         yf =  n/zeta;
6924         x0 =  0.0;
6925         y0 =  0.0;
6926         break;
6927       case 2:
6928         xf = -l/zeta;
6929         yf =  n/zeta;
6930         x0 =  2.0;
6931         y0 =  0.0;
6932         break;
6933       case 3:
6934         xf = -m/zeta;
6935         yf =  n/zeta;
6936         x0 =  4.0;
6937         y0 =  0.0;
6938         break;
6939       case 4:
6940         xf =  l/zeta;
6941         yf =  n/zeta;
6942         x0 =  6.0;
6943         y0 =  0.0;
6944         break;
6945       case 5:
6946         xf =  m/zeta;
6947         yf =  l/zeta;
6948         x0 =  0.0;
6949         y0 = -2.0;
6950         break;
6951       default:
6952         // face == 0
6953         xf =  m/zeta;
6954         yf = -l/zeta;
6955         x0 =  0.0;
6956         y0 =  2.0;
6957         break;
6958       }
6959 
6960       istat = 0;
6961       if (fabs(xf) > 1.0) {
6962         if (fabs(xf) > 1.0+tol) {
6963           istat = 1;
6964           if (!status) status = PRJERR_BAD_WORLD_SET("tscs2x");
6965         }
6966         xf = copysign(1.0, xf);
6967       }
6968       if (fabs(yf) > 1.0) {
6969         if (fabs(yf) > 1.0+tol) {
6970           istat = 1;
6971           if (!status) status = PRJERR_BAD_WORLD_SET("tscs2x");
6972         }
6973         yf = copysign(1.0, yf);
6974       }
6975 
6976       *xp = prj->w[0]*(xf + x0) - prj->x0;
6977       *yp = prj->w[0]*(yf + y0) - prj->y0;
6978       *(statp++) = istat;
6979     }
6980   }
6981 
6982   return status;
6983 }
6984 
6985 /*============================================================================
6986 *   CSC: COBE quadrilateralized spherical cube projection.
6987 *
6988 *   Given and/or returned:
6989 *      prj->r0      Reset to 180/pi if 0.
6990 *      prj->phi0    Reset to 0.0 if undefined.
6991 *      prj->theta0  Reset to 0.0 if undefined.
6992 *
6993 *   Returned:
6994 *      prj->flag     CSC
6995 *      prj->code    "CSC"
6996 *      prj->x0      Fiducial offset in x.
6997 *      prj->y0      Fiducial offset in y.
6998 *      prj->w[0]    r0*(pi/4)
6999 *      prj->w[1]    (4/pi)/r0
7000 *      prj->prjx2s  Pointer to cscx2s().
7001 *      prj->prjs2x  Pointer to cscs2x().
7002 *===========================================================================*/
7003 
cscset(struct prjprm * prj)7004 int cscset(struct prjprm *prj)
7005 
7006 {
7007   if (prj == 0x0) return PRJERR_NULL_POINTER;
7008 
7009   prj->flag = CSC;
7010   strcpy(prj->code, "CSC");
7011 
7012   strcpy(prj->name, "COBE quadrilateralized spherical cube");
7013   prj->category  = QUADCUBE;
7014   prj->pvrange   = 0;
7015   prj->simplezen = 0;
7016   prj->equiareal = 0;
7017   prj->conformal = 0;
7018   prj->global    = 1;
7019   prj->divergent = 0;
7020 
7021   if (prj->r0 == 0.0) {
7022     prj->r0 = R2D;
7023     prj->w[0] = 45.0;
7024     prj->w[1] = 1.0/45.0;
7025   } else {
7026     prj->w[0] = prj->r0*PI/4.0;
7027     prj->w[1] = 1.0/prj->w[0];
7028   }
7029 
7030   prj->prjx2s = cscx2s;
7031   prj->prjs2x = cscs2x;
7032 
7033   return prjoff(prj, 0.0, 0.0);
7034 }
7035 
7036 //----------------------------------------------------------------------------
7037 
cscx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])7038 int cscx2s(
7039   struct prjprm *prj,
7040   int nx,
7041   int ny,
7042   int sxy,
7043   int spt,
7044   const double x[],
7045   const double y[],
7046   double phi[],
7047   double theta[],
7048   int stat[])
7049 
7050 {
7051   int face, mx, my, rowlen, rowoff, status;
7052   double l, m, n, t;
7053   register int ix, iy, *statp;
7054   register const double *xp, *yp;
7055   register double *phip, *thetap;
7056 
7057   float chi, psi, xf, xx, yf, yy, z0, z1, z2, z3, z4, z5, z6;
7058   const float p00 = -0.27292696f;
7059   const float p10 = -0.07629969f;
7060   const float p20 = -0.22797056f;
7061   const float p30 =  0.54852384f;
7062   const float p40 = -0.62930065f;
7063   const float p50 =  0.25795794f;
7064   const float p60 =  0.02584375f;
7065   const float p01 = -0.02819452f;
7066   const float p11 = -0.01471565f;
7067   const float p21 =  0.48051509f;
7068   const float p31 = -1.74114454f;
7069   const float p41 =  1.71547508f;
7070   const float p51 = -0.53022337f;
7071   const float p02 =  0.27058160f;
7072   const float p12 = -0.56800938f;
7073   const float p22 =  0.30803317f;
7074   const float p32 =  0.98938102f;
7075   const float p42 = -0.83180469f;
7076   const float p03 = -0.60441560f;
7077   const float p13 =  1.50880086f;
7078   const float p23 = -0.93678576f;
7079   const float p33 =  0.08693841f;
7080   const float p04 =  0.93412077f;
7081   const float p14 = -1.41601920f;
7082   const float p24 =  0.33887446f;
7083   const float p05 = -0.63915306f;
7084   const float p15 =  0.52032238f;
7085   const float p06 =  0.14381585f;
7086 
7087   // Initialize.
7088   if (prj == 0x0) return PRJERR_NULL_POINTER;
7089   if (prj->flag != CSC) {
7090     if ((status = cscset(prj))) return status;
7091   }
7092 
7093   if (ny > 0) {
7094     mx = nx;
7095     my = ny;
7096   } else {
7097     mx = 1;
7098     my = 1;
7099     ny = nx;
7100   }
7101 
7102   status = 0;
7103 
7104 
7105   // Do x dependence.
7106   xp = x;
7107   rowoff = 0;
7108   rowlen = nx*spt;
7109   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
7110     xf = (float)((*xp + prj->x0)*prj->w[1]);
7111 
7112     phip = phi + rowoff;
7113     for (iy = 0; iy < my; iy++) {
7114       *phip = xf;
7115       phip += rowlen;
7116     }
7117   }
7118 
7119 
7120   // Do y dependence.
7121   yp = y;
7122   phip   = phi;
7123   thetap = theta;
7124   statp  = stat;
7125   for (iy = 0; iy < ny; iy++, yp += sxy) {
7126     yf = (float)((*yp + prj->y0)*prj->w[1]);
7127 
7128     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
7129       xf = (float)(*phip);
7130 
7131       // Bounds checking.
7132       if (fabs((double)xf) <= 1.0) {
7133         if (fabs((double)yf) > 3.0) {
7134           *phip = 0.0;
7135           *thetap = 0.0;
7136           *(statp++) = 1;
7137           if (!status) status = PRJERR_BAD_PIX_SET("cscx2s");
7138           continue;
7139         }
7140       } else {
7141         if (fabs((double)xf) > 7.0 || fabs((double)yf) > 1.0) {
7142           *phip = 0.0;
7143           *thetap = 0.0;
7144           *(statp++) = 1;
7145           if (!status) status = PRJERR_BAD_PIX_SET("cscx2s");
7146           continue;
7147         }
7148       }
7149 
7150       // Map negative faces to the other side.
7151       if (xf < -1.0f) xf += 8.0f;
7152 
7153       // Determine the face.
7154       if (xf > 5.0f) {
7155         face = 4;
7156         xf = xf - 6.0f;
7157       } else if (xf > 3.0f) {
7158         face = 3;
7159         xf = xf - 4.0f;
7160       } else if (xf > 1.0f) {
7161         face = 2;
7162         xf = xf - 2.0f;
7163       } else if (yf > 1.0f) {
7164         face = 0;
7165         yf = yf - 2.0f;
7166       } else if (yf < -1.0f) {
7167         face = 5;
7168         yf = yf + 2.0f;
7169       } else {
7170         face = 1;
7171       }
7172 
7173       xx  =  xf*xf;
7174       yy  =  yf*yf;
7175 
7176       z0 = p00 + xx*(p10 + xx*(p20 + xx*(p30 + xx*(p40 + xx*(p50 +
7177                  xx*(p60))))));
7178       z1 = p01 + xx*(p11 + xx*(p21 + xx*(p31 + xx*(p41 + xx*(p51)))));
7179       z2 = p02 + xx*(p12 + xx*(p22 + xx*(p32 + xx*(p42))));
7180       z3 = p03 + xx*(p13 + xx*(p23 + xx*(p33)));
7181       z4 = p04 + xx*(p14 + xx*(p24));
7182       z5 = p05 + xx*(p15);
7183       z6 = p06;
7184 
7185       chi = z0 + yy*(z1 + yy*(z2 + yy*(z3 + yy*(z4 + yy*(z5 + yy*z6)))));
7186       chi = xf + xf*(1.0f - xx)*chi;
7187 
7188       z0 = p00 + yy*(p10 + yy*(p20 + yy*(p30 + yy*(p40 + yy*(p50 +
7189                  yy*(p60))))));
7190       z1 = p01 + yy*(p11 + yy*(p21 + yy*(p31 + yy*(p41 + yy*(p51)))));
7191       z2 = p02 + yy*(p12 + yy*(p22 + yy*(p32 + yy*(p42))));
7192       z3 = p03 + yy*(p13 + yy*(p23 + yy*(p33)));
7193       z4 = p04 + yy*(p14 + yy*(p24));
7194       z5 = p05 + yy*(p15);
7195       z6 = p06;
7196 
7197       psi = z0 + xx*(z1 + xx*(z2 + xx*(z3 + xx*(z4 + xx*(z5 + xx*z6)))));
7198       psi = yf + yf*(1.0f - yy)*psi;
7199 
7200       t = 1.0/sqrt((double)(chi*chi + psi*psi) + 1.0);
7201       switch (face) {
7202       case 1:
7203         l =  t;
7204         m =  chi*l;
7205         n =  psi*l;
7206         break;
7207       case 2:
7208         m =  t;
7209         l = -chi*m;
7210         n =  psi*m;
7211         break;
7212       case 3:
7213         l = -t;
7214         m =  chi*l;
7215         n = -psi*l;
7216         break;
7217       case 4:
7218         m = -t;
7219         l = -chi*m;
7220         n = -psi*m;
7221         break;
7222       case 5:
7223         n = -t;
7224         l = -psi*n;
7225         m = -chi*n;
7226         break;
7227       default:
7228         // face == 0
7229         n =  t;
7230         l = -psi*n;
7231         m =  chi*n;
7232         break;
7233       }
7234 
7235       if (l == 0.0 && m == 0.0) {
7236         *phip = 0.0;
7237       } else {
7238         *phip = atan2d(m, l);
7239       }
7240 
7241       *thetap = asind(n);
7242       *(statp++) = 0;
7243     }
7244   }
7245 
7246 
7247   // Do bounds checking on the native coordinates.
7248   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
7249     if (!status) status = PRJERR_BAD_PIX_SET("cscx2s");
7250   }
7251 
7252   return status;
7253 }
7254 
7255 //----------------------------------------------------------------------------
7256 
cscs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])7257 int cscs2x(
7258   struct prjprm *prj,
7259   int nphi,
7260   int ntheta,
7261   int spt,
7262   int sxy,
7263   const double phi[],
7264   const double theta[],
7265   double x[],
7266   double y[],
7267   int stat[])
7268 
7269 {
7270   int face, mphi, mtheta, rowlen, rowoff, status;
7271   double cosphi, costhe, eta, l, m, n, sinphi, sinthe, xi, zeta;
7272   const double tol = 1.0e-7;
7273   register int iphi, istat, itheta, *statp;
7274   register const double *phip, *thetap;
7275   register double *xp, *yp;
7276 
7277   float chi, chi2, chi2psi2, chi4, chipsi, psi, psi2, psi4, chi2co, psi2co,
7278         x0, xf, y0, yf;
7279   const float gstar  =  1.37484847732f;
7280   const float mm     =  0.004869491981f;
7281   const float gamma  = -0.13161671474f;
7282   const float omega1 = -0.159596235474f;
7283   const float d0  =  0.0759196200467f;
7284   const float d1  = -0.0217762490699f;
7285   const float c00 =  0.141189631152f;
7286   const float c10 =  0.0809701286525f;
7287   const float c01 = -0.281528535557f;
7288   const float c11 =  0.15384112876f;
7289   const float c20 = -0.178251207466f;
7290   const float c02 =  0.106959469314f;
7291 
7292 
7293   // Initialize.
7294   if (prj == 0x0) return PRJERR_NULL_POINTER;
7295   if (prj->flag != CSC) {
7296     if ((status = cscset(prj))) return status;
7297   }
7298 
7299   if (ntheta > 0) {
7300     mphi   = nphi;
7301     mtheta = ntheta;
7302   } else {
7303     mphi   = 1;
7304     mtheta = 1;
7305     ntheta = nphi;
7306   }
7307 
7308   status = 0;
7309 
7310 
7311   // Do phi dependence.
7312   phip = phi;
7313   rowoff = 0;
7314   rowlen = nphi*sxy;
7315   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
7316     sincosd(*phip, &sinphi, &cosphi);
7317 
7318     xp = x + rowoff;
7319     yp = y + rowoff;
7320     for (itheta = 0; itheta < mtheta; itheta++) {
7321       *xp = cosphi;
7322       *yp = sinphi;
7323       xp += rowlen;
7324       yp += rowlen;
7325     }
7326   }
7327 
7328 
7329   // Do theta dependence.
7330   thetap = theta;
7331   xp = x;
7332   yp = y;
7333   statp = stat;
7334   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
7335     sincosd(*thetap, &sinthe, &costhe);
7336 
7337     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
7338       l = costhe*(*xp);
7339       m = costhe*(*yp);
7340       n = sinthe;
7341 
7342       face = 0;
7343       zeta = n;
7344       if (l > zeta) {
7345         face = 1;
7346         zeta = l;
7347       }
7348       if (m > zeta) {
7349         face = 2;
7350         zeta = m;
7351       }
7352       if (-l > zeta) {
7353         face = 3;
7354         zeta = -l;
7355       }
7356       if (-m > zeta) {
7357         face = 4;
7358         zeta = -m;
7359       }
7360       if (-n > zeta) {
7361         face = 5;
7362         zeta = -n;
7363       }
7364 
7365       switch (face) {
7366       case 1:
7367         xi  =  m;
7368         eta =  n;
7369         x0  =  0.0;
7370         y0  =  0.0;
7371         break;
7372       case 2:
7373         xi  = -l;
7374         eta =  n;
7375         x0  =  2.0;
7376         y0  =  0.0;
7377         break;
7378       case 3:
7379         xi  = -m;
7380         eta =  n;
7381         x0  =  4.0;
7382         y0  =  0.0;
7383         break;
7384       case 4:
7385         xi  =  l;
7386         eta =  n;
7387         x0  =  6.0;
7388         y0  =  0.0;
7389         break;
7390       case 5:
7391         xi  =  m;
7392         eta =  l;
7393         x0  =  0.0;
7394         y0  = -2.0;
7395         break;
7396       default:
7397         // face == 0
7398         xi  =  m;
7399         eta = -l;
7400         x0  =  0.0;
7401         y0  =  2.0;
7402         break;
7403       }
7404 
7405       chi = (float)( xi/zeta);
7406       psi = (float)(eta/zeta);
7407 
7408       chi2 = chi*chi;
7409       psi2 = psi*psi;
7410       chi2co = 1.0f - chi2;
7411       psi2co = 1.0f - psi2;
7412 
7413       // Avoid floating underflows.
7414       chipsi = (float)fabs((double)(chi*psi));
7415       chi4   = (chi2 > 1.0e-16f) ? chi2*chi2 : 0.0f;
7416       psi4   = (psi2 > 1.0e-16f) ? psi2*psi2 : 0.0f;
7417       chi2psi2 = (chipsi > 1.0e-16f) ? chi2*psi2 : 0.0f;
7418 
7419       xf = chi*(chi2 + chi2co*(gstar + psi2*(gamma*chi2co + mm*chi2 +
7420                 psi2co*(c00 + c10*chi2 + c01*psi2 + c11*chi2psi2 + c20*chi4 +
7421                 c02*psi4)) + chi2*(omega1 - chi2co*(d0 + d1*chi2))));
7422       yf = psi*(psi2 + psi2co*(gstar + chi2*(gamma*psi2co + mm*psi2 +
7423                 chi2co*(c00 + c10*psi2 + c01*chi2 + c11*chi2psi2 + c20*psi4 +
7424                 c02*chi4)) + psi2*(omega1 - psi2co*(d0 + d1*psi2))));
7425 
7426       istat = 0;
7427       if (fabs((double)xf) > 1.0) {
7428         if (fabs((double)xf) > 1.0+tol) {
7429           istat = 1;
7430           if (!status) status = PRJERR_BAD_WORLD_SET("cscs2x");
7431         }
7432         xf = (float)copysign(1.0, (double)xf);
7433       }
7434       if (fabs((double)yf) > 1.0) {
7435         if (fabs((double)yf) > 1.0+tol) {
7436           istat = 1;
7437           if (!status) status = PRJERR_BAD_WORLD_SET("cscs2x");
7438         }
7439         yf = (float)copysign(1.0, (double)yf);
7440       }
7441 
7442       *xp = prj->w[0]*(xf + x0) - prj->x0;
7443       *yp = prj->w[0]*(yf + y0) - prj->y0;
7444       *(statp++) = istat;
7445     }
7446   }
7447 
7448   return status;
7449 }
7450 
7451 /*============================================================================
7452 *   QSC: quadrilaterilized spherical cube projection.
7453 *
7454 *   Given and/or returned:
7455 *      prj->r0      Reset to 180/pi if 0.
7456 *      prj->phi0    Reset to 0.0 if undefined.
7457 *      prj->theta0  Reset to 0.0 if undefined.
7458 *
7459 *   Returned:
7460 *      prj->flag     QSC
7461 *      prj->code    "QSC"
7462 *      prj->x0      Fiducial offset in x.
7463 *      prj->y0      Fiducial offset in y.
7464 *      prj->w[0]    r0*(pi/4)
7465 *      prj->w[1]    (4/pi)/r0
7466 *      prj->prjx2s  Pointer to qscx2s().
7467 *      prj->prjs2x  Pointer to qscs2x().
7468 *===========================================================================*/
7469 
qscset(struct prjprm * prj)7470 int qscset(struct prjprm *prj)
7471 
7472 {
7473   if (prj == 0x0) return PRJERR_NULL_POINTER;
7474 
7475   prj->flag = QSC;
7476   strcpy(prj->code, "QSC");
7477 
7478   strcpy(prj->name, "quadrilateralized spherical cube");
7479   prj->category  = QUADCUBE;
7480   prj->pvrange   = 0;
7481   prj->simplezen = 0;
7482   prj->equiareal = 1;
7483   prj->conformal = 0;
7484   prj->global    = 1;
7485   prj->divergent = 0;
7486 
7487   if (prj->r0 == 0.0) {
7488     prj->r0 = R2D;
7489     prj->w[0] = 45.0;
7490     prj->w[1] = 1.0/45.0;
7491   } else {
7492     prj->w[0] = prj->r0*PI/4.0;
7493     prj->w[1] = 1.0/prj->w[0];
7494   }
7495 
7496   prj->prjx2s = qscx2s;
7497   prj->prjs2x = qscs2x;
7498 
7499   return prjoff(prj, 0.0, 0.0);
7500 }
7501 
7502 //----------------------------------------------------------------------------
7503 
qscx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])7504 int qscx2s(
7505   struct prjprm *prj,
7506   int nx,
7507   int ny,
7508   int sxy,
7509   int spt,
7510   const double x[],
7511   const double y[],
7512   double phi[],
7513   double theta[],
7514   int stat[])
7515 
7516 {
7517   int direct, face, mx, my, rowlen, rowoff, status;
7518   double cosw, l, m, n, omega, sinw, tau, xf, yf, w, zeco, zeta;
7519   const double tol = 1.0e-12;
7520   register int ix, iy, *statp;
7521   register const double *xp, *yp;
7522   register double *phip, *thetap;
7523 
7524 
7525   // Initialize.
7526   if (prj == 0x0) return PRJERR_NULL_POINTER;
7527   if (prj->flag != QSC) {
7528     if ((status = qscset(prj))) return status;
7529   }
7530 
7531   if (ny > 0) {
7532     mx = nx;
7533     my = ny;
7534   } else {
7535     mx = 1;
7536     my = 1;
7537     ny = nx;
7538   }
7539 
7540   status = 0;
7541 
7542 
7543   // Do x dependence.
7544   xp = x;
7545   rowoff = 0;
7546   rowlen = nx*spt;
7547   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
7548     xf = (*xp + prj->x0)*prj->w[1];
7549 
7550     phip = phi + rowoff;
7551     for (iy = 0; iy < my; iy++) {
7552       *phip = xf;
7553       phip += rowlen;
7554     }
7555   }
7556 
7557 
7558   // Do y dependence.
7559   yp = y;
7560   phip   = phi;
7561   thetap = theta;
7562   statp  = stat;
7563   for (iy = 0; iy < ny; iy++, yp += sxy) {
7564     yf = (*yp + prj->y0)*prj->w[1];
7565 
7566     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
7567       xf = *phip;
7568 
7569       // Bounds checking.
7570       if (fabs(xf) <= 1.0) {
7571         if (fabs(yf) > 3.0) {
7572           *phip = 0.0;
7573           *thetap = 0.0;
7574           *(statp++) = 1;
7575           if (!status) status = PRJERR_BAD_PIX_SET("qscx2s");
7576           continue;
7577         }
7578       } else {
7579         if (fabs(xf) > 7.0 || fabs(yf) > 1.0) {
7580           *phip = 0.0;
7581           *thetap = 0.0;
7582           *(statp++) = 1;
7583           if (!status) status = PRJERR_BAD_PIX_SET("qscx2s");
7584           continue;
7585         }
7586       }
7587 
7588       // Map negative faces to the other side.
7589       if (xf < -1.0) xf += 8.0;
7590 
7591       // Determine the face.
7592       if (xf > 5.0) {
7593         face = 4;
7594         xf -= 6.0;
7595       } else if (xf > 3.0) {
7596         face = 3;
7597         xf -= 4.0;
7598       } else if (xf > 1.0) {
7599         face = 2;
7600         xf -= 2.0;
7601       } else if (yf > 1.0) {
7602         face = 0;
7603         yf -= 2.0;
7604       } else if (yf < -1.0) {
7605         face = 5;
7606         yf += 2.0;
7607       } else {
7608         face = 1;
7609       }
7610 
7611       direct = (fabs(xf) > fabs(yf));
7612       if (direct) {
7613         if (xf == 0.0) {
7614           omega = 0.0;
7615           tau  = 1.0;
7616           zeta = 1.0;
7617           zeco = 0.0;
7618         } else {
7619           w = 15.0*yf/xf;
7620           omega = sind(w)/(cosd(w) - SQRT2INV);
7621           tau  = 1.0 + omega*omega;
7622           zeco = xf*xf*(1.0 - 1.0/sqrt(1.0 + tau));
7623           zeta = 1.0 - zeco;
7624         }
7625       } else {
7626         if (yf == 0.0) {
7627           omega = 0.0;
7628           tau  = 1.0;
7629           zeta = 1.0;
7630           zeco = 0.0;
7631         } else {
7632           w = 15.0*xf/yf;
7633           sincosd(w, &sinw, &cosw);
7634           omega = sinw/(cosw - SQRT2INV);
7635           tau  = 1.0 + omega*omega;
7636           zeco = yf*yf*(1.0 - 1.0/sqrt(1.0 + tau));
7637           zeta = 1.0 - zeco;
7638         }
7639       }
7640 
7641       if (zeta < -1.0) {
7642         if (zeta < -1.0-tol) {
7643           *phip = 0.0;
7644           *thetap = 0.0;
7645           *(statp++) = 1;
7646           if (!status) status = PRJERR_BAD_PIX_SET("qscx2s");
7647           continue;
7648         }
7649 
7650         zeta = -1.0;
7651         zeco =  2.0;
7652         w    =  0.0;
7653       } else {
7654         w = sqrt(zeco*(2.0-zeco)/tau);
7655       }
7656 
7657       switch (face) {
7658       case 1:
7659         l = zeta;
7660         if (direct) {
7661           m = w;
7662           if (xf < 0.0) m = -m;
7663           n = m*omega;
7664         } else {
7665           n = w;
7666           if (yf < 0.0) n = -n;
7667           m = n*omega;
7668         }
7669         break;
7670       case 2:
7671         m = zeta;
7672         if (direct) {
7673           l = w;
7674           if (xf > 0.0) l = -l;
7675           n = -l*omega;
7676         } else {
7677           n = w;
7678           if (yf < 0.0) n = -n;
7679           l = -n*omega;
7680         }
7681         break;
7682       case 3:
7683         l = -zeta;
7684         if (direct) {
7685           m = w;
7686           if (xf > 0.0) m = -m;
7687           n = -m*omega;
7688         } else {
7689           n = w;
7690           if (yf < 0.0) n = -n;
7691           m = -n*omega;
7692         }
7693         break;
7694       case 4:
7695         m = -zeta;
7696         if (direct) {
7697           l = w;
7698           if (xf < 0.0) l = -l;
7699           n = l*omega;
7700         } else {
7701           n = w;
7702           if (yf < 0.0) n = -n;
7703           l = n*omega;
7704         }
7705         break;
7706       case 5:
7707         n = -zeta;
7708         if (direct) {
7709           m = w;
7710           if (xf < 0.0) m = -m;
7711           l = m*omega;
7712         } else {
7713           l = w;
7714           if (yf < 0.0) l = -l;
7715           m = l*omega;
7716         }
7717         break;
7718       default:
7719         // face == 0
7720         n = zeta;
7721         if (direct) {
7722           m = w;
7723           if (xf < 0.0) m = -m;
7724           l = -m*omega;
7725         } else {
7726           l = w;
7727           if (yf > 0.0) l = -l;
7728           m = -l*omega;
7729         }
7730         break;
7731       }
7732 
7733       if (l == 0.0 && m == 0.0) {
7734         *phip = 0.0;
7735       } else {
7736         *phip = atan2d(m, l);
7737       }
7738 
7739       *thetap = asind(n);
7740       *(statp++) = 0;
7741     }
7742   }
7743 
7744 
7745   // Do bounds checking on the native coordinates.
7746   if (prj->bounds&4 && prjbchk(1.0e-13, nx, my, spt, phi, theta, stat)) {
7747     if (!status) status = PRJERR_BAD_PIX_SET("qscx2s");
7748   }
7749 
7750   return status;
7751 }
7752 
7753 //----------------------------------------------------------------------------
7754 
qscs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])7755 int qscs2x(
7756   struct prjprm *prj,
7757   int nphi,
7758   int ntheta,
7759   int spt,
7760   int sxy,
7761   const double phi[],
7762   const double theta[],
7763   double x[],
7764   double y[],
7765   int stat[])
7766 
7767 {
7768   int face, mphi, mtheta, rowlen, rowoff, status;
7769   double cosphi, costhe, eta, l, m, n, omega, p, sinphi, sinthe, t, tau, x0,
7770          xf, xi, y0, yf, zeco, zeta;
7771   const double tol = 1.0e-12;
7772   register int iphi, istat, itheta, *statp;
7773   register const double *phip, *thetap;
7774   register double *xp, *yp;
7775 
7776 
7777   // Initialize.
7778   if (prj == 0x0) return PRJERR_NULL_POINTER;
7779   if (prj->flag != QSC) {
7780     if ((status = qscset(prj))) return status;
7781   }
7782 
7783   if (ntheta > 0) {
7784     mphi   = nphi;
7785     mtheta = ntheta;
7786   } else {
7787     mphi   = 1;
7788     mtheta = 1;
7789     ntheta = nphi;
7790   }
7791 
7792   status = 0;
7793 
7794 
7795   // Do phi dependence.
7796   phip = phi;
7797   rowoff = 0;
7798   rowlen = nphi*sxy;
7799   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
7800     sincosd(*phip, &sinphi, &cosphi);
7801 
7802     xp = x + rowoff;
7803     yp = y + rowoff;
7804     for (itheta = 0; itheta < mtheta; itheta++) {
7805       *xp = cosphi;
7806       *yp = sinphi;
7807       xp += rowlen;
7808       yp += rowlen;
7809     }
7810   }
7811 
7812 
7813   // Do theta dependence.
7814   thetap = theta;
7815   xp = x;
7816   yp = y;
7817   statp = stat;
7818   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
7819     sincosd(*thetap, &sinthe, &costhe);
7820 
7821     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
7822       if (fabs(*thetap) == 90.0) {
7823         *xp = -prj->x0;
7824         *yp = copysign(2.0*prj->w[0], *thetap) - prj->y0;
7825         *(statp++) = 0;
7826         continue;
7827       }
7828 
7829       l = costhe*(*xp);
7830       m = costhe*(*yp);
7831       n = sinthe;
7832 
7833       face = 0;
7834       zeta = n;
7835       if (l > zeta) {
7836         face = 1;
7837         zeta = l;
7838       }
7839       if (m > zeta) {
7840         face = 2;
7841         zeta = m;
7842       }
7843       if (-l > zeta) {
7844         face = 3;
7845         zeta = -l;
7846       }
7847       if (-m > zeta) {
7848         face = 4;
7849         zeta = -m;
7850       }
7851       if (-n > zeta) {
7852         face = 5;
7853         zeta = -n;
7854       }
7855 
7856       zeco = 1.0 - zeta;
7857 
7858       switch (face) {
7859       case 1:
7860         xi  = m;
7861         eta = n;
7862         if (zeco < 1.0e-8) {
7863           // Small angle formula.
7864           t = (*thetap)*D2R;
7865           p = atan2(*yp, *xp);
7866           zeco = (p*p + t*t)/2.0;
7867         }
7868         x0 = 0.0;
7869         y0 = 0.0;
7870         break;
7871       case 2:
7872         xi  = -l;
7873         eta =  n;
7874         if (zeco < 1.0e-8) {
7875           // Small angle formula.
7876           t = (*thetap)*D2R;
7877           p = atan2(*yp, *xp) - PI/2.0;
7878           zeco = (p*p + t*t)/2.0;
7879         }
7880         x0 = 2.0;
7881         y0 = 0.0;
7882         break;
7883       case 3:
7884         xi  = -m;
7885         eta =  n;
7886         if (zeco < 1.0e-8) {
7887           // Small angle formula.
7888           t = (*thetap)*D2R;
7889           p = atan2(*yp, *xp);
7890           p -= copysign(PI, p);
7891           zeco = (p*p + t*t)/2.0;
7892         }
7893         x0 = 4.0;
7894         y0 = 0.0;
7895         break;
7896       case 4:
7897         xi  = l;
7898         eta = n;
7899         if (zeco < 1.0e-8) {
7900           // Small angle formula.
7901           t = (*thetap)*D2R;
7902           p = atan2(*yp, *xp) + PI/2.0;
7903           zeco = (p*p + t*t)/2.0;
7904         }
7905         x0 = 6;
7906         y0 = 0.0;
7907         break;
7908       case 5:
7909         xi  =  m;
7910         eta =  l;
7911         if (zeco < 1.0e-8) {
7912           // Small angle formula.
7913           t = (*thetap + 90.0)*D2R;
7914           zeco = t*t/2.0;
7915         }
7916         x0 =  0.0;
7917         y0 = -2;
7918          break;
7919       default:
7920         // face == 0
7921         xi  =  m;
7922         eta = -l;
7923         if (zeco < 1.0e-8) {
7924           // Small angle formula.
7925           t = (90.0 - *thetap)*D2R;
7926           zeco = t*t/2.0;
7927         }
7928         x0 = 0.0;
7929         y0 = 2.0;
7930         break;
7931       }
7932 
7933       xf = 0.0;
7934       yf = 0.0;
7935       if (xi != 0.0 || eta != 0.0) {
7936         if (-xi > fabs(eta)) {
7937           omega = eta/xi;
7938           tau = 1.0 + omega*omega;
7939           xf  = -sqrt(zeco/(1.0 - 1.0/sqrt(1.0+tau)));
7940           yf  = (xf/15.0)*(atand(omega) - asind(omega/sqrt(tau+tau)));
7941         } else if (xi > fabs(eta)) {
7942           omega = eta/xi;
7943           tau = 1.0 + omega*omega;
7944           xf  =  sqrt(zeco/(1.0 - 1.0/sqrt(1.0+tau)));
7945           yf  = (xf/15.0)*(atand(omega) - asind(omega/sqrt(tau+tau)));
7946         } else if (-eta >= fabs(xi)) {
7947           omega = xi/eta;
7948           tau = 1.0 + omega*omega;
7949           yf  = -sqrt(zeco/(1.0 - 1.0/sqrt(1.0+tau)));
7950           xf  = (yf/15.0)*(atand(omega) - asind(omega/sqrt(tau+tau)));
7951         } else if (eta >= fabs(xi)) {
7952           omega = xi/eta;
7953           tau = 1.0 + omega*omega;
7954           yf  =  sqrt(zeco/(1.0 - 1.0/sqrt(1.0+tau)));
7955           xf  = (yf/15.0)*(atand(omega) - asind(omega/sqrt(tau+tau)));
7956         }
7957       }
7958 
7959       istat = 0;
7960       if (fabs(xf) > 1.0) {
7961         if (fabs(xf) > 1.0+tol) {
7962           istat = 1;
7963           if (!status) status = PRJERR_BAD_WORLD_SET("qscs2x");
7964         }
7965         xf = copysign(1.0, xf);
7966       }
7967       if (fabs(yf) > 1.0) {
7968         if (fabs(yf) > 1.0+tol) {
7969           istat = 1;
7970           if (!status) status = PRJERR_BAD_WORLD_SET("qscs2x");
7971         }
7972         yf = copysign(1.0, yf);
7973       }
7974 
7975       *xp = prj->w[0]*(xf + x0) - prj->x0;
7976       *yp = prj->w[0]*(yf + y0) - prj->y0;
7977       *(statp++) = istat;
7978     }
7979   }
7980 
7981   return status;
7982 }
7983 
7984 /*============================================================================
7985 *   HPX: HEALPix projection.
7986 *
7987 *   Given:
7988 *      prj->pv[1]   H - the number of facets in longitude.
7989 *      prj->pv[2]   K - the number of facets in latitude
7990 *
7991 *   Given and/or returned:
7992 *      prj->r0      Reset to 180/pi if 0.
7993 *      prj->phi0    Reset to 0.0 if undefined.
7994 *      prj->theta0  Reset to 0.0 if undefined.
7995 *
7996 *   Returned:
7997 *      prj->flag     HPX
7998 *      prj->code    "HPX"
7999 *      prj->x0      Fiducial offset in x.
8000 *      prj->y0      Fiducial offset in y.
8001 *      prj->m       True if H is odd.
8002 *      prj->n       True if K is odd.
8003 *      prj->w[0]    r0*(pi/180)
8004 *      prj->w[1]    (180/pi)/r0
8005 *      prj->w[2]    (K-1)/K
8006 *      prj->w[3]    90*K/H
8007 *      prj->w[4]    (K+1)/2
8008 *      prj->w[5]    90*(K-1)/H
8009 *      prj->w[6]    180/H
8010 *      prj->w[7]    H/360
8011 *      prj->w[8]    r0*(pi/180)*(90*K/H)
8012 *      prj->w[9]    r0*(pi/180)*(180/H)
8013 *      prj->prjx2s  Pointer to hpxx2s().
8014 *      prj->prjs2x  Pointer to hpxs2x().
8015 *===========================================================================*/
8016 
hpxset(struct prjprm * prj)8017 int hpxset(struct prjprm *prj)
8018 
8019 {
8020   if (prj == 0x0) return PRJERR_NULL_POINTER;
8021 
8022   prj->flag = HPX;
8023   strcpy(prj->code, "HPX");
8024 
8025   if (undefined(prj->pv[1])) prj->pv[1] = 4.0;
8026   if (undefined(prj->pv[2])) prj->pv[2] = 3.0;
8027 
8028   strcpy(prj->name, "HEALPix");
8029   prj->category  = HEALPIX;
8030   prj->pvrange   = 102;
8031   prj->simplezen = 0;
8032   prj->equiareal = 1;
8033   prj->conformal = 0;
8034   prj->global    = 1;
8035   prj->divergent = 0;
8036 
8037   if (prj->pv[1] <= 0.0 || prj->pv[2] <= 0.0) {
8038     return PRJERR_BAD_PARAM_SET("hpxset");
8039   }
8040 
8041   prj->m = ((int)(prj->pv[1]+0.5))%2;
8042   prj->n = ((int)(prj->pv[2]+0.5))%2;
8043 
8044   if (prj->r0 == 0.0) {
8045     prj->r0 = R2D;
8046     prj->w[0] = 1.0;
8047     prj->w[1] = 1.0;
8048   } else {
8049     prj->w[0] = prj->r0*D2R;
8050     prj->w[1] = R2D/prj->r0;
8051   }
8052 
8053   prj->w[2] = (prj->pv[2] - 1.0) / prj->pv[2];
8054   prj->w[3] = 90.0 * prj->pv[2] / prj->pv[1];
8055   prj->w[4] = (prj->pv[2] + 1.0) / 2.0;
8056   prj->w[5] = 90.0 * (prj->pv[2] - 1.0) / prj->pv[1];
8057   prj->w[6] = 180.0 / prj->pv[1];
8058   prj->w[7] = prj->pv[1] / 360.0;
8059   prj->w[8] = prj->w[3] * prj->w[0];
8060   prj->w[9] = prj->w[6] * prj->w[0];
8061 
8062   prj->prjx2s = hpxx2s;
8063   prj->prjs2x = hpxs2x;
8064 
8065   return prjoff(prj, 0.0, 0.0);
8066 }
8067 
8068 //----------------------------------------------------------------------------
8069 
hpxx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])8070 int hpxx2s(
8071   struct prjprm *prj,
8072   int nx,
8073   int ny,
8074   int sxy,
8075   int spt,
8076   const double x[],
8077   const double y[],
8078   double phi[],
8079   double theta[],
8080   int stat[])
8081 
8082 {
8083   int h, mx, my, offset, rowlen, rowoff, status;
8084   double absy, r, s, sigma, slim, t, ylim, yr;
8085   register int istat, ix, iy, *statp;
8086   register const double *xp, *yp;
8087   register double *phip, *thetap;
8088 
8089 
8090   // Initialize.
8091   if (prj == 0x0) return PRJERR_NULL_POINTER;
8092   if (prj->flag != HPX) {
8093     if ((status = hpxset(prj))) return status;
8094   }
8095 
8096   slim = prj->w[6] + 1e-12;
8097   ylim = prj->w[9] * prj->w[4];
8098 
8099   if (ny > 0) {
8100     mx = nx;
8101     my = ny;
8102   } else {
8103     mx = 1;
8104     my = 1;
8105     ny = nx;
8106   }
8107 
8108   status = 0;
8109 
8110 
8111   // Do x dependence.
8112   xp = x;
8113   rowoff = 0;
8114   rowlen = nx*spt;
8115   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
8116     s = prj->w[1] * (*xp + prj->x0);
8117     // x_c for K odd or theta > 0.
8118     t = -180.0 + (2.0 * floor((*xp + 180.0) * prj->w[7]) + 1.0) * prj->w[6];
8119     t = prj->w[1] * (*xp - t);
8120 
8121     phip   = phi + rowoff;
8122     thetap = theta + rowoff;
8123     for (iy = 0; iy < my; iy++) {
8124       // theta[] is used to hold (x - x_c).
8125       *phip   = s;
8126       *thetap = t;
8127       phip   += rowlen;
8128       thetap += rowlen;
8129     }
8130   }
8131 
8132 
8133   // Do y dependence.
8134   yp = y;
8135   phip   = phi;
8136   thetap = theta;
8137   statp  = stat;
8138   for (iy = 0; iy < ny; iy++, yp += sxy) {
8139     yr = prj->w[1]*(*yp + prj->y0);
8140     absy = fabs(yr);
8141 
8142     istat = 0;
8143     if (absy <= prj->w[5]) {
8144       // Equatorial regime.
8145       t = asind(yr/prj->w[3]);
8146       for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
8147         *thetap = t;
8148         *(statp++) = 0;
8149       }
8150 
8151     } else if (absy <= ylim) {
8152       // Polar regime.
8153       offset = (prj->n || *yp > 0.0) ? 0 : 1;
8154 
8155       sigma = prj->w[4] - absy / prj->w[6];
8156 
8157       if (sigma == 0.0) {
8158         s = 1e9;
8159         t = 90.0;
8160 
8161       } else {
8162         t = 1.0 - sigma*sigma/prj->pv[2];
8163         if (t < -1.0) {
8164           s = 0.0;
8165           t = 0.0;
8166           istat = 1;
8167           if (!status) status = PRJERR_BAD_PIX_SET("hpxx2s");
8168         } else {
8169           s = 1.0/sigma;
8170           t = asind(t);
8171         }
8172       }
8173       if (*yp < 0.0) t = -t;
8174 
8175       for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
8176         if (offset) {
8177           // Offset the southern polar half-facets for even K.
8178           h = (int)floor(*phip / prj->w[6]) + prj->m;
8179           if (h%2) {
8180             *thetap -= prj->w[6];
8181           } else {
8182             *thetap += prj->w[6];
8183           }
8184         }
8185 
8186         // Recall that theta[] holds (x - x_c).
8187         r = s * *thetap;
8188 
8189         // Bounds checking.
8190         if (prj->bounds&2) {
8191           if (slim <= fabs(r)) {
8192             istat = 1;
8193             if (!status) status = PRJERR_BAD_PIX_SET("hpxx2s");
8194           }
8195         }
8196 
8197         if (r != 0.0) r -= *thetap;
8198         *phip  += r;
8199         *thetap = t;
8200 
8201         *(statp++) = istat;
8202       }
8203 
8204     } else {
8205       // Beyond latitude range.
8206       for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
8207         *phip   = 0.0;
8208         *thetap = 0.0;
8209         *(statp++) = 1;
8210       }
8211       if (!status) status = PRJERR_BAD_PIX_SET("hpxx2s");
8212     }
8213   }
8214 
8215 
8216   // Do bounds checking on the native coordinates.
8217   if (prj->bounds&4 && prjbchk(1.0e-12, nx, my, spt, phi, theta, stat)) {
8218     if (!status) status = PRJERR_BAD_PIX_SET("hpxx2s");
8219   }
8220 
8221   return status;
8222 }
8223 
8224 //----------------------------------------------------------------------------
8225 
hpxs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])8226 int hpxs2x(
8227   struct prjprm *prj,
8228   int nphi,
8229   int ntheta,
8230   int spt,
8231   int sxy,
8232   const double phi[],
8233   const double theta[],
8234   double x[],
8235   double y[],
8236   int stat[])
8237 
8238 {
8239   int h, mphi, mtheta, offset, rowlen, rowoff, status;
8240   double abssin, eta, sigma, sinthe, t, xi;
8241   register int iphi, itheta, *statp;
8242   register const double *phip, *thetap;
8243   register double *xp, *yp;
8244 
8245 
8246   // Initialize.
8247   if (prj == 0x0) return PRJERR_NULL_POINTER;
8248   if (prj->flag != HPX) {
8249     if ((status = hpxset(prj))) return status;
8250   }
8251 
8252   if (ntheta > 0) {
8253     mphi   = nphi;
8254     mtheta = ntheta;
8255   } else {
8256     mphi   = 1;
8257     mtheta = 1;
8258     ntheta = nphi;
8259   }
8260 
8261 
8262   // Do phi dependence.
8263   phip = phi;
8264   rowoff = 0;
8265   rowlen = nphi*sxy;
8266   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
8267     xi = prj->w[0] * (*phip) - prj->x0;
8268 
8269     // phi_c for K odd or theta > 0.
8270     t = -180.0 + (2.0*floor((*phip+180.0) * prj->w[7]) + 1.0) * prj->w[6];
8271     t = prj->w[0] * (*phip - t);
8272 
8273     xp = x + rowoff;
8274     yp = y + rowoff;
8275     for (itheta = 0; itheta < mtheta; itheta++) {
8276       // y[] is used to hold (phi - phi_c).
8277       *xp = xi;
8278       *yp = t;
8279       xp += rowlen;
8280       yp += rowlen;
8281     }
8282   }
8283 
8284 
8285   // Do theta dependence.
8286   thetap = theta;
8287   xp = x;
8288   yp = y;
8289   statp = stat;
8290   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
8291     sinthe = sind(*thetap);
8292     abssin = fabs(sinthe);
8293 
8294     if (abssin <= prj->w[2]) {
8295       // Equatorial regime.
8296       eta = prj->w[8] * sinthe - prj->y0;
8297       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
8298         *yp = eta;
8299         *(statp++) = 0;
8300       }
8301 
8302     } else {
8303       // Polar regime.
8304       offset = (prj->n || *thetap > 0.0) ? 0 : 1;
8305 
8306       sigma = sqrt(prj->pv[2]*(1.0 - abssin));
8307       xi = sigma - 1.0;
8308 
8309       eta = prj->w[9] * (prj->w[4] - sigma);
8310       if (*thetap < 0) eta = -eta;
8311       eta -= prj->y0;
8312 
8313       for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
8314         if (offset) {
8315           // Offset the southern polar half-facets for even K.
8316           h = (int)floor((*xp + prj->x0) / prj->w[9]) + prj->m;
8317           if (h%2) {
8318             *yp -= prj->w[9];
8319           } else {
8320             *yp += prj->w[9];
8321           }
8322         }
8323 
8324         // Recall that y[] holds (phi - phi_c).
8325         *xp += *yp * xi;
8326         *yp = eta;
8327         *(statp++) = 0;
8328 
8329         // Put the phi = 180 meridian in the expected place.
8330         if (180.0 < *xp) *xp = 360.0 - *xp;
8331       }
8332     }
8333   }
8334 
8335   return 0;
8336 }
8337 
8338 /*============================================================================
8339 *   XPH: HEALPix polar, aka "butterfly" projection.
8340 *
8341 *   Given and/or returned:
8342 *      prj->r0      Reset to 180/pi if 0.
8343 *      prj->phi0    Reset to 0.0 if undefined.
8344 *      prj->theta0  Reset to 0.0 if undefined.
8345 *
8346 *   Returned:
8347 *      prj->flag     XPH
8348 *      prj->code    "XPH"
8349 *      prj->x0      Fiducial offset in x.
8350 *      prj->y0      Fiducial offset in y.
8351 *      prj->w[0]    r0*(pi/180)/sqrt(2)
8352 *      prj->w[1]    (180/pi)/r0/sqrt(2)
8353 *      prj->w[2]    2/3
8354 *      prj->w[3]    tol (= 1e-4)
8355 *      prj->w[4]    sqrt(2/3)*(180/pi)
8356 *      prj->w[5]    90 - tol*sqrt(2/3)*(180/pi)
8357 *      prj->w[6]    sqrt(3/2)*(pi/180)
8358 *      prj->prjx2s  Pointer to xphx2s().
8359 *      prj->prjs2x  Pointer to xphs2x().
8360 *===========================================================================*/
8361 
xphset(struct prjprm * prj)8362 int xphset(struct prjprm *prj)
8363 
8364 {
8365   if (prj == 0x0) return PRJERR_NULL_POINTER;
8366 
8367   prj->flag = XPH;
8368   strcpy(prj->code, "XPH");
8369 
8370   strcpy(prj->name, "butterfly");
8371   prj->category  = HEALPIX;
8372   prj->pvrange   = 0;
8373   prj->simplezen = 0;
8374   prj->equiareal = 1;
8375   prj->conformal = 0;
8376   prj->global    = 1;
8377   prj->divergent = 0;
8378 
8379   if (prj->r0 == 0.0) {
8380     prj->r0 = R2D;
8381     prj->w[0] = 1.0;
8382     prj->w[1] = 1.0;
8383   } else {
8384     prj->w[0] = prj->r0*D2R;
8385     prj->w[1] = R2D/prj->r0;
8386   }
8387 
8388   prj->w[0] /= sqrt(2.0);
8389   prj->w[1] /= sqrt(2.0);
8390   prj->w[2]  = 2.0/3.0;
8391   prj->w[3]  = 1e-4;
8392   prj->w[4]  = sqrt(prj->w[2])*R2D;
8393   prj->w[5]  = 90.0 - prj->w[3]*prj->w[4];
8394   prj->w[6]  = sqrt(1.5)*D2R;
8395 
8396   prj->prjx2s = xphx2s;
8397   prj->prjs2x = xphs2x;
8398 
8399   return prjoff(prj, 0.0, 90.0);
8400 }
8401 
8402 //----------------------------------------------------------------------------
8403 
xphx2s(struct prjprm * prj,int nx,int ny,int sxy,int spt,const double x[],const double y[],double phi[],double theta[],int stat[])8404 int xphx2s(
8405   struct prjprm *prj,
8406   int nx,
8407   int ny,
8408   int sxy,
8409   int spt,
8410   const double x[],
8411   const double y[],
8412   double phi[],
8413   double theta[],
8414   int stat[])
8415 
8416 {
8417   int mx, my, rowlen, rowoff, status;
8418   double abseta, eta, eta1, sigma, xi, xi1, xr, yr;
8419   const double tol = 1.0e-12;
8420   register int istat, ix, iy, *statp;
8421   register const double *xp, *yp;
8422   register double *phip, *thetap;
8423 
8424 
8425   // Initialize.
8426   if (prj == 0x0) return PRJERR_NULL_POINTER;
8427   if (prj->flag != XPH) {
8428     if ((status = xphset(prj))) return status;
8429   }
8430 
8431   if (ny > 0) {
8432     mx = nx;
8433     my = ny;
8434   } else {
8435     mx = 1;
8436     my = 1;
8437     ny = nx;
8438   }
8439 
8440   status = 0;
8441 
8442 
8443   // Do x dependence.
8444   xp = x;
8445   rowoff = 0;
8446   rowlen = nx*spt;
8447   for (ix = 0; ix < nx; ix++, rowoff += spt, xp += sxy) {
8448     xr = (*xp + prj->x0)*prj->w[1];
8449 
8450     phip = phi + rowoff;
8451     for (iy = 0; iy < my; iy++) {
8452       *phip = xr;
8453       phip  += rowlen;
8454     }
8455   }
8456 
8457 
8458   // Do y dependence.
8459   yp = y;
8460   phip   = phi;
8461   thetap = theta;
8462   statp  = stat;
8463   for (iy = 0; iy < ny; iy++, yp += sxy) {
8464     yr = (*yp + prj->y0)*prj->w[1];
8465 
8466     for (ix = 0; ix < mx; ix++, phip += spt, thetap += spt) {
8467       xr = *phip;
8468 
8469       if (xr <= 0.0 && 0.0 < yr) {
8470         xi1  = -xr - yr;
8471         eta1 =  xr - yr;
8472         *phip = -180.0;
8473       } else if (xr < 0.0 && yr <= 0.0) {
8474         xi1  =  xr - yr;
8475         eta1 =  xr + yr;
8476         *phip = -90.0;
8477       } else if (0.0 <= xr && yr < 0.0) {
8478         xi1  =  xr + yr;
8479         eta1 = -xr + yr;
8480         *phip = 0.0;
8481       } else {
8482         xi1  = -xr + yr;
8483         eta1 = -xr - yr;
8484         *phip = 90.0;
8485       }
8486 
8487       xi  = xi1  + 45.0;
8488       eta = eta1 + 90.0;
8489       abseta = fabs(eta);
8490 
8491       if (abseta <= 90.0) {
8492         if (abseta <= 45.0) {
8493           // Equatorial regime.
8494           *phip  += xi;
8495           *thetap = asind(eta/67.5);
8496           istat = 0;
8497 
8498           // Bounds checking.
8499           if (prj->bounds&2) {
8500             if (45.0+tol < fabs(xi1)) {
8501               istat = 1;
8502               if (!status) status = PRJERR_BAD_PIX_SET("xphx2s");
8503             }
8504           }
8505 
8506           *(statp++) = istat;
8507 
8508         } else {
8509           // Polar regime.
8510           sigma = (90.0 - abseta) / 45.0;
8511 
8512           // Ensure an exact result for points on the boundary.
8513           if (xr == 0.0) {
8514             if (yr <= 0.0) {
8515               *phip = 0.0;
8516             } else {
8517               *phip = 180.0;
8518             }
8519           } else if (yr == 0.0) {
8520             if (xr < 0.0) {
8521               *phip = -90.0;
8522             } else {
8523               *phip =  90.0;
8524             }
8525           } else {
8526             *phip += 45.0 + xi1/sigma;
8527           }
8528 
8529           if (sigma < prj->w[3]) {
8530             *thetap = 90.0 - sigma*prj->w[4];
8531           } else {
8532             *thetap = asind(1.0 - sigma*sigma/3.0);
8533           }
8534           if (eta < 0.0) *thetap = -(*thetap);
8535 
8536           // Bounds checking.
8537           istat = 0;
8538           if (prj->bounds&2) {
8539             if (eta < -45.0 && eta+90.0+tol < fabs(xi1)) {
8540               istat = 1;
8541               if (!status) status = PRJERR_BAD_PIX_SET("xphx2s");
8542             }
8543           }
8544 
8545           *(statp++) = istat;
8546         }
8547 
8548       } else {
8549         // Beyond latitude range.
8550         *phip   = 0.0;
8551         *thetap = 0.0;
8552         *(statp++) = 1;
8553         if (!status) status = PRJERR_BAD_PIX_SET("xphx2s");
8554       }
8555     }
8556   }
8557 
8558 
8559   // Do bounds checking on the native coordinates.
8560   if (prj->bounds&4 && prjbchk(1.0e-12, nx, my, spt, phi, theta, stat)) {
8561     if (!status) status = PRJERR_BAD_PIX_SET("xphx2s");
8562   }
8563 
8564   return status;
8565 }
8566 
8567 //----------------------------------------------------------------------------
8568 
xphs2x(struct prjprm * prj,int nphi,int ntheta,int spt,int sxy,const double phi[],const double theta[],double x[],double y[],int stat[])8569 int xphs2x(
8570   struct prjprm *prj,
8571   int nphi,
8572   int ntheta,
8573   int spt,
8574   int sxy,
8575   const double phi[],
8576   const double theta[],
8577   double x[],
8578   double y[],
8579   int stat[])
8580 
8581 {
8582   int mphi, mtheta, rowlen, rowoff, status;
8583   double abssin, chi, eta, psi, sigma, sinthe, xi;
8584   register int iphi, itheta, *statp;
8585   register const double *phip, *thetap;
8586   register double *xp, *yp;
8587 
8588 
8589   // Initialize.
8590   if (prj == 0x0) return PRJERR_NULL_POINTER;
8591   if (prj->flag != XPH) {
8592     if ((status = xphset(prj))) return status;
8593   }
8594 
8595   if (ntheta > 0) {
8596     mphi   = nphi;
8597     mtheta = ntheta;
8598   } else {
8599     mphi   = 1;
8600     mtheta = 1;
8601     ntheta = nphi;
8602   }
8603 
8604 
8605   // Do phi dependence.
8606   phip = phi;
8607   rowoff = 0;
8608   rowlen = nphi*sxy;
8609   for (iphi = 0; iphi < nphi; iphi++, rowoff += sxy, phip += spt) {
8610     chi = *phip;
8611     if (180.0 <= fabs(chi)) {
8612       chi = fmod(chi, 360.0);
8613       if (chi < -180.0) {
8614         chi += 360.0;
8615       } else if (180.0 <= chi) {
8616         chi -= 360.0;
8617       }
8618     }
8619 
8620     // phi is also recomputed from chi to avoid rounding problems.
8621     chi += 180.0;
8622     psi = fmod(chi, 90.0);
8623 
8624     xp = x + rowoff;
8625     yp = y + rowoff;
8626     for (itheta = 0; itheta < mtheta; itheta++) {
8627       // y[] is used to hold phi (rounded).
8628       *xp = psi;
8629       *yp = chi - 180.0;
8630       xp += rowlen;
8631       yp += rowlen;
8632     }
8633   }
8634 
8635 
8636   // Do theta dependence.
8637   thetap = theta;
8638   xp = x;
8639   yp = y;
8640   statp = stat;
8641   for (itheta = 0; itheta < ntheta; itheta++, thetap += spt) {
8642     sinthe = sind(*thetap);
8643     abssin = fabs(sinthe);
8644 
8645     for (iphi = 0; iphi < mphi; iphi++, xp += sxy, yp += sxy) {
8646       if (abssin <= prj->w[2]) {
8647         // Equatorial regime.
8648         xi  = *xp;
8649         eta = 67.5 * sinthe;
8650 
8651       } else {
8652         // Polar regime.
8653         if (*thetap < prj->w[5]) {
8654           sigma = sqrt(3.0*(1.0 - abssin));
8655         } else {
8656           sigma = (90.0 - *thetap)*prj->w[6];
8657         }
8658 
8659         xi  = 45.0 + (*xp - 45.0)*sigma;
8660         eta = 45.0 * (2.0 - sigma);
8661         if (*thetap < 0.0) eta = -eta;
8662       }
8663 
8664       xi  -= 45.0;
8665       eta -= 90.0;
8666 
8667       // Recall that y[] holds phi.
8668       if (*yp < -90.0) {
8669         *xp = prj->w[0]*(-xi + eta) - prj->x0;
8670         *yp = prj->w[0]*(-xi - eta) - prj->y0;
8671 
8672       } else if (*yp <  0.0) {
8673         *xp = prj->w[0]*(+xi + eta) - prj->x0;
8674         *yp = prj->w[0]*(-xi + eta) - prj->y0;
8675 
8676       } else if (*yp < 90.0) {
8677         *xp = prj->w[0]*( xi - eta) - prj->x0;
8678         *yp = prj->w[0]*( xi + eta) - prj->y0;
8679 
8680       } else {
8681         *xp = prj->w[0]*(-xi - eta) - prj->x0;
8682         *yp = prj->w[0]*( xi - eta) - prj->y0;
8683       }
8684 
8685       *(statp++) = 0;
8686     }
8687   }
8688 
8689   return 0;
8690 }
8691