1 /*
2 *class++
3 *  Name:
4 *     WcsMap
5 
6 *  Purpose:
7 *     Implement a FITS-WCS sky projection.
8 
9 *  Constructor Function:
10 c     astWcsMap
11 f     AST_WCSMAP
12 
13 *  Description:
14 *     This class is used to represent sky coordinate projections as
15 *     described in the FITS world coordinate system (FITS-WCS) paper II
16 *     "Representations of Celestial Coordinates in FITS" by M. Calabretta
17 *     and E.W. Griesen. This paper defines a set of functions, or sky
18 *     projections, which transform longitude-latitude pairs representing
19 *     spherical celestial coordinates into corresponding pairs of Cartesian
20 *     coordinates (and vice versa).
21 *
22 *     A WcsMap is a specialised form of Mapping which implements these
23 *     sky projections and applies them to a specified pair of coordinates.
24 *     All the projections in the FITS-WCS paper are supported, plus the now
25 *     deprecated "TAN with polynomial correction terms" projection which
26 *     is refered to here by the code "TPN". Using the FITS-WCS terminology,
27 *     the transformation is between "native spherical" and "projection
28 *     plane" coordinates (also called "intermediate world coordinates".
29 *     These coordinates may, optionally, be embedded in a space with more
30 *     than two dimensions, the remaining coordinates being copied unchanged.
31 *     Note, however, that for consistency with other AST facilities, a
32 *     WcsMap handles coordinates that represent angles in radians (rather
33 *     than the degrees used by FITS-WCS).
34 *
35 *     The type of FITS-WCS projection to be used and the coordinates
36 *     (axes) to which it applies are specified when a WcsMap is first
37 *     created. The projection type may subsequently be determined
38 *     using the WcsType attribute and the coordinates on which it acts
39 *     may be determined using the WcsAxis(lonlat) attribute.
40 *
41 *     Each WcsMap also allows up to 100 "projection parameters" to be
42 *     associated with each axis. These specify the precise form of the
43 *     projection, and are accessed using PVi_m attribute, where "i" is
44 *     the integer axis index (starting at 1), and m is an integer
45 *     "parameter index" in the range 0 to 99. The number of projection
46 *     parameters required by each projection, and their meanings, are
47 *     dependent upon the projection type (most projections either do not
48 *     use any projection parameters, or use parameters 1 and 2 associated
49 *     with the latitude axis). Before creating a WcsMap you should consult
50 *     the FITS-WCS paper for details of which projection parameters are
51 *     required, and which have defaults. When creating the WcsMap, you must
52 *     explicitly set values for all those required projection parameters
53 *     which do not have defaults defined in this paper.
54 
55 *  Inheritance:
56 *     The WcsMap class inherits from the Mapping class.
57 
58 *  Attributes:
59 *     In addition to those attributes common to all Mappings, every
60 *     WcsMap also has the following attributes:
61 *
62 *     - NatLat: Native latitude of the reference point of a FITS-WCS projection
63 *     - NatLon: Native longitude of the reference point of a FITS-WCS projection
64 *     - PVi_m: FITS-WCS projection parameters
65 *     - PVMax: Maximum number of FITS-WCS projection parameters
66 *     - WcsAxis(lonlat): FITS-WCS projection axes
67 *     - WcsType: FITS-WCS projection type
68 
69 *  Functions:
70 c     The WcsMap class does not define any new functions beyond those
71 f     The WcsMap class does not define any new routines beyond those
72 *     which are applicable to all Mappings.
73 
74 *  Copyright:
75 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
76 *     Research Councils
77 
78 *  Licence:
79 *     This program is free software: you can redistribute it and/or
80 *     modify it under the terms of the GNU Lesser General Public
81 *     License as published by the Free Software Foundation, either
82 *     version 3 of the License, or (at your option) any later
83 *     version.
84 *
85 *     This program is distributed in the hope that it will be useful,
86 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
87 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
88 *     GNU Lesser General Public License for more details.
89 *
90 *     You should have received a copy of the GNU Lesser General
91 *     License along with this program.  If not, see
92 *     <http://www.gnu.org/licenses/>.
93 
94 *  Authors:
95 *     DSB: D.S. Berry (Starlink)
96 *     RFWS: R.F. Warren-Smith (Starlink)
97 
98 *  History:
99 *     15-FEB-1996 (DSB):
100 *        Original version.
101 *     23-MAR-1996 (DSB):
102 *        Added support for PointSets with more than 2 axes.
103 *     14-NOV-1996 (DSB):
104 *        Added I/O facilities, external interface, attributes, etc.
105 *     16-JAN-1997 (DSB):
106 *        Allowed WCSBAD as a projection type in astWcsMap.
107 *     24-APR-1997 (RFWS):
108 *        Tidied prologues.
109 *     26-SEP-1997 (DSB):
110 *        o  Long descriptions of projections changed to include a textual
111 *        description as well as the three letter acronym.
112 *        o  Added protected function astPrjDesc.
113 *        o  String values now used instead of integers to represent
114 *        "choice" attributes externally (eg WcsType).
115 *     8-APR-1998 (DSB):
116 *        Modified MapMerge so that a WcsMap can merge with its own
117 *        inverse when astSimplify is used.
118 *     20-APR-1998 (DSB):
119 *        Modified MapMerge to avoid the possibility of returning an
120 *        empty mappings list.
121 *     4-SEP-1998 (DSB):
122 *        Changed MapMerge to allow WcsMaps to swap with PermMaps in
123 *        order to bring mergable WcsMaps closer together.
124 *     5-MAY-1999 (DSB):
125 *        More corrections to MapMerge: Cleared up errors in the use of the
126 *        supplied invert flags, and corrected logic for deciding which
127 *        neighbouring Mapping to swap with.
128 *     12-JUL-1999 (DSB):
129 *        -  Report an error if too many or two few projection parameters are
130 *        supplied in a WcsMap.
131 *        -  Corrected MapMerge to prevent unset projection parameters
132 *        being copied to any new WcsMaps.
133 *        -  Correct handling of invert flags in WcsPerm.
134 *     16-JUL-1999 (DSB):
135 *        Fixed memory leak in MapMerge.
136 *     11-FEB-2000 (DSB):
137 *        Added PVj_m attributes. Attributes ProjP(0) to ProjP(9) are now
138 *        aliases for PV(axlat)_0 to PV(axlat)_9. Renamed GLS projection
139 *        as SFL (GLS retained as alias for SFL).
140 *     10-AUG-2000 (DSB):
141 *        MapMerge no longer simplifies a CAR projection. Previously they
142 *        were replaced by a UnitMap, but this removed the cylic nature of
143 *        the mapping (i.e. 2.PI == 0 ).
144 *     6-OCT-2000 (DSB):
145 *        Ignore leading and trailing spaces in astWCsPrjType (some
146 *        CTYPE FITS keywords have appeared with trailing white space).
147 *     26-SEP-2001 (DSB):
148 *        Changed names of all functions and structure to avoid name clashes
149 *        with wcslib.
150 *     10-OCT-2002 (DSB):
151 *        Added astIsZenithal.
152 *     22-OCT-2002 (DSB):
153 *        - GetPV now returns the FITS default value instead of AST__BAD
154 *        if a defaultable latitude projection parameter has not been set.
155 *        - A number of changes needed to support WcsLib v2.9.
156 *        - Added AST__TPN projection.
157 *     8-JAN-2003 (DSB):
158 *        Changed private InitVtab method to protected astInitWcsMapVtab
159 *        method.
160 *     4-JUN-2003 (DSB):
161 *        - Added attribute "NatLon".
162 *        - Changed to allow a user-specified fiducial point to be stored
163 *        in projection parameter PVi_1 and PVi_2 for the longitude axis.
164 *        - Changed "PVj_m" to "PVi_m" for consistency with FITS-WCS paper II.
165 *     18-AUG-2003 (DSB):
166 *        In function Map, assign zero longitude to output positions which
167 *        are very close to a pole.
168 *     23-SEP-2003 (DSB):
169 *        - Changed so that the NatLat and NatLon attributes refer to the
170 *        fixed values for the projections defined in FITS-WCS paper II, rather
171 *        than the user-defined values stored in projection parameter PVi_1 and
172 *        PVi_2 for the longitude axis.
173 *     11-FEB-2004 (DSB):
174 *        Corrected axis numbering when reporting missing keywords in
175 *        Transform.
176 *     23-APR-2004 (DSB):
177 *        Changes to simplification algorithm.
178 *     1-SEP-2004 (DSB):
179 *        CopyPV rewritten to avoid assumption that the input and output
180 *        WcsMaps have the same number of axes and that the lon/lat axes have
181 *        the same indices.
182 *     7-DEC-2005 (DSB):
183 *        Free memory allocated by calls to astReadString.
184 *     14-FEB-2006 (DSB):
185 *        Override astGetObjSize.
186 *     15-FEB-2006 (DSB):
187 *        Use dynamic rather than static memory for the parameter arrays in
188 *        the AstPrjPrm structure.Override astGetObjSize. This is to
189 *        reduce the in-memory size of a WcsMap.
190 *     10-MAY-2006 (DSB):
191 *        Override astEqual.
192 *     10-AUG-2006 (DSB):
193 *        Correct astLoadWcsMap to take acount of the different number of
194 *        PVi_m values that can be associated with each axis.
195 *     4-JAN-2007 (DSB):
196 *        Correct astLoadWcsMap to load the projection parameter with
197 *        highest index correctly.
198 *     23-FEB-2007 (DSB):
199 *        Added HPX projection.
200 *     1-MAR-2011 (DSB):
201 *        In function Map, do not allow valid longitude range to include both
202 *        the high limit and the low limt (since they are both the same point on
203 *        the sky).
204 *     7-MAR-2011 (DSB):
205 *        In function Map, only do the longitude check if the projection
206 *        is not cyclic.
207 *     24-MAY-2011 (DSB):
208 *        Added protected FITSProj and TPNTan attributes (they should be
209 *        removed when the PolyMap class has an iterative inverse).
210 *     6-MAR-2014 (DSB):
211 *        Revert the change made on 18-AUG-2003 since setting the
212 *        longitude arbitrarily to zero for points close to the pole
213 *        causes significant round trip errors when doing pixel->sky->pixel
214 *        transformation for points very close to the pole, if the pixel
215 *        size is very small. The longitude at the pole is indeterminate,
216 *        but whatever random numerical value is returned by atan2 is
217 *        no less useful (and no more useful) than a fixed value of zero.
218 *     12-JUN-2014 (DSB):
219 *        Added XPH projection.
220 *class--
221 */
222 
223 /* Module Macros. */
224 /* ============== */
225 /* Set the name of the class we are implementing. This indicates to
226    the header files that define class interfaces that they should make
227    "protected" symbols available. */
228 #define astCLASS WcsMap
229 
230 /* Macros which return the maximum and minimum of two values. */
231 #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb))
232 #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb))
233 
234 /* Macros to check for equality of floating point values. We cannot
235    compare bad values directory because of the danger of floating point
236    exceptions, so bad values are dealt with explicitly. */
237 #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN))))
238 
239 /*
240 *
241 *  Name:
242 *     MAKE_CLEAR
243 
244 *  Purpose:
245 *     Implement a method to clear a single value in a multi-valued attribute.
246 
247 *  Type:
248 *     Private macro.
249 
250 *  Synopsis:
251 *     #include "wcsmap.h"
252 *     MAKE_CLEAR(attr,component,assign,nval)
253 
254 *  Class Membership:
255 *     Defined by the WcsMap class.
256 
257 *  Description:
258 *     This macro expands to an implementation of a private member function of
259 *     the form:
260 *
261 *        static void Clear<Attribute>( AstWcsMap *this, int axis )
262 *
263 *     and an external interface function of the form:
264 *
265 *        void astClear<Attribute>_( AstWcsMap *this, int axis )
266 *
267 *     which implement a method for clearing a single value in a specified
268 *     multi-valued attribute for an axis of a WcsMap.
269 
270 *  Parameters:
271 *     attr
272 *        The name of the attribute to be cleared, as it appears in the function
273 *        name (e.g. Label in "astClearLabelAt").
274 *     component
275 *        The name of the class structure component that holds the attribute
276 *        value.
277 *     assign
278 *        An expression that evaluates to the value to assign to the component
279 *        to clear its value. The variable "axis" can be used to refer to
280 *        the zero-based index of the attribute component being cleared.
281 *     nval
282 *        Specifies the number of values in the multi-valued attribute. The
283 *        "axis" values supplied to the created function should be in the
284 *        range zero to (nval - 1).
285 
286 *  Notes:
287 *     -  To avoid problems with some compilers, you should not leave any white
288 *     space around the macro arguments.
289 *
290 */
291 
292 /* Define the macro. */
293 #define MAKE_CLEAR(attr,component,assign,nval) \
294 \
295 /* Private member function. */ \
296 /* ------------------------ */ \
297 static void Clear##attr( AstWcsMap *this, int axis, int *status ) { \
298 \
299 /* Check the global error status. */ \
300    if ( !astOK ) return; \
301 \
302 /* Validate the axis index. */ \
303    if( axis < 0 || axis >= nval ){ \
304       astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \
305                 #attr " - it should be in the range 1 to %d.", status, \
306                 "astClear" #attr, astGetClass( this ), \
307                 axis + 1, nval ); \
308 \
309 /* Assign the "clear" value. */ \
310    } else { \
311       this->component[ axis ] = (assign); \
312    } \
313 } \
314 \
315 /* External interface. */ \
316 /* ------------------- */ \
317 void astClear##attr##_( AstWcsMap *this, int axis, int *status ) { \
318 \
319 /* Check the global error status. */ \
320    if ( !astOK ) return; \
321 \
322 /* Invoke the required method via the virtual function table. */ \
323    (**astMEMBER(this,WcsMap,Clear##attr))( this, axis, status ); \
324 }
325 
326 
327 /*
328 *
329 *  Name:
330 *     MAKE_GET
331 
332 *  Purpose:
333 *     Implement a method to get a single value in a multi-valued attribute.
334 
335 *  Type:
336 *     Private macro.
337 
338 *  Synopsis:
339 *     #include "wcsmap.h"
340 *     MAKE_GET(attr,type,bad_value,assign,nval)
341 
342 *  Class Membership:
343 *     Defined by the WcsMap class.
344 
345 *  Description:
346 *     This macro expands to an implementation of a private member function of
347 *     the form:
348 *
349 *        static <Type> Get<Attribute>( AstWcsMap *this, int axis )
350 *
351 *     and an external interface function of the form:
352 *
353 *        <Type> astGet<Attribute>_( AstWcsMap *this, int axis )
354 *
355 *     which implement a method for getting a single value from a specified
356 *     multi-valued attribute for an axis of a WcsMap.
357 
358 *  Parameters:
359 *     attr
360 *        The name of the attribute whose value is to be obtained, as it
361 *        appears in the function name (e.g. Label in "astGetLabel").
362 *     type
363 *        The C type of the attribute.
364 *     bad_value
365 *        A constant value to return if the global error status is set, or if
366 *        the function fails.
367 *     assign
368 *        An expression that evaluates to the value to be returned. This can
369 *        use the string "axis" to represent the zero-based value index.
370 *     nval
371 *        Specifies the number of values in the multi-valued attribute. The
372 *        "axis" values supplied to the created function should be in the
373 *        range zero to (nval - 1).
374 
375 *  Notes:
376 *     -  To avoid problems with some compilers, you should not leave any white
377 *     space around the macro arguments.
378 *
379 */
380 
381 /* Define the macro. */
382 #define MAKE_GET(attr,type,bad_value,assign,nval) \
383 \
384 /* Private member function. */ \
385 /* ------------------------ */ \
386 static type Get##attr( AstWcsMap *this, int axis, int *status ) { \
387    type result;                  /* Result to be returned */ \
388 \
389 /* Initialise */ \
390    result = (bad_value); \
391 \
392 /* Check the global error status. */ \
393    if ( !astOK ) return result; \
394 \
395 /* Validate the axis index. */ \
396    if( axis < 0 || axis >= nval ){ \
397       astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \
398                 #attr " - it should be in the range 1 to %d.", status, \
399                 "astGet" #attr, astGetClass( this ), \
400                 axis + 1, nval ); \
401 \
402 /* Assign the result value. */ \
403    } else { \
404       result = (assign); \
405    } \
406 \
407 /* Check for errors and clear the result if necessary. */ \
408    if ( !astOK ) result = (bad_value); \
409 \
410 /* Return the result. */ \
411    return result; \
412 } \
413 /* External interface. */ \
414 /* ------------------- */  \
415 type astGet##attr##_( AstWcsMap *this, int axis, int *status ) { \
416 \
417 /* Check the global error status. */ \
418    if ( !astOK ) return (bad_value); \
419 \
420 /* Invoke the required method via the virtual function table. */ \
421    return (**astMEMBER(this,WcsMap,Get##attr))( this, axis, status ); \
422 }
423 
424 /*
425 *
426 *  Name:
427 *     MAKE_SET
428 
429 *  Purpose:
430 *     Implement a method to set a single value in a multi-valued attribute
431 *     for a WcsMap.
432 
433 *  Type:
434 *     Private macro.
435 
436 *  Synopsis:
437 *     #include "wcsmap.h"
438 *     MAKE_SET(attr,type,component,assign,nval)
439 
440 *  Class Membership:
441 *     Defined by the WcsMap class.
442 
443 *  Description:
444 *     This macro expands to an implementation of a private member function of
445 *     the form:
446 *
447 *        static void Set<Attribute>( AstWcsMap *this, int axis, <Type> value )
448 *
449 *     and an external interface function of the form:
450 *
451 *        void astSet<Attribute>_( AstWcsMap *this, int axis, <Type> value )
452 *
453 *     which implement a method for setting a single value in a specified
454 *     multi-valued attribute for a WcsMap.
455 
456 *  Parameters:
457 *      attr
458 *         The name of the attribute to be set, as it appears in the function
459 *         name (e.g. Label in "astSetLabelAt").
460 *      type
461 *         The C type of the attribute.
462 *      component
463 *         The name of the class structure component that holds the attribute
464 *         value.
465 *      assign
466 *         An expression that evaluates to the value to be assigned to the
467 *         component.
468 *      nval
469 *         Specifies the number of values in the multi-valued attribute. The
470 *         "axis" values supplied to the created function should be in the
471 *         range zero to (nval - 1).
472 
473 *  Notes:
474 *     -  To avoid problems with some compilers, you should not leave any white
475 *     space around the macro arguments.
476 *-
477 */
478 
479 /* Define the macro. */
480 #define MAKE_SET(attr,type,component,assign,nval) \
481 \
482 /* Private member function. */ \
483 /* ------------------------ */ \
484 static void Set##attr( AstWcsMap *this, int axis, type value, int *status ) { \
485 \
486 /* Check the global error status. */ \
487    if ( !astOK ) return; \
488 \
489 /* Validate the axis index. */ \
490    if( axis < 0 || axis >= nval ){ \
491       astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \
492                 #attr " - it should be in the range 1 to %d.", status, \
493                 "astSet" #attr, astGetClass( this ), \
494                 axis + 1, nval ); \
495 \
496 /* Store the new value in the structure component. */ \
497    } else { \
498       this->component[ axis ] = (assign); \
499    } \
500 } \
501 \
502 /* External interface. */ \
503 /* ------------------- */ \
504 void astSet##attr##_( AstWcsMap *this, int axis, type value, int *status ) { \
505 \
506 /* Check the global error status. */ \
507    if ( !astOK ) return; \
508 \
509 /* Invoke the required method via the virtual function table. */ \
510    (**astMEMBER(this,WcsMap,Set##attr))( this, axis, value, status ); \
511 }
512 
513 /*
514 *
515 *  Name:
516 *     MAKE_TEST
517 
518 *  Purpose:
519 *     Implement a method to test if a single value has been set in a
520 *     multi-valued attribute for a class.
521 
522 *  Type:
523 *     Private macro.
524 
525 *  Synopsis:
526 *     #include "wcsmap.h"
527 *     MAKE_TEST(attr,assign,nval)
528 
529 *  Class Membership:
530 *     Defined by the WcsMap class.
531 
532 *  Description:
533 *     This macro expands to an implementation of a private member function of
534 *     the form:
535 *
536 *        static int Test<Attribute>( AstWcsMap *this, int axis )
537 *
538 *     and an external interface function of the form:
539 *
540 *        int astTest<Attribute>_( AstWcsMap *this, int axis )
541 *
542 *     which implement a method for testing if a single value in a specified
543 *     multi-valued attribute has been set for a class.
544 
545 *  Parameters:
546 *      attr
547 *         The name of the attribute to be tested, as it appears in the function
548 *         name (e.g. Label in "astTestLabelAt").
549 *      assign
550 *         An expression that evaluates to 0 or 1, to be used as the returned
551 *         value. This can use the string "axis" to represent the zero-based
552 *         index of the value within the attribute.
553 *      nval
554 *         Specifies the number of values in the multi-valued attribute. The
555 *         "axis" values supplied to the created function should be in the
556 *         range zero to (nval - 1).
557 
558 *  Notes:
559 *     -  To avoid problems with some compilers, you should not leave any white
560 *     space around the macro arguments.
561 *-
562 */
563 
564 /* Define the macro. */
565 #define MAKE_TEST(attr,assign,nval) \
566 \
567 /* Private member function. */ \
568 /* ------------------------ */ \
569 static int Test##attr( AstWcsMap *this, int axis, int *status ) { \
570    int result;                   /* Value to return */ \
571 \
572 /* Initialise */ \
573    result = 0; \
574 \
575 /* Check the global error status. */ \
576    if ( !astOK ) return result; \
577 \
578 \
579 /* Validate the axis index. */ \
580    if( axis < 0 || axis >= nval ){ \
581       astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \
582                 #attr " - it should be in the range 1 to %d.", status, \
583                 "astTest" #attr, astGetClass( this ), \
584                 axis + 1, nval ); \
585 \
586 /* Assign the result value. */ \
587    } else { \
588       result = (assign); \
589    } \
590 \
591 /* Check for errors and clear the result if necessary. */ \
592    if ( !astOK ) result = 0; \
593 \
594 /* Return the result. */ \
595    return result; \
596 } \
597 /* External interface. */ \
598 /* ------------------- */ \
599 int astTest##attr##_( AstWcsMap *this, int axis, int *status ) { \
600 \
601 /* Check the global error status. */ \
602    if ( !astOK ) return 0; \
603 \
604 /* Invoke the required method via the virtual function table. */ \
605    return (**astMEMBER(this,WcsMap,Test##attr))( this, axis, status ); \
606 }
607 
608 
609 /* Include files. */
610 /* ============== */
611 /* Interface definitions. */
612 /* ---------------------- */
613 
614 #include "globals.h"             /* Thread-safe global data access */
615 #include "error.h"               /* Error reporting facilities */
616 #include "memory.h"              /* Memory allocation facilities */
617 #include "globals.h"             /* Thread-safe global data access */
618 #include "object.h"              /* Base Object class */
619 #include "pointset.h"            /* Sets of points/coordinates */
620 #include "mapping.h"             /* Coordinate mappings (parent class) */
621 #include "unitmap.h"             /* Unit mappings */
622 #include "permmap.h"             /* Axis permutation mappings */
623 #include "wcsmap.h"              /* Interface definition for this class */
624 #include "pal.h"                 /* SLALIB function prototypes */
625 #include "channel.h"             /* I/O channels */
626 #include "proj.h"                /* WCSLIB projections and WCSLIB_MXPAR */
627 
628 /* Error code definitions. */
629 /* ----------------------- */
630 #include "ast_err.h"             /* AST error codes */
631 
632 /* C header files. */
633 /* --------------- */
634 #include <ctype.h>
635 #include <math.h>
636 #include <stdio.h>
637 #include <stdlib.h>
638 #include <string.h>
639 #include <limits.h>
640 
641 /* Local Type Definitions. */
642 /* ----------------------- */
643 /* This structure is used to hold information describing a WCSLIB
644    projection. */
645 typedef struct PrjData {
646    int prj;                     /* WCSLIB projection identifier value */
647    int mxpar;                   /* Max index for a lat axis projection param */
648    int mxpar2;                  /* Max index for a lon axis projection param */
649    char desc[60];               /* Long projection description */
650    char ctype[5];               /* FITS CTYPE identifying string */
651    int (* WcsFwd)(double, double, struct AstPrjPrm *, double *, double *);
652                                 /* Pointer to forward projection function */
653    int (* WcsRev)(double, double, struct AstPrjPrm *, double *, double *);
654                                 /* Pointer to reverse projection function */
655    double theta0;               /* Default native latitude of fiducial point */
656 } PrjData;
657 
658 /* Module Variables. */
659 /* ================= */
660 
661 /* Address of this static variable is used as a unique identifier for
662    member of this class. */
663 static int class_check;
664 
665 /* Pointers to parent class methods which are extended by this class. */
666 static int (* parent_getobjsize)( AstObject *, int * );
667 static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
668 static const char *(* parent_getattrib)( AstObject *, const char *, int * );
669 static int (* parent_testattrib)( AstObject *, const char *, int * );
670 static void (* parent_clearattrib)( AstObject *, const char *, int * );
671 static void (* parent_setattrib)( AstObject *, const char *, int * );
672 static int *(* parent_mapsplit)( AstMapping *, int, const int *, AstMapping **, int * );
673 
674 /* The following array of PrjData structured describes each of the WCSLIB
675    projections. The last entry in the list should be for the AST__WCSBAD
676    projection. This marks the end of the list. */
677 static PrjData PrjInfo[] = {
678    { AST__AZP,  2, 4, "zenithal perspective", "-AZP", astAZPfwd, astAZPrev, AST__DPIBY2 },
679    { AST__SZP,  3, 4, "slant zenithal perspective", "-SZP", astSZPfwd, astSZPrev, AST__DPIBY2 },
680    { AST__TAN,  0, 4, "gnomonic", "-TAN",  astTANfwd, astTANrev, AST__DPIBY2 },
681    { AST__STG,  0, 4, "stereographic", "-STG",  astSTGfwd, astSTGrev, AST__DPIBY2 },
682    { AST__SIN,  2, 4, "orthographic", "-SIN",  astSINfwd, astSINrev, AST__DPIBY2 },
683    { AST__ARC,  0, 4, "zenithal equidistant", "-ARC",  astARCfwd, astARCrev, AST__DPIBY2 },
684    { AST__ZPN,  WCSLIB_MXPAR, 4, "zenithal polynomial", "-ZPN",  astZPNfwd, astZPNrev, AST__DPIBY2 },
685    { AST__ZEA,  0, 4, "zenithal equal area", "-ZEA",  astZEAfwd, astZEArev, AST__DPIBY2 },
686    { AST__AIR,  1, 4, "Airy", "-AIR",  astAIRfwd, astAIRrev, AST__DPIBY2 },
687    { AST__CYP,  2, 4, "cylindrical perspective", "-CYP",  astCYPfwd, astCYPrev, 0.0 },
688    { AST__CEA,  1, 4, "cylindrical equal area", "-CEA",  astCEAfwd, astCEArev, 0.0 },
689    { AST__CAR,  0, 4, "Cartesian", "-CAR",  astCARfwd, astCARrev, 0.0 },
690    { AST__MER,  0, 4, "Mercator", "-MER",  astMERfwd, astMERrev, 0.0 },
691    { AST__SFL,  0, 4, "Sanson-Flamsteed", "-SFL",  astSFLfwd, astSFLrev, 0.0 },
692    { AST__PAR,  0, 4, "parabolic", "-PAR",  astPARfwd, astPARrev, 0.0 },
693    { AST__MOL,  0, 4, "Mollweide", "-MOL",  astMOLfwd, astMOLrev, 0.0 },
694    { AST__AIT,  0, 4, "Hammer-Aitoff", "-AIT",  astAITfwd, astAITrev, 0.0 },
695    { AST__COP,  2, 4, "conical perspective", "-COP",  astCOPfwd, astCOPrev, AST__BAD },
696    { AST__COE,  2, 4, "conical equal area", "-COE",  astCOEfwd, astCOErev, AST__BAD },
697    { AST__COD,  2, 4, "conical equidistant", "-COD",  astCODfwd, astCODrev, AST__BAD },
698    { AST__COO,  2, 4, "conical orthomorphic", "-COO",  astCOOfwd, astCOOrev, AST__BAD },
699    { AST__BON,  1, 4, "Bonne's equal area", "-BON",  astBONfwd, astBONrev, 0.0 },
700    { AST__PCO,  0, 4, "polyconic", "-PCO",  astPCOfwd, astPCOrev, 0.0 },
701    { AST__TSC,  0, 4, "tangential spherical cube", "-TSC",  astTSCfwd, astTSCrev, 0.0 },
702    { AST__CSC,  0, 4, "cobe quadrilateralized spherical cube", "-CSC", astCSCfwd, astCSCrev, 0.0 },
703    { AST__QSC,  0, 4, "quadrilateralized spherical cube", "-QSC",  astQSCfwd, astQSCrev, 0.0 },
704    { AST__NCP,  2, 4, "AIPS north celestial pole", "-NCP",  NULL,   NULL, 0.0 },
705    { AST__GLS,  0, 4, "sinusoidal", "-GLS",  astSFLfwd, astSFLrev, 0.0 },
706    { AST__HPX,  2, 4, "HEALPix", "-HPX",  astHPXfwd, astHPXrev, 0.0 },
707    { AST__XPH,  0, 4, "polar HEALPix", "-XPH",  astXPHfwd, astXPHrev, AST__DPIBY2 },
708    { AST__TPN,  WCSLIB_MXPAR, WCSLIB_MXPAR, "gnomonic polynomial", "-TPN",  astTPNfwd, astTPNrev, AST__DPIBY2 },
709    { AST__WCSBAD, 0, 4, "<null>",   "    ",  NULL,   NULL, 0.0 } };
710 
711 /* Define macros for accessing each item of thread specific global data. */
712 #ifdef THREAD_SAFE
713 
714 /* Define how to initialise thread-specific globals. */
715 #define GLOBAL_inits \
716    globals->Class_Init = 0; \
717    globals->GetAttrib_Buff[ 0 ] = 0;
718 
719 /* Create the function that initialises global data for this module. */
720 astMAKE_INITGLOBALS(WcsMap)
721 
722 /* Define macros for accessing each item of thread specific global data. */
723 #define class_init astGLOBAL(WcsMap,Class_Init)
724 #define class_vtab astGLOBAL(WcsMap,Class_Vtab)
725 #define getattrib_buff astGLOBAL(WcsMap,GetAttrib_Buff)
726 
727 
728 
729 /* If thread safety is not needed, declare and initialise globals at static
730    variables. */
731 #else
732 
733 static char getattrib_buff[ 101 ];
734 
735 
736 /* Define the class virtual function table and its initialisation flag
737    as static variables. */
738 static AstWcsMapVtab class_vtab;   /* Virtual function table */
739 static int class_init = 0;       /* Virtual function table initialised? */
740 
741 #endif
742 
743 /* External Interface Function Prototypes. */
744 /* ======================================= */
745 /* The following functions have public prototypes only (i.e. no
746    protected prototypes), so we must provide local prototypes for use
747    within this module. */
748 AstWcsMap *astWcsMapId_( int, int, int, int, const char *options, ... );
749 
750 /* Prototypes for Private Member Functions. */
751 /* ======================================== */
752 static int GetObjSize( AstObject *, int * );
753 static double GetPV( AstWcsMap *, int, int, int * );
754 static int TestPV( AstWcsMap *, int, int, int * );
755 static void ClearPV( AstWcsMap *, int, int, int * );
756 static void SetPV( AstWcsMap *, int, int, double, int * );
757 
758 static int GetPVMax( AstWcsMap *, int, int * );
759 static int GetWcsType( AstWcsMap *, int * );
760 static double GetNatLat( AstWcsMap *, int * );
761 static double GetNatLon( AstWcsMap *, int * );
762 static int GetWcsAxis( AstWcsMap *, int, int * );
763 
764 static int GetFITSProj( AstWcsMap *, int * );
765 static int TestFITSProj( AstWcsMap *, int * );
766 static void ClearFITSProj( AstWcsMap *, int * );
767 static void SetFITSProj( AstWcsMap *, int, int * );
768 
769 static int GetTPNTan( AstWcsMap *, int * );
770 static int TestTPNTan( AstWcsMap *, int * );
771 static void ClearTPNTan( AstWcsMap *, int * );
772 static void SetTPNTan( AstWcsMap *, int, int * );
773 
774 static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
775 static const PrjData *FindPrjData( int, int * );
776 static const char *GetAttrib( AstObject *, const char *, int * );
777 static int CanMerge( AstMapping *, int, AstMapping *, int, int * );
778 static int CanSwap( AstMapping *, AstMapping *, int, int, int *, int * );
779 static int Equal( AstObject *, AstObject *, int * );
780 static int GetNP( AstWcsMap *, int, int * );
781 static int IsZenithal( AstWcsMap *, int * );
782 static int LongRange( const PrjData *, struct AstPrjPrm *, double *, double *, int * );
783 static int Map( AstWcsMap *, int, int, double *, double *, double *, double *, int * );
784 static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * );
785 static int TestAttrib( AstObject *, const char *, int * );
786 static void ClearAttrib( AstObject *, const char *, int * );
787 static void Copy( const AstObject *, AstObject *, int * );
788 static void CopyPV( AstWcsMap *, AstWcsMap *, int * );
789 static void Delete( AstObject *obj, int * );
790 static void Dump( AstObject *, AstChannel *, int * );
791 static void FreePV( AstWcsMap *, int * );
792 static void InitPrjPrm( AstWcsMap *, int * );
793 static void PermGet( AstPermMap *, int **, int **, double **, int * );
794 static void SetAttrib( AstObject *, const char *, int * );
795 static void WcsPerm( AstMapping **, int *, int, int * );
796 static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * );
797 
798 /* Member functions. */
799 /* ================= */
CanMerge(AstMapping * map1,int inv1,AstMapping * map2,int inv2,int * status)800 static int CanMerge( AstMapping *map1, int inv1, AstMapping *map2, int inv2, int *status ){
801 /*
802 *
803 *  Name:
804 *     CanMerge
805 
806 *  Purpose:
807 *     Checks if two WcsMaps can be merged.
808 
809 *  Type:
810 *     Private function.
811 
812 *  Synopsis:
813 *     #include "wcsmap.h"
814 *     int CanMerge( AstMapping *map1, int inv1, AstMapping *map2, int inv2, int *status )
815 
816 *  Class Membership:
817 *     WcsMap internal utility function.
818 
819 *  Description:
820 *     This function checks the two supplied Mappings to see if they are
821 *     two WcsMaps which can be merged. This is only possible if they
822 *     form an inverse pair.
823 
824 *  Parameters:
825 *     map1
826 *        A pointer to the first mapping.
827 *     map2
828 *        A pointer to the second mapping.
829 *     inv1
830 *        The invert flag to use with the first mapping.
831 *     inv2
832 *        The invert flag to use with the second mapping.
833 *     status
834 *        Pointer to the inherited status variable.
835 
836 *  Returned Value:
837 *     1 if the WcsMaps can be merged, zero otherwise.
838 
839 */
840 
841 /* Local Variables: */
842    AstWcsMap *wcs1;               /* Pointer to first WcsMap */
843    AstWcsMap *wcs2;               /* Pointer to second WcsMap */
844    int m;                         /* Projection parameter index */
845    int ret;                       /* Can the Mappings be merged? */
846    int i;                         /* Axis index */
847 
848 /* Initialise the returned value. */
849    ret = 0;
850 
851 /* Check the global error status. */
852    if ( !astOK ) return ret;
853 
854 /* Both Mappings must be WcsMaps to merge. */
855    if( !strcmp( "WcsMap", astGetClass( map1 ) ) &&
856        !strcmp( "WcsMap", astGetClass( map2 ) ) ) {
857 
858 /* Get pointers to the WcsMaps. */
859       wcs1 = (AstWcsMap *) map1;
860       wcs2 = (AstWcsMap *) map2;
861 
862 /* Check that the two WcsMaps performs the same sort of projection, and
863    have the same number of axes. */
864       if( astGetWcsType( wcs1 ) == astGetWcsType( wcs2 ) &&
865           astGetNin( wcs1 ) == astGetNin( wcs2 ) ) {
866 
867 /* Check that the Mappings are applied in opposite senses. */
868          if( inv1 != inv2 ) {
869 
870 /* Check that the latitude and longitude axes have the same indices in
871    both WcsMaps. */
872             if( astGetWcsAxis( wcs1, 0 ) == astGetWcsAxis( wcs2, 0 ) &&
873                 astGetWcsAxis( wcs1, 1 ) == astGetWcsAxis( wcs2, 1 ) ){
874 
875 /* We nopw check the projection parameters are equal. Assume they are for
876    the moment. */
877                ret = 1;
878 
879 /* Check the parameters for each axis in turn. */
880                for( i = 0; i < astGetNin( wcs1 ); i++ ){
881 
882 /* If the two WcsMaps have a different number of parameters for this axes,
883    they cannot merge. */
884                   if( GetNP( wcs1, i, status ) != GetNP( wcs1, i, status ) ){
885                      ret = 0;
886                      break;
887 
888 /* Otherwise, check each parameter value in turn. If any are found which
889    are not equal, the WcsMaps cannot merge. */
890                   } else {
891                      for( m = 0; m < GetNP( wcs1, i, status ); m++ ){
892                         if( !EQUAL( astGetPV( wcs1, i, m ),
893                                     astGetPV( wcs2, i, m ) ) ){
894                            ret = 0;
895                            break;
896                         }
897                      }
898                      if( !ret ) break;
899                   }
900                }
901             }
902          }
903       }
904    }
905 
906 /* Return the answer. */
907    return ret;
908 }
909 
CanSwap(AstMapping * map1,AstMapping * map2,int inv1,int inv2,int * simpler,int * status)910 static int CanSwap( AstMapping *map1, AstMapping *map2, int inv1, int inv2,
911                     int *simpler, int *status ){
912 /*
913 *  Name:
914 
915 *     CanSwap
916 
917 *  Purpose:
918 *     Determine if two Mappings could be swapped.
919 
920 *  Type:
921 *     Private function.
922 
923 *  Synopsis:
924 *     #include "wcsmap.h"
925 *     int CanSwap( AstMapping *map1, AstMapping *map2, int inv1, int inv2,
926 *                  int *simpler )
927 
928 *  Class Membership:
929 *     WcsMap member function
930 
931 *  Description:
932 *     This function returns a flag indicating if the pair of supplied
933 *     Mappings could be replaced by an equivalent pair of Mappings from the
934 *     same classes as the supplied pair, but in reversed order. Each pair
935 *     of Mappings is considered to be compunded in series. The supplied
936 *     Mapings are not changed in any way.
937 
938 *  Parameters:
939 *     map1
940 *        The Mapping to be applied first.
941 *     map2
942 *        The Mapping to be applied second.
943 *     inv1
944 *        The invert flag to use with map1. A value of zero causes the forward
945 *        mapping to be used, and a non-zero value causes the inverse
946 *        mapping to be used.
947 *     inv2
948 *        The invert flag to use with map2.
949 *     simpler
950 *        Addresss of a location at which to return a flag indicating if
951 *        the swapped Mappings would be intrinsically simpler than the
952 *        original Mappings.
953 
954 *  Returned Value:
955 *     1 if the Mappings could be swapped, 0 otherwise.
956 
957 *  Notes:
958 *     -  One of the supplied pair of Mappings must be a WcsMap.
959 *     -  A value of 0 is returned if the two Mappings could be merged into
960 *     a single Mapping.
961 *     -  A value of 0 is returned if an error has already occurred, or if
962 *     this function should fail for any reason.
963 */
964 
965 /* Local Variables: */
966    AstMapping *nowcs;        /* Pointer to non-WcsMap Mapping */
967    AstWcsMap  *wcs;          /* Pointer to WcsMap Mapping */
968    const char *class1;       /* Pointer to map1 class string */
969    const char *class2;       /* Pointer to map2 class string */
970    const char *nowcs_class;  /* Pointer to non-WcsMap class string */
971    double *consts;           /* Pointer to constants array */
972    int *inperm;              /* Pointer to input axis permutation array */
973    int *outperm;             /* Pointer to output axis permutation array */
974    int i;                    /* Loop count */
975    int invert[ 2 ];          /* Original invert flags */
976    int latax;                /* Index of latitude axis in WcsMap */
977    int lonax;                /* Index of longitude axis in WcsMap */
978    int nin;                  /* No. of input coordinates for the PermMap */
979    int nout;                 /* No. of output coordinates for the PermMap */
980    int ret;                  /* Returned flag */
981 
982 /* Check the global error status. */
983    if ( !astOK ) return 0;
984 
985 /* Initialise */
986    ret = 0;
987    *simpler = 0;
988 
989 /* Temporarily set the Invert attributes of both Mappings to the supplied
990    values. */
991    invert[ 0 ] = astGetInvert( map1 );
992    astSetInvert( map1, inv1 );
993 
994    invert[ 1 ] = astGetInvert( map2 );
995    astSetInvert( map2, inv2 );
996 
997 /* Get the classes of the two mappings. */
998    class1 = astGetClass( map1 );
999    class2 = astGetClass( map2 );
1000    if( astOK ){
1001 
1002 /* Get a pointer to the non-WcsMap Mapping. */
1003       if( !strcmp( class1, "WcsMap" ) ){
1004          wcs = (AstWcsMap *) map1;
1005          nowcs = map2;
1006          nowcs_class = class2;
1007       } else {
1008          nowcs = map1;
1009          wcs = (AstWcsMap *) map2;
1010          nowcs_class = class1;
1011       }
1012 
1013 /* If it is a PermMap, the Mappings can be swapped so long as:
1014    1) all links between input and output axes in the PermMap are
1015    bi-directional. This does not preclude the existence of unconnected axes,
1016    which do not have links (bi-directional or otherwise).
1017    2) The PermMap passesd though both the longitude and latitude axes of
1018    the WcsMap */
1019       if( !strcmp( nowcs_class, "PermMap" ) ){
1020 
1021 /* Get the number of input and output coordinates. */
1022          nin = astGetNin( nowcs );
1023          nout = astGetNout( nowcs );
1024 
1025 /* We need to know the axis permutation arrays and constants array for
1026    the PermMap. */
1027          PermGet( (AstPermMap *) nowcs, &outperm, &inperm, &consts, status );
1028          if( astOK ) {
1029 
1030 /* Indicate we can swap with the PermMap. */
1031             ret = 1;
1032 
1033 /* Check each output axis. If any links between axes are found which are
1034    not bi-directional, indicate that we cannot swap with the PermMap. */
1035             for( i = 0; i < nout; i++ ){
1036                if( outperm[ i ] >= 0 && outperm[ i ] < nin ) {
1037                   if( inperm[ outperm[ i ] ] != i ) {
1038                      ret = 0;
1039                      break;
1040                   }
1041                }
1042             }
1043 
1044 /* Check each input axis. If any links between axes are found which are
1045    not bi-directional, indicate that we cannot swap with the PermMap. */
1046             for( i = 0; i < nin; i++ ){
1047                if( inperm[ i ] >= 0 && inperm[ i ] < nout ) {
1048                   if( outperm[ inperm[ i ] ] != i ) {
1049                      ret = 0;
1050                      break;
1051                   }
1052                }
1053             }
1054 
1055 /* Check that the longitude and latitude axes both have bi-directional
1056    links in the PermMap, or are both unassigned. */
1057             if( ret ) {
1058 
1059 /* Get the indices of the longitude and latitude axes in the WcsMap */
1060                lonax = astGetWcsAxis( wcs, 0 );
1061                latax = astGetWcsAxis( wcs, 1 );
1062 
1063 /* If the WcsMap is applied first... */
1064                if( wcs == (AstWcsMap *) map1 ) {
1065                   if( inperm[ lonax] < 0 && inperm[ latax ] < 0 ) {
1066                      ret = 1;
1067                   } else if( inperm[ lonax ] < 0 || inperm[ lonax ] >= nout ||
1068                              inperm[ latax ] < 0 || inperm[ latax ] >= nout ) {
1069                      ret = 0;
1070                   }
1071 
1072 /* If the WcsMap is applied second ... */
1073                } else {
1074                   if( outperm[ lonax ] < 0 && outperm[ latax ] < 0 ) {
1075                      ret = 1;
1076                   } else if( outperm[ lonax ] < 0 || outperm[ lonax ] >= nin ||
1077                              outperm[ latax ] < 0 || outperm[ latax ] >= nin ) {
1078                      ret = 0;
1079                   }
1080                }
1081             }
1082 
1083 /* If we can swap with the PermMap, the swapped Mappings may be
1084    intrinsically simpler than the original mappings. */
1085             if( ret ) {
1086 
1087 /* If the PermMap precedes the WcsMap, this will be the case if the PermMap
1088    has more outputs than inputs. If the WcsMap precedes the PermMap, this
1089    will be the case if the PermMap has more inputs than outputs. */
1090                *simpler = ( nowcs == map1 ) ? nout > nin : nin > nout;
1091             }
1092 
1093 /* Free the axis permutation and constants arrays. */
1094             outperm = (int *) astFree( (void *) outperm );
1095             inperm = (int *) astFree( (void *) inperm );
1096             consts = (double *) astFree( (void *) consts );
1097          }
1098       }
1099    }
1100 
1101 /* Re-instate the original settings of the Invert attributes for the
1102    supplied MatrixMaps. */
1103    astSetInvert( map1, invert[ 0 ] );
1104    astSetInvert( map2, invert[ 1 ] );
1105 
1106 /* Return the answer. */
1107    return astOK ? ret : 0;
1108 }
1109 
ClearAttrib(AstObject * this_object,const char * attrib,int * status)1110 static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
1111 /*
1112 *  Name:
1113 *     ClearAttrib
1114 
1115 *  Purpose:
1116 *     Clear an attribute value for a WcsMap.
1117 
1118 *  Type:
1119 *     Private function.
1120 
1121 *  Synopsis:
1122 *     #include "wcsmap.h"
1123 *     void ClearAttrib( AstObject *this, const char *attrib, int *status )
1124 
1125 *  Class Membership:
1126 *     WcsMap member function (over-rides the astClearAttrib protected
1127 *     method inherited from the Mapping class).
1128 
1129 *  Description:
1130 *     This function clears the value of a specified attribute for a
1131 *     WcsMap, so that the default value will subsequently be used.
1132 
1133 *  Parameters:
1134 *     this
1135 *        Pointer to the WcsMap.
1136 *     attrib
1137 *        Pointer to a null terminated string specifying the attribute
1138 *        name.  This should be in lower case with no surrounding white
1139 *        space.
1140 *     status
1141 *        Pointer to the inherited status variable.
1142 */
1143 
1144 /* Local Variables: */
1145    AstWcsMap *this;             /* Pointer to the WcsMap structure */
1146    int i;                       /* Axis index */
1147    int len;                     /* Length of the attribute name */
1148    int m;                       /* Projection parameter index */
1149    int nc;                      /* No. of characters read by astSscanf */
1150 
1151 /* Check the global error status. */
1152    if ( !astOK ) return;
1153 
1154 /* Obtain a pointer to the WcsMap structure. */
1155    this = (AstWcsMap *) this_object;
1156 
1157 /* Obtain the length of the attrib string. */
1158    len = strlen( attrib );
1159 
1160 /* Check the attribute name and clear the appropriate attribute. */
1161 
1162 /* ProjP. */
1163 /* ------ */
1164    if ( nc = 0, ( 1 == astSscanf( attrib, "prpjp(%d)%n", &m, &nc ) )
1165                   && ( nc >= len ) ) {
1166       astClearPV( this, astGetWcsAxis( this, 1 ), m );
1167 
1168 /* PV. */
1169 /* ------ */
1170    } else if ( nc = 0, ( 2 == astSscanf( attrib, "pv%d_%d%n", &i, &m, &nc ) )
1171                   && ( nc >= len ) ) {
1172       astClearPV( this, i - 1, m );
1173 
1174 /* If the name was not recognised, test if it matches any of the
1175    read-only attributes of this class. If it does, then report an
1176    error. */
1177    } else if ( ( nc = 0, ( 1 == astSscanf( attrib, "wcsaxis(%d)%n", &i, &nc ) )
1178                            && ( nc >= len ) ) ||
1179         !strcmp( attrib, "wcstype" ) ||
1180         !strcmp( attrib, "natlat" ) ||
1181         !strcmp( attrib, "natlon" ) ){
1182       astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" "
1183                 "value for a %s.", status, attrib, astGetClass( this ) );
1184       astError( AST__NOWRT, "This is a read-only attribute." , status);
1185 
1186 /* If the attribute is still not recognised, pass it on to the parent
1187    method for further interpretation. */
1188    } else {
1189       (*parent_clearattrib)( this_object, attrib, status );
1190    }
1191 }
1192 
ClearPV(AstWcsMap * this,int i,int m,int * status)1193 static void ClearPV( AstWcsMap *this, int i, int m, int *status ) {
1194 /*
1195 *+
1196 *  Name:
1197 *     astClearPV
1198 
1199 *  Purpose:
1200 *     Clear a PVi_m attribute.
1201 
1202 *  Type:
1203 *     Protected function.
1204 
1205 *  Synopsis:
1206 *     #include "wcsmap.h"
1207 *     void astClearPV( AstWcsMap *this, int i, int m )
1208 
1209 *  Class Membership:
1210 *     WcsMap protected function
1211 
1212 *  Description:
1213 *     This function clears a specified member of the PV attribute array, by
1214 *     resetting its value to AST__BAD.
1215 
1216 *  Parameters:
1217 *     this
1218 *        A pointer to the WcsMap.
1219 *     i
1220 *        Zero based axis index.
1221 *     m
1222 *        Zero based parameter index.
1223 
1224 *-
1225 */
1226 /* Local Variables; */
1227    int npar;
1228    int mxpar;
1229 
1230 /* Check the global error status. */
1231    if ( !astOK ) return;
1232 
1233 /* Validate the axis index. */
1234    if( i < 0 || i >= astGetNin( this ) ){
1235       astError( AST__AXIIN, "astClearPV(%s): Axis index (%d) is invalid in "
1236                 "attribute PV%d_%d  - it should be in the range 1 to %d.",
1237                 status, astGetClass( this ), i + 1, i + 1, m,
1238                 astGetNin( this ) );
1239 
1240    } else {
1241 
1242 /* Find the maximum number of parameters allowed for the axis. */
1243       mxpar = astGetPVMax( this, i );
1244 
1245 /* Ignore unused parameters. */
1246       if( m < 0 || m > mxpar ){
1247 
1248 /* See if the parameter is currently set. Is so, set its value to
1249    AST__BAD. */
1250       } else if( this->np && this->p ){
1251          npar = this->np[ i ];
1252          if( m < npar && this->p[ i ] ) this->p[ i ][ m ] = AST__BAD;
1253       }
1254 
1255 /* Re-initialize the values stored in the "AstPrjPrm" structure. */
1256       InitPrjPrm( this, status );
1257    }
1258 }
1259 
ClearTPNTan(AstWcsMap * this,int * status)1260 static void ClearTPNTan( AstWcsMap *this, int *status ) {
1261 /*
1262 *+
1263 *  Name:
1264 *     astClearTPNTan
1265 
1266 *  Purpose:
1267 *     Clear the TPNTan attribute.
1268 
1269 *  Type:
1270 *     Protected function.
1271 
1272 *  Synopsis:
1273 *     #include "wcsmap.h"
1274 *     void ClearTPNTan( AstWcsMap *this, int *status )
1275 
1276 *  Class Membership:
1277 *     WcsMap protected function
1278 
1279 *  Description:
1280 *     This function clears the TPNTan attribute, ensuring the projection
1281 *     parameters used by WCSLIB are adjusted accordingly.
1282 
1283 *  Parameters:
1284 *     this
1285 *        A pointer to the WcsMap.
1286 
1287 *-
1288 */
1289 
1290 /* Check the global error status. */
1291    if ( !astOK ) return;
1292 
1293 /* Clear the value. */
1294    this->tpn_tan = -INT_MAX;
1295 
1296 /* Re-initialize the values stored in the "AstPrjPrm" structure. */
1297    InitPrjPrm( this, status );
1298 }
1299 
CopyPV(AstWcsMap * in,AstWcsMap * out,int * status)1300 static void CopyPV( AstWcsMap *in, AstWcsMap *out, int *status ) {
1301 /*
1302 *  Name:
1303 *     CopyPV
1304 
1305 *  Purpose:
1306 *     Copy projection parameter information from one WcsMap to another.
1307 
1308 *  Type:
1309 *     Private function.
1310 
1311 *  Synopsis:
1312 *     void CopyPV( AstWcsMap *in, AstWcsMap *out )
1313 
1314 *  Description:
1315 *     This function copies projection parameter information from one
1316 *     WcsMap to another.
1317 
1318 *  Parameters:
1319 *     in
1320 *        Pointer to the input WcsMap.
1321 *     out
1322 *        Pointer to the output WcsMap.
1323 
1324 */
1325 
1326 
1327 /* Local Variables: */
1328    int i;                        /* Axis index */
1329    int latax_in;                 /* Index of input latitude axis */
1330    int latax_out;                /* Index of output latitude axis */
1331    int lonax_in;                 /* Index of input longitude axis */
1332    int lonax_out;                /* Index of output longitude axis */
1333    int nax_out;                  /* No. of axis in the output WcsMap */
1334 
1335 /* Check the global error status. */
1336    if ( !astOK ) return;
1337 
1338 /* Nullify the pointers stored in the output WcsMap since these may
1339    currently be pointing at good data. Otherwise, the good data could be
1340    freed by accident if the output object is deleted due to an error
1341    occuring in this function. */
1342    out->np = NULL;
1343    out->p = NULL;
1344 
1345 /* Do nothing more if either of the input pointers are null (i.e. if there
1346    are no projection parameters. */
1347    if( in->np && in->p ){
1348 
1349 /* Store the number of axes in the input and output WcsMaps */
1350       nax_out = astGetNin( out );
1351 
1352 /* Allocate memory for the array holding the number of projection parameters
1353    associated with each axis. */
1354       out->np = (int *) astMalloc( sizeof( int )*nax_out );
1355 
1356 /* Allocate memory for the array of pointers which identify the arrays
1357    holding the parameter values. */
1358       out->p = (double **) astMalloc( sizeof( double *)*nax_out );
1359 
1360 /* Check pointers can be used */
1361       if( astOK ) {
1362 
1363 /* Initialise the above arrays. */
1364          for( i = 0; i < nax_out; i++ ) {
1365             (out->np)[ i ] = 0;
1366             (out->p)[ i ] = NULL;
1367          }
1368 
1369 /* Copy the longitude and latitude values from in to out (other axes do
1370    not have projection parameters). */
1371          lonax_in = astGetWcsAxis( in, 0 );
1372          latax_in = astGetWcsAxis( in, 1 );
1373          lonax_out = astGetWcsAxis( out, 0 );
1374          latax_out = astGetWcsAxis( out, 1 );
1375 
1376          (out->np)[ lonax_out ] = (in->np)[ lonax_in ];
1377          (out->p)[ lonax_out ] = (double *) astStore( NULL,
1378                                           (void *) (in->p)[ lonax_in ],
1379                                           sizeof(double)*(in->np)[ lonax_in ] );
1380 
1381          (out->np)[ latax_out ] = (in->np)[ latax_in ];
1382          (out->p)[ latax_out ] = (double *) astStore( NULL,
1383                                           (void *) (in->p)[ latax_in ],
1384                                           sizeof(double)*(in->np)[ latax_in ] );
1385       }
1386 
1387 /* If an error has occurred, free the output arrays. */
1388       if( !astOK ) FreePV( out, status );
1389 
1390    }
1391 
1392 /* Re-initialize the values stored in the "AstPrjPrm" structure. */
1393    InitPrjPrm( out, status );
1394 
1395 }
1396 
Equal(AstObject * this_object,AstObject * that_object,int * status)1397 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
1398 /*
1399 *  Name:
1400 *     Equal
1401 
1402 *  Purpose:
1403 *     Test if two WcsMaps are equivalent.
1404 
1405 *  Type:
1406 *     Private function.
1407 
1408 *  Synopsis:
1409 *     #include "wcsmap.h"
1410 *     int Equal( AstObject *this, AstObject *that, int *status )
1411 
1412 *  Class Membership:
1413 *     WcsMap member function (over-rides the astEqual protected
1414 *     method inherited from the astMapping class).
1415 
1416 *  Description:
1417 *     This function returns a boolean result (0 or 1) to indicate whether
1418 *     two WcsMaps are equivalent.
1419 
1420 *  Parameters:
1421 *     this
1422 *        Pointer to the first Object (a WcsMap).
1423 *     that
1424 *        Pointer to the second Object.
1425 *     status
1426 *        Pointer to the inherited status variable.
1427 
1428 *  Returned Value:
1429 *     One if the WcsMaps are equivalent, zero otherwise.
1430 
1431 *  Notes:
1432 *     - A value of zero will be returned if this function is invoked
1433 *     with the global status set, or if it should fail for any reason.
1434 */
1435 
1436 /* Local Variables: */
1437    AstWcsMap *that;
1438    AstWcsMap *this;
1439    int i, j;
1440    int nin;
1441    int nout;
1442    int result;
1443 
1444 /* Initialise. */
1445    result = 0;
1446 
1447 /* Check the global error status. */
1448    if ( !astOK ) return result;
1449 
1450 /* Obtain pointers to the two WcsMap structures. */
1451    this = (AstWcsMap *) this_object;
1452    that = (AstWcsMap *) that_object;
1453 
1454 /* Check the second object is a WcsMap. We know the first is a
1455    WcsMap since we have arrived at this implementation of the virtual
1456    function. */
1457    if( astIsAWcsMap( that ) ) {
1458 
1459 /* Get the number of inputs and outputs and check they are the same for both. */
1460       nin = astGetNin( this );
1461       nout = astGetNout( this );
1462       if( astGetNin( that ) == nin && astGetNout( that ) == nout ) {
1463 
1464 /* If the Invert flags for the two WcsMaps differ, it may still be possible
1465    for them to be equivalent. First compare the WcsMaps if their Invert
1466    flags are the same. In this case all the attributes of the two WcsMaps
1467    must be identical. */
1468          if( astGetInvert( this ) == astGetInvert( that ) ) {
1469 
1470             if( this->type == that->type &&
1471                 this->wcsaxis[ 0 ] == that->wcsaxis[ 0 ] &&
1472                 this->wcsaxis[ 1 ] == that->wcsaxis[ 1 ] ) {
1473 
1474                result = 1;
1475 
1476                if( this->np && that->np ){
1477 
1478                   for( i = 0; i < nout && result; i++ ) {
1479 
1480                      if( (this->np)[ i ] != (that->np)[ i ] ) {
1481                         result = 0;
1482 
1483                      } else if( (this->p)[ i ] && !(this->p)[ i ] ) {
1484                         result = 0;
1485 
1486                      } else if( !(this->p)[ i ] && (this->p)[ i ] ) {
1487                         result = 0;
1488 
1489                      } else if( (this->p)[ i ] && (this->p)[ i ] ) {
1490 
1491                         for( j = 0; j < (this->np)[ i ]; j++ ) {
1492                            if( !astEQUAL( (this->p)[ i ][ j ],
1493                                           (that->p)[ i ][ j ] ) ) {
1494                               result = 0;
1495                               break;
1496                            }
1497                         }
1498                      }
1499                   }
1500                }
1501 
1502             } else if( this->np || that->np ){
1503                result = 0;
1504             }
1505 
1506 /* If the Invert flags for the two WcsMaps differ, the attributes of the two
1507    WcsMaps must be inversely related to each other. */
1508          } else {
1509 
1510 /* In the specific case of a WcsMap, Invert flags must be equal. */
1511             result = 0;
1512 
1513          }
1514       }
1515    }
1516 
1517 /* If an error occurred, clear the result value. */
1518    if ( !astOK ) result = 0;
1519 
1520 /* Return the result, */
1521    return result;
1522 }
1523 
FindPrjData(int type,int * status)1524 static const PrjData *FindPrjData( int type, int *status ){
1525 /*
1526 *+
1527 *  Name:
1528 *     FindPrjData
1529 
1530 *  Purpose:
1531 *     Get information about a WCSLIB projection given a projection type.
1532 
1533 *  Type:
1534 *     Private function.
1535 
1536 *  Synopsis:
1537 *     #include "wcsmap.h"
1538 *     const PrjData *FindPrjData( int type, int *status )
1539 
1540 *  Class Membership:
1541 *     WcsMap member function
1542 
1543 *  Description:
1544 *     This function returns a pointer to an PrjData structure describing
1545 *     the WCSLIB projection with the supplied type.
1546 
1547 *  Parameters:
1548 *     type
1549 *        The projection type.
1550 *     status
1551 *        Pointer to the inherited status variable.
1552 
1553 *  Returned Value:
1554 *     A pointer to the "const" PrjData structure describing the projection.
1555 
1556 *  Notes:
1557 *     -  The returned pointer points to an element in a static array and
1558 *     should not be freed.
1559 *     -  This function attempts to execute even if an error has already
1560 *     occurred. A description of a "null" projection will be returned if
1561 *     this function subsequently fails (for instance if the projection is
1562 *     not recognised).
1563 *-
1564 */
1565 
1566    const PrjData *data;
1567    data = PrjInfo;
1568    while( data->prj != AST__WCSBAD && data->prj != type ) data++;
1569    return data;
1570 }
1571 
FreePV(AstWcsMap * this,int * status)1572 static void FreePV( AstWcsMap *this, int *status ) {
1573 /*
1574 *
1575 *  Name:
1576 *     FreePV
1577 
1578 *  Purpose:
1579 *     Free memory used to hold projection parameters
1580 
1581 *  Type:
1582 *     Private function.
1583 
1584 *  Synopsis:
1585 *     #include "wcsmap.h"
1586 *     FreePV( AstWcsMap *this, int *status )
1587 
1588 *  Class Membership:
1589 *     WcsMap private function
1590 
1591 *  Description:
1592 *     This function frees all the dynamic memory used to store projection
1593 *     parameter information in the supplied WcsMap.
1594 
1595 *  Parameters:
1596 *     this
1597 *        A pointer to the WcsMap.
1598 *     status
1599 *        Pointer to the inherited status variable.
1600 
1601 *  Notes:
1602 *     This function attempts to execute even if an error has already occurred.
1603 
1604 *
1605 */
1606    int i;              /* Axis index */
1607 
1608    if( this->np ) this->np = (int *) astFree( (void *) this->np );
1609    if( this->p ){
1610       for( i = 0; i < astGetNin( this ); i++ ){
1611          this->p[ i ]  = (double *) astFree( (void *) this->p[ i ] );
1612       }
1613       this->p = (double **) astFree( (void *) this->p );
1614    }
1615 
1616 /* Re-initialize the values stored in the "AstPrjPrm" structure. */
1617    InitPrjPrm( this, status );
1618 
1619 
1620 }
1621 
GetObjSize(AstObject * this_object,int * status)1622 static int GetObjSize( AstObject *this_object, int *status ) {
1623 /*
1624 *  Name:
1625 *     GetObjSize
1626 
1627 *  Purpose:
1628 *     Return the in-memory size of an Object.
1629 
1630 *  Type:
1631 *     Private function.
1632 
1633 *  Synopsis:
1634 *     #include "wcsmap.h"
1635 *     int GetObjSize( AstObject *this, int *status )
1636 
1637 *  Class Membership:
1638 *     WcsMap member function (over-rides the astGetObjSize protected
1639 *     method inherited from the parent class).
1640 
1641 *  Description:
1642 *     This function returns the in-memory size of the supplied WcsMap,
1643 *     in bytes.
1644 
1645 *  Parameters:
1646 *     this
1647 *        Pointer to the WcsMap.
1648 *     status
1649 *        Pointer to the inherited status variable.
1650 
1651 *  Returned Value:
1652 *     The Object size, in bytes.
1653 
1654 *  Notes:
1655 *     - A value of zero will be returned if this function is invoked
1656 *     with the global status set, or if it should fail for any reason.
1657 */
1658 
1659 /* Local Variables: */
1660    AstWcsMap *this;         /* Pointer to WcsMap structure */
1661    int result;              /* Result value to return */
1662    int i;                   /* Axis index */
1663 
1664 /* Initialise. */
1665    result = 0;
1666 
1667 /* Check the global error status. */
1668    if ( !astOK ) return result;
1669 
1670 /* Obtain a pointers to the WcsMap structure. */
1671    this = (AstWcsMap *) this_object;
1672 
1673 /* Invoke the GetObjSize method inherited from the parent class, and then
1674    add on any components of the class structure defined by thsi class
1675    which are stored in dynamically allocated memory. */
1676    result = (*parent_getobjsize)( this_object, status );
1677 
1678    result += astTSizeOf( this->np );
1679    if( this->p ){
1680       for( i = 0; i < astGetNin( this ); i++ ){
1681          result += astTSizeOf( (void *) this->p[ i ] );
1682       }
1683       result += astTSizeOf( this->p );
1684    }
1685 
1686    result += astTSizeOf( this->params.p );
1687    result += astTSizeOf( this->params.p2 );
1688 
1689 /* If an error occurred, clear the result value. */
1690    if ( !astOK ) result = 0;
1691 
1692 /* Return the result, */
1693    return result;
1694 }
1695 
GetAttrib(AstObject * this_object,const char * attrib,int * status)1696 static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
1697 /*
1698 *  Name:
1699 *     GetAttrib
1700 
1701 *  Purpose:
1702 *     Get the value of a specified attribute for a WcsMap.
1703 
1704 *  Type:
1705 *     Private function.
1706 
1707 *  Synopsis:
1708 *     #include "wcsmap.h"
1709 *     const char *GetAttrib( AstObject *this, const char *attrib, int *status )
1710 
1711 *  Class Membership:
1712 *     WcsMap member function (over-rides the protected astGetAttrib
1713 *     method inherited from the Mapping class).
1714 
1715 *  Description:
1716 *     This function returns a pointer to the value of a specified
1717 *     attribute for a WcsMap, formatted as a character string.
1718 
1719 *  Parameters:
1720 *     this
1721 *        Pointer to the WcsMap.
1722 *     attrib
1723 *        Pointer to a null-terminated string containing the name of
1724 *        the attribute whose value is required. This name should be in
1725 *        lower case, with all white space removed.
1726 *     status
1727 *        Pointer to the inherited status variable.
1728 
1729 *  Returned Value:
1730 *     - Pointer to a null-terminated string containing the attribute
1731 *     value.
1732 
1733 *  Notes:
1734 *     - The returned string pointer may point at memory allocated
1735 *     within the WcsMap, or at static memory. The contents of the
1736 *     string may be over-written or the pointer may become invalid
1737 *     following a further invocation of the same function or any
1738 *     modification of the WcsMap. A copy of the string should
1739 *     therefore be made if necessary.
1740 *     - A NULL pointer will be returned if this function is invoked
1741 *     with the global error status set, or if it should fail for any
1742 *     reason.
1743 */
1744 
1745 /* Local Variables: */
1746    astDECLARE_GLOBALS           /* Pointer to thread-specific global data */
1747    AstWcsMap *this;             /* Pointer to the WcsMap structure */
1748    const char *result;          /* Pointer value to return */
1749    double dval;                 /* Floating point attribute value */
1750    int i;                       /* Axis index */
1751    int ival;                    /* Integer attribute value */
1752    int len;                     /* Length of attribute string */
1753    int m;                       /* Projection parameter index */
1754    int nc;                      /* No. of characters read by astSscanf */
1755 
1756 /* Initialise. */
1757    result = NULL;
1758 
1759 /* Check the global error status. */
1760    if ( !astOK ) return result;
1761 
1762 /* Get a pointer to the thread specific global data structure. */
1763    astGET_GLOBALS(this_object);
1764 
1765 /* Obtain a pointer to the WcsMap structure. */
1766    this = (AstWcsMap *) this_object;
1767 
1768 /* Obtain the length of the attrib string. */
1769    len = strlen( attrib );
1770 
1771 /* Compare "attrib" with each recognised attribute name in turn,
1772    obtaining the value of the required attribute. If necessary, write
1773    the value into "getattrib_buff" as a null-terminated string in an appropriate
1774    format.  Set "result" to point at the result string. */
1775 
1776 /* ProjP. */
1777 /* ------ */
1778    if ( nc = 0, ( 1 == astSscanf( attrib, "projp(%d)%n", &m, &nc ) )
1779                   && ( nc >= len ) ) {
1780       dval = astGetPV( this, astGetWcsAxis( this, 1 ), m );
1781       if ( astOK ) {
1782          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
1783          result = getattrib_buff;
1784       }
1785 
1786 /* PV. */
1787 /* --- */
1788    } else if ( nc = 0, ( 2 == astSscanf( attrib, "pv%d_%d%n", &i, &m, &nc ) )
1789                   && ( nc >= len ) ) {
1790       dval = astGetPV( this, i - 1, m );
1791       if ( astOK ) {
1792          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
1793          result = getattrib_buff;
1794       }
1795 
1796 /* WcsType */
1797 /* ======= */
1798    } else if ( !strcmp( attrib, "wcstype" ) ) {
1799       ival = astGetWcsType( this );
1800       if ( astOK ) {
1801          (void) sprintf( getattrib_buff, "%d", ival );
1802          result = getattrib_buff;
1803       }
1804 
1805 /* PVMax */
1806 /* ===== */
1807    } else if ( nc = 0, ( 1 == astSscanf( attrib, "pvmax(%d)%n", &i, &nc ) )
1808                   && ( nc >= len ) ) {
1809       ival = astGetPVMax( this, i - 1 );
1810       if ( astOK ) {
1811          (void) sprintf( getattrib_buff, "%d", ival );
1812          result = getattrib_buff;
1813       }
1814 
1815 /* NatLat */
1816 /* ====== */
1817    } else if ( !strcmp( attrib, "natlat" ) ) {
1818       dval = astGetNatLat( this );
1819       if ( astOK ) {
1820          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
1821          result = getattrib_buff;
1822       }
1823 
1824 /* NatLon */
1825 /* ====== */
1826    } else if ( !strcmp( attrib, "natlon" ) ) {
1827       dval = astGetNatLon( this );
1828       if ( astOK ) {
1829          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
1830          result = getattrib_buff;
1831       }
1832 
1833 
1834 /* WcsAxis */
1835 /* ======= */
1836    } else if ( nc = 0, ( 1 == astSscanf( attrib, "wcsaxis(%d)%n", &i, &nc ) )
1837                          && ( nc >= len ) ) {
1838       ival = astGetWcsAxis( this, i - 1 ) + 1;
1839       if ( astOK ) {
1840          (void) sprintf( getattrib_buff, "%d", ival );
1841          result = getattrib_buff;
1842       }
1843 
1844 /* If the attribute name was not recognised, pass it on to the parent
1845    method for further interpretation. */
1846    } else {
1847       result = (*parent_getattrib)( this_object, attrib, status );
1848    }
1849 
1850 /* Return the result. */
1851    return result;
1852 }
1853 
GetNatLat(AstWcsMap * this,int * status)1854 static double GetNatLat( AstWcsMap *this, int *status ) {
1855 /*
1856 *+
1857 *  Name:
1858 *     GetNatLat
1859 
1860 *  Purpose:
1861 *     Get the value of the NatLat attribute.
1862 
1863 *  Type:
1864 *     Protected function.
1865 
1866 *  Synopsis:
1867 *     #include "wcsmap.h"
1868 *     double GetNatLat( AstWcsMap *this, int *status )
1869 
1870 *  Class Membership:
1871 *     WcsMap protected function
1872 
1873 *  Description:
1874 *     This function returns the value of the NatLat attribute. This is
1875 *     fixed value for most projection types , defined in the FITS-WCS paper
1876 *     II. For instance, all zenithal projections have NatLat = PI/2 (90
1877 *     degrees). For some prjections (e.g. conics), the value is defined
1878 *     by a projection parameter.
1879 
1880 *  Parameters:
1881 *     this
1882 *        A pointer to the WcsMap.
1883 *     status
1884 *        Pointer to the inherited status variable.
1885 
1886 *  Returned Value:
1887 *     The attribute value, in radians.
1888 
1889 *-
1890 */
1891    double ret;     /* Returned value */
1892 
1893 /* The native latitude of the reference point of the projection is
1894    constant for most projection, but for some (the conics) it is
1895    specified by projection one on the latitude axis. */
1896    ret = FindPrjData( this->type, status )->theta0;
1897    if( ret == AST__BAD ){
1898       ret = astGetPV( this, astGetWcsAxis( this, 1 ), 1 );
1899       if( ret != AST__BAD ) ret *= AST__DD2R;
1900    }
1901 
1902 /* Return the result. */
1903    return ret;
1904 }
1905 
GetNatLon(AstWcsMap * this,int * status)1906 static double GetNatLon( AstWcsMap *this, int *status ) {
1907 /*
1908 *+
1909 *  Name:
1910 *     GetNatLon
1911 
1912 *  Purpose:
1913 *     Get the value of the NatLon attribute.
1914 
1915 *  Type:
1916 *     Protected function.
1917 
1918 *  Synopsis:
1919 *     #include "wcsmap.h"
1920 *     double GetNatLon( AstWcsMap *this, int *status )
1921 
1922 *  Class Membership:
1923 *     WcsMap protected function
1924 
1925 *  Description:
1926 *     This function returns the value of the NatLon attribute. This is
1927 *     fixed value of zero for all projection types.
1928 
1929 *  Parameters:
1930 *     this
1931 *        A pointer to the WcsMap.
1932 *     status
1933 *        Pointer to the inherited status variable.
1934 
1935 *  Returned Value:
1936 *     The attribute value, in radians.
1937 
1938 *-
1939 */
1940    return 0.0;
1941 }
1942 
GetNP(AstWcsMap * this,int i,int * status)1943 static int GetNP( AstWcsMap *this, int i, int *status ) {
1944 /*
1945 *+
1946 *  Name:
1947 *     GetNP
1948 
1949 *  Purpose:
1950 *     Get the number of projection parameters for a specified axis.
1951 
1952 *  Type:
1953 *     Protected function.
1954 
1955 *  Synopsis:
1956 *     #include "wcsmap.h"
1957 *     int GetNP( AstWcsMap *this, int i, int *status )
1958 
1959 *  Class Membership:
1960 *     WcsMap protected function
1961 
1962 *  Description:
1963 *     This function returns the current number of projection parameters
1964 *     associated with the speified axis. Some of these may be unset (i.e.
1965 *     equal to AST__BAD). The returned number is the size of the array
1966 *     holding the projection parameters.
1967 
1968 *  Parameters:
1969 *     this
1970 *        A pointer to the WcsMap.
1971 *     i
1972 *        Zero based axis index.
1973 *     status
1974 *        Pointer to the inherited status variable.
1975 
1976 *  Returned Value:
1977 *     The number of projection parameters for the specified axis.
1978 
1979 *-
1980 */
1981    double ret;
1982 
1983 /* Initialise */
1984    ret = 0;
1985 
1986 /* Check the global error status. */
1987    if ( !astOK ) return ret;
1988 
1989 /* Validate the axis index, and get the count. */
1990    if( i >= 0 && this->np && i < astGetNin( this ) ) ret = this->np[ i ];
1991 
1992    return ret;
1993 
1994 }
1995 
GetPV(AstWcsMap * this,int i,int m,int * status)1996 static double GetPV( AstWcsMap *this, int i, int m, int *status ) {
1997 /*
1998 *+
1999 *  Name:
2000 *     astGetPV
2001 
2002 *  Purpose:
2003 *     Get the value of a PVi_m attribute.
2004 
2005 *  Type:
2006 *     Protected function.
2007 
2008 *  Synopsis:
2009 *     #include "wcsmap.h"
2010 *     double astGetPV( AstWcsMap *this, int i, int m )
2011 
2012 *  Class Membership:
2013 *     WcsMap protected function
2014 
2015 *  Description:
2016 *     This function returns the current value of a specified member of the
2017 *     PV attribute array. A value of AST__BAD is returned if no value has
2018 *     been set for the parameter.
2019 
2020 *  Parameters:
2021 *     this
2022 *        A pointer to the WcsMap.
2023 *     i
2024 *        Zero based axis index.
2025 *     m
2026 *        Zero based parameter index.
2027 
2028 *  Returned Value:
2029 *     The value of the requested attribute, of AST__BAD if not set.
2030 
2031 *-
2032 */
2033 
2034 /* Local Variables: */
2035    double ret;
2036    int npar;
2037    int mxpar;
2038 
2039 /* Initialise */
2040    ret = AST__BAD;
2041 
2042 /* Check the global error status. */
2043    if ( !astOK ) return ret;
2044 
2045 /* Validate the axis index. */
2046    if( i < 0 || i >= astGetNin( this ) ){
2047       astError( AST__AXIIN, "astGetPV(%s): Axis index (%d) is invalid in "
2048                 "attribute PV%d_%d  - it should be in the range 1 to %d.",
2049                 status, astGetClass( this ), i + 1, i + 1, m, astGetNin( this ) );
2050 
2051 /* Find the maximum number of parameters allowed for the axis. */
2052    } else {
2053       mxpar = astGetPVMax( this, i );
2054 
2055 /* Validate the parameter index. */
2056       if( m < 0 || m > mxpar ){
2057          astError( AST__AXIIN, "astGetPV(%s): Parameter index (%d) is invalid "
2058                    "in attribute PV%d_%d for a \"%s\" projection - it should be "
2059                    "in the range 0 to %d.", status, astGetClass( this ), m, i + 1, m,
2060                    FindPrjData( this->type, status )->ctype, mxpar );
2061 
2062 /* For latitude parameters use the values in the "params" structure which will
2063    have been defaulted. */
2064       } else if( i == astGetWcsAxis( this, 1 ) ) {
2065          ret = (this->params).p[ m ];
2066 
2067 /* For other axes, see if the arrays stored in the WcsMap structure extend as
2068    far as the requested parameter. If so, return the required attribute value.
2069    Otherwise the AST__BAD value initialised above is retained. */
2070       } else if( this->np && this->p ){
2071          npar = this->np[ i ];
2072          if( m < npar && this->p[ i ] ) ret = this->p[ i ][ m ];
2073       }
2074 
2075 /* FITS-WCS paper II gives defaults for the first 3 longitude axis
2076    parameters. The AST-specific TPN projection does not use this
2077    convention since it needs all projection parameters to specify
2078    correction terms. */
2079       if( ret == AST__BAD && i == astGetWcsAxis( this, 0 ) &&
2080           astGetWcsType( this ) != AST__TPN ) {
2081 
2082 /* Parameter zero has a default of zero. */
2083          if( m == 0 ) {
2084             ret = 0.0;
2085 
2086 /* Parameter one has a default equal to the native longitude of the
2087    reference point of the projection, in degrees. */
2088          } else if( m == 1 ) {
2089             ret = astGetNatLon( this )*AST__DR2D;
2090 
2091 /* Parameter two has a default equal to the native latitude of the
2092    reference point of the projection (in degrees). This is constant for
2093    most projection, but for some (the conics) it is specified by
2094    projection one on the latitude axis. */
2095          } else if( m == 2 ) {
2096             ret = astGetNatLat( this )*AST__DR2D;
2097          }
2098       }
2099    }
2100 
2101    return ret;
2102 
2103 }
2104 
GetPVMax(AstWcsMap * this,int i,int * status)2105 static int GetPVMax( AstWcsMap *this, int i, int *status ) {
2106 /*
2107 *+
2108 *  Name:
2109 *     astGetPVMax
2110 
2111 *  Purpose:
2112 *     Get the maximum projection parameter index for a WcsMap.
2113 
2114 *  Type:
2115 *     Protected function.
2116 
2117 *  Synopsis:
2118 *     #include "wcsmap.h"
2119 *     int astGetPVMax( AstWcsMap *this, int i )
2120 
2121 *  Class Membership:
2122 *     WcsMap protected function
2123 
2124 *  Description:
2125 *     This function returns the largest legal projection parameter index
2126 *     for a specified axis of the given WcsMap (i.e. the largest value of
2127 *     "m" in the attribute "PVi_m").
2128 
2129 *  Parameters:
2130 *     this
2131 *        A pointer to the WcsMap.
2132 *     i
2133 *        Zero based axis index.
2134 
2135 *  Returned Value:
2136 *     The largest legal projection parameter index, or -1 if no
2137 *     projection parameters are allowed on the specified axis.
2138 
2139 *-
2140 */
2141 
2142 /* Local Variables: */
2143    int mxpar;
2144 
2145 /* Initialise */
2146    mxpar = 0;
2147 
2148 /* Check the global error status. */
2149    if ( !astOK ) return -1;
2150 
2151 /* Validate the axis index. */
2152    if( i < 0 || i >= astGetNin( this ) ){
2153       astError( AST__AXIIN, "astGetPVMax(%s): Axis index (%d) is invalid in "
2154                 "attribute PVMax(%d)  - it should be in the range 1 to %d.",
2155                 status, astGetClass( this ), i + 1, i + 1, astGetNin( this ) );
2156 
2157 /* Find the maximum number of parameters allowed for the axis. */
2158    } else if( i == astGetWcsAxis( this, 0 ) ) {
2159       mxpar = astSizeOf( this->params.p2 )/sizeof( double );
2160 
2161    } else if( i == astGetWcsAxis( this, 1 ) ) {
2162       mxpar = astSizeOf( this->params.p )/sizeof( double );
2163 
2164    }
2165 
2166 /* The mxpar variable holds the max number of parameters. Return the the
2167    largest legal parameter index (one less than the max number of
2168    parameters). */
2169    return mxpar - 1;
2170 }
2171 
InitPrjPrm(AstWcsMap * this,int * status)2172 static void InitPrjPrm( AstWcsMap *this, int *status ) {
2173 /*
2174 *  Name:
2175 *     InitPrjPrm
2176 
2177 *  Purpose:
2178 *     Initialise the WcsLib PrjPrm structure, assigning default values for
2179 *     missing parameters.
2180 
2181 *  Type:
2182 *     Private function.
2183 
2184 *  Synopsis:
2185 *     void InitPrjPrm( AstWcsMap *this, int *status )
2186 
2187 *  Description:
2188 *     This function initializes the projection parameter information
2189 *     stored within the WcsLib AstPrjPrm structure associated with the
2190 *     supplied WcsMap. Default values are assigned to any unspecified
2191 *     parameter values. AST__BAD values are assigned if any parameters
2192 *     have not been supplied for which there is no default.
2193 
2194 *  Parameters:
2195 *     this
2196 *        The WcsMap.
2197 *     status
2198 *        Pointer to the inherited status variable.
2199 
2200 */
2201 
2202 
2203 /* Local Variables: */
2204    struct AstPrjPrm *params;     /* The AstPrjPrm structure from the WcsMap */
2205    int i;                        /* Loop index */
2206    int latax;                    /* Index of latitude axis */
2207    int lonax;                    /* Index of longitude axis */
2208    int npar;                     /* No. of parameters supplied */
2209    int plen;                     /* Length of params array */
2210    int plen2;                    /* Length of latitude params array */
2211    int type;                     /* Projection type */
2212 
2213 /* Check the global error status. */
2214    if ( !astOK ) return;
2215 
2216 /* Get a pointer to the AstPrjPrm structure*/
2217    params = &(this->params);
2218 
2219 /* Tell the routines within the WcsLib "proj.c" module  to re-calculate
2220    intermediate values. */
2221    params->flag = 0;
2222    params->r0 = 0;
2223 
2224 /* If this is a TPN projection, indicate whether or not the
2225    transformation should include the TAN projection or just the
2226    polynomial transformation. */
2227    if( this->type == AST__TPN ) params->n = astGetTPNTan( this );
2228 
2229 /* Find the max number of projection parameters associated with each
2230    axis.*/
2231    plen2 = astSizeOf( params->p2 )/sizeof( double );
2232    plen = astSizeOf( params->p )/sizeof( double );
2233 
2234 /* Initially set all parameter to AST__BAD. */
2235    for( i = 0; i < plen; i++ ) (params->p)[i] = AST__BAD;
2236    for( i = 0; i < plen2; i++ ) (params->p2)[i] = AST__BAD;
2237 
2238 /* If the WcsMap contains any projection parameter values... */
2239    if( this->np && this->p ){
2240 
2241 /* Get the index of the latitude axis. Currently, all projection
2242    parameters are associated with the latitude axis (except for
2243    the TPN projection, which is a hang-over from a earlier draft of the
2244    FITS-WCS paper). */
2245       latax = astGetWcsAxis( this, 1 );
2246 
2247 /* Find the number of projection parameters in the WcsMap for the
2248    latitude axis. */
2249       npar = (this->np)[ latax ];
2250       if( npar > plen ) {
2251          astError( AST__INTER, "InitPrjPrm(WcsMap): Too many projection "
2252                    "parameters on the latitude axis (%d > %d) (internal "
2253                    "AST programming error).", status, npar, plen );
2254       }
2255 
2256 /* Copy the parameters to the AstPrjPrm structure. Do not copy more than
2257    can be stored in the AstPrjPrm structure. */
2258       for( i = 0; i < npar && i < plen; i++ ) {
2259          (params->p)[ i ] = (this->p)[ latax ][ i ];
2260       }
2261 
2262 /* Do the same for the longitude axis (for the benefit of the TPN projection). */
2263       lonax = astGetWcsAxis( this, 0 );
2264       npar = (this->np)[ lonax ];
2265 
2266       if( npar > plen2 ) {
2267          astError( AST__INTER, "InitPrjPrm(WcsMap): Too many projection "
2268                    "parameters on the longitude axis (%d > %d) (internal "
2269                    "AST programming error).", status, npar, plen2 );
2270       }
2271 
2272       for( i = 0; i < npar && i < plen2; i++ ) {
2273          (params->p2)[ i ] = (this->p)[ lonax ][ i ];
2274       }
2275 
2276    }
2277 
2278 /* Get the projection type. */
2279    type = astGetWcsType( this );
2280 
2281 /* First supply default values for any missing projection parameters which
2282    do not default to zero. */
2283    if( type == AST__SZP ){
2284       if( (params->p)[ 3 ] == AST__BAD ) (params->p)[ 3 ] = 90.0;
2285 
2286    } else if( type == AST__AIR ){
2287       if( (params->p)[ 1 ] == AST__BAD ) (params->p)[ 1 ] = 90.0;
2288 
2289    } else if( type == AST__CYP ){
2290       if( (params->p)[ 1 ] == AST__BAD ) (params->p)[ 1 ] = 1.0;
2291       if( (params->p)[ 2 ] == AST__BAD ) (params->p)[ 2 ] = 1.0;
2292 
2293    } else if( type == AST__CEA ){
2294       if( (params->p)[ 1 ] == AST__BAD ) (params->p)[ 1 ] = 1.0;
2295 
2296    } else if( type == AST__TPN ){
2297       if( (params->p)[ 1 ] == AST__BAD ) (params->p)[ 1 ] = 1.0;
2298       if( (params->p2)[ 1 ] == AST__BAD ) (params->p2)[ 1 ] = 1.0;
2299 
2300    } else if( type == AST__HPX ){
2301       if( (params->p)[ 1 ] == AST__BAD ) (params->p)[ 1 ] = 4.0;
2302       if( (params->p)[ 2 ] == AST__BAD ) (params->p)[ 2 ] = 3.0;
2303 
2304    }
2305 
2306 /* Now use a default value of zero for any remaining unspecified values,
2307    except for un-defaultable projection parameters. */
2308    for( i = 0; i < plen; i++ ){
2309 
2310 /* Retain any AST__BAD value for these undefaultable parameters. */
2311       if( i == 1 && ( type == AST__BON ||
2312                      type == AST__COP || type == AST__COE ||
2313                      type == AST__COD || type == AST__COO ) ){
2314 
2315 /* Use a default of zero for all other parameters. */
2316       } else {
2317          if( (params->p)[ i ] == AST__BAD ) (params->p)[ i ] = 0.0;
2318       }
2319    }
2320 
2321 /* Do the same for the latitude projection parameters (if any) */
2322    for( i = 0; i < plen2; i++ ){
2323       if( i == 1 && ( type == AST__BON ||
2324                       type == AST__COP || type == AST__COE ||
2325                       type == AST__COD || type == AST__COO ) ){
2326       } else {
2327          if( (params->p2)[ i ] == AST__BAD ) (params->p2)[ i ] = 0.0;
2328       }
2329    }
2330 }
2331 
astInitWcsMapVtab_(AstWcsMapVtab * vtab,const char * name,int * status)2332 void astInitWcsMapVtab_(  AstWcsMapVtab *vtab, const char *name, int *status ) {
2333 /*
2334 *+
2335 *  Name:
2336 *     astInitWcsMapVtab
2337 
2338 *  Purpose:
2339 *     Initialise a virtual function table for a WcsMap.
2340 
2341 *  Type:
2342 *     Protected function.
2343 
2344 *  Synopsis:
2345 *     #include "wcsmap.h"
2346 *     void astInitWcsMapVtab( AstWcsMapVtab *vtab, const char *name )
2347 
2348 *  Class Membership:
2349 *     WcsMap vtab initialiser.
2350 
2351 *  Description:
2352 *     This function initialises the component of a virtual function
2353 *     table which is used by the WcsMap class.
2354 
2355 *  Parameters:
2356 *     vtab
2357 *        Pointer to the virtual function table. The components used by
2358 *        all ancestral classes will be initialised if they have not already
2359 *        been initialised.
2360 *     name
2361 *        Pointer to a constant null-terminated character string which contains
2362 *        the name of the class to which the virtual function table belongs (it
2363 *        is this pointer value that will subsequently be returned by the Object
2364 *        astClass function).
2365 *-
2366 */
2367 
2368 /* Local Variables: */
2369    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2370    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
2371    AstMappingVtab *mapping;      /* Pointer to Mapping component of Vtab */
2372 
2373 /* Check the local error status. */
2374    if ( !astOK ) return;
2375 
2376 /* Get a pointer to the thread specific global data structure. */
2377    astGET_GLOBALS(NULL);
2378 
2379 /* Initialize the component of the virtual function table used by the
2380    parent class. */
2381    astInitMappingVtab( (AstMappingVtab *) vtab, name );
2382 
2383 /* Store a unique "magic" value in the virtual function table. This
2384    will be used (by astIsAWcsMap) to determine if an object belongs
2385    to this class.  We can conveniently use the address of the (static)
2386    class_check variable to generate this unique value. */
2387    vtab->id.check = &class_check;
2388    vtab->id.parent = &(((AstMappingVtab *) vtab)->id);
2389 
2390 /* Initialise member function pointers. */
2391 /* ------------------------------------ */
2392 /* Store pointers to the member functions (implemented here) that provide
2393    virtual methods for this class. */
2394    vtab->ClearPV = ClearPV;
2395    vtab->GetNatLat = GetNatLat;
2396    vtab->GetNatLon = GetNatLon;
2397    vtab->GetPV = GetPV;
2398    vtab->GetWcsAxis = GetWcsAxis;
2399    vtab->GetPVMax = GetPVMax;
2400    vtab->GetWcsType = GetWcsType;
2401    vtab->SetPV = SetPV;
2402    vtab->TestPV = TestPV;
2403    vtab->IsZenithal = IsZenithal;
2404 
2405    vtab->ClearFITSProj = ClearFITSProj;
2406    vtab->TestFITSProj = TestFITSProj;
2407    vtab->GetFITSProj = GetFITSProj;
2408    vtab->SetFITSProj = SetFITSProj;
2409 
2410    vtab->ClearTPNTan = ClearTPNTan;
2411    vtab->TestTPNTan = TestTPNTan;
2412    vtab->GetTPNTan = GetTPNTan;
2413    vtab->SetTPNTan = SetTPNTan;
2414 
2415 /* Save the inherited pointers to methods that will be extended, and
2416    replace them with pointers to the new member functions. */
2417    object = (AstObjectVtab *) vtab;
2418    mapping = (AstMappingVtab *) vtab;
2419    parent_getobjsize = object->GetObjSize;
2420    object->GetObjSize = GetObjSize;
2421 
2422    parent_clearattrib = object->ClearAttrib;
2423    object->ClearAttrib = ClearAttrib;
2424    parent_getattrib = object->GetAttrib;
2425    object->GetAttrib = GetAttrib;
2426    parent_setattrib = object->SetAttrib;
2427    object->SetAttrib = SetAttrib;
2428    parent_testattrib = object->TestAttrib;
2429    object->TestAttrib = TestAttrib;
2430 
2431    parent_transform = mapping->Transform;
2432    mapping->Transform = Transform;
2433 
2434    parent_mapsplit = mapping->MapSplit;
2435    mapping->MapSplit = MapSplit;
2436 
2437 /* Store replacement pointers for methods which will be over-ridden by
2438    new member functions implemented here. */
2439    object->Equal = Equal;
2440    mapping->MapMerge = MapMerge;
2441 
2442 /* Declare the destructor and copy constructor. */
2443    astSetDelete( (AstObjectVtab *) vtab, Delete );
2444    astSetCopy( (AstObjectVtab *) vtab, Copy );
2445 
2446 /* Declare the class dump function. */
2447    astSetDump( vtab, Dump, "WcsMap", "FITS-WCS sky projection" );
2448 
2449 /* If we have just initialised the vtab for the current class, indicate
2450    that the vtab is now initialised, and store a pointer to the class
2451    identifier in the base "object" level of the vtab. */
2452    if( vtab == &class_vtab ) {
2453       class_init = 1;
2454       astSetVtabClassIdentifier( vtab, &(vtab->id) );
2455    }
2456 }
2457 
IsZenithal(AstWcsMap * this,int * status)2458 static int IsZenithal( AstWcsMap *this, int *status ){
2459 /*
2460 *+
2461 *  Name:
2462 *     IsZenithal
2463 
2464 *  Purpose:
2465 *     Determine if this WcsMap represents a zenithal projection.
2466 
2467 *  Type:
2468 *     Protected function.
2469 
2470 *  Synopsis:
2471 *     #include "wcsmap.h"
2472 *     int IsZenithal( AstWcsMap *this, int *status )
2473 
2474 *  Class Membership:
2475 *     WcsMap protected function
2476 
2477 *  Description:
2478 *     This function returns a flag indicating if this WcsMap is a zenithal
2479 *     projection. Some projections which are classed as zenithal in the
2480 *     Calabretta and Greisen paper are only genuinely zenithal if the
2481 *     projection parameters have certain values. These projections are
2482 *     not considered to be zenithal unless the projection parameters have
2483 *     appropriate values.
2484 
2485 *  Parameters:
2486 *     this
2487 *        The WcsMap.
2488 *     status
2489 *        Pointer to the inherited status variable.
2490 
2491 *  Returned Value:
2492 *     A non-zero value if the WcsMap represents a zenithal projection.
2493 
2494 *-
2495 */
2496 
2497 /* Local Variables: */
2498    double p1;                    /* PVi_1 */
2499    double p2;                    /* PVi_2 */
2500    double p3;                    /* PVi_3 */
2501    int latax;                    /* Index of latitude axis */
2502    int ret;                      /* Returned flag */
2503    int type;                     /* Projection type */
2504 
2505 /* Initialise the returned value. */
2506    ret = 0;
2507 
2508 /* Check the global error status. */
2509    if ( !astOK ) return ret;
2510 
2511 /* Get the projection type. */
2512    type = astGetWcsType( this );
2513 
2514 /* Get the index of the latitude axis. */
2515    latax = astGetWcsAxis( this, 1 );
2516 
2517 /* The following are always zenithal... */
2518    if( type == AST__TAN  || type == AST__STG  || type == AST__ARC  ||
2519        type == AST__ZPN  || type == AST__ZEA  || type == AST__AIR ||
2520        type == AST__TPN ) {
2521       ret = 1;
2522 
2523 /* The following are sometimes zenithal... */
2524    } else if( type == AST__AZP ) {
2525       p2 = astGetPV( this, latax, 2 );
2526       if( p2 == AST__BAD || p2 == 0.0 ) ret = 1;
2527 
2528    } else if( type == AST__SIN ) {
2529       p1 = astGetPV( this, latax, 1 );
2530       p2 = astGetPV( this, latax, 2 );
2531       if( p1 == AST__BAD ) p1 = 0.0;
2532       if( p2 == AST__BAD ) p2 = 0.0;
2533       if( p1 == 0.0 && p2 == 0.0 ) ret = 1;
2534 
2535    } else if( type == AST__SZP ) {
2536       p3 = astGetPV( this, latax, 2 );
2537       if( p3 == AST__BAD ) p3 = 90.0;
2538       if( p3 == 90.0 || p3 == -90.0 ) ret = 1;
2539 
2540    }
2541 
2542    return ret;
2543 }
2544 
LongRange(const PrjData * prjdata,struct AstPrjPrm * params,double * high,double * low,int * status)2545 static int LongRange( const PrjData *prjdata, struct AstPrjPrm *params,
2546                        double *high, double *low, int *status ){
2547 /*
2548 *
2549 *  Name:
2550 *     LongRange
2551 
2552 *  Purpose:
2553 *     See if primary range of longitude produced by a WCSLIB mapping is
2554 *     [0,360] or [-180,+180].
2555 
2556 *  Type:
2557 *     Private function.
2558 
2559 *  Synopsis:
2560 *     #include "wcsmap.h"
2561 *     void LongRange( const PrjData *prjdata, struct AstPrjPrm *params,
2562 *                     double *high, double *low, int *status )
2563 
2564 *  Class Membership:
2565 *     WcsMap internal utility function.
2566 
2567 *  Description:
2568 *     This function uses the WCSLIB library to transform the supplied input
2569 *     positions.
2570 
2571 *  Parameters:
2572 *     prjdata
2573 *        A pointer to information about the mapping.
2574 *     params
2575 *        Pointer to a WCSLIB "AstPrjPrm" structure containing the projection
2576 *        parameters, etc.
2577 *     high
2578 *        A pointer to a location at which is returned the upper bound of
2579 *        the primary longitude range.
2580 *     low
2581 *        A pointer to a location at which is returned the lower bound of
2582 *        the primary longitude range.
2583 *     status
2584 *        Pointer to the inherited status variable.
2585 
2586 *  Returned Value:
2587 *     A flag indicating if the sky->xy transformation is cyclic (i.e.
2588 *     [a,0] gets mapped to the same (x,y) position as [a+2.PI,0]).
2589 */
2590 
2591 
2592 /* Local Variables: */
2593    int point;                    /* Loop counter for points */
2594    static double xx[ 4 ] = { -1.0E-6,    0.0, 1.0E-6,     0.0 };
2595    static double yy[ 4 ] = {     0.0, 1.0E-6,    0.0, -1.0E-6 };
2596    double aa;
2597    double bb;
2598    double xxx[ 2 ];
2599    double yyy[ 2 ];
2600    int cyclic;
2601 
2602 /* Initialise the returned values. */
2603    *high = 180.0;
2604    *low = -180.0;
2605 
2606 /* Check the global error status. */
2607    if ( !astOK ) return 0;
2608 
2609 /* Project each of the points. If any longitude value is found which is
2610    greater than 180 degrees, return [0,360] as the longitude range. */
2611    for( point = 0; point < 4; point++ ){
2612       if( !prjdata->WcsRev( xx[ point ], yy[ point ], params, &aa, &bb ) ){
2613          if( aa > 180.0 ){
2614             *high = 360.0;
2615             *low = 0.0;
2616             break;
2617          }
2618       }
2619    }
2620 
2621 /* See if the projection is cyclic. Transform the sky positions [90,bb] and
2622    [450,bb] into cartesian positions and see if they are the same. */
2623    prjdata->WcsFwd( 90.0, bb, params, xxx, yyy );
2624    prjdata->WcsFwd( 450.0, bb, params, xxx + 1, yyy + 1 );
2625    cyclic = ( fabs( xxx[ 0 ] - xxx[ 1 ] ) < 1.0E-10 &&
2626               fabs( yyy[ 0 ] - yyy[ 1 ] ) < 1.0E-10 );
2627 
2628 /* Return. */
2629    return cyclic;
2630 
2631 }
2632 
Map(AstWcsMap * this,int forward,int npoint,double * in0,double * in1,double * out0,double * out1,int * status)2633 static int Map( AstWcsMap *this, int forward, int npoint, double *in0,
2634                 double *in1, double *out0, double *out1, int *status ){
2635 /*
2636 *
2637 *  Name:
2638 *     Map
2639 
2640 *  Purpose:
2641 *     Transform a set of points using a function from the WCSLIB library.
2642 
2643 *  Type:
2644 *     Private function.
2645 
2646 *  Synopsis:
2647 *     #include "wcsmap.h"
2648 *     int Map( AstWcsMap *this, int forward, int npoint, double *in0,
2649 *              double *in1, double *out0, double *out1 )
2650 
2651 *  Class Membership:
2652 *     WcsMap internal utility function.
2653 
2654 *  Description:
2655 *     This function uses the WCSLIB library to transform the supplied input
2656 *     positions.
2657 
2658 *  Parameters:
2659 *     this
2660 *        Pointer to the WcsMap.
2661 *     forward
2662 *        A non-zero value indicates that the forward projection from
2663 *        (long,lat) to (x,y) is required, while a zero value requests the
2664 *        reverse transformation.
2665 *     npoint
2666 *        The number of points to transform (i.e. the size of the
2667 *        in0, in1, out0 and out1 arrays).
2668 *     in0
2669 *        A pointer to the input coordinate data for the 0th axis (i.e.
2670 *        longitude or X depending on "forward").
2671 *     in1
2672 *        A pointer to the input coordinate data for the 1st axis (i.e.
2673 *        latitude or Y depending on "forward").
2674 *     out0
2675 *        A pointer to the returned output coordinate data for the 0th axis
2676 *        (i.e. X or longitude depending on "forward").
2677 *     out1
2678 *        A pointer to the returned output coordinate data for the 1st axis
2679 *        (i.e. Y or latitude depending on "forward").
2680 
2681 *  Returned Value:
2682 *     The status value: 0 - Success
2683 *                       1 - Unrecognised projection type
2684 *                       2 - Invalid projection parameters values.
2685 *                       4 - Error existed on entry
2686 *                       100 - 399: Longitude axis projection parameter
2687 *                           (status-100) not supplied.
2688 *                       400 - 699: Latitude axis projection parameter
2689 *                           (status-400) not supplied.
2690 
2691 
2692 *  Notes:
2693 *     -  This function does not report any errors. Reporting of suitable
2694 *     error messages is the responsibility of the calling function.
2695 *     -  The value 4 will be returned if this function is invoked with the
2696 *     global error status set.
2697 *
2698 */
2699 
2700 /* Local Variables: */
2701    const PrjData *prjdata;       /* Information about the projection */
2702    double factor;                /* Factor that scales input into radians. */
2703    double latitude;              /* Latitude value in degrees */
2704    double longhi;                /* Upper longitude limit in degrees */
2705    double longitude;             /* Longitude value in degrees */
2706    double longlo;                /* Lower longitude limit in degrees */
2707    double x;                     /* X Cartesian coordinate in degrees */
2708    double y;                     /* Y Cartesian coordinate in degrees */
2709    int cyclic;                   /* Is sky->xy transformation cyclic? */
2710    int i;                        /* Loop count */
2711    int plen;                     /* Length of proj par array */
2712    int point;                    /* Loop counter for points */
2713    int type;                     /* Projection type */
2714    int wcs_status;               /* Status from WCSLIB functions */
2715    struct AstPrjPrm *params;     /* Pointer to structure holding WCSLIB info */
2716 
2717 /* Check the global error status. */
2718    if ( !astOK ) return 4;
2719 
2720 /* Initialise variables to avoid compiler warnings. */
2721    longlo = AST__BAD;
2722    longhi = AST__BAD;
2723 
2724 /* Store the projection type. */
2725    type = astGetWcsType( this );
2726 
2727 /* Get information about the projection. */
2728    prjdata = FindPrjData( type, status );
2729 
2730 /* Return if there are no WcsLib mapping functons associated with the
2731    projection. */
2732    if( ( !prjdata->WcsFwd && forward ) ||
2733        ( !prjdata->WcsRev && !forward ) ) return 1;
2734 
2735 /* Check that all necessary projection parameters have been supplied, or
2736    can be defaulted. */
2737    params = &(this->params);
2738    plen = astSizeOf( params->p )/sizeof( double );
2739    for( i = 0; i < plen; i++ ) {
2740       if( ( params->p)[ i ] == AST__BAD ) return 400+i;
2741    }
2742 
2743 /* If we are doing a reverse mapping, get the acceptable range of longitude
2744    values. */
2745    cyclic = forward ? 0 : LongRange( prjdata, params, &longhi, &longlo,
2746                                      status );
2747 
2748 /* The WcsMap input and output values are normally in radians, but if
2749    the TPNTan attribute has been reset then they are in degrees. The
2750    WCSLIB projection functions always expect and return degrees. Get
2751    the factor that scales the WcsMap input into radians. */
2752    factor = astGetTPNTan( this ) ? 1.0 : AST__DD2R;
2753 
2754 /* Loop to apply the projection to each point in turn, checking for
2755    (and propagating) bad values in the process. */
2756    for ( point = 0; point < npoint; point++ ) {
2757        if ( in0[ point ] == AST__BAD ||
2758            in1[ point ] == AST__BAD ){
2759           out0[ point ] = AST__BAD;
2760           out1[ point ] = AST__BAD;
2761        } else {
2762 
2763 /* First deal with forward projection calls */
2764          if ( forward ){
2765 
2766 /* The input coordinates are assumed to be longitude and latitude, in
2767    radians or degrees (as specified by the TPNTan attribute). Convert them
2768    to degrees ensuring that the longitude value is in the range [-180,180]
2769    and the latitude is in the range [-90,90] (as required by the WCSLIB
2770    library). Any point with a latitude outside the range [-90,90] is
2771    converted to the equivalent point on the complementary meridian. */
2772             latitude = AST__DR2D*palDrange(  factor*in1[ point ] );
2773             if ( latitude > 90.0 ){
2774                latitude = 180.0 - latitude;
2775                longitude = AST__DR2D*palDrange( AST__DPI + factor*in0[ point ] );
2776 
2777             } else if ( latitude < -90.0 ){
2778                latitude = -180.0 - latitude;
2779                longitude = AST__DR2D*palDrange( AST__DPI + factor*in0[ point ] );
2780 
2781             } else {
2782                longitude = AST__DR2D*palDrange( factor*in0[ point ] );
2783             }
2784 
2785 /* Call the relevant WCSLIB forward projection function. */
2786             wcs_status = prjdata->WcsFwd( longitude, latitude, params, &x, &y );
2787 
2788 /* Store the returned Cartesian coordinates, converting them from degrees
2789    to radians. If the position could not be projected, use the value
2790    AST__BAD.  Abort for any other bad status. */
2791             if( wcs_status == 0 ){
2792                out0[ point ] = (AST__DD2R/factor)*x;
2793                out1[ point ] = (AST__DD2R/factor)*y;
2794 
2795             } else if( wcs_status == 1 ){
2796                return 2;
2797 
2798             } else if( wcs_status == 2 ){
2799                out0[ point ] = AST__BAD;
2800                out1[ point ] = AST__BAD;
2801 
2802             } else {
2803                return wcs_status;
2804             }
2805 
2806 /* Now deal with reverse projection calls */
2807          } else {
2808 
2809 /* Convert the supplied Cartesian coordinates from radians to degrees. */
2810             x = (AST__DR2D*factor)*in0[ point ];
2811             y = (AST__DR2D*factor)*in1[ point ];
2812 
2813 /* Call the relevant WCSLIB reverse projection function. */
2814             wcs_status = prjdata->WcsRev( x, y, params, &longitude, &latitude );
2815 
2816 /* Store the returned longitude and latitude, converting them from degrees
2817    to radians. Many projections (ARC, AIT, ZPN, etc) are not cyclic (i.e.
2818    [long,lat]=[0,0] does not get mapped to the same place as
2819    [long,lat]=[360,0] ). Only accept values in the primary longitude or
2820    latitude ranges. This avoids (x,y) points outside the physical domain
2821    of the mapping being assigned valid (long,lat) values. */
2822             if( wcs_status == 0 ){
2823                if( ( cyclic || ( longitude < longhi &&
2824                                  longitude >= longlo ) ) &&
2825                    fabs( latitude ) <= 90.0 ){
2826 
2827                   out0[ point ] = (AST__DD2R/factor)*longitude;
2828                   out1[ point ] = (AST__DD2R/factor)*latitude;
2829 
2830                } else {
2831                   out0[ point ] = AST__BAD;
2832                   out1[ point ] = AST__BAD;
2833                }
2834 
2835 /* Abort if projection parameters were unusable. */
2836             } else if( wcs_status == 1 ){
2837                return 2;
2838 
2839 /* If the position could not be projected, use the value AST__BAD. */
2840             } else if( wcs_status == 2 ){
2841                out0[ point ] = AST__BAD;
2842                out1[ point ] = AST__BAD;
2843 
2844 /* Abort if projection parameters were not supplied. */
2845             } else {
2846                return wcs_status;
2847             }
2848 
2849          }
2850 
2851       }
2852 
2853    }
2854 
2855    return 0;
2856 }
2857 
MapMerge(AstMapping * this,int where,int series,int * nmap,AstMapping *** map_list,int ** invert_list,int * status)2858 static int MapMerge( AstMapping *this, int where, int series, int *nmap,
2859                      AstMapping ***map_list, int **invert_list, int *status ) {
2860 /*
2861 *  Name:
2862 *     MapMerge
2863 
2864 *  Purpose:
2865 *     Simplify a sequence of Mappings containing a WcsMap.
2866 
2867 *  Type:
2868 *     Private function.
2869 
2870 *  Synopsis:
2871 *     #include "wcsmap.h"
2872 *     int MapMerge( AstMapping *this, int where, int series, int *nmap,
2873 *                   AstMapping ***map_list, int **invert_list, int *status )
2874 
2875 *  Class Membership:
2876 *     WcsMap method (over-rides the protected astMapMerge method
2877 *     inherited from the Mapping class).
2878 
2879 *  Description:
2880 *     This function attempts to simplify a sequence of Mappings by
2881 *     merging a nominated WcsMap in the sequence with its neighbours,
2882 *     so as to shorten the sequence if possible.
2883 *
2884 *     In many cases, simplification will not be possible and the
2885 *     function will return -1 to indicate this, without further
2886 *     action.
2887 *
2888 *     In most cases of interest, however, this function will either
2889 *     attempt to replace the nominated WcsMap with a Mapping which it
2890 *     considers simpler, or to merge it with the Mappings which
2891 *     immediately precede it or follow it in the sequence (both will
2892 *     normally be considered). This is sufficient to ensure the
2893 *     eventual simplification of most Mapping sequences by repeated
2894 *     application of this function.
2895 *
2896 *     In some cases, the function may attempt more elaborate
2897 *     simplification, involving any number of other Mappings in the
2898 *     sequence. It is not restricted in the type or scope of
2899 *     simplification it may perform, but will normally only attempt
2900 *     elaborate simplification in cases where a more straightforward
2901 *     approach is not adequate.
2902 
2903 *  Parameters:
2904 *     this
2905 *        Pointer to the nominated WcsMap which is to be merged with
2906 *        its neighbours. This should be a cloned copy of the WcsMap
2907 *        pointer contained in the array element "(*map_list)[where]"
2908 *        (see below). This pointer will not be annulled, and the
2909 *        WcsMap it identifies will not be modified by this function.
2910 *     where
2911 *        Index in the "*map_list" array (below) at which the pointer
2912 *        to the nominated WcsMap resides.
2913 *     series
2914 *        A non-zero value indicates that the sequence of Mappings to
2915 *        be simplified will be applied in series (i.e. one after the
2916 *        other), whereas a zero value indicates that they will be
2917 *        applied in parallel (i.e. on successive sub-sets of the
2918 *        input/output coordinates).
2919 *     nmap
2920 *        Address of an int which counts the number of Mappings in the
2921 *        sequence. On entry this should be set to the initial number
2922 *        of Mappings. On exit it will be updated to record the number
2923 *        of Mappings remaining after simplification.
2924 *     map_list
2925 *        Address of a pointer to a dynamically allocated array of
2926 *        Mapping pointers (produced, for example, by the astMapList
2927 *        method) which identifies the sequence of Mappings. On entry,
2928 *        the initial sequence of Mappings to be simplified should be
2929 *        supplied.
2930 *
2931 *        On exit, the contents of this array will be modified to
2932 *        reflect any simplification carried out. Any form of
2933 *        simplification may be performed. This may involve any of: (a)
2934 *        removing Mappings by annulling any of the pointers supplied,
2935 *        (b) replacing them with pointers to new Mappings, (c)
2936 *        inserting additional Mappings and (d) changing their order.
2937 *
2938 *        The intention is to reduce the number of Mappings in the
2939 *        sequence, if possible, and any reduction will be reflected in
2940 *        the value of "*nmap" returned. However, simplifications which
2941 *        do not reduce the length of the sequence (but improve its
2942 *        execution time, for example) may also be performed, and the
2943 *        sequence might conceivably increase in length (but normally
2944 *        only in order to split up a Mapping into pieces that can be
2945 *        more easily merged with their neighbours on subsequent
2946 *        invocations of this function).
2947 *
2948 *        If Mappings are removed from the sequence, any gaps that
2949 *        remain will be closed up, by moving subsequent Mapping
2950 *        pointers along in the array, so that vacated elements occur
2951 *        at the end. If the sequence increases in length, the array
2952 *        will be extended (and its pointer updated) if necessary to
2953 *        accommodate any new elements.
2954 *
2955 *        Note that any (or all) of the Mapping pointers supplied in
2956 *        this array may be annulled by this function, but the Mappings
2957 *        to which they refer are not modified in any way (although
2958 *        they may, of course, be deleted if the annulled pointer is
2959 *        the final one).
2960 *     invert_list
2961 *        Address of a pointer to a dynamically allocated array which,
2962 *        on entry, should contain values to be assigned to the Invert
2963 *        attributes of the Mappings identified in the "*map_list"
2964 *        array before they are applied (this array might have been
2965 *        produced, for example, by the astMapList method). These
2966 *        values will be used by this function instead of the actual
2967 *        Invert attributes of the Mappings supplied, which are
2968 *        ignored.
2969 *
2970 *        On exit, the contents of this array will be updated to
2971 *        correspond with the possibly modified contents of the
2972 *        "*map_list" array.  If the Mapping sequence increases in
2973 *        length, the "*invert_list" array will be extended (and its
2974 *        pointer updated) if necessary to accommodate any new
2975 *        elements.
2976 *     status
2977 *        Pointer to the inherited status variable.
2978 
2979 *  Returned Value:
2980 *     If simplification was possible, the function returns the index
2981 *     in the "map_list" array of the first element which was
2982 *     modified. Otherwise, it returns -1 (and makes no changes to the
2983 *     arrays supplied).
2984 
2985 *  Notes:
2986 *     - A value of -1 will be returned if this function is invoked
2987 *     with the global error status set, or if it should fail for any
2988 *     reason.
2989 */
2990 
2991 /* Local Variables: */
2992    AstMapping *mc[2];    /* Copies of supplied Mappings to swap */
2993    AstMapping *smc0;     /* Simplied Mapping */
2994    AstMapping *smc1;     /* Simplied Mapping */
2995    const char *nclass;   /* Pointer to neighbouring Mapping class */
2996    const char *class1;   /* Pointer to first Mapping class string */
2997    const char *class2;   /* Pointer to second Mapping class string */
2998    int do1;              /* Would a backward swap make a simplification? */
2999    int do2;              /* Would a forward swap make a simplification? */
3000    int i1;               /* Lower index of the two WcsMaps being merged */
3001    int i2;               /* Upper index of the two WcsMaps being merged */
3002    int i;                /* Mapping index */
3003    int ic[2];            /* Copies of supplied invert flags to swap */
3004    int merge;            /* Can WcsMap merge with a neighbour? */
3005    int nin;              /* Number of coordinates for WcsMap */
3006    int nstep1;           /* No. of Mappings backwards to next mergable Mapping */
3007    int nstep2;           /* No. of Mappings forward to next mergable Mapping */
3008    int result;           /* Result value to return */
3009    int swaphi;           /* Can WcsMap be swapped with higher neighbour? */
3010    int swaplo;           /* Can WcsMap be swapped with lower neighbour? */
3011    int type;             /* Projection type */
3012 
3013 /* Initialise. */
3014    result = -1;
3015 
3016 /* Check the global error status. */
3017    if ( !astOK ) return result;
3018 
3019 /* Initialise variables to avoid "used of uninitialised variable"
3020    messages from dumb compilers. */
3021    i1 = 0;
3022    i2 = 0;
3023 
3024 /* Get the number of axes for the WcsMap. */
3025    nin = astGetNin( ( *map_list )[ where ] );
3026 
3027 /* First of all, see if the WcsMap can be replaced by a simpler Mapping,
3028    without reference to the neighbouring Mappings in the list.           */
3029 /* ======================================================================*/
3030 /* WcsMaps with map type of AST__WCSBAD are equivalent to a UnitMap. */
3031    type = astGetWcsType( this );
3032    if( type == AST__WCSBAD ){
3033 
3034 /* Annul the WcsMap pointer in the list and replace it with a UnitMap
3035    pointer, and indicate that the forward transformation of the returned
3036    UnitMap should be used. */
3037       (void) astAnnul( ( *map_list )[ where ] );
3038       ( *map_list )[ where ] = (AstMapping *) astUnitMap( nin, "", status );
3039       ( *invert_list )[ where ] = 0;
3040 
3041 /* Return the index of the first modified element. */
3042       result = where;
3043 
3044 /* If the WcsMap itself could not be simplified, see if it can be merged
3045    with the Mappings on either side of it in the list. This can only be
3046    done in series for a WcsMap. */
3047 /* ===================================================================== */
3048    } else if( series && *nmap > 1 ) {
3049 
3050 /* Store the classes of the neighbouring Mappings in the list. */
3051       class1 = ( where > 0 ) ? astGetClass( ( *map_list )[ where - 1 ] ) : NULL;
3052       class2 = ( where < *nmap - 1 ) ? astGetClass( ( *map_list )[ where + 1 ] ) : NULL;
3053 
3054 /* A WcsMap can only combine with its own inverse. Set a flag indicating
3055    that we have not yet found a neighbour with which the WcsMap can be
3056    merged. */
3057       merge = 0;
3058 
3059 /* First check the lower neighbour (if any). */
3060       if( where > 0 ) {
3061          i1 = where - 1;
3062          i2 = where;
3063          merge = CanMerge( ( *map_list )[ i1 ], (* invert_list)[ i1 ],
3064                            ( *map_list )[ i2 ], (* invert_list)[ i2 ], status );
3065       }
3066 
3067 /* If the WcsMap can not be merged with its lower neighbour, check its
3068    upper neighbour (if any) in the same way. */
3069       if( !merge && where < *nmap - 1 ) {
3070          i1 = where;
3071          i2 = where + 1;
3072          merge = CanMerge( ( *map_list )[ i1 ], (* invert_list)[ i1 ],
3073                            ( *map_list )[ i2 ], (* invert_list)[ i2 ], status );
3074       }
3075 
3076 /* If either neighbour has passed these checks, it is the inverse of the
3077    WcsMap being checked. The pair of WcsMaps can be replaced by a single
3078    UnitMap. */
3079       if( merge ) {
3080 
3081 /* Annul the two WcsMaps. */
3082          (void) astAnnul( ( *map_list )[ i1 ] );
3083          (void) astAnnul( ( *map_list )[ i2 ] );
3084 
3085 /* Create a UnitMap, and store a pointer for it in place of the first
3086    WcsMap. */
3087          ( *map_list )[ i1 ] = (AstMapping *) astUnitMap( nin, "", status );
3088          ( *invert_list )[ i1 ] = 0;
3089 
3090 /* Shuffle down the remaining Mappings to fill the hole left by the
3091    second WcsMap. */
3092          for ( i = i2 + 1; i < *nmap; i++ ) {
3093             ( *map_list )[ i - 1 ] = ( *map_list )[ i ];
3094             ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ];
3095          }
3096 
3097 /* Clear the vacated element at the end. */
3098          ( *map_list )[ *nmap - 1 ] = NULL;
3099          ( *invert_list )[ *nmap - 1 ] = 0;
3100 
3101 /* Decrement the Mapping count and return the index of the first
3102    modified element. */
3103          (*nmap)--;
3104          result = i1;
3105 
3106 /* If the WcsMap could not merge directly with either of its neighbours,
3107    we consider whether it would be worthwhile to swap the WcsMap with
3108    either of its neighbours. This can only be done for certain PermMaps,
3109    and will usually require both Mappings to be modified (unless they are
3110    commutative). The advantage of swapping the order of the Mappings is that
3111    it may result in the WcsMap being adjacent to a Mapping with which it can
3112    merge directly on the next invocation of this function, thus reducing the
3113    number of Mappings in the list. */
3114       } else {
3115 
3116 /* Set a flag if we could swap the WcsMap with its higher neighbour. "do2"
3117    is returned if swapping the Mappings would simplify either of the
3118    Mappings. */
3119          if( where + 1 < *nmap ){
3120             swaphi = CanSwap(  ( *map_list )[ where ],
3121                                ( *map_list )[ where + 1 ],
3122                                ( *invert_list )[ where ],
3123                                ( *invert_list )[ where + 1 ], &do2, status );
3124          } else {
3125             do2 = 0;
3126             swaphi = 0;
3127          }
3128 
3129 /* If so, step through each of the Mappings which follow the WcsMap,
3130    looking for a Mapping with which the WcsMap could merge directly. Stop
3131    when such a Mapping is found, or if a Mapping is found with which the
3132    WcsMap could definitely not swap. Note the number of Mappings which
3133    separate the WcsMap from the Mapping with which it could merge (if
3134    any). */
3135          nstep2 = -1;
3136          if( swaphi ){
3137             for( i2 = where + 1; i2 < *nmap; i2++ ){
3138 
3139 /* See if we can merge with this Mapping. If so, note the number of steps
3140    between the two Mappings and leave the loop. */
3141                if( CanMerge( ( *map_list )[ i2 ], ( *invert_list )[ i2 ],
3142                              ( *map_list )[ where ], ( *invert_list )[ where ], status ) ) {
3143                   nstep2 = i2 - where - 1;
3144                   break;
3145                }
3146 
3147 /* If there is no chance that we can swap with this Mapping, leave the loop
3148    with -1 for the number of steps to indicate that no merging is possible.
3149    WcsMaps can swap only with some PermMaps. */
3150                nclass = astGetClass( ( *map_list )[ i2 ] );
3151                if( strcmp( nclass, "PermMap" ) ) {
3152                   break;
3153                }
3154 
3155             }
3156 
3157          }
3158 
3159 /* Do the same working forward from the WcsMap towards the start of the map
3160    list. */
3161          if( where > 0 ){
3162             swaplo = CanSwap(  ( *map_list )[ where - 1 ],
3163                                ( *map_list )[ where ],
3164                                ( *invert_list )[ where - 1 ],
3165                                ( *invert_list )[ where ], &do1, status );
3166          } else {
3167             do1 = 0;
3168             swaplo = 0;
3169          }
3170 
3171          nstep1 = -1;
3172          if( swaplo ){
3173             for( i1 = where - 1; i1 >= 0; i1-- ){
3174 
3175                if( CanMerge( ( *map_list )[ i1 ], ( *invert_list )[ i1 ],
3176                              ( *map_list )[ where ], ( *invert_list )[ where ], status ) ) {
3177                   nstep1 = where - 1 - i1;
3178                   break;
3179                }
3180 
3181                nclass = astGetClass( ( *map_list )[ i1 ] );
3182                if( strcmp( nclass, "PermMap" ) ) {
3183                   break;
3184                }
3185 
3186             }
3187 
3188          }
3189 
3190 /* Choose which neighbour to swap with so that the WcsMap moves towards the
3191    nearest Mapping with which it can merge. */
3192          if( do1 || (
3193              nstep1 != -1 && ( nstep2 == -1 || nstep2 > nstep1 ) ) ){
3194             nclass = class1;
3195             i1 = where - 1;
3196             i2 = where;
3197          } else if( do2 || nstep2 != -1 ){
3198             nclass = class2;
3199             i1 = where;
3200             i2 = where + 1;
3201          } else {
3202             nclass = NULL;
3203          }
3204 
3205 /* If there is a target Mapping in the list with which the WcsMap could
3206    merge, replace the supplied Mappings with swapped Mappings to bring a
3207    WcsMap closer to the target Mapping. */
3208          if( nclass ){
3209 
3210             WcsPerm( (*map_list) + i1, (*invert_list) + i1, where - i1, status );
3211 
3212 /* Store the index of the first modified Mapping. */
3213             result = i1;
3214 
3215 /* If there is no Mapping available for merging, it may still be
3216    advantageous to swap with a neighbour because the swapped Mapping may
3217    be simpler than the original Mappings. */
3218          } else if( swaphi || swaplo ) {
3219 
3220 /*  Choose a neightbour to swap with. If both are suitable for swapping,
3221     swap with the lower. */
3222             if( swaplo ){
3223                nclass = class1;
3224                i1 = where - 1;
3225                i2 = where;
3226             } else {
3227                nclass = class2;
3228                i1 = where;
3229                i2 = where + 1;
3230             }
3231 
3232 /* Take copies of the Mapping and Invert flag arrays so we do not change
3233    the supplied values. */
3234             mc[ 0 ] = (AstMapping *) astCopy( ( (*map_list) + i1 )[0] );
3235             mc[ 1 ] = (AstMapping *) astCopy( ( (*map_list) + i1 )[1] );
3236             ic[ 0 ] = ( (*invert_list) + i1 )[0];
3237             ic[ 1 ] = ( (*invert_list) + i1 )[1];
3238 
3239 /* Swap these Mappings. */
3240             WcsPerm( mc, ic, where - i1, status );
3241 
3242 /* If neither of the swapped Mappings can be simplified further, then there
3243    is no point in swapping the Mappings, so just annul the map copies. */
3244             smc0 = astSimplify( mc[0] );
3245             smc1 = astSimplify( mc[1] );
3246 
3247             if( astGetClass( smc0 ) == astGetClass( mc[0] ) &&
3248                 astGetClass( smc1 ) == astGetClass( mc[1] ) ) {
3249 
3250                mc[ 0 ] = (AstMapping *) astAnnul( mc[ 0 ] );
3251                mc[ 1 ] = (AstMapping *) astAnnul( mc[ 1 ] );
3252 
3253 /* If one or both of the swapped Mappings could be simplified, then annul
3254    the supplied Mappings and return the swapped mappings, storing the index
3255    of the first modified Mapping. */
3256             } else {
3257                (void ) astAnnul( ( (*map_list) + i1 )[0] );
3258                (void ) astAnnul( ( (*map_list) + i1 )[1] );
3259 
3260                ( (*map_list) + i1 )[0] = mc[ 0 ];
3261                ( (*map_list) + i1 )[1] = mc[ 1 ];
3262 
3263                ( (*invert_list) + i1 )[0] = ic[ 0 ];
3264                ( (*invert_list) + i1 )[1] = ic[ 1 ];
3265 
3266                result = i1;
3267 
3268             }
3269 
3270 /* Annul the simplied Mappings */
3271             smc0 = astAnnul( smc0 );
3272             smc1 = astAnnul( smc1 );
3273 
3274          }
3275       }
3276    }
3277 
3278 /* Return the result. */
3279    return result;
3280 }
3281 
MapSplit(AstMapping * this_map,int nin,const int * in,AstMapping ** map,int * status)3282 static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){
3283 /*
3284 *  Name:
3285 *     MapSplit
3286 
3287 *  Purpose:
3288 *     Create a Mapping representing a subset of the inputs of an existing
3289 *     WcsMap.
3290 
3291 *  Type:
3292 *     Private function.
3293 
3294 *  Synopsis:
3295 *     #include "wcsmap.h"
3296 *     int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status )
3297 
3298 *  Class Membership:
3299 *     WcsMap method (over-rides the protected astMapSplit method
3300 *     inherited from the Mapping class).
3301 
3302 *  Description:
3303 *     This function creates a new Mapping by picking specified inputs from
3304 *     an existing WcsMap. This is only possible if the specified inputs
3305 *     correspond to some subset of the WcsMap outputs. That is, there
3306 *     must exist a subset of the WcsMap outputs for which each output
3307 *     depends only on the selected WcsMap inputs, and not on any of the
3308 *     inputs which have not been selected. If this condition is not met
3309 *     by the supplied WcsMap, then a NULL Mapping is returned.
3310 
3311 *  Parameters:
3312 *     this
3313 *        Pointer to the WcsMap to be split (the WcsMap is not actually
3314 *        modified by this function).
3315 *     nin
3316 *        The number of inputs to pick from "this".
3317 *     in
3318 *        Pointer to an array of indices (zero based) for the inputs which
3319 *        are to be picked. This array should have "nin" elements. If "Nin"
3320 *        is the number of inputs of the supplied WcsMap, then each element
3321 *        should have a value in the range zero to Nin-1.
3322 *     map
3323 *        Address of a location at which to return a pointer to the new
3324 *        Mapping. This Mapping will have "nin" inputs (the number of
3325 *        outputs may be different to "nin"). A NULL pointer will be
3326 *        returned if the supplied WcsMap has no subset of outputs which
3327 *        depend only on the selected inputs.
3328 *     status
3329 *        Pointer to the inherited status variable.
3330 
3331 *  Returned Value:
3332 *     A pointer to a dynamically allocated array of ints. The number of
3333 *     elements in this array will equal the number of outputs for the
3334 *     returned Mapping. Each element will hold the index of the
3335 *     corresponding output in the supplied WcsMap. The array should be
3336 *     freed using astFree when no longer needed. A NULL pointer will
3337 *     be returned if no output Mapping can be created.
3338 
3339 *  Notes:
3340 *     - If this function is invoked with the global error status set,
3341 *     or if it should fail for any reason, then NULL values will be
3342 *     returned as the function value and for the "map" pointer.
3343 */
3344 
3345 /* Local Variables: */
3346    AstWcsMap *newwcs;         /* Pointer to returned WcsMap */
3347    AstWcsMap *this;           /* Pointer to WcsMap structure */
3348    int *result;               /* Pointer to returned array */
3349    int *inperm;               /* Input axis permutation array */
3350    int *outperm;              /* Output axis permutation array */
3351    int i;                     /* Loop count */
3352    int iin;                   /* Mapping input index */
3353    int ilat;                  /* Index of latitude axis in new WcsMap */
3354    int ilatlon;               /* Index of last lat or lon axis */
3355    int ilon;                  /* Index of longitude axis in new WcsMap */
3356    int latax;                 /* Index of latitude axis in supplied WcsMap */
3357    int lonax;                 /* Index of longitude axis in supplied WcsMap */
3358    int mnin;                  /* No. of Mapping inputs */
3359    int ok;                    /* Are input indices OK? */
3360 
3361 /* Initialise */
3362    result = NULL;
3363    *map = NULL;
3364 
3365 /* Check the global error status. */
3366    if ( !astOK ) return result;
3367 
3368 /* Invoke the parent astMapSplit method to see if it can do the job. */
3369    result = (*parent_mapsplit)( this_map, nin, in, map, status );
3370 
3371 /* If not, we provide a special implementation here. */
3372    if( !result ) {
3373 
3374 /* Get a pointer to the WcsMap structure. */
3375       this = (AstWcsMap *) this_map;
3376 
3377 /* Prevent compiler warnings. */
3378       ilatlon = -1;
3379 
3380 /* Allocate memory for the returned array. */
3381       result = astMalloc( sizeof( int )*(size_t) nin );
3382       if( astOK ) {
3383 
3384 /* Get the indices of the longitude and latitude axes in the WcsMap */
3385          lonax = astGetWcsAxis( this, 0 );
3386          latax = astGetWcsAxis( this, 1 );
3387 
3388 /* See if the selected axes include the longitude and/or latitude axis.
3389    At the same time check the axis indices are ok, and set up the output
3390    axis array. */
3391          ilat = -1;
3392          ilon = -1;
3393          mnin = astGetNin( this );
3394          ok = 1;
3395          for( i = 0; i < nin; i++ ) {
3396             iin = in[ i ];
3397             if( iin < 0 || iin >= mnin ) {
3398                ok = 0;
3399                break;
3400             } else if( iin == lonax ) {
3401                ilon = i;
3402                ilatlon = i;
3403             } else if( iin == latax ) {
3404                ilat = i;
3405                ilatlon = i;
3406             }
3407             result[ i ] = iin;
3408          }
3409 
3410 /* If any of the input indices were invalid, free the returned array. */
3411          if( !ok ) {
3412             result = astFree( result );
3413 
3414 /* If both longitude and latitude axes are selected, then the returned Mapping
3415    is a WcsMap. Create one based on the supplied WcsMap. */
3416          } else if( ilat != -1 && ilon != -1 ) {
3417             newwcs = astWcsMap( nin, astGetWcsType( this ), ilon + 1, ilat + 1,
3418                                 "", status );
3419             CopyPV( this, newwcs, status );
3420             astSetInvert( newwcs, astGetInvert( this ) );
3421             *map = (AstMapping *) newwcs;
3422 
3423 /* If neither the longitude nor the latitude axis has been selected, then
3424    the returned Mapping is a UnitMap. */
3425          } else if( ilat == -1 && ilon == -1 ) {
3426             *map = (AstMapping *) astUnitMap( nin, "", status );
3427 
3428 /* If only one of the latitude and longitude axes was selected we remove
3429    it from the returned Mapping (a PermMap) and list of outputs */
3430          } else if( nin > 1 ) {
3431 
3432             for( i = ilatlon; i < nin - 1; i++ ) {
3433                result[ i ] = result[ i + 1 ];
3434             }
3435             result[ i ] = -1;
3436 
3437             inperm = astMalloc( sizeof( int )*(size_t) nin );
3438             outperm = astMalloc( sizeof( int )*(size_t) ( nin - 1 ) );
3439             if( outperm ) {
3440                for( i = 0; i < ilatlon; i++ ) {
3441                   inperm[ i ] = i;
3442                   outperm[ i ] = i;
3443                }
3444                inperm[ ilatlon ] = INT_MAX;
3445                for( i = ilatlon + 1; i < nin; i++ ) {
3446                   inperm[ i ] = i - 1;
3447                   outperm[ i - 1 ] = i;
3448                }
3449 
3450                *map = (AstMapping *) astPermMap( nin, inperm, nin - 1, outperm, NULL, " ", status );
3451 
3452             }
3453             inperm = astFree( inperm );
3454             outperm = astFree( outperm );
3455 
3456          } else {
3457             result = astFree( result );
3458          }
3459       }
3460    }
3461 
3462 /* Free returned resources if an error has occurred. */
3463    if( !astOK ) {
3464       result = astFree( result );
3465       *map = astAnnul( *map );
3466    }
3467 
3468 /* Return the list of output indices. */
3469    return result;
3470 }
3471 
PermGet(AstPermMap * map,int ** outperm,int ** inperm,double ** consts,int * status)3472 static void PermGet( AstPermMap *map, int **outperm, int **inperm,
3473                      double **consts, int *status ){
3474 /*
3475 *  Name:
3476 *     PermGet
3477 
3478 *  Purpose:
3479 *     Get the axis permutation and constants array for a PermMap.
3480 
3481 *  Type:
3482 *     Private function.
3483 
3484 *  Synopsis:
3485 *     #include "wcsmap.h"
3486 *     void PermGet( AstPermMap *map, int **outperm, int **inperm,
3487 *                   double **const, int *status )
3488 
3489 *  Class Membership:
3490 *     WcsMap member function
3491 
3492 *  Description:
3493 *     This function returns axis permutation and constants arrays which can
3494 *     be used to create a PermMap which is equivalent to the supplied PermMap.
3495 
3496 *  Parameters:
3497 *     map
3498 *        The PermMap.
3499 *     outperm
3500 *        An address at which to return a popinter to an array of ints
3501 *        holding the output axis permutation array. The array should be
3502 *        released using astFree when no longer needed.
3503 *     inperm
3504 *        An address at which to return a popinter to an array of ints
3505 *        holding the input axis permutation array. The array should be
3506 *        released using astFree when no longer needed.
3507 *     consts
3508 *        An address at which to return a popinter to an array of doubles
3509 *        holding the constants array. The array should be released using
3510 *        astFree when no longer needed.
3511 *     status
3512 *        Pointer to the inherited status variable.
3513 
3514 *  Notes:
3515 *     -  NULL pointers are returned if an error has already occurred, or if
3516 *     this function should fail for any reason.
3517 */
3518 
3519 /* Local Variables: */
3520    AstPointSet *pset1;       /* PointSet holding input positions for PermMap */
3521    AstPointSet *pset2;       /* PointSet holding output positions for PermMap */
3522    double **ptr1;            /* Pointer to pset1 data */
3523    double **ptr2;            /* Pointer to pset2 data */
3524    double *cnst;             /* Pointer to constants array */
3525    double cn;                /* Potential new constant value */
3526    double ip;                /* Potential output axis index */
3527    double op;                /* Potential input axis index */
3528    int *inprm;               /* Pointer to input axis permutation array */
3529    int *outprm;              /* Pointer to output axis permutation array */
3530    int i;                    /* Axis count */
3531    int nc;                   /* Number of constants stored so far */
3532    int nin;                  /* No. of input coordinates for the PermMap */
3533    int nout;                 /* No. of output coordinates for the PermMap */
3534 
3535 /* Initialise. */
3536    if( outperm ) *outperm = NULL;
3537    if( inperm ) *inperm = NULL;
3538    if( consts ) *consts = NULL;
3539 
3540 /* Check the global error status and the supplied pointers. */
3541    if ( !astOK || !outperm || !inperm || !consts ) return;
3542 
3543 /* Initialise variables to avoid "used of uninitialised variable"
3544    messages from dumb compilers. */
3545    nc = 0;
3546 
3547 /* Get the number of input and output axes for the supplied PermMap. */
3548    nin = astGetNin( map );
3549    nout = astGetNout( map );
3550 
3551 /* Allocate the memory for the returned arrays. */
3552    outprm = (int *) astMalloc( sizeof( int )* (size_t) nout );
3553    inprm = (int *) astMalloc( sizeof( int )* (size_t) nin );
3554    cnst = (double *) astMalloc( sizeof( double )* (size_t) ( nout + nin ) );
3555 
3556 /* Returned the pointers to these arrays.*/
3557    *outperm = outprm;
3558    *inperm = inprm;
3559    *consts = cnst;
3560 
3561 /* Create two PointSets, each holding two points, which can be used for
3562    input and output positions with the PermMap. */
3563    pset1 = astPointSet( 2, nin, "", status );
3564    pset2 = astPointSet( 2, nout, "", status );
3565 
3566 /* Set up the two input positions to be [0,1,2...] and [-1,-1,-1,...]. The
3567    first position is used to enumerate the axes, and the second is used to
3568    check for constant axis values. */
3569    ptr1 = astGetPoints( pset1 );
3570    if( astOK ){
3571       for( i = 0; i < nin; i++ ){
3572          ptr1[ i ][ 0 ] = ( double ) i;
3573          ptr1[ i ][ 1 ] = -1.0;
3574       }
3575    }
3576 
3577 /* Use the PermMap to transform these positions in the forward direction. */
3578    (void) astTransform( map, pset1, 1, pset2 );
3579 
3580 /* Look at the mapped positions to determine the output axis permutation
3581    array. */
3582    ptr2 = astGetPoints( pset2 );
3583    if( astOK ){
3584 
3585 /* No constant axis valeus found yet. */
3586       nc = 0;
3587 
3588 /* Do each output axis. */
3589       for( i = 0; i < nout; i++ ){
3590 
3591 /* If the output axis value is copied from an input axis value, the index
3592    of the appropriate input axis will be in the mapped first position. */
3593          op = ptr2[ i ][ 0 ];
3594 
3595 /* If the output axis value is assigned a constant value, the result of
3596    mapping the two different input axis values will be the same. */
3597          cn = ptr2[ i ][ 1 ];
3598          if( op == cn ) {
3599 
3600 /* We have found another constant. Store it in the constants array, and
3601    store the index of the constant in the output axis permutation array. */
3602             cnst[ nc ] = cn;
3603             outprm[ i ] = -( nc + 1 );
3604             nc++;
3605 
3606 /* If the output axis values are different, then the output axis value
3607    must be copied from the input axis value. */
3608          } else {
3609             outprm[ i ] = (int) ( op + 0.5 );
3610          }
3611       }
3612    }
3613 
3614 /* Now do the same thing to determine the input permutation array. */
3615    if( astOK ){
3616       for( i = 0; i < nout; i++ ){
3617          ptr2[ i ][ 0 ] = ( double ) i;
3618          ptr2[ i ][ 1 ] = -1.0;
3619       }
3620    }
3621 
3622    (void) astTransform( map, pset2, 0, pset1 );
3623 
3624    if( astOK ){
3625 
3626       for( i = 0; i < nin; i++ ){
3627 
3628          ip = ptr1[ i ][ 0 ];
3629          cn = ptr1[ i ][ 1 ];
3630          if( ip == cn ) {
3631 
3632             cnst[ nc ] = cn;
3633             inprm[ i ] = -( nc + 1 );
3634             nc++;
3635 
3636          } else {
3637             inprm[ i ] = (int) ( ip + 0.5 );
3638          }
3639       }
3640    }
3641 
3642 /* Annul the PointSets. */
3643    pset1 = astAnnul( pset1 );
3644    pset2 = astAnnul( pset2 );
3645 
3646 /* If an error has occurred, attempt to free the returned arrays. */
3647    if( !astOK ) {
3648       *outperm = (int *) astFree( (void *) *outperm );
3649       *inperm = (int *) astFree( (void *) *inperm );
3650       *consts = (double *) astFree( (void *) *consts );
3651    }
3652 
3653 /* Return. */
3654    return;
3655 }
3656 
SetAttrib(AstObject * this_object,const char * setting,int * status)3657 static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
3658 /*
3659 *  Name:
3660 *     SetAttrib
3661 
3662 *  Purpose:
3663 *     Set an attribute value for a WcsMap.
3664 
3665 *  Type:
3666 *     Private function.
3667 
3668 *  Synopsis:
3669 *     #include "wcsmap.h"
3670 *     void SetAttrib( AstObject *this, const char *setting )
3671 
3672 *  Class Membership:
3673 *     WcsMap member function (over-rides the astSetAttrib protected
3674 *     method inherited from the Mapping class).
3675 
3676 *  Description:
3677 *     This function assigns an attribute value for a WcsMap, the
3678 *     attribute and its value being specified by means of a string of
3679 *     the form:
3680 *
3681 *        "attribute= value "
3682 *
3683 *     Here, "attribute" specifies the attribute name and should be in
3684 *     lower case with no white space present. The value to the right
3685 *     of the "=" should be a suitable textual representation of the
3686 *     value to be assigned and this will be interpreted according to
3687 *     the attribute's data type.  White space surrounding the value is
3688 *     only significant for string attributes.
3689 
3690 *  Parameters:
3691 *     this
3692 *        Pointer to the WcsMap.
3693 *     setting
3694 *        Pointer to a null-terminated string specifying the new attribute
3695 *        value.
3696 */
3697 
3698 /* Local Variables: */
3699    AstWcsMap *this;              /* Pointer to the WcsMap structure */
3700    double dval;                  /* Attribute value */
3701    int len;                      /* Length of setting string */
3702    int nc;                       /* Number of characters read by astSscanf */
3703    int i;                        /* Axis index */
3704    int m;                        /* Projection parameter number */
3705 
3706 /* Check the global error status. */
3707    if ( !astOK ) return;
3708 
3709 /* Obtain a pointer to the WcsMap structure. */
3710    this = (AstWcsMap *) this_object;
3711 
3712 /* Obtain the length of the setting string. */
3713    len = (int) strlen( setting );
3714 
3715 /* Test for each recognised attribute in turn, using "astSscanf" to parse
3716    the setting string and extract the attribute value (or an offset to
3717    it in the case of string values). In each case, use the value set
3718    in "nc" to check that the entire string was matched. Once a value
3719    has been obtained, use the appropriate method to set it. */
3720 
3721 /* ProjP(i). */
3722 /* --------- */
3723    if ( nc = 0, ( 2 == astSscanf( setting, "projp(%d)= %lg %n", &m, &dval, &nc ) )
3724                   && ( nc >= len ) ) {
3725       astSetPV( this, astGetWcsAxis( this, 1 ), m, dval );
3726 
3727 /* PV. */
3728 /* --- */
3729    } else if ( nc = 0, ( 3 == astSscanf( setting, "pv%d_%d= %lg %n", &i, &m, &dval, &nc ) )
3730                   && ( nc >= len ) ) {
3731       astSetPV( this, i - 1, m, dval );
3732 
3733 /* Define macros to see if the setting string matches any of the
3734    read-only attributes of this class. */
3735 #define MATCH(attrib) \
3736         ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \
3737                   ( nc >= len ) )
3738 
3739 #define MATCH2(attrib) \
3740         ( nc = 0, ( 1 == astSscanf( setting, attrib "(%d)=%*[^\n]%n", &i, &nc ) ) && \
3741                   ( nc >= len ) )
3742 
3743 /* If the attribute was not recognised, use this macro to report an error
3744    if a read-only attribute has been specified. */
3745    } else if ( MATCH( "wcstype" ) ||
3746         MATCH( "natlat" ) ||
3747         MATCH( "natlon" ) ||
3748         MATCH2( "wcsaxis" ) ) {
3749       astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status,
3750                 setting, astGetClass( this ) );
3751       astError( AST__NOWRT, "This is a read-only attribute." , status);
3752 
3753 /* If the attribute is still not recognised, pass it on to the parent
3754    method for further interpretation. */
3755    } else {
3756       (*parent_setattrib)( this_object, setting, status );
3757    }
3758 
3759 /* Undefine macros local to this function. */
3760 #undef MATCH
3761 #undef MATCH2
3762 }
3763 
SetPV(AstWcsMap * this,int i,int m,double val,int * status)3764 static void SetPV( AstWcsMap *this, int i, int m, double val, int *status ) {
3765 /*
3766 *+
3767 *  Name:
3768 *     astSetPV
3769 
3770 *  Purpose:
3771 *     Set the value of a PVi_m attribute.
3772 
3773 *  Type:
3774 *     Protected function.
3775 
3776 *  Synopsis:
3777 *     #include "wcsmap.h"
3778 *     void astSetPV( AstWcsMap *this, int i, int m, double val )
3779 
3780 *  Class Membership:
3781 *     WcsMap protected function
3782 
3783 *  Description:
3784 *     This function stores a value for the specified member of the PV
3785 *     attribute array.
3786 
3787 *  Parameters:
3788 *     this
3789 *        A pointer to the WcsMap.
3790 *     i
3791 *        Zero based axis index.
3792 *     m
3793 *        Zero based parameter index.
3794 
3795 *-
3796 */
3797 /* Local Variables: */
3798    int naxis;       /* No. of axes in WcsMap */
3799    int mm;          /* Loop count */
3800    int mxpar;       /* Max number of parameters allowed for the axis */
3801 
3802 /* Check the global error status. */
3803    if ( !astOK ) return;
3804 
3805 /* Find the number of axes in the WcsMap. */
3806    naxis = astGetNin( this );
3807 
3808 /* Validate the axis index. */
3809    if( i < 0 || i >= naxis ){
3810       astError( AST__AXIIN, "astSetPV(%s): Axis index (%d) is invalid in "
3811                 "attribute PV%d_%d  - it should be in the range 1 to %d.",
3812                 status, astGetClass( this ), i + 1, i + 1, m, naxis );
3813 
3814 /* Validate the parameter index. */
3815    } else {
3816       mxpar = astGetPVMax( this, i );
3817       if( m < 0 || m > mxpar ){
3818          astError( AST__AXIIN, "astSetPV(%s): Parameter index (%d) is invalid "
3819                    "in attribute PV%d_%d for a \"%s\" projection - it should be "
3820                    "in the range 0 to %d.", status, astGetClass( this ), m, i + 1, m,
3821                    FindPrjData( this->type, status )->ctype, mxpar );
3822 
3823 /* If the dynamic arrays used to hold the parameters have not yet been
3824    created, create them now, and store pointers to them in the WcsMap
3825    structure. */
3826       } else {
3827          if( !this->np || !this->p ) {
3828             this->np = (int *) astMalloc( sizeof(int)*naxis );
3829             this->p = (double **) astMalloc( sizeof(double *)*naxis );
3830             if( astOK ) {
3831                for( mm = 0; mm < naxis; mm++ ) {
3832                   this->np[ mm ] = 0;
3833                   this->p[ mm ] = NULL;
3834                }
3835             }
3836 
3837 /* Release the dynamic arrays if an error has occurred. */
3838             if( !astOK ) FreePV( this, status );
3839 
3840          }
3841       }
3842 
3843 /* Check we can use the arrays. */
3844       if( astOK ) {
3845 
3846 /* Ensure the dynamic array used to hold parameter values for the
3847    specified axis is big enough to hold the specified parameter. */
3848          this->p[ i ] = (double *) astGrow( (void *) this->p[ i ],
3849                                             m + 1, sizeof(double) );
3850 
3851 /* Check we can use this array. */
3852          if( astOK ) {
3853 
3854 /* Store the supplied value in the relevant element of this array. */
3855             this->p[ i ][ m ] = val;
3856 
3857 /* If the array was extended to hold this parameter... */
3858             if( this->np[ i ] <= m ) {
3859 
3860 /* Fill any other new elements in this array with AST__BAD */
3861                for( mm = this->np[ i ]; mm < m; mm++ ) this->p[ i ][ mm ] = AST__BAD;
3862 
3863 /* Remember the new array size. */
3864                this->np[ i ] = m + 1;
3865             }
3866          }
3867       }
3868    }
3869 
3870 /* Re-initialize the values stored in the "AstPrjPrm" structure. */
3871    InitPrjPrm( this, status );
3872 }
3873 
SetTPNTan(AstWcsMap * this,int val,int * status)3874 static void SetTPNTan( AstWcsMap *this, int val, int *status ) {
3875 /*
3876 *+
3877 *  Name:
3878 *     astSetTPNTan
3879 
3880 *  Purpose:
3881 *     Set the value of a TPNTan attribute.
3882 
3883 *  Type:
3884 *     Protected function.
3885 
3886 *  Synopsis:
3887 *     #include "wcsmap.h"
3888 *     void astSetTPNTan( AstWcsMap *this, int val )
3889 
3890 *  Class Membership:
3891 *     WcsMap protected function
3892 
3893 *  Description:
3894 *     This function stores a value for the TPNTan attribute and updates
3895 *     the projection parameters used by WCSLIB accordingly.
3896 
3897 *  Parameters:
3898 *     this
3899 *        A pointer to the WcsMap.
3900 *     val
3901 *        New attribute value.
3902 
3903 *-
3904 */
3905 
3906 /* Check the global error status. */
3907    if ( !astOK ) return;
3908 
3909 /* Store the new value. */
3910    this->tpn_tan = ( val != 0 );
3911 
3912 /* Re-initialize the values stored in the "AstPrjPrm" structure. */
3913    InitPrjPrm( this, status );
3914 }
3915 
TestAttrib(AstObject * this_object,const char * attrib,int * status)3916 static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
3917 /*
3918 *  Name:
3919 *     TestAttrib
3920 
3921 *  Purpose:
3922 *     Test if a specified attribute value is set for a WcsMap.
3923 
3924 *  Type:
3925 *     Private function.
3926 
3927 *  Synopsis:
3928 *     #include "wcsmap.h"
3929 *     int TestAttrib( AstObject *this, const char *attrib, int *status )
3930 
3931 *  Class Membership:
3932 *     WcsMap member function (over-rides the astTestAttrib protected
3933 *     method inherited from the Mapping class).
3934 
3935 *  Description:
3936 *     This function returns a boolean result (0 or 1) to indicate whether
3937 *     a value has been set for one of a WcsMap's attributes.
3938 
3939 *  Parameters:
3940 *     this
3941 *        Pointer to the WcsMap.
3942 *     attrib
3943 *        Pointer to a null-terminated string specifying the attribute
3944 *        name.  This should be in lower case with no surrounding white
3945 *        space.
3946 *     status
3947 *        Pointer to the inherited status variable.
3948 
3949 *  Returned Value:
3950 *     One if a value has been set, otherwise zero.
3951 
3952 *  Notes:
3953 *     - A value of zero will be returned if this function is invoked
3954 *     with the global status set, or if it should fail for any reason.
3955 */
3956 
3957 /* Local Variables: */
3958    AstWcsMap *this;             /* Pointer to the WcsMap structure */
3959    int i;                       /* Axis index */
3960    int m;                       /* Projection parameter index */
3961    int len;                     /* Length os supplied string */
3962    int nc;                      /* No. of characters read by astSscanf */
3963    int result;                  /* Result value to return */
3964 
3965 /* Initialise. */
3966    result = 0;
3967 
3968 /* Check the global error status. */
3969    if ( !astOK ) return result;
3970 
3971 /* Obtain a pointer to the WcsMap structure. */
3972    this = (AstWcsMap *) this_object;
3973 
3974 /* Obtain the length of the attrib string. */
3975    len = strlen( attrib );
3976 
3977 /* Check the attribute name and test the appropriate attribute. */
3978 
3979 
3980 /* ProjP(i). */
3981 /* --------- */
3982    if ( nc = 0, ( 1 == astSscanf( attrib, "projp(%d)%n", &m, &nc ) )
3983                   && ( nc >= len ) ) {
3984       result = astTestPV( this, astGetWcsAxis( this, 1 ), m );
3985 
3986 /* PV. */
3987 /* --- */
3988    } else if ( nc = 0, ( 2 == astSscanf( attrib, "pv%d_%d%n", &i, &m, &nc ) )
3989                   && ( nc >= len ) ) {
3990       result = astTestPV( this, i - 1, m );
3991 
3992 /* If the name is not recognised, test if it matches any of the
3993    read-only attributes of this class. If it does, then return
3994    zero. */
3995    } else if ( !strcmp( attrib, "wcstype" ) ||
3996                !strcmp( attrib, "natlat" ) ||
3997                !strcmp( attrib, "natlon" ) ||
3998                ( nc = 0, ( 1 == astSscanf( attrib, "wcsaxis(%d)%n", &i, &nc ) )
3999                            && ( nc >= len ) ) ) {
4000       result = 0;
4001 
4002 /* If the attribute is still not recognised, pass it on to the parent
4003    method for further interpretation. */
4004    } else {
4005       result = (*parent_testattrib)( this_object, attrib, status );
4006    }
4007 
4008 /* Return the result, */
4009    return result;
4010 }
4011 
TestPV(AstWcsMap * this,int i,int m,int * status)4012 static int TestPV( AstWcsMap *this, int i, int m, int *status ) {
4013 /*
4014 *+
4015 *  Name:
4016 *     astTestPV
4017 
4018 *  Purpose:
4019 *     Test a PVi_m attribute.
4020 
4021 *  Type:
4022 *     Protected function.
4023 
4024 *  Synopsis:
4025 *     #include "wcsmap.h"
4026 *     int astTestPV( AstWcsMap *this, int i, int m )
4027 
4028 *  Class Membership:
4029 *     WcsMap protected function
4030 
4031 *  Description:
4032 *     This function returns 1 if a specified member of the PV attribute
4033 *     array is currently set, and 0 otherwise.
4034 
4035 *  Parameters:
4036 *     this
4037 *        A pointer to the WcsMap.
4038 *     i
4039 *        Zero based axis index.
4040 *     m
4041 *        Zero based parameter index.
4042 
4043 *  Returned Value:
4044 *     1 if the attribute is set, 0 otherwise.
4045 
4046 *-
4047 */
4048 /* Local Variables: */
4049    int ret;
4050    int npar;
4051    int mxpar;
4052 
4053 /* Initialise */
4054    ret = 0;
4055 
4056 /* Check the global error status. */
4057    if ( !astOK ) return ret;
4058 
4059 /* Validate the axis index. */
4060    if( i < 0 || i >= astGetNin( this ) ){
4061       astError( AST__AXIIN, "astTestPV(%s): Axis index (%d) is invalid in "
4062                 "attribute PV%d_%d  - it should be in the range 1 to %d.",
4063                 status, astGetClass( this ), i + 1, i + 1, m, astGetNin( this ) );
4064 
4065 /* Find the maximum number of parameters allowed for the axis. */
4066    } else {
4067       mxpar = astGetPVMax( this, i );
4068 
4069 /* Ignore unused parameters. */
4070       if( m < 0 || m > mxpar ){
4071 
4072 /* See if the parameter is currently set. */
4073       } else if( this->np && this->p ){
4074          npar = this->np[ i ];
4075          if( m < npar && this->p[ i ] ){
4076             ret = ( this->p[ i ][ m ] != AST__BAD );
4077          }
4078       }
4079    }
4080 
4081    return ret;
4082 }
4083 
Transform(AstMapping * this,AstPointSet * in,int forward,AstPointSet * out,int * status)4084 static AstPointSet *Transform( AstMapping *this, AstPointSet *in,
4085                                int forward, AstPointSet *out, int *status ) {
4086 /*
4087 *+
4088 *  Name:
4089 *     Transform
4090 
4091 *  Purpose:
4092 *     Apply a WcsMap to a set of points.
4093 
4094 *  Type:
4095 *     Private function.
4096 
4097 *  Synopsis:
4098 *     #include "wcsmap.h"
4099 *     AstPointSet *Transform( AstMapping *this, AstPointSet *in,
4100 *                             int forward, AstPointSet *out, int *status )
4101 
4102 *  Class Membership:
4103 *     WcsMap member function (over-rides the astTransform method inherited
4104 *     from the Mapping class).
4105 
4106 *  Description:
4107 *     This function takes a WcsMap and a set of points encapsulated in a
4108 *     PointSet and transforms the points using the requested projection.
4109 
4110 *  Parameters:
4111 *     this
4112 *        Pointer to the WcsMap.
4113 *     in
4114 *        Pointer to the PointSet holding the input coordinate data.
4115 *     forward
4116 *        A non-zero value indicates that the forward coordinate transformation
4117 *        should be applied, while a zero value requests the inverse
4118 *        transformation.
4119 *     out
4120 *        Pointer to a PointSet which will hold the transformed (output)
4121 *        coordinate values. A NULL value may also be given, in which case a
4122 *        new PointSet will be created by this function.
4123 *     status
4124 *        Pointer to the inherited status variable.
4125 
4126 *  Returned Value:
4127 *     Pointer to the output (possibly new) PointSet.
4128 
4129 *  Notes:
4130 *     -  Assuming the WcsMap has not been inverted, the forward mapping
4131 *     transforms spherical (longitude,latitude) pairs into Cartesian (x,y)
4132 *     pairs. Longitude and latitude values are given and returned in radians,
4133 *     and no restrictions are imposed on their ranges. X and Y values are
4134 *     also given and returned in radians, with no restrictions imposed on
4135 *     their ranges.
4136 *     -  A null pointer will be returned if this function is invoked with the
4137 *     global error status set, or if it should fail for any reason.
4138 *     -  The number of coordinate values per point in the input PointSet must
4139 *     match the number of coordinates for the WcsMap being applied.
4140 *     -  If an output PointSet is supplied, it must have space for sufficient
4141 *     number of points and coordinate values per point to accommodate the
4142 *     result. Any excess space will be ignored.
4143 *-
4144 */
4145 
4146 /* Local Variables: */
4147    AstPointSet *result;          /* Pointer to output PointSet */
4148    AstWcsMap *map;               /* Pointer to WcsMap to be applied */
4149    double **ptr_in;              /* Pointer to input coordinate data */
4150    double **ptr_out;             /* Pointer to output coordinate data */
4151    int i;                        /* Axis count */
4152    int latax;                    /* Latitude axis index */
4153    int lonax;                    /* Longitude axis index */
4154    int npoint;                   /* Number of points */
4155    int status_value;                   /* Status from Map function */
4156 
4157 /* Check the global error status. */
4158    if ( !astOK ) return NULL;
4159 
4160 /* Obtain a pointer to the WcsMap. */
4161    map = (AstWcsMap *) this;
4162 
4163 /* Apply the parent mapping using the stored pointer to the Transform member
4164    function inherited from the parent Mapping class. This function validates
4165    all arguments and generates an output PointSet if necessary, but does not
4166    actually transform any coordinate values. */
4167    result = (*parent_transform)( this, in, forward, out, status );
4168 
4169 /* We will now extend the parent astTransform method by performing the
4170    calculations needed to generate the output coordinate values. */
4171 
4172 /* Determine the numbers of points from the input PointSet and obtain pointers
4173    for accessing the input and output coordinate values. */
4174    npoint = astGetNpoint( in );
4175    ptr_in = astGetPoints( in );
4176    ptr_out = astGetPoints( result );
4177 
4178 /* If a genuine FITS-WCS projection is being performed... */
4179    if( astGetWcsType( map ) != AST__WCSBAD ){
4180 
4181 /* Determine whether to apply the forward or inverse mapping, according to the
4182    direction specified and whether the mapping has been inverted. */
4183       if ( astGetInvert( map ) ) forward = !forward;
4184 
4185 /* Do the coordinate transformation. */
4186       lonax = astGetWcsAxis( map, 0 );
4187       latax = astGetWcsAxis( map, 1 );
4188       status_value = Map( map, forward, npoint, ptr_in[ lonax ], ptr_in[ latax ],
4189                           ptr_out[ lonax ], ptr_out[ latax ], status );
4190 
4191 /* Report an error if the projection type was unrecognised. */
4192       if ( status_value == 1 ) {
4193          astError( AST__WCSTY, "astTransform(%s): The %s specifies an "
4194                    "illegal projection type ('%s').", status, astClass( this ),
4195                    astClass( this ), FindPrjData( map->type, status )->desc  );
4196 
4197 /* Report an error if the projection parameters were invalid. */
4198        } else if ( status_value == 2 ) {
4199           astError( AST__WCSPA, "astTransform(%s): The %s projection "
4200                     "parameter values in this %s are unusable.", status,
4201                     astClass( this ), FindPrjData( map->type, status )->desc,
4202                     astClass( this )  );
4203 
4204 /* Report an error if required projection parameters were not supplied. */
4205        } else if ( status_value >= 400 ) {
4206           astError( AST__WCSPA, "astTransform(%s): Required projection "
4207                     "parameter PV%d_%d was not supplied for a %s "
4208                     "projection.", status, astClass( this ), latax+1, status_value - 400,
4209                     FindPrjData( map->type, status )->desc  );
4210 
4211        } else if ( status_value >= 100 ) {
4212           astError( AST__WCSPA, "astTransform(%s): Required projection "
4213                     "parameter PV%d_%d was not supplied for a %s "
4214                     "projection.", status, astClass( this ), lonax+1, status_value - 100,
4215                     FindPrjData( map->type, status )->desc  );
4216        }
4217 
4218 /* Copy the remaining axes (i.e. all axes except the longitude and latitude
4219    axes) from the input to the output. */
4220       for( i = 0; i < astGetNcoord( in ); i++ ){
4221          if( ( i != lonax && i != latax ) ){
4222             (void) memcpy( ptr_out[ i ], ptr_in[ i ], sizeof( double )*
4223                            (size_t) npoint );
4224          }
4225 
4226       }
4227 
4228 /* If there is no FITS-WCS projection, just copy all the axes from input to
4229    output. */
4230    } else {
4231       for( i = 0; i < astGetNcoord( in ); i++ ){
4232          (void) memcpy( ptr_out[ i ], ptr_in[ i ], sizeof( double )*
4233                         (size_t) npoint );
4234       }
4235    }
4236 
4237 /* If an error has occurred, attempt to delete the results PointSet. */
4238    if ( !astOK ) result = astDelete( result );
4239 
4240 /* Return a pointer to the output PointSet. */
4241    return result;
4242 
4243 }
4244 
astWcsPrjType_(const char * ctype,int * status)4245 int astWcsPrjType_( const char *ctype, int *status ){
4246 /*
4247 *+
4248 *  Name:
4249 *     astWcsPrjType
4250 
4251 *  Purpose:
4252 *     Get the integer identifier for a WCSLIB projection given by a FITS
4253 *     CTYPE keyword value.
4254 
4255 *  Type:
4256 *     Protected function.
4257 
4258 *  Synopsis:
4259 *     #include "wcsmap.h"
4260 *     int astWcsPrjType( const char *ctype )
4261 
4262 *  Class Membership:
4263 *     WcsMap protected function
4264 
4265 *  Description:
4266 *     This function returns the integer identifier for the WCSLIB projection
4267 *     specified by the supplied FITS CTYPE keyword value. The returned
4268 *     value can be passed to astWcsMap to create a WcsMap which implements
4269 *     the corresponding projection.
4270 
4271 *  Parameters:
4272 *     ctype
4273 *        A pointer to the last 4 characters of a FITS CTYPE1 (etc) keyword.
4274 
4275 *  Returned Value:
4276 *     The integer identifier associated with the projection.
4277 
4278 *  Notes:
4279 *     -  A value of AST__WCSBAD is returned if the projection type is
4280 *     unknown, but no error is reported.
4281 *-
4282 */
4283 
4284    PrjData *data;
4285    char buffer[81];
4286    const char *a;
4287    char *b;
4288 
4289 /* Remove leading and trailing blanks from the supplied string. */
4290    a = ctype;
4291    b = buffer;
4292    while( *a && (b - buffer) < 80 ){
4293       if( !isspace( (int) *a ) ) {
4294          *(b++) = *a;
4295       }
4296       a++;
4297    }
4298    *b = 0;
4299 
4300 /* Search for the projection in the list of available projectons. */
4301    data = PrjInfo;
4302    while( data->prj != AST__WCSBAD && strcmp( data->ctype, buffer ) ) data ++;
4303 
4304    return data->prj;
4305 }
4306 
astWcsPrjName_(int type,int * status)4307 const char *astWcsPrjName_( int type, int *status ){
4308 /*
4309 *+
4310 *  Name:
4311 *     astWcsPrjName
4312 
4313 *  Purpose:
4314 *     Get the name of a projection given its integer identifier.
4315 
4316 *  Type:
4317 *     Protected function.
4318 
4319 *  Synopsis:
4320 *     #include "wcsmap.h"
4321 *     const char *astWcsPrjName( int type )
4322 
4323 *  Class Membership:
4324 *     WcsMap protected function
4325 
4326 *  Description:
4327 *     This function returns a string holding 4 characters which can be
4328 *     used as the last 4 characters of a FITS CTYPE keyword value
4329 *     describing the WCSLIB projection specified by the supplied type.
4330 
4331 *  Parameters:
4332 *     type
4333 *        The projection type.
4334 
4335 *  Returned Value:
4336 *     A pointer to a null-terminated const character string holding the
4337 *     last 4 CTYPE characters describing the projection.
4338 
4339 *  Notes:
4340 *     -  This function attempts to execute even if an error has already
4341 *     occurred.
4342 *-
4343 */
4344 
4345    PrjData *data;
4346    data = PrjInfo;
4347    while( data->prj != AST__WCSBAD && data->prj != type ) data ++;
4348    return data->ctype;
4349 }
4350 
astWcsPrjDesc_(int type,int * status)4351 const char *astWcsPrjDesc_( int type, int *status ){
4352 /*
4353 *+
4354 *  Name:
4355 *     astWcsPrjDesc
4356 
4357 *  Purpose:
4358 *     Get a textual description of a projection given its integer
4359 *     identifier.
4360 
4361 *  Type:
4362 *     Protected function.
4363 
4364 *  Synopsis:
4365 *     #include "wcsmap.h"
4366 *     const char *astWcsPrjDesc( int type )
4367 
4368 *  Class Membership:
4369 *     WcsMap protected function
4370 
4371 *  Description:
4372 *     This function returns a pointer to a string string holding a
4373 *     textual description of the specified projection type.
4374 
4375 *  Parameters:
4376 *     type
4377 *        The projection type.
4378 
4379 *  Returned Value:
4380 *     A pointer to a null-terminated const character string holding the
4381 *     projection description.
4382 
4383 *  Notes:
4384 *     -  This function attempts to execute even if an error has already
4385 *     occurred.
4386 *-
4387 */
4388 
4389    PrjData *data;
4390    data = PrjInfo;
4391    while( data->prj != AST__WCSBAD && data->prj != type ) data ++;
4392    return data->desc;
4393 }
4394 
WcsPerm(AstMapping ** maps,int * inverts,int iwm,int * status)4395 static void WcsPerm( AstMapping **maps, int *inverts, int iwm, int *status ){
4396 /*
4397 *  Name:
4398 *     WcsPerm
4399 
4400 *  Purpose:
4401 *     Swap a WcsMap and a PermMap.
4402 
4403 *  Type:
4404 *     Private function.
4405 
4406 *  Synopsis:
4407 *     #include "wcsmap.h"
4408 *     void WcsPerm( AstMapping **maps, int *inverts, int iwm, int *status )
4409 
4410 *  Class Membership:
4411 *     WcsMap member function
4412 
4413 *  Description:
4414 *     A list of two Mappings is supplied containing a WcsMap and a
4415 *     PermMap. These Mappings are annulled, and replaced with
4416 *     another pair of Mappings consisting of a WcsMap and a PermMap
4417 *     in the opposite order. These Mappings are chosen so that their
4418 *     combined effect is the same as the original pair of Mappings.
4419 
4420 *  Parameters:
4421 *     maps
4422 *        A pointer to an array of two Mapping pointers.
4423 *     inverts
4424 *        A pointer to an array of two invert flags.
4425 *     iwm
4426 *        The index within "maps" of the WcsMap.
4427 *     status
4428 *        Pointer to the inherited status variable.
4429 
4430 *  Notes:
4431 *     -  All links between input and output axes in the PermMap must
4432 *     be bi-directional, but there can be unconnected axes, and there
4433 *     need not be the same number of input and output axes. Both
4434 *     longitude and latitude axes must be passed by the PermMap.
4435 
4436 */
4437 
4438 /* Local Variables: */
4439    AstPermMap *pm;               /* Pointer to the supplied PermMap */
4440    AstPermMap *newpm;            /* Pointer to the returned PermMap */
4441    AstMapping *newwm;            /* Pointer to the returned WcsMap */
4442    AstWcsMap *wm;                /* Pointer to the supplied WcsMap */
4443    double *consts;               /* Pointer to constants array */
4444    int *inperm;                  /* Pointer to input axis permutation array */
4445    int *outperm;                 /* Pointer to output axis permutation array */
4446    int latax;                    /* Index of latitude axis */
4447    int lonax;                    /* Index of longitude axis */
4448    int npin;                     /* No. of input axes in supplied PermMap */
4449    int npout;                    /* No. of output axes in supplied PermMap */
4450    int old_pinv;                 /* Invert value for the supplied PermMap */
4451    int old_winv;                 /* Invert value for the supplied WcsMap */
4452    int type;                     /* Projection type */
4453    int done;                     /* Have Mappings been swapped? */
4454    int i;                        /* AXis index */
4455    double *p;                    /* Pointer to input position */
4456    double *q;                    /* Pointer to output position */
4457 
4458 /* Check the global error status. */
4459    if ( !astOK ) return;
4460 
4461 /* Initialise variables to avoid "used of uninitialised variable"
4462    messages from dumb compilers. */
4463    newpm = NULL;
4464    newwm = NULL;
4465 
4466 /* Store pointers to the supplied WcsMap and the PermMap. */
4467    wm = (AstWcsMap *) maps[ iwm ];
4468    pm = (AstPermMap *) maps[ 1 - iwm ];
4469 
4470 /* Temporarily set the Invert attribute of the supplied PermMap to the
4471    supplied values. */
4472    old_pinv = astGetInvert( pm );
4473    astSetInvert( pm, inverts[ 1 - iwm ] );
4474    old_winv = astGetInvert( wm );
4475    astSetInvert( wm, inverts[ iwm ] );
4476 
4477 /* Get the projection type of the supplied WcsMap and the indices of the
4478    longitude and latitude axes. */
4479    type = astGetWcsType( wm );
4480    lonax = astGetWcsAxis( wm, 0 );
4481    latax = astGetWcsAxis( wm, 1 );
4482 
4483 /* Get the axis permutation and constants arrays representing the
4484    PermMap. Note, no constants are used more than once in the returned
4485    arrays (i.e. duplicate constants are returned in "consts" if more than
4486    one axis uses a given constant). */
4487    PermGet( pm, &outperm, &inperm, &consts, status );
4488 
4489    if( astOK ) {
4490 
4491 /* Get the number of input and output axes in the PermMap. */
4492       npin = astGetNin( pm );
4493       npout = astGetNout( pm );
4494 
4495 /* If the lon and lat axes of the WcsMap are unassigned, we return a
4496    UnitMap instead of a WcsMap.
4497    ================================================================ */
4498       done = 0;
4499 
4500 /* If the PermMap comes after the WcsMap... */
4501       if( iwm == 0 ) {
4502          if( inperm[ lonax ] < 0 && inperm[ latax ] < 0 ) {
4503             done = 1;
4504 
4505 /* Transform the constant values, using AST__BAD for other axes. */
4506             p = (double *) astMalloc( sizeof( double )*(size_t) npin );
4507             q = (double *) astMalloc( sizeof( double )*(size_t) npin );
4508             if( astOK ) {
4509                for( i = 0; i < npin; i++ ) {
4510                   if( inperm[ i ] < 0 ) {
4511                      p[ i ] = consts[ -inperm[ i ] - 1 ];
4512                   } else {
4513                      p[ i ] = AST__BAD;
4514                   }
4515                }
4516 
4517 /* Transform this position using the inverse WcsMap. */
4518                astTranN( wm, 1, npin, 1, p, 0, npin, 1, q );
4519 
4520 /* The new PermMap has the same axis permutations as the original, but it
4521    has different constants. */
4522                for( i = 0; i < npin; i++ ) {
4523                   if( inperm[ i ] < 0 ) {
4524                      consts[ -inperm[ i ] - 1 ] = q[ i ];
4525                   }
4526                }
4527 
4528                newpm = astPermMap( npin, inperm, npout, outperm, consts, "", status );
4529 
4530 /* Use a UnitMap instead of the WcsMap. */
4531                newwm = (AstMapping *) astUnitMap( npout, "", status );
4532 
4533             }
4534 
4535 /* Free memory */
4536             p = astFree( p );
4537             q = astFree( q );
4538 
4539          }
4540 
4541 /* If the WcsMap comes after the PermMap... */
4542       } else {
4543          if( outperm[ lonax ] < 0 && outperm[ latax ] < 0 ) {
4544             done = 1;
4545 
4546 /* Transform the constant values, using AST__BAD for other axes. */
4547             p = (double *) astMalloc( sizeof( double )*(size_t) npout );
4548             q = (double *) astMalloc( sizeof( double )*(size_t) npout );
4549             if( astOK ) {
4550                for( i = 0; i < npout; i++ ) {
4551                   if( outperm[ i ] < 0 ) {
4552                      p[ i ] = consts[ -outperm[ i ] - 1 ];
4553                   } else {
4554                      p[ i ] = AST__BAD;
4555                   }
4556                }
4557 
4558 /* Transform this position using the forward WcsMap. */
4559                astTranN( wm, 1, npout, 1, p, 1, npout, 1, q );
4560 
4561 /* The new PermMap has the same axis permutations as the original, but it
4562    has different constants. */
4563                for( i = 0; i < npout; i++ ) {
4564                   if( outperm[ i ] < 0 ) {
4565                      consts[ -outperm[ i ] - 1 ] = q[ i ];
4566                   }
4567                }
4568 
4569                newpm = astPermMap( npin, inperm, npout, outperm, consts, "", status );
4570 
4571 /* Use a UnitMap instead ofhte WcsMap. */
4572                newwm = (AstMapping *) astUnitMap( npin, "", status );
4573 
4574             }
4575 
4576 /* Free memory */
4577             p = astFree( p );
4578             q = astFree( q );
4579 
4580          }
4581       }
4582 
4583 /* If the lon and lat axes of the WcsMap are both assigned, we return a
4584    WcsMap.
4585    ================================================================ */
4586       if( !done ) {
4587 
4588 /* Create the new WcsMap with permuted longitude and latitude axes. Note,
4589    the private interface to astWcsMap uses 1-based axis indices. */
4590          if( iwm == 0 ) {
4591             newwm = (AstMapping *) astWcsMap( npout, type, inperm[ lonax ] + 1,
4592                                               inperm[ latax ] + 1, "", status );
4593          } else {
4594             newwm = (AstMapping *) astWcsMap( npin, type, outperm[ lonax ] + 1,
4595                                               outperm[ latax ] + 1, "", status );
4596          }
4597 
4598 /* Copy any projection parameters which have been set. */
4599          CopyPV( wm, (AstWcsMap *) newwm, status );
4600 
4601 /* Set the invert flag. */
4602          astSetInvert( newwm, inverts[ iwm ] );
4603 
4604 /* The returned PermMap is a clone of the supplied PermMap */
4605          newpm = astClone( pm );
4606       }
4607 
4608 /* Free the axis permutation and constants arrays. */
4609       outperm = (int *) astFree( (void *) outperm );
4610       inperm = (int *) astFree( (void *) inperm );
4611       consts = (double *) astFree( (void *) consts );
4612    }
4613 
4614 /* Re-instate the original value of the Invert attributes. */
4615    astSetInvert( pm, old_pinv );
4616    astSetInvert( wm, old_winv );
4617 
4618 /* Annul the supplied pointers */
4619    pm = astAnnul( pm );
4620    wm = astAnnul( wm );
4621 
4622 /* Store the returned Mappings. */
4623    maps[ iwm ] = (AstMapping *) newpm;
4624    inverts[ iwm ] = astGetInvert( newpm );
4625    maps[ 1 - iwm ] = newwm;
4626    inverts[ 1 - iwm ] = astGetInvert( newwm );
4627 
4628 /* Return. */
4629    return;
4630 }
4631 
4632 /* Functions which access class attributes. */
4633 /* ---------------------------------------- */
4634 /* Implement member functions to access the attributes associated with
4635    this class using the macros defined for this purpose in the
4636    "object.h" file. For a description of each attribute, see the class
4637    interface (in the associated .h file). */
4638 
4639 
4640 /*
4641 *att+
4642 *  Name:
4643 *     FITSProj
4644 
4645 *  Purpose:
4646 *     Is this WcsMap used as a FITS-WCS projection?
4647 
4648 *  Type:
4649 *     Protected attribute.
4650 
4651 *  Synopsis:
4652 *     Integer (boolean).
4653 
4654 *  Description:
4655 *     This attribute controls how a WcsMap is used when creating a set
4656 *     of FITS headers. If the WcsMap is contained within a FrameSet
4657 *     that is to be  converted into a set of FITS headers using the
4658 c     astWrite funtion,
4659 f     AST_WRITE routine,
4660 *     the WcsMap will be used to define the projection code appeneded to
4661 *     the FITS "CTYPEi" keywords if, and only if, the FITSProj attribute
4662 *     is set non-zero in the WcsMap. In order for the conversion to be
4663 *     successful, the compoound Mapping connecting the base and current
4664 *     Frames in the FrameSet must contained one (and only one) WcsMap
4665 *     that has a non-zero value for its FITSProj attribute.
4666 *
4667 *     The default value is one.
4668 
4669 *  Applicability:
4670 *     WcsMap
4671 *        All Frames have this attribute.
4672 *att-
4673 */
4674 astMAKE_CLEAR(WcsMap,FITSProj,fits_proj,-INT_MAX)
4675 astMAKE_GET(WcsMap,FITSProj,int,1,( ( this->fits_proj != -INT_MAX ) ?
4676                                        this->fits_proj : 1 ))
4677 astMAKE_SET(WcsMap,FITSProj,int,fits_proj,( value != 0 ))
4678 astMAKE_TEST(WcsMap,FITSProj,( this->fits_proj != -INT_MAX ))
4679 
4680 /*
4681 *att+
4682 *  Name:
4683 *     TPNTan
4684 
4685 *  Purpose:
4686 *     Should the TPN projection include a TAN projection?
4687 
4688 *  Type:
4689 *     Protected attribute.
4690 
4691 *  Synopsis:
4692 *     Integer (boolean).
4693 
4694 *  Description:
4695 *     This attribute controls how a WcsMap with a AST__TPN projection
4696 *     type behaves. If the attribute value is non-zero (the default),
4697 *     the complete projection is performed as described in the draft
4698 *     version of FITS-WCS paper II. If it is zero, then the TAN
4699 *     projection from (psi,theta) to (xi,eta) is replaced by a unit
4700 *     transformation, so that the WcsMap implements the polynomial
4701 *     transformation only, without any preceding TAN projection.
4702 *
4703 *     In addition if the TPNTan value is zero, then the WcsMap
4704 *     assumes that the input and output values are in degrees rather
4705 *     than radians.
4706 
4707 *  Applicability:
4708 *     WcsMap
4709 *        All Frames have this attribute.
4710 *att-
4711 */
4712 astMAKE_GET(WcsMap,TPNTan,int,1,( ( this->tpn_tan != -INT_MAX ) ?
4713                                        this->tpn_tan : 1 ))
4714 astMAKE_TEST(WcsMap,TPNTan,( this->tpn_tan != -INT_MAX ))
4715 
4716 /* ProjP. */
4717 /* ------ */
4718 /*
4719 *att++
4720 *  Name:
4721 *     ProjP(m)
4722 
4723 *  Purpose:
4724 *     FITS-WCS projection parameters.
4725 
4726 *  Type:
4727 *     Public attribute.
4728 
4729 *  Synopsis:
4730 *     Floating point.
4731 
4732 *  Description:
4733 *     This attribute provides aliases for the PV attributes, which
4734 *     specifies the projection parameter values to be used by a WcsMap
4735 *     when implementing a FITS-WCS sky projection. ProjP is retained for
4736 *     compatibility with previous versions of FITS-WCS and AST. New
4737 *     applications should use the PV attibute instead.
4738 *
4739 *     Attributes ProjP(0) to ProjP(9) correspond to attributes PV<axlat>_0
4740 *     to PV<axlat>_9, where <axlat> is replaced by the index of the
4741 *     latitude axis (given by attribute WcsAxis(2)). See PV for further
4742 *     details.
4743 
4744 *  Applicability:
4745 *     WcsMap
4746 *        All WcsMaps have this attribute.
4747 
4748 *att--
4749 */
4750 
4751 /* PV. */
4752 /* --- */
4753 /*
4754 *att++
4755 *  Name:
4756 *     PVi_m
4757 
4758 *  Purpose:
4759 *     FITS-WCS projection parameters.
4760 
4761 *  Type:
4762 *     Public attribute.
4763 
4764 *  Synopsis:
4765 *     Floating point.
4766 
4767 *  Description:
4768 *     This attribute specifies the projection parameter values to be
4769 *     used by a WcsMap when implementing a FITS-WCS sky projection.
4770 *     Each PV attribute name should include two integers, i and m,
4771 *     separated by an underscore. The axis index is specified
4772 *     by i, and should be in the range 1 to 99. The parameter number
4773 *     is specified by m, and should be in the range 0 to 99. For
4774 *     example, "PV2_1=45.0" would specify a value for projection
4775 *     parameter 1 of axis 2 in a WcsMap.
4776 *
4777 *     These projection parameters correspond exactly to the values
4778 *     stored using the FITS-WCS keywords "PV1_1", "PV1_2", etc. This
4779 *     means that projection parameters which correspond to angles must
4780 *     be given in degrees (despite the fact that the angular
4781 *     coordinates and other attributes used by a WcsMap are in
4782 *     radians).
4783 *
4784 *     The set of projection parameters used by a WcsMap depends on the
4785 *     type of projection, which is determined by its WcsType
4786 *     parameter.  Most projections either do not require projection
4787 *     parameters, or use parameters 1 and 2 associated with the latitude
4788 *     axis. You should consult the FITS-WCS paper for details.
4789 *
4790 *     Some projection parameters have default values (as defined in
4791 *     the FITS-WCS paper) which apply if no explicit value is given.
4792 *     You may omit setting a value for these "optional" parameters and the
4793 *     default will apply. Some projection parameters, however, have no
4794 *     default and a value must be explicitly supplied.  This is most
4795 *     conveniently
4796 c     done using the "options" argument of astWcsMap (q.v.) when a WcsMap
4797 f     done using the OPTIONS argument of AST_WCSMAP (q.v.) when a WcsMap
4798 *     is first created. An error will result when a WcsMap is used to
4799 *     transform coordinates if any of its required projection
4800 *     parameters has not been set and lacks a default value.
4801 
4802 *     A "get" operation for a parameter which has not been assigned a value
4803 *     will return the default value defined in the FITS-WCS paper, or
4804 *     AST__BAD if the paper indicates that the parameter has no default.
4805 *     A default value of zero is returned for parameters which are not
4806 *     accessed by the projection.
4807 *
4808 *     Note, the FITS-WCS paper reserves parameters 1 and 2 on the longitude
4809 *     axis to hold the native longitude and latitude of the fiducial
4810 *     point of the projection, in degrees. The default values for these
4811 *     parameters are determined by the projection type. The AST-specific
4812 *     TPN projection does not use this convention - all projection
4813 *     parameters for both axes are used to represent polynomical correction
4814 *     terms, and the native longitude and latitude at the fiducial point may
4815 *     not be changed from the default values of zero and 90 degrees.
4816 
4817 *  Applicability:
4818 *     WcsMap
4819 *        All WcsMaps have this attribute.
4820 
4821 *  Notes:
4822 *     - If the projection parameter values given for a WcsMap do not
4823 *     satisfy all the required constraints (as defined in the FITS-WCS
4824 *     paper), then an error will result when the WcsMap is used to
4825 *     transform coordinates.
4826 *att--
4827 */
4828 
4829 /* PVMax. */
4830 /* ------ */
4831 /*
4832 *att++
4833 *  Name:
4834 *     PVMax(i)
4835 
4836 *  Purpose:
4837 *     Maximum number of FITS-WCS projection parameters.
4838 
4839 *  Type:
4840 *     Public attribute.
4841 
4842 *  Synopsis:
4843 *     Integer, read-only.
4844 
4845 *  Description:
4846 *     This attribute specifies the largest legal index for a PV projection
4847 *     parameter attached to a specified axis of the WcsMap (i.e. the
4848 *     largest legal value for "m" when accessing the "PVi_m" attribute).
4849 *     The axis index is specified by i, and should be in the range 1 to 99.
4850 *     The value for each axis is determined by the projection type specified
4851 *     when the WcsMap
4852 c     is first created using astWcsMap and cannot subsequently be
4853 f     is first created using AST_WCSMAP and cannot subsequently be
4854 *     changed.
4855 
4856 *  Applicability:
4857 *     WcsMap
4858 *        All WcsMaps have this attribute.
4859 *att--
4860 */
4861 
4862 /* WcsType. */
4863 /* -------- */
4864 /*
4865 *att++
4866 *  Name:
4867 *     WcsType
4868 
4869 *  Purpose:
4870 *     FITS-WCS projection type.
4871 
4872 *  Type:
4873 *     Public attribute.
4874 
4875 *  Synopsis:
4876 *     Integer, read-only.
4877 
4878 *  Description:
4879 *     This attribute specifies which type of FITS-WCS projection will
4880 *     be performed by a WcsMap. The value is specified when a WcsMap
4881 c     is first created using astWcsMap and cannot subsequently be
4882 f     is first created using AST_WCSMAP and cannot subsequently be
4883 *     changed.
4884 *
4885 c     The values used are represented by macros with names of
4886 f     The values used are represented by symbolic constants with names of
4887 *     the form "AST__XXX", where "XXX" is the (upper case) 3-character
4888 *     code used by the FITS-WCS "CTYPEi" keyword to identify the
4889 *     projection. For example, possible values are AST__TAN (for the
4890 *     tangent plane or gnomonic projection) and AST__AIT (for the
4891 *     Hammer-Aitoff projection). AST__TPN is an exception in that it
4892 *     is not part of the FITS-WCS standard (it represents a TAN
4893 *     projection with polynomial correction terms as defined in an early
4894 *     draft of the FITS-WCS paper).
4895 
4896 *  Applicability:
4897 *     WcsMap
4898 *        All WcsMaps have this attribute.
4899 
4900 *  Notes:
4901 *     - For a list of available projections, see the FITS-WCS paper.
4902 *att--
4903 */
4904 
4905 /* Type of FITS-WCS projection. Read only. */
4906 astMAKE_GET(WcsMap,WcsType,int,AST__WCSBAD,this->type)
4907 
4908 /* NatLat. */
4909 /* ------- */
4910 /*
4911 *att++
4912 *  Name:
4913 *     NatLat
4914 
4915 *  Purpose:
4916 *     Native latitude of the reference point of a FITS-WCS projection.
4917 
4918 *  Type:
4919 *     Public attribute.
4920 
4921 *  Synopsis:
4922 *     Floating point, read-only.
4923 
4924 *  Description:
4925 *     This attribute gives the latitude of the reference point of the
4926 *     FITS-WCS projection implemented by a WcsMap. The value is in
4927 *     radians in the "native spherical" coordinate system. This value is
4928 *     fixed for most projections, for instance it is PI/2 (90 degrees)
4929 *     for all zenithal projections. For some projections (e.g. the conics)
4930 *     the value is not fixed, but is specified by parameter one on the
4931 *     latitude axis.
4932 *
4933 *     FITS-WCS paper II introduces the concept of a "fiducial point"
4934 *     which is logical distinct from the projection reference point.
4935 *     It is easy to confuse the use of these two points. The fiducial
4936 *     point is the point which has celestial coordinates given by the
4937 *     CRVAL FITS keywords. The native spherical coordinates for this point
4938 *     default to the values of the NatLat and NatLon, but these defaults
4939 *     mey be over-ridden by values stored in the PVi_j keywords. Put
4940 *     another way, the CRVAL keywords will by default give the celestial
4941 *     coordinates of the projection reference point, but may refer to
4942 *     some other point if alternative native longitude and latitude values
4943 *     are provided through the PVi_j keywords.
4944 *
4945 *     The NatLat attribute is read-only.
4946 
4947 *  Applicability:
4948 *     WcsMap
4949 *        All WcsMaps have this attribute.
4950 
4951 *  Notes:
4952 *     - A default value of AST__BAD is used if no latitude value is available.
4953 *att--
4954 */
4955 
4956 /*
4957 *att++
4958 *  Name:
4959 *     NatLon
4960 
4961 *  Purpose:
4962 *     Native longitude of the reference point of a FITS-WCS projection.
4963 
4964 *  Type:
4965 *     Public attribute.
4966 
4967 *  Synopsis:
4968 *     Floating point, read-only.
4969 
4970 *  Description:
4971 *     This attribute gives the longitude of the reference point of the
4972 *     FITS-WCS projection implemented by a WcsMap. The value is in
4973 *     radians in the "native spherical" coordinate system, and will
4974 *     usually be zero. See the description of attribute NatLat for further
4975 *     information.
4976 *
4977 *     The NatLon attribute is read-only.
4978 
4979 *  Applicability:
4980 *     WcsMap
4981 *        All WcsMaps have this attribute.
4982 
4983 *  Notes:
4984 *att--
4985 */
4986 
4987 /* WcsAxis. */
4988 /* -------- */
4989 /*
4990 *att++
4991 *  Name:
4992 *     WcsAxis(lonlat)
4993 
4994 *  Purpose:
4995 *     FITS-WCS projection axes.
4996 
4997 *  Type:
4998 *     Public attribute.
4999 
5000 *  Synopsis:
5001 *     Integer, read-only.
5002 
5003 *  Description:
5004 *     This attribute gives the indices of the longitude and latitude
5005 *     coordinates of the FITS-WCS projection within the coordinate
5006 *     space used by a WcsMap. These indices are defined when the
5007 c     WcsMap is first created using astWcsMap and cannot
5008 f     WcsMap is first created using AST_WCSMAP and cannot
5009 *     subsequently be altered.
5010 *
5011 *     If "lonlat" is 1, the index of the longitude axis is
5012 *     returned. Otherwise, if it is 2, the index of the latitude axis
5013 *     is returned.
5014 
5015 *  Applicability:
5016 *     WcsMap
5017 *        All WcsMaps have this attribute.
5018 *att--
5019 */
5020 
5021 /* Index of the latitude or longitude axis. */
5022 MAKE_GET(WcsAxis,int,0,this->wcsaxis[ axis ],2)
5023 
5024 /* Copy constructor. */
5025 /* ----------------- */
Copy(const AstObject * objin,AstObject * objout,int * status)5026 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
5027 /*
5028 *  Name:
5029 *     Copy
5030 
5031 *  Purpose:
5032 *     Copy constructor for WcsMap objects.
5033 
5034 *  Type:
5035 *     Private function.
5036 
5037 *  Synopsis:
5038 *     void Copy( const AstObject *objin, AstObject *objout, int *status )
5039 
5040 *  Description:
5041 *     This function implements the copy constructor for WcsMap objects.
5042 
5043 *  Parameters:
5044 *     objin
5045 *        Pointer to the object to be copied.
5046 *     objout
5047 *        Pointer to the object being constructed.
5048 *     status
5049 *        Pointer to the inherited status variable.
5050 
5051 *  Returned Value:
5052 *     void
5053 
5054 *  Notes:
5055 *     -  This constructor makes a deep copy, including a copy of the
5056 *     projection parameter values associated with the input WcsMap.
5057 */
5058 
5059 
5060 /* Local Variables: */
5061    AstWcsMap *in;                /* Pointer to input WcsMap */
5062    AstWcsMap *out;               /* Pointer to output WcsMap */
5063 
5064 /* Check the global error status. */
5065    if ( !astOK ) return;
5066 
5067 /* Obtain pointers to the input and output WcsMaps. */
5068    in = (AstWcsMap *) objin;
5069    out = (AstWcsMap *) objout;
5070 
5071 /* Allocate memory to hold the projection parameters within the AstPrjPrm
5072    structure used by WCSLIB. */
5073    (out->params).p = astMalloc( astSizeOf( (in->params).p ) );
5074    (out->params).p2 = astMalloc( astSizeOf( (in->params).p2 ) );
5075 
5076 /* Copy the projection parameter information. */
5077    CopyPV( in, out, status );
5078 
5079    return;
5080 
5081 }
5082 
5083 /* Destructor. */
5084 /* ----------- */
Delete(AstObject * obj,int * status)5085 static void Delete( AstObject *obj, int *status ) {
5086 /*
5087 *  Name:
5088 *     Delete
5089 
5090 *  Purpose:
5091 *     Destructor for WcsMap objects.
5092 
5093 *  Type:
5094 *     Private function.
5095 
5096 *  Synopsis:
5097 *     void Delete( AstObject *obj, int *status )
5098 
5099 *  Description:
5100 *     This function implements the destructor for WcsMap objects.
5101 
5102 *  Parameters:
5103 *     obj
5104 *        Pointer to the object to be deleted.
5105 *     status
5106 *        Pointer to the inherited status variable.
5107 
5108 *  Returned Value:
5109 *     void
5110 
5111 *  Notes:
5112 *     This function attempts to execute even if the global error status is
5113 *     set.
5114 */
5115 
5116 /* Local Variables: */
5117    AstWcsMap *this;            /* Pointer to WcsMap */
5118 
5119 /* Obtain a pointer to the WcsMap structure. */
5120    this = (AstWcsMap *) obj;
5121 
5122 /* Free the arrays used to store projection parameters. */
5123    FreePV( this, status );
5124 
5125 /* Free memory used to hold the projection parameters within the AstPrjPrm
5126    structure used by WCSLIB. */
5127    this->params.p = astFree( this->params.p );
5128    this->params.p2 = astFree( this->params.p2 );
5129 
5130 }
5131 
5132 /* Dump function. */
5133 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)5134 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
5135 /*
5136 *  Name:
5137 *     Dump
5138 
5139 *  Purpose:
5140 *     Dump function for WcsMap objects.
5141 
5142 *  Type:
5143 *     Private function.
5144 
5145 *  Synopsis:
5146 *     void Dump( AstObject *this, AstChannel *channel, int *status )
5147 
5148 *  Description:
5149 *     This function implements the Dump function which writes out data
5150 *     for the WcsMap class to an output Channel.
5151 
5152 *  Parameters:
5153 *     this
5154 *        Pointer to the WcsMap whose data are being written.
5155 *     channel
5156 *        Pointer to the Channel to which the data are being written.
5157 *     status
5158 *        Pointer to the inherited status variable.
5159 */
5160 
5161 #define COMMENT_LEN 150          /* Maximum length of a keyword comment */
5162 #define KEY_LEN 50               /* Maximum length of a keyword */
5163 
5164 /* Local Variables: */
5165    AstWcsMap *this;              /* Pointer to the WcsMap structure */
5166    char *comment;                /* Pointer to comment string */
5167    char buff[ KEY_LEN + 1 ];     /* Buffer for keyword string */
5168    char comment_buff[ COMMENT_LEN + 1 ]; /* Buffer for keyword comment */
5169    const PrjData *prjdata;       /* Information about the projection */
5170    double dval;                  /* Double precision value */
5171    int axis;                     /* Zero based axis index */
5172    int i;                        /* Axis index */
5173    int m;                        /* Parameter index */
5174    int ival;                     /* Integer value */
5175    int set;                      /* Attribute value set? */
5176 
5177 /* Check the global error status. */
5178    if ( !astOK ) return;
5179 
5180 /* Obtain a pointer to the WcsMap structure. */
5181    this = (AstWcsMap *) this_object;
5182 
5183 /* Write out values representing the instance variables for the
5184    WcsMap class.  Accompany these with appropriate comment strings,
5185    possibly depending on the values being written.*/
5186 
5187 /* In the case of attributes, we first use the appropriate (private)
5188    Test...  member function to see if they are set. If so, we then use
5189    the (private) Get... function to obtain the value to be written
5190    out. Note, all read-only attributes are considered to be set.
5191 
5192    For attributes which are not set, we use the astGet... method to
5193    obtain the value instead. This will supply a default value
5194    (possibly provided by a derived class which over-rides this method)
5195    which is more useful to a human reader as it corresponds to the
5196    actual default attribute value.  Since "set" will be zero, these
5197    values are for information only and will not be read back. */
5198 
5199 /* WcsType. */
5200 /* -------- */
5201    ival = GetWcsType( this, status );
5202    prjdata = FindPrjData( ival, status );
5203    (void) sprintf( comment_buff, "%s projection", prjdata->desc );
5204    comment_buff[ 0 ] = toupper( comment_buff[ 0 ] );
5205    astWriteString( channel, "Type", 1, 1, prjdata->ctype + 1, comment_buff );
5206 
5207 /* FITSProj */
5208 /* -------- */
5209    set = TestFITSProj( this, status );
5210    ival = set ? GetFITSProj( this, status ) : astGetFITSProj( this );
5211    astWriteInt( channel, "FitsPrj", set, 0, ival,
5212                 ival ? "Defines the FITS-WCS projection" :
5213                        "Does not define the FITS-WCS projection" );
5214 
5215 /* TPNTan */
5216 /* ------ */
5217    set = TestTPNTan( this, status );
5218    ival = set ? GetTPNTan( this, status ) : astGetTPNTan( this );
5219    astWriteInt( channel, "TpnTan", set, 0, ival,
5220                 ival ? "Include TAN projection in TPN mapping" :
5221                        "Exclude TAN projection from TPN mapping" );
5222 
5223 /* PVi_m. */
5224 /* ------ */
5225    for( i = 0; i < astGetNin( this ); i++ ){
5226       if( this->np ) {
5227          for( m = 0; m < this->np[ i ]; m++ ){
5228             set = TestPV( this, i, m, status );
5229             if( set ) {
5230                dval = set ? GetPV( this, i, m, status ) : astGetPV( this, i, m );
5231                (void) sprintf( buff, "PV%d_%d", i + 1, m );
5232                (void) sprintf( comment_buff, "Projection parameter %d for axis %d", m, i + 1 );
5233                astWriteDouble( channel, buff, set, 0, dval, comment_buff );
5234             }
5235          }
5236       }
5237    }
5238 
5239 /* WcsAxis(axis). */
5240 /* -------------- */
5241    for( axis = 0; axis < 2; axis++ ){
5242       ival =  GetWcsAxis( this, axis, status );
5243       (void) sprintf( buff, "WcsAx%d", axis + 1 );
5244       if( axis == 0 ) {
5245          comment = "Index of celestial longitude axis";
5246       } else {
5247          comment = "Index of celestial latitude axis";
5248       }
5249       astWriteInt( channel, buff, (axis!=ival), 0, ival + 1, comment );
5250    }
5251 
5252 /* Note, the "params" component of the AstWcsMap structure is not written out
5253    because it can be re-generated from the other components. */
5254 
5255 /* Return. */
5256    return;
5257 
5258 /* Undefine macros local to this function. */
5259 #undef COMMENT_LEN
5260 #undef KEY_LEN
5261 }
5262 
5263 /* Standard class functions. */
5264 /* ========================= */
5265 /* Implement the astIsAWcsMap and astCheckWcsMap functions using the macros
5266    defined for this purpose in the "object.h" header file. */
astMAKE_ISA(WcsMap,Mapping)5267 astMAKE_ISA(WcsMap,Mapping)
5268 astMAKE_CHECK(WcsMap)
5269 
5270 AstWcsMap *astWcsMap_( int ncoord, int type, int lonax, int latax,
5271                        const char *options, int *status, ...){
5272 /*
5273 *++
5274 *  Name:
5275 c     astWcsMap
5276 f     AST_WCSMAP
5277 
5278 *  Purpose:
5279 *     Create a WcsMap.
5280 
5281 *  Type:
5282 *     Public function.
5283 
5284 *  Synopsis:
5285 c     #include "wcsmap.h"
5286 c     AstWcsMap *astWcsMap( int ncoord, int type, int lonax, int latax,
5287 c                           const char *options, ... )
5288 f     RESULT = AST_WCSMAP( NCOORD, TYPE, LONAX, LATAX, OPTIONS, STATUS )
5289 
5290 *  Class Membership:
5291 *     WcsMap constructor.
5292 
5293 *  Description:
5294 *     This function creates a new WcsMap and optionally initialises its
5295 *     attributes.
5296 *
5297 *     A WcsMap is used to represent sky coordinate projections as
5298 *     described in the (draft) FITS world coordinate system (FITS-WCS)
5299 *     paper by E.W. Griesen and M. Calabretta (A & A, in preparation).
5300 *     This paper defines a set of functions, or sky projections, which
5301 *     transform longitude-latitude pairs representing spherical
5302 *     celestial coordinates into corresponding pairs of Cartesian
5303 *     coordinates (and vice versa).
5304 *
5305 *     A WcsMap is a specialised form of Mapping which implements these
5306 *     sky projections and applies them to a specified pair of coordinates.
5307 *     All the projections in the FITS-WCS paper are supported, plus the now
5308 *     deprecated "TAN with polynomial correction terms" projection which
5309 *     is refered to here by the code "TPN". Using the FITS-WCS terminology,
5310 *     the transformation is between "native spherical" and "projection
5311 *     plane" coordinates.  These coordinates may, optionally, be embedded in
5312 *     a space with more than two dimensions, the remaining coordinates being
5313 *     copied unchanged. Note, however, that for consistency with other AST
5314 *     facilities, a WcsMap handles coordinates that represent angles
5315 *     in radians (rather than the degrees used by FITS-WCS).
5316 *
5317 *     The type of FITS-WCS projection to be used and the coordinates
5318 *     (axes) to which it applies are specified when a WcsMap is first
5319 *     created. The projection type may subsequently be determined
5320 *     using the WcsType attribute and the coordinates on which it acts
5321 *     may be determined using the WcsAxis(lonlat) attribute.
5322 *
5323 *     Each WcsMap also allows up to 100 "projection parameters" to be
5324 *     associated with each axis. These specify the precise form of the
5325 *     projection, and are accessed using PVi_m attribute, where "i" is
5326 *     the integer axis index (starting at 1), and m is an integer
5327 *     "parameter index" in the range 0 to 99. The number of projection
5328 *     parameters required by each projection, and their meanings, are
5329 *     dependent upon the projection type (most projections either do not
5330 *     use any projection parameters, or use parameters 1 and 2 associated
5331 *     with the latitude axis). Before creating a WcsMap you should consult
5332 *     the FITS-WCS paper for details of which projection parameters are
5333 *     required, and which have defaults. When creating the WcsMap, you must
5334 *     explicitly set values for all those required projection parameters
5335 *     which do not have defaults defined in this paper.
5336 
5337 *  Parameters:
5338 c     ncoord
5339 f     NCOORD = INTEGER (Given)
5340 *        The number of coordinate values for each point to be
5341 *        transformed (i.e. the number of dimensions of the space in
5342 *        which the points will reside). This must be at least 2. The
5343 *        same number is applicable to both input and output points.
5344 c     type
5345 f     TYPE = INTEGER (Given)
5346 *        The type of FITS-WCS projection to apply. This should be
5347 c        given using a macro value such as AST__TAN (for a tangent
5348 f        given as a symbolic value such as AST__TAN (for a tangent
5349 *        plane projection), where the characters following the double
5350 *        underscore give the projection type code (in upper case) as
5351 *        used in the FITS-WCS "CTYPEi" keyword. You should consult the
5352 *        FITS-WCS paper for a list of the available projections. The
5353 *        additional code of AST__TPN can be supplied which represents a
5354 *        TAN projection with polynomial correction terms as defined in an
5355 *        early draft of the FITS-WCS paper.
5356 c     lonax
5357 f     LONAX = INTEGER (Given)
5358 *        The index of the longitude axis. This should lie in the range
5359 c        1 to "ncoord".
5360 f        1 to NCOORD.
5361 c     latax
5362 f     LATAX = INTEGER (Given)
5363 *        The index of the latitude axis. This should lie in the range
5364 c        1 to "ncoord" and be distinct from "lonax".
5365 f        1 to NCOORD and be distinct from LONAX.
5366 c     options
5367 f     OPTIONS = CHARACTER * ( * ) (Given)
5368 c        Pointer to a null-terminated string containing an optional
5369 c        comma-separated list of attribute assignments to be used for
5370 c        initialising the new WcsMap. The syntax used is identical to
5371 c        that for the astSet function and may include "printf" format
5372 c        specifiers identified by "%" symbols in the normal way.
5373 f        A character string containing an optional comma-separated
5374 f        list of attribute assignments to be used for initialising the
5375 f        new WcsMap. The syntax used is identical to that for the
5376 f        AST_SET routine.
5377 *
5378 *        If the sky projection to be implemented requires projection
5379 *        parameter values to be set, then this should normally be done
5380 *        here via the PVi_m attribute (see the "Examples"
5381 *        section). Setting values for these parameters is mandatory if
5382 *        they do not have default values (as defined in the FITS-WCS
5383 *        paper).
5384 c     ...
5385 c        If the "options" string contains "%" format specifiers, then
5386 c        an optional list of additional arguments may follow it in
5387 c        order to supply values to be substituted for these
5388 c        specifiers. The rules for supplying these are identical to
5389 c        those for the astSet function (and for the C "printf"
5390 c        function).
5391 f     STATUS = INTEGER (Given and Returned)
5392 f        The global status.
5393 
5394 *  Returned Value:
5395 c     astWcsMap()
5396 f     AST_WCSMAP = INTEGER
5397 *        A pointer to the new WcsMap.
5398 
5399 *  Examples:
5400 c     wcsmap = astWcsMap( 2, AST__MER, 1, 2, "" );
5401 f     WCSMAP = AST_WCSMAP( 2, AST__MER, 1, 2, ' ', STATUS )
5402 *        Creates a WcsMap that implements a FITS-WCS Mercator
5403 *        projection on pairs of coordinates, with coordinates 1 and 2
5404 *        representing the longitude and latitude respectively. Note
5405 *        that the FITS-WCS Mercator projection does not require any
5406 *        projection parameters.
5407 c     wcsmap = astWcsMap( 3, AST__COE, 2, 3, "PV3_1=40.0" );
5408 f     WCSMAP = AST_WCSMAP( 3, AST__COE, 2, 3, 'PV3_1=40.0', STATUS )
5409 *        Creates a WcsMap that implements a FITS-WCS conical equal
5410 *        area projection. The WcsMap acts on points in a 3-dimensional
5411 *        space; coordinates 2 and 3 represent longitude and latitude
5412 *        respectively, while the values of coordinate 1 are copied
5413 *        unchanged.  Projection parameter 1 associatyed with the latitude
5414 *        axis (corresponding to FITS keyword "PV3_1") is required and has
5415 *        no default, so is set explicitly to 40.0 degrees. Projection
5416 *        parameter 2 (corresponding to FITS keyword "PV3_2") is required
5417 *        but has a default of zero, so need not be specified.
5418 
5419 *  Notes:
5420 *     - The forward transformation of a WcsMap converts between
5421 *     FITS-WCS "native spherical" and "relative physical" coordinates,
5422 *     while the inverse transformation converts in the opposite
5423 *     direction. This arrangement may be reversed, if required, by
5424 c     using astInvert or by setting the Invert attribute to a non-zero
5425 f     using AST_INVERT or by setting the Invert attribute to a non-zero
5426 *     value.
5427 *     - If any set of coordinates cannot be transformed (for example,
5428 *     many projections do not cover the entire celestial sphere), then
5429 *     a WcsMap will yield coordinate values of AST__BAD.
5430 *     - The validity of any projection parameters given via the PVi_m
5431 c     parameter in the "options" string is not checked by this
5432 f     parameter in the OPTIONS string is not checked by this
5433 *     function. However, their validity is checked when the resulting
5434 *     WcsMap is used to transform coordinates, and an error will
5435 *     result if the projection parameters do not satisfy all the
5436 *     required constraints (as defined in the FITS-WCS paper).
5437 *     - A null Object pointer (AST__NULL) will be returned if this
5438 c     function is invoked with the AST error status set, or if it
5439 f     function is invoked with STATUS set to an error value, or if it
5440 *     should fail for any reason.
5441 
5442 *  Status Handling:
5443 *     The protected interface to this function includes an extra
5444 *     parameter at the end of the parameter list descirbed above. This
5445 *     parameter is a pointer to the integer inherited status
5446 *     variable: "int *status".
5447 
5448 *--
5449 */
5450 
5451 /* Local Variables: */
5452    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
5453    AstWcsMap *new;               /* Pointer to new WcsMap */
5454    va_list args;                 /* Variable argument list */
5455 
5456 /* Check the global status. */
5457    if ( !astOK ) return NULL;
5458 
5459 /* Get a pointer to the thread specific global data structure. */
5460    astGET_GLOBALS(NULL);
5461 
5462 /* Initialise the WcsMap, allocating memory and initialising the
5463    virtual function table as well if necessary. */
5464    new = astInitWcsMap( NULL, sizeof( AstWcsMap ), !class_init, &class_vtab,
5465                         "WcsMap", ncoord, type, lonax - 1, latax - 1 );
5466 
5467 /* If successful, note that the virtual function table has been
5468    initialised. */
5469    if ( astOK ) {
5470       class_init = 1;
5471 
5472 /* Obtain the variable argument list and pass it along with the options string
5473    to the astVSet method to initialise the new WcsMap's attributes. */
5474       va_start( args, status );
5475       astVSet( new, options, NULL, args );
5476       va_end( args );
5477 
5478 /* If an error occurred, clean up by deleting the new object. */
5479       if ( !astOK ) new = astDelete( new );
5480    }
5481 
5482 /* Return a pointer to the new WcsMap. */
5483    return new;
5484 }
5485 
astWcsMapId_(int ncoord,int type,int lonax,int latax,const char * options,...)5486 AstWcsMap *astWcsMapId_( int ncoord, int type, int lonax, int latax,
5487                          const char *options, ... ){
5488 /*
5489 *  Name:
5490 *     astWcsMapId_
5491 
5492 *  Purpose:
5493 *     Create a WcsMap.
5494 
5495 *  Type:
5496 *     Private function.
5497 
5498 *  Synopsis:
5499 *     #include "wcsmap.h"
5500 *     AstWcsMap *astWcsMap_( int ncoord, int type, int lonax, int latax,
5501 *                            const char *options, ... )
5502 
5503 *  Class Membership:
5504 *     WcsMap constructor.
5505 
5506 *  Description:
5507 *     This function implements the external (public) interface to the
5508 *     astWcsMap constructor function. It returns an ID value (instead
5509 *     of a true C pointer) to external users, and must be provided
5510 *     because astWcsMap_ has a variable argument list which cannot be
5511 *     encapsulated in a macro (where this conversion would otherwise
5512 *     occur).
5513 *
5514 *     The variable argument list also prevents this function from
5515 *     invoking astWcsMap_ directly, so it must be a re-implementation
5516 *     of it in all respects, except for the final conversion of the
5517 *     result to an ID value.
5518 
5519 *  Parameters:
5520 *     As for astWcsMap_.
5521 
5522 *  Returned Value:
5523 *     The ID value associated with the new WcsMap.
5524 */
5525 
5526 /* Local Variables: */
5527    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
5528    AstWcsMap *new;               /* Pointer to new WcsMap */
5529    va_list args;                 /* Variable argument list */
5530    int *status;                  /* Pointer to inherited status value */
5531 
5532 /* Get a pointer to the inherited status value. */
5533    status = astGetStatusPtr;
5534 
5535 /* Get a pointer to the thread specific global data structure. */
5536    astGET_GLOBALS(NULL);
5537 
5538 /* Check the global status. */
5539    if ( !astOK ) return NULL;
5540 
5541 /* Initialise the WcsMap, allocating memory and initialising the
5542    virtual function table as well if necessary. */
5543    new = astInitWcsMap( NULL, sizeof( AstWcsMap ), !class_init, &class_vtab,
5544                         "WcsMap", ncoord, type, lonax - 1, latax - 1 );
5545 
5546 /* If successful, note that the virtual function table has been
5547    initialised. */
5548    if ( astOK ) {
5549       class_init = 1;
5550 
5551 /* Obtain the variable argument list and pass it along with the options string
5552    to the astVSet method to initialise the new WcsMap's attributes. */
5553       va_start( args, options );
5554       astVSet( new, options, NULL, args );
5555       va_end( args );
5556 
5557 /* If an error occurred, clean up by deleting the new object. */
5558       if ( !astOK ) new = astDelete( new );
5559    }
5560 
5561 /* Return an ID value for the new WcsMap. */
5562    return astMakeId( new );
5563 }
5564 
astInitWcsMap_(void * mem,size_t size,int init,AstWcsMapVtab * vtab,const char * name,int ncin,int type,int lonax,int latax,int * status)5565 AstWcsMap *astInitWcsMap_( void *mem, size_t size, int init,
5566                            AstWcsMapVtab *vtab, const char *name,
5567                            int ncin, int type, int lonax, int latax, int *status ) {
5568 /*
5569 *+
5570 *  Name:
5571 *     astInitWcsMap
5572 
5573 *  Purpose:
5574 *     Initialise a WcsMap.
5575 
5576 *  Type:
5577 *     Protected function.
5578 
5579 *  Synopsis:
5580 *     #include "wcsmap.h"
5581 *     AstWcsMap *astInitWcsMap( void *mem, size_t size, int init,
5582 *                               AstWcsMapVtab *vtab, const char *name,
5583 *                               int ncin, int type, int lonax, int latax )
5584 
5585 *  Class Membership:
5586 *     WcsMap initialiser.
5587 
5588 *  Description:
5589 *     This function is provided for use by class implementations to initialise
5590 *     a new WcsMap object. It allocates memory (if necessary) to accommodate
5591 *     the WcsMap plus any additional data associated with the derived class.
5592 *     It then initialises a WcsMap structure at the start of this memory. If
5593 *     the "init" flag is set, it also initialises the contents of a virtual
5594 *     function table for a WcsMap at the start of the memory passed via the
5595 *     "vtab" parameter.
5596 
5597 *  Parameters:
5598 *     mem
5599 *        A pointer to the memory in which the WcsMap is to be initialised.
5600 *        This must be of sufficient size to accommodate the WcsMap data
5601 *        (sizeof(WcsMap)) plus any data used by the derived class. If a value
5602 *        of NULL is given, this function will allocate the memory itself using
5603 *        the "size" parameter to determine its size.
5604 *     size
5605 *        The amount of memory used by the WcsMap (plus derived class data).
5606 *        This will be used to allocate memory if a value of NULL is given for
5607 *        the "mem" parameter. This value is also stored in the WcsMap
5608 *        structure, so a valid value must be supplied even if not required for
5609 *        allocating memory.
5610 *     init
5611 *        A logical flag indicating if the WcsMap's virtual function table is
5612 *        to be initialised. If this value is non-zero, the virtual function
5613 *        table will be initialised by this function.
5614 *     vtab
5615 *        Pointer to the start of the virtual function table to be associated
5616 *        with the new WcsMap.
5617 *     name
5618 *        Pointer to a constant null-terminated character string which contains
5619 *        the name of the class to which the new object belongs (it is this
5620 *        pointer value that will subsequently be returned by the astGetClass
5621 *        method).
5622 *     ncin
5623 *        The number of coordinate values per point.
5624 *     type
5625 *        The type of projection to use, choosen from the list available
5626 *        in the FITS celestial coordinates system. These are specified by
5627 *        symbolic values such as AST__TAN (specifying a tangent plane
5628 *        projection), where the characters following the double underscore
5629 *        gives the FITS projection type (in upper case) as used in the FITS
5630 *        "CTYPEn" keyword.
5631 *     lonax
5632 *        The index of the longitude axis. The first axis has index 0.
5633 *     latax
5634 *        The index of the latitude axis. The first axis has index 0.
5635 
5636 *  Returned Value:
5637 *     A pointer to the new WcsMap.
5638 
5639 *  Notes:
5640 *     -  A null pointer will be returned if this function is invoked with the
5641 *     global error status set, or if it should fail for any reason.
5642 *-
5643 */
5644 
5645 /* Local Variables: */
5646    const PrjData *prjdata;      /* Information about the projection */
5647    AstWcsMap *new;              /* Pointer to new WcsMap */
5648 
5649 /* Check the global status. */
5650    if ( !astOK ) return NULL;
5651 
5652 /* If necessary, initialise the virtual function table. */
5653    if ( init ) astInitWcsMapVtab( vtab, name );
5654 
5655 /* Initialise. */
5656    new = NULL;
5657 
5658 /* If a genuine FITS-WCS projection has been specified, check the initialisation
5659    value(s) for validity, reporting an error if necessary. Prefix the error
5660    report with the name of the function and the class of object being
5661    processed. First check that at least two dimensions are to be mapped. */
5662    if( type != AST__WCSBAD ){
5663       if ( ncin < 2 ){
5664          astError( AST__WCSNC, "astInitWcsMap(%s): Too few axes (%d) "
5665                    "specified. Must be at least 2.", status, name, ncin );
5666 
5667 /* Report an error if either the longitude or latitude axes are out of
5668    bounds. */
5669       } else if ( lonax < 0 || lonax >= ncin ){
5670          astError( AST__WCSAX, "astInitWcsMap(%s): Specified longitude axis (%d) "
5671                    "does not exist within a %d dimensional coordinate system. ", status,
5672                    name, lonax + 1, ncin );
5673 
5674       } else if ( latax < 0 || latax >= ncin ){
5675          astError( AST__WCSAX, "astInitWcsMap(%s): Specified latitude axis (%d) "
5676                    "does not exist within a %d dimensional coordinate system. ", status,
5677                    name, latax + 1, ncin );
5678 
5679 /* Report an error if the longitude or latitude axes are the same. */
5680       } else if ( lonax == latax ){
5681          astError( AST__WCSAX, "astInitWcsMap(%s): The same axis (%d) has been "
5682                    "given for both the longitude and the latitude axis.", status, name,
5683                    lonax + 1 );
5684 
5685 /* Report an error if projection type is unknown. */
5686       } else if ( type < 1 || type >= AST__WCSBAD ){
5687          astError( AST__WCSTY, "astInitWcsMap(%s): Projection type %d is "
5688                    "undefined. Projection types must be in the range 1 to %d.", status,
5689                    name, type, AST__WCSBAD - 1 );
5690       }
5691    }
5692 
5693 /* Get a description of the requeste dprojection type. */
5694    prjdata = FindPrjData( type, status );
5695 
5696 /* If all the above checks have been passed succesfully... */
5697    if( astOK ){
5698 
5699 /* Initialise a Mapping structure (the parent class) as the first component
5700    within the WcsMap structure, allocating memory if necessary. Specify that
5701    the Mapping should be defined in both the forward and inverse directions. */
5702       new = (AstWcsMap *) astInitMapping( mem, size, 0,
5703                                           (AstMappingVtab *) vtab, name,
5704                                           ncin, ncin, 1, 1 );
5705 
5706       if ( astOK ) {
5707 
5708 /* Initialise the WcsMap data. */
5709 /* ---------------------------- */
5710 /* Store the projection type. */
5711          new->type = type;
5712 
5713 /* Store the "use as FITS-WCS projection" flag. */
5714          new->fits_proj = -INT_MAX;
5715 
5716 /* Store the "include TAN component in TPN Mapping" flag. */
5717          new->tpn_tan = -INT_MAX;
5718 
5719 /* Store the axes associated with longitude and latitude. */
5720          new->wcsaxis[0] = lonax;
5721          new->wcsaxis[1] = latax;
5722 
5723 /* Store NULL pointers for the arrays holding projection parameters. */
5724          new->p = NULL;
5725          new->np = NULL;
5726 
5727 /* Allocate memory of the right size to hold the maximum number of
5728    projection parameters needed by the projection. */
5729          new->params.p = astMalloc( sizeof( double ) * (prjdata->mxpar + 1) );
5730          new->params.p2 = astMalloc( sizeof( double ) * (prjdata->mxpar2 + 1) );
5731 
5732 /* Initialise the "AstPrjPrm" structure (defined in proj.h). */
5733          InitPrjPrm( new, status );
5734 
5735 /* If an error occurred, clean up by deleting the new WcsMap. */
5736          if ( !astOK ) new = astDelete( new );
5737       }
5738    }
5739 
5740 /* Return a pointer to the new WcsMap. */
5741    return new;
5742 }
5743 
astLoadWcsMap_(void * mem,size_t size,AstWcsMapVtab * vtab,const char * name,AstChannel * channel,int * status)5744 AstWcsMap *astLoadWcsMap_( void *mem, size_t size,
5745                            AstWcsMapVtab *vtab, const char *name,
5746                            AstChannel *channel, int *status ) {
5747 /*
5748 *+
5749 *  Name:
5750 *     astLoadWcsMap
5751 
5752 *  Purpose:
5753 *     Load a WcsMap.
5754 
5755 *  Type:
5756 *     Protected function.
5757 
5758 *  Synopsis:
5759 *     #include "wcsmap.h"
5760 *     AstWcsMap *astLoadWcsMap( void *mem, size_t size,
5761 *                               AstWcsMapVtab *vtab, const char *name,
5762 *                               AstChannel *channel )
5763 
5764 *  Class Membership:
5765 *     WcsMap loader.
5766 
5767 *  Description:
5768 *     This function is provided to load a new WcsMap using data read
5769 *     from a Channel. It first loads the data used by the parent class
5770 *     (which allocates memory if necessary) and then initialises a
5771 *     WcsMap structure in this memory, using data read from the input
5772 *     Channel.
5773 *
5774 *     If the "init" flag is set, it also initialises the contents of a
5775 *     virtual function table for a WcsMap at the start of the memory
5776 *     passed via the "vtab" parameter.
5777 
5778 
5779 *  Parameters:
5780 *     mem
5781 *        A pointer to the memory into which the WcsMap is to be
5782 *        loaded.  This must be of sufficient size to accommodate the
5783 *        WcsMap data (sizeof(WcsMap)) plus any data used by derived
5784 *        classes. If a value of NULL is given, this function will
5785 *        allocate the memory itself using the "size" parameter to
5786 *        determine its size.
5787 *     size
5788 *        The amount of memory used by the WcsMap (plus derived class
5789 *        data).  This will be used to allocate memory if a value of
5790 *        NULL is given for the "mem" parameter. This value is also
5791 *        stored in the WcsMap structure, so a valid value must be
5792 *        supplied even if not required for allocating memory.
5793 *
5794 *        If the "vtab" parameter is NULL, the "size" value is ignored
5795 *        and sizeof(AstWcsMap) is used instead.
5796 *     vtab
5797 *        Pointer to the start of the virtual function table to be
5798 *        associated with the new WcsMap. If this is NULL, a pointer
5799 *        to the (static) virtual function table for the WcsMap class
5800 *        is used instead.
5801 *     name
5802 *        Pointer to a constant null-terminated character string which
5803 *        contains the name of the class to which the new object
5804 *        belongs (it is this pointer value that will subsequently be
5805 *        returned by the astGetClass method).
5806 *
5807 *        If the "vtab" parameter is NULL, the "name" value is ignored
5808 *        and a pointer to the string "WcsMap" is used instead.
5809 
5810 *  Returned Value:
5811 *     A pointer to the new WcsMap.
5812 
5813 *  Notes:
5814 *     - A null pointer will be returned if this function is invoked
5815 *     with the global error status set, or if it should fail for any
5816 *     reason.
5817 *-
5818 */
5819 
5820 #define KEY_LEN 50               /* Maximum length of a keyword */
5821 
5822    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
5823 /* Local Variables: */
5824    const PrjData *prjdata;      /* Information about the projection */
5825    AstWcsMap *new;              /* Pointer to the new WcsMap */
5826    char *text;                  /* Textual form of an integer value */
5827    char buff[ KEY_LEN + 1 ];    /* Buffer for keyword string */
5828    double pv;                   /* Projection parameter */
5829    int axis;                    /* Axis index */
5830    int i;                       /* Axis index */
5831    int m;                       /* Parameter index */
5832    int mxpar;                   /* Maximum number of PVi_m values */
5833 
5834 /* Get a pointer to the thread specific global data structure. */
5835    astGET_GLOBALS(channel);
5836 
5837 /* Initialise. */
5838    new = NULL;
5839 
5840 /* Check the global error status. */
5841    if ( !astOK ) return new;
5842 
5843 /* If a NULL virtual function table has been supplied, then this is
5844    the first loader to be invoked for this WcsMap. In this case the
5845    WcsMap belongs to this class, so supply appropriate values to be
5846    passed to the parent class loader (and its parent, etc.). */
5847    if ( !vtab ) {
5848       size = sizeof( AstWcsMap );
5849       vtab = &class_vtab;
5850       name = "WcsMap";
5851 
5852 /* If required, initialise the virtual function table for this class. */
5853       if ( !class_init ) {
5854          astInitWcsMapVtab( vtab, name );
5855          class_init = 1;
5856       }
5857    }
5858 
5859 /* Invoke the parent class loader to load data for all the ancestral
5860    classes of the current one, returning a pointer to the resulting
5861    partly-built WcsMap. */
5862    new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name,
5863                          channel );
5864 
5865    if ( astOK ) {
5866 
5867 /* Read input data. */
5868 /* ================ */
5869 /* Request the input Channel to read all the input data appropriate to
5870    this class into the internal "values list". */
5871       astReadClassData( channel, "WcsMap" );
5872 
5873 /* Now read each individual data item from this list and use it to
5874    initialise the appropriate instance variable(s) for this class. */
5875 
5876 /* In the case of attributes, we first read the "raw" input value,
5877    supplying the "unset" value as the default. If a "set" value is
5878    obtained, we then use the appropriate (private) Set... member
5879    function to validate and set the value properly. Note, this is only
5880    done for read/write attributes, not read-only ones. */
5881 
5882 /* FITSProj */
5883 /* -------- */
5884       new->fits_proj = astReadInt( channel, "fitsprj", -INT_MAX );
5885       if ( TestFITSProj( new, status ) ) {
5886          SetFITSProj( new, new->fits_proj, status );
5887       }
5888 
5889 /* TPNTan */
5890 /* -------- */
5891       new->tpn_tan = astReadInt( channel, "tpntan", -INT_MAX );
5892       if ( TestTPNTan( new, status ) ) {
5893          SetTPNTan( new, new->tpn_tan, status );
5894       }
5895 
5896 /* WcsType */
5897 /* ------- */
5898       text = astReadString( channel, "type", " " );
5899       if( strcmp( text, " " ) ){
5900          char tmp[ 10 ];
5901          (void) sprintf( tmp, "-%.8s", text );
5902          new->type = astWcsPrjType( tmp );
5903       } else {
5904          new->type = AST__WCSBAD;
5905       }
5906       text = astFree( text );
5907       prjdata = FindPrjData( new->type, status );
5908 
5909 /* WcsAxis(axis). */
5910 /* -------------- */
5911       for( axis = 0; axis < 2; axis++ ){
5912          (void) sprintf( buff, "wcsax%d", axis + 1 );
5913          new->wcsaxis[ axis ] = astReadInt( channel, buff, axis + 1 ) - 1;
5914       }
5915 
5916 /* Initialise the pointers to the projection parameter information. */
5917       new->p = NULL;
5918       new->np = NULL;
5919       new->params.p = astMalloc( sizeof( double ) * (prjdata->mxpar + 1) );
5920       new->params.p2 = astMalloc( sizeof( double ) * (prjdata->mxpar2 + 1) );
5921 
5922 /* Initialise the structure used by WCSLIB to hold intermediate values,
5923    so that the values will be re-calculated on the first invocation of a
5924    mapping function. */
5925       InitPrjPrm( new, status );
5926 
5927 /* ProjP(m). */
5928 /* --------- */
5929       for( m = 0; m < AST__WCSMX; m++ ){
5930          (void) sprintf( buff, "projp%d", m );
5931          pv = astReadDouble( channel, buff, AST__BAD );
5932          if( pv != AST__BAD ) SetPV( new, new->wcsaxis[ 1 ], m, pv, status );
5933       }
5934 
5935 /* PVi_m. */
5936 /* -------*/
5937       for( i = 0; i < astGetNin( new ); i++ ){
5938 
5939          if( i == new->wcsaxis[ 0 ] ) {
5940             mxpar = prjdata->mxpar2;
5941          } else if( i == new->wcsaxis[ 1 ] ) {
5942             mxpar = prjdata->mxpar;
5943          } else {
5944             mxpar = 0;
5945          }
5946 
5947          for( m = 0; m <= mxpar; m++ ){
5948             (void) sprintf( buff, "pv%d_%d", i + 1, m );
5949             pv = astReadDouble( channel, buff, AST__BAD );
5950             if( pv != AST__BAD ) SetPV( new, i, m, pv, status );
5951          }
5952       }
5953 
5954 /* If an error occurred, clean up by deleting the new WcsMap. */
5955       if ( !astOK ) new = astDelete( new );
5956    }
5957 
5958 /* Return the new WcsMap pointer. */
5959    return new;
5960 
5961 /* Undefine macros local to this function. */
5962 #undef KEY_LEN
5963 }
5964 
5965 /* Virtual function interfaces. */
5966 /* ============================ */
5967 /* These provide the external interface to the virtual functions defined by
5968    this class. Each simply checks the global error status and then locates and
5969    executes the appropriate member function, using the function pointer stored
5970    in the object's virtual function table (this pointer is located using the
5971    astMEMBER macro defined in "object.h").
5972 
5973    Note that the member function may not be the one defined here, as it may
5974    have been over-ridden by a derived class. However, it should still have the
5975    same interface. */
5976 
astClearPV_(AstWcsMap * this,int i,int m,int * status)5977 void astClearPV_( AstWcsMap *this, int i, int m, int *status ) {
5978    if ( !astOK ) return;
5979    (**astMEMBER(this,WcsMap,ClearPV))( this, i, m, status );
5980 }
5981 
astClearTPNTan_(AstWcsMap * this,int * status)5982 void astClearTPNTan_( AstWcsMap *this, int *status ) {
5983    if ( !astOK ) return;
5984    (**astMEMBER(this,WcsMap,ClearTPNTan))( this, status );
5985 }
5986 
astGetPV_(AstWcsMap * this,int i,int m,int * status)5987 double astGetPV_( AstWcsMap *this, int i, int m, int *status ) {
5988    if ( !astOK ) return AST__BAD;
5989    return (**astMEMBER(this,WcsMap,GetPV))( this, i, m, status );
5990 }
5991 
astSetPV_(AstWcsMap * this,int i,int m,double val,int * status)5992 void astSetPV_( AstWcsMap *this, int i, int m, double val, int *status ) {
5993    if ( !astOK ) return;
5994    (**astMEMBER(this,WcsMap,SetPV))( this, i, m, val, status );
5995 }
5996 
astSetTPNTan_(AstWcsMap * this,int val,int * status)5997 void astSetTPNTan_( AstWcsMap *this, int val, int *status ) {
5998    if ( !astOK ) return;
5999    (**astMEMBER(this,WcsMap,SetTPNTan))( this, val, status );
6000 }
6001 
astTestPV_(AstWcsMap * this,int i,int m,int * status)6002 int astTestPV_( AstWcsMap *this, int i, int m, int *status ) {
6003    if ( !astOK ) return 0;
6004    return (**astMEMBER(this,WcsMap,TestPV))( this, i, m, status );
6005 }
6006 
astIsZenithal_(AstWcsMap * this,int * status)6007 int astIsZenithal_( AstWcsMap *this, int *status ) {
6008    if ( !astOK ) return 0;
6009    return (**astMEMBER(this,WcsMap,IsZenithal))( this, status );
6010 }
6011 
astGetNatLat_(AstWcsMap * this,int * status)6012 double astGetNatLat_( AstWcsMap *this, int *status ) {
6013    if ( !astOK ) return AST__BAD;
6014    return (**astMEMBER(this,WcsMap,GetNatLat))( this, status );
6015 }
6016 
astGetNatLon_(AstWcsMap * this,int * status)6017 double astGetNatLon_( AstWcsMap *this, int *status ) {
6018    if ( !astOK ) return AST__BAD;
6019    return (**astMEMBER(this,WcsMap,GetNatLon))( this, status );
6020 }
6021 
astGetPVMax_(AstWcsMap * this,int i,int * status)6022 int astGetPVMax_( AstWcsMap *this, int i, int *status ) {
6023    if ( !astOK ) return -1;
6024    return (**astMEMBER(this,WcsMap,GetPVMax))( this, i, status );
6025 }
6026 
6027 
6028 
6029 
6030 
6031 
6032 
6033