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