1 /*
2 *class++
3 *  Name:
4 *     SpecFluxFrame
5 
6 *  Purpose:
7 *     Compound spectrum/flux Frame.
8 
9 *  Constructor Function:
10 c     astSpecFluxFrame
11 f     AST_SPECFLUXFRAME
12 
13 *  Description:
14 *     A SpecFluxFrame combines a SpecFrame and a FluxFrame into a single
15 *     2-dimensional compound Frame. Such a Frame can for instance be used
16 *     to describe a Plot of a spectrum in which the first axis represents
17 *     spectral position and the second axis represents flux.
18 
19 *  Inheritance:
20 *     The SpecFluxFrame class inherits from the CmpFrame class.
21 
22 *  Attributes:
23 *     The SpecFluxFrame class does not define any new attributes beyond
24 *     those which are applicable to all CmpFrames. However, the attributes
25 *     of the component Frames can be accessed as if they were attributes
26 *     of the SpecFluxFrame. For instance, the SpecFluxFrame will recognise
27 *     the "StdOfRest" attribute and forward access requests to the component
28 *     SpecFrame. An axis index can optionally be appended to the end of any
29 *     attribute name, in which case the request to access the attribute will
30 *     be forwarded to the primary Frame defining the specified axis.
31 
32 *  Functions:
33 c     The SpecFluxFrame class does not define any new functions beyond those
34 f     The SpecFluxFrame class does not define any new routines beyond those
35 *     which are applicable to all CmpFrames.
36 
37 *  Copyright:
38 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
39 *     Research Councils
40 
41 *  Licence:
42 *     This program is free software: you can redistribute it and/or
43 *     modify it under the terms of the GNU Lesser General Public
44 *     License as published by the Free Software Foundation, either
45 *     version 3 of the License, or (at your option) any later
46 *     version.
47 *
48 *     This program is distributed in the hope that it will be useful,
49 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
50 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
51 *     GNU Lesser General Public License for more details.
52 *
53 *     You should have received a copy of the GNU Lesser General
54 *     License along with this program.  If not, see
55 *     <http://www.gnu.org/licenses/>.
56 
57 *  Authors:
58 *     DSB: David S. Berry (Starlink)
59 
60 *  History:
61 *     8-DEC-2004 (DSB):
62 *        Original version.
63 *     29-APR-2011 (DSB):
64 *        Prevent astFindFrame from matching a subclass template against a
65 *        superclass target.
66 *class--
67 */
68 
69 /* Module Macros. */
70 /* ============== */
71 /* Set the name of the class we are implementing. This indicates to
72    the header files that define class interfaces that they should make
73    "protected" symbols available. */
74 #define astCLASS SpecFluxFrame
75 
76 /* Define the first and last acceptable System values. */
77 #define FIRST_SYSTEM AST__COMP
78 #define LAST_SYSTEM AST__COMP
79 
80 /* Include files. */
81 /* ============== */
82 /* Interface definitions. */
83 /* ---------------------- */
84 
85 #include "globals.h"             /* Thread-safe global data access */
86 #include "error.h"               /* Error reporting facilities */
87 #include "memory.h"              /* Memory allocation facilities */
88 #include "globals.h"             /* Thread-safe global data access */
89 #include "object.h"              /* Base Object class */
90 #include "mapping.h"             /* Coordinate Mappings */
91 #include "unitmap.h"             /* Unit Mappings */
92 #include "permmap.h"             /* Coordinate permutation Mappings */
93 #include "cmpmap.h"              /* Compound Mappings */
94 #include "axis.h"                /* Coordinate axes */
95 #include "cmpframe.h"            /* Parent CmpFrame class */
96 #include "tranmap.h"             /* Separated transformation Mappings */
97 #include "mathmap.h"             /* Algebraic Mappings */
98 #include "ratemap.h"             /* Differential Mappings */
99 #include "specframe.h"           /* SpecFrame class */
100 #include "fluxframe.h"           /* FluxFrame class */
101 #include "specfluxframe.h"       /* Interface definition for this class */
102 
103 /* Error code definitions. */
104 /* ----------------------- */
105 #include "ast_err.h"             /* AST error codes */
106 
107 /* C header files. */
108 /* --------------- */
109 #include <float.h>
110 #include <math.h>
111 #include <ctype.h>
112 #include <stdarg.h>
113 #include <stddef.h>
114 #include <stdio.h>
115 #include <stdlib.h>
116 #include <string.h>
117 
118 /* Module Variables. */
119 /* ================= */
120 
121 /* Address of this static variable is used as a unique identifier for
122    member of this class. */
123 static int class_check;
124 
125 /* Pointers to parent class methods which are extended by this class. */
126 static int (* parent_match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
127 static int (* parent_subframe)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
128 static const char *(* parent_gettitle)( AstFrame *, int * );
129 
130 /* Define macros for accessing each item of thread specific global data. */
131 #ifdef THREAD_SAFE
132 
133 /* Define how to initialise thread-specific globals. */
134 #define GLOBAL_inits \
135    globals->Class_Init = 0; \
136    globals->GetTitle_Buff[ 0 ] = 0;
137 
138 /* Create the function that initialises global data for this module. */
139 astMAKE_INITGLOBALS(SpecFluxFrame)
140 
141 /* Define macros for accessing each item of thread specific global data. */
142 #define class_init astGLOBAL(SpecFluxFrame,Class_Init)
143 #define class_vtab astGLOBAL(SpecFluxFrame,Class_Vtab)
144 #define gettitle_buff astGLOBAL(SpecFluxFrame,GetTitle_Buff)
145 
146 
147 
148 /* If thread safety is not needed, declare and initialise globals at static
149    variables. */
150 #else
151 
152 static char gettitle_buff[ 101 ];
153 
154 
155 /* Define the class virtual function table and its initialisation flag
156    as static variables. */
157 static AstSpecFluxFrameVtab class_vtab;   /* Virtual function table */
158 static int class_init = 0;       /* Virtual function table initialised? */
159 
160 #endif
161 
162 /* External Interface Function Prototypes. */
163 /* ======================================= */
164 /* The following functions have public prototypes only (i.e. no
165    protected prototypes), so we must provide local prototypes for use
166    within this module. */
167 AstSpecFluxFrame *astSpecFluxFrameId_( void *, void *, const char *, ... );
168 
169 /* Prototypes for Private Member Functions. */
170 /* ======================================== */
171 static AstFluxFrame *GetFluxFrame( AstSpecFluxFrame *, int, int * );
172 static AstMapping *MakeMap2( AstSpecFluxFrame *, int * );
173 static AstMapping *MakeMap3( AstSpecFluxFrame *, AstSpecFluxFrame *, int * );
174 static AstMapping *MakeMapF( AstFluxFrame *, AstSpecFrame *, AstFluxFrame *, AstSpecFrame *, int * );
175 static AstMapping *MakeMapI( AstFluxFrame *, AstSpecFrame *, AstFluxFrame *, AstSpecFrame *, int * );
176 static AstSpecFrame *GetSpecFrame( AstSpecFluxFrame *, int, int * );
177 static const char *GetTitle( AstFrame *, int * );
178 static int MakeSFMapping( AstSpecFluxFrame *, AstSpecFluxFrame *, AstMapping **, int * );
179 static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
180 static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
181 static void Dump( AstObject *, AstChannel *, int * );
182 
183 /* Member functions. */
184 /* ================= */
185 
GetFluxFrame(AstSpecFluxFrame * this,int std,int * status)186 static AstFluxFrame *GetFluxFrame( AstSpecFluxFrame *this, int std, int *status ){
187 /*
188 *  Name:
189 *     GetFluxFrame
190 
191 *  Purpose:
192 *     Return a pointer to the FluxFrame in a FluxSpecFrame.
193 
194 *  Type:
195 *     Private function.
196 
197 *  Synopsis:
198 *     #include "specfluxframe.h"
199 *     AstFluxFrame *GetFluxFrame( AstSpecFluxFrame *this, int std, int *status )
200 
201 *  Class Membership:
202 *     SpecFluxFrame member function.
203 
204 *  Description:
205 *     Returns a pointer to the FluxFrame in a SpecFluxFrame.
206 
207 *  Parameters:
208 *     this
209 *        Pointer to the SpecFluxFrame.
210 *     std
211 *        If non zero, then the returned FluxFrame is a standardised copy of
212 *        the FluxFrame in the supplied SpecFluxFrame, in which the System has
213 *        been set explicitly (rather than potentially being defaulted), and
214 *        the Units have been cleared to use default units appropriate to
215 *        the flux System.
216 *     status
217 *        Pointer to the inherited status variable.
218 
219 *  Returned Value:
220 *     A pointer to the FluxFrame. Should be freed using astAnnul when no
221 *     longer needed.
222 
223 *  Notes:
224 *     NULL is returned if this function is invoked with the global error
225 *     status set or if it should fail for any reason.
226 */
227 
228 /* Local Variables; */
229    AstFluxFrame *ff;
230    AstFluxFrame *ret;
231 
232 /* Check the global error status. */
233    if ( !astOK ) return NULL;
234 
235 /* The FluxFrame is always the second Frame in the parent CmpFrame. */
236    ff = (AstFluxFrame *) ((AstCmpFrame *)this)->frame2;
237 
238 /* Produce a standardised copy of the FluxFrame if required, or clone the
239    above pointer otherwise. */
240    if( std ) {
241       ret = astCopy( ff );
242       astSetSystem( ret, astGetSystem( ff ) );
243       astClearUnit( ret, 0 );
244    } else {
245       ret = astClone( ff );
246    }
247 
248 /* Annul the returned pointer if anything went wrong. */
249    if( !astOK ) ret = astAnnul( ret );
250 
251 /* Return the result. */
252    return ret;
253 }
254 
GetSpecFrame(AstSpecFluxFrame * this,int std,int * status)255 static AstSpecFrame *GetSpecFrame( AstSpecFluxFrame *this, int std, int *status ){
256 /*
257 *  Name:
258 *     GetSpecFrame
259 
260 *  Purpose:
261 *     Return a pointer to the SpecFrame in a FluxSpecFrame.
262 
263 *  Type:
264 *     Private function.
265 
266 *  Synopsis:
267 *     #include "specfluxframe.h"
268 *     AstSpecFrame *GetSpecFrame( AstSpecFluxFrame *this, int std, int *status )
269 
270 *  Class Membership:
271 *     SpecFluxFrame member function.
272 
273 *  Description:
274 *     Returns a pointer to the SpecFrame in a SpecFluxFrame.
275 
276 *  Parameters:
277 *     this
278 *        Pointer to the SpecFluxFrame.
279 *     std
280 *        If non zero, then the returned SpecFrame is a standardised copy of
281 *        the SpecFrame in the supplied SpecFluxFrame, in which the System
282 *        and Units have been set explicitly to the values appropriate to the
283 *        flux system in use in the FluxFrame in the supplied SpecFluxFrame.
284 *     status
285 *        Pointer to the inherited status variable.
286 
287 *  Returned Value:
288 *     A pointer to the FluxFrame. Should be freed using astAnnul when no
289 *     longer needed.
290 
291 *  Notes:
292 *     NULL is returned if this function is invoked with the global error
293 *     status set or if it should fail for any reason.
294 */
295 
296 /* Local Variables; */
297    AstFluxFrame *ff;
298    AstSpecFrame *ret;
299    AstSpecFrame *sf;
300 
301 /* Check the global error status. */
302    if ( !astOK ) return NULL;
303 
304 /* Get a pointer to the SpecFrame (the first Frame in the parent CmpFrame). */
305    sf = (AstSpecFrame *) ((AstCmpFrame *)this)->frame1;
306 
307 /* If we want a standardised version of the SpecFrame... */
308    if( std ) {
309 
310 /* The FluxFrame is always the second Frame in the parent CmpFrame. */
311       ff = (AstFluxFrame *) ((AstCmpFrame *)this)->frame2;
312 
313 /* Produce a copy of the SpecFrame and set its System and Units
314    appropriate to the flux system (expressed in default units). */
315       ret = astCopy( sf );
316       astSetSystem( ret, astGetDensitySystem( ff ) );
317       astSetUnit( ret, 0, astGetDensityUnit( ff ) );
318 
319 /* If we are not standardising the SpecFrame, just return a clone of the
320    pointer in the parent CmpFrame. */
321    } else {
322       ret = astClone( sf );
323    }
324 
325 /* Annul the returned pointer if anything went wrong. */
326    if( !astOK ) ret = astAnnul( ret );
327 
328 /* Return the result. */
329    return ret;
330 }
331 
GetTitle(AstFrame * this_frame,int * status)332 static const char *GetTitle( AstFrame *this_frame, int *status ) {
333 /*
334 *  Name:
335 *     GetTitle
336 
337 *  Purpose:
338 *     Obtain a pointer to the Title string for a SpecFluxFrame.
339 
340 *  Type:
341 *     Private function.
342 
343 *  Synopsis:
344 *     #include "specfluxframe.h"
345 *     const char *GetTitle( AstFrame *this_frame, int *status )
346 
347 *  Class Membership:
348 *     SpecFluxFrame member function (over-rides the astGetTitle method
349 *     inherited from the CmpFrame class).
350 
351 *  Description:
352 *     This function returns a pointer to the Title string for a SpecFluxFrame.
353 *     A pointer to a suitable default string is returned if no Title value has
354 *     previously been set.
355 
356 *  Parameters:
357 *     this
358 *        Pointer to the SpecFluxFrame.
359 *     status
360 *        Pointer to the inherited status variable.
361 
362 *  Returned Value:
363 *     Pointer to a null-terminated character string containing the requested
364 *     information.
365 
366 *  Notes:
367 *     -  A NULL pointer will be returned if this function is invoked with the
368 *     global error status set, or if it should fail for any reason.
369 */
370 
371 /* Local Variables: */
372    astDECLARE_GLOBALS
373    AstSpecFluxFrame *this;
374    AstSpecFrame *sf;
375    AstFluxFrame *ff;
376    const char *result;
377 
378 /* Check the global error status. */
379    if ( !astOK ) return NULL;
380 
381 /* Get a pointer to the thread specific global data structure. */
382    astGET_GLOBALS(this_frame);
383 
384 /* Initialise. */
385    result = NULL;
386 
387 /* Obtain a pointer to the SpecFluxFrame structure. */
388    this = (AstSpecFluxFrame *) this_frame;
389 
390 /* See if a Title string has been set. If so, use the parent astGetTitle
391    method to obtain a pointer to it. */
392    if ( astTestTitle( this ) ) {
393       result = (*parent_gettitle)( this_frame, status );
394 
395 /* Otherwise, we will generate a default Title string. Obtain the values of the
396    SpecFrame's attributes that determine what this string will be. */
397    } else {
398       ff = GetFluxFrame( this, 0, status );
399       sf = GetSpecFrame( this, 0, status );
400 
401       if( astOK ) {
402          sprintf( gettitle_buff, "%s versus %s", astGetLabel( ff, 0 ),
403                   astGetLabel( sf, 0 ) );
404          gettitle_buff[ 0 ] = toupper( gettitle_buff[ 0 ] );
405          result = gettitle_buff;
406       }
407 
408       ff = astAnnul( ff );
409       sf = astAnnul( sf );
410 
411    }
412 
413 /* If an error occurred, clear the returned pointer value. */
414    if ( !astOK ) result = NULL;
415 
416 /* Return the result. */
417    return result;
418 }
419 
astInitSpecFluxFrameVtab_(AstSpecFluxFrameVtab * vtab,const char * name,int * status)420 void astInitSpecFluxFrameVtab_(  AstSpecFluxFrameVtab *vtab, const char *name, int *status ) {
421 /*
422 *+
423 *  Name:
424 *     astInitSpecFluxFrameVtab
425 
426 *  Purpose:
427 *     Initialise a virtual function table for a SpecFluxFrame.
428 
429 *  Type:
430 *     Protected function.
431 
432 *  Synopsis:
433 *     #include "specfluxframe.h"
434 *     void astInitSpecFluxFrameVtab( AstSpecFluxFrameVtab *vtab, const char *name )
435 
436 *  Class Membership:
437 *     SpecFluxFrame vtab initialiser.
438 
439 *  Description:
440 *     This function initialises the component of a virtual function
441 *     table which is used by the SpecFluxFrame class.
442 
443 *  Parameters:
444 *     vtab
445 *        Pointer to the virtual function table. The components used by
446 *        all ancestral classes will be initialised if they have not already
447 *        been initialised.
448 *     name
449 *        Pointer to a constant null-terminated character string which contains
450 *        the name of the class to which the virtual function table belongs (it
451 *        is this pointer value that will subsequently be returned by the Object
452 *        astClass function).
453 *-
454 */
455 
456 /* Local Variables: */
457    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
458    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
459    AstFrameVtab *frame;          /* Pointer to Frame component of Vtab */
460    AstMappingVtab *mapping;      /* Pointer to Mapping component of Vtab */
461 
462 /* Check the local error status. */
463    if ( !astOK ) return;
464 
465 /* Get a pointer to the thread specific global data structure. */
466    astGET_GLOBALS(NULL);
467 
468 /* Initialize the component of the virtual function table used by the
469    parent class. */
470    astInitCmpFrameVtab( (AstCmpFrameVtab *) vtab, name );
471 
472 /* Store a unique "magic" value in the virtual function table. This
473    will be used (by astIsASpecFluxFrame) to determine if an object belongs
474    to this class.  We can conveniently use the address of the (static)
475    class_check variable to generate this unique value. */
476    vtab->id.check = &class_check;
477    vtab->id.parent = &(((AstCmpFrameVtab *) vtab)->id);
478 
479 /* Initialise member function pointers. */
480 /* ------------------------------------ */
481 /* Store pointers to the member functions (implemented here) that
482    provide virtual methods for this class. */
483 
484 /* Save the inherited pointers to methods that will be extended, and
485    replace them with pointers to the new member functions. */
486    object = (AstObjectVtab *) vtab;
487    frame = (AstFrameVtab *) vtab;
488    mapping = (AstMappingVtab *) vtab;
489 
490 /* Store replacement pointers for methods which will be over-ridden by
491    new member functions implemented here. */
492 
493    parent_match = frame->Match;
494    frame->Match = Match;
495 
496    parent_subframe = frame->SubFrame;
497    frame->SubFrame = SubFrame;
498 
499    parent_gettitle = frame->GetTitle;
500    frame->GetTitle = GetTitle;
501 
502 /* Declare the copy constructor, destructor and class dump
503    function. */
504    astSetDump( vtab, Dump, "SpecFluxFrame",
505                "Compound spectral/flux coordinate system description" );
506 
507 /* If we have just initialised the vtab for the current class, indicate
508    that the vtab is now initialised, and store a pointer to the class
509    identifier in the base "object" level of the vtab. */
510    if( vtab == &class_vtab ) {
511       class_init = 1;
512       astSetVtabClassIdentifier( vtab, &(vtab->id) );
513    }
514 }
515 
MakeMap2(AstSpecFluxFrame * this,int * status)516 static AstMapping *MakeMap2( AstSpecFluxFrame *this, int *status ){
517 /*
518 *  Name:
519 *     MakeMap2
520 
521 *  Purpose:
522 *     Generate the second Mapping required by MakeSFMapping
523 
524 *  Type:
525 *     Private function.
526 
527 *  Synopsis:
528 *     #include "specfluxframe.h"
529 *     AstMapping *MakeMap2( AstSpecFluxFrame *this, int *status )
530 
531 *  Class Membership:
532 *     SpecFluxFrame member function.
533 
534 *  Description:
535 *     The second Mapping used by MakeSFMapping contains three Mappings in
536 *     parallel which converts v1 (flux value) and x1 (spectral position) into
537 *     default units, and passes the third axis (a copy of flux value)
538 *     unchanged.
539 
540 *  Parameters:
541 *     this
542 *        Pointer to the SpecFluxFrame to use.
543 *     status
544 *        Pointer to the inherited status variable.
545 
546 *  Returned Value:
547 *     A pointer to the required Mapping, or NULL if the Mapping cannot be
548 *     created. The Mapping will have 3 inputs and 3 outputs.
549 
550 *  Notes:
551 *     NULL is returned if this function is invoked with the global error
552 *     status set or if it should fail for any reason.
553 */
554 
555 /* Local Variables: */
556    AstFrame *f1;
557    AstFrame *f2;
558    AstFrameSet *fs;
559    AstMapping *ax1_map;
560    AstMapping *ax2_map;
561    AstMapping *ax3_map;
562    AstMapping *ret;
563    AstMapping *tmap;
564 
565 /* Initialise. */
566    ret = NULL;
567 
568 /* Check the global error status. */
569    if ( !astOK ) return ret;
570 
571 /* Input 0 is the supplied FluxFrame value and output 0 is the corresponding
572    value in the default units for the FluxFrame system. Take a copy of the
573    supplied FluxFrame, and fix its System value (which may be a default value
574    based on the Units string), and then clear the Units so that it represents
575    default units for the System. */
576    f1 = (AstFrame *) GetFluxFrame( this, 0, status );
577    f2 = (AstFrame *) GetFluxFrame( this, 1, status );
578 
579 /* Now, if conversion was possible, get the Mapping from the supplied
580    FluxFrame to the default units FluxFrame. */
581    fs = astConvert( f1, f2, "" );
582    f1 = astAnnul( f1 );
583    f2 = astAnnul( f2 );
584 
585    if( fs ) {
586       ax1_map = astGetMapping( fs, AST__BASE, AST__CURRENT );
587       fs = astAnnul( fs );
588 
589 /* Input 1 is the supplied SpecFrame value and output 1 is the corresponding
590    value in the spectral system used by the flux system (wavelength or
591    frequency). Take a copy of the supplied SpecFrame, and fix its System
592    value to wavelength or frequency (depending on the System value of the
593    FluxFrame), and set up units of Hz or Angstrom (these are the spectral
594    position units used within the default flux units for a FluxFrame). */
595       f1 = (AstFrame *) GetSpecFrame( this, 0, status );
596       f2 = (AstFrame *) GetSpecFrame( this, 1, status );
597 
598 /* Now, if conversion was possible, get the Mapping from the supplied
599    SpecFrame to the required SpecFrame. */
600       fs = astConvert( f1, f2, "" );
601       f1 = astAnnul( f1 );
602       f2 = astAnnul( f2 );
603 
604       if( fs ) {
605          ax2_map = astGetMapping( fs, AST__BASE, AST__CURRENT );
606          fs = astAnnul( fs );
607 
608 /* Create a UnitMap for the 3rd axis. */
609          ax3_map = (AstMapping *) astUnitMap( 1, "", status );
610 
611 /* Create a parallel CmpMap containing the three Mappings. */
612          tmap = (AstMapping *) astCmpMap( ax1_map, ax2_map, 0, "", status );
613          ret = (AstMapping *) astCmpMap( tmap, ax3_map, 0, "", status );
614 
615 /* Free remaining resources. */
616          tmap = astAnnul( tmap );
617          ax2_map = astAnnul( ax2_map );
618          ax3_map = astAnnul( ax3_map );
619 
620       }
621       ax1_map = astAnnul( ax1_map );
622    }
623 
624 /* If an error has occurred, return NULL. */
625    if( !astOK ) ret = astAnnul( ret );
626 
627 /* Return the result */
628    return ret;
629 }
630 
MakeMap3(AstSpecFluxFrame * target,AstSpecFluxFrame * result,int * status)631 static AstMapping *MakeMap3( AstSpecFluxFrame *target, AstSpecFluxFrame *result, int *status ){
632 /*
633 *  Name:
634 *     MakeMap3
635 
636 *  Purpose:
637 *     Generate the third Mapping required by MakeSFMapping
638 
639 *  Type:
640 *     Private function.
641 
642 *  Synopsis:
643 *     #include "specfluxframe.h"
644 *     AstMapping *MakeMap3( AstSpecFluxFrame *target, AstSpecFluxFrame *result, int *status )
645 
646 *  Class Membership:
647 *     SpecFluxFrame member function.
648 
649 *  Description:
650 *     The third Mapping used by MakeSFMapping converts input (v1,x1) in
651 *     default units to output (v2,x2) in default units. The third axis (x1)
652 *     in original units is converted to x2 in original units.
653 
654 *  Parameters:
655 *     target
656 *        Pointer to the first SpecFluxFrame.
657 *     result
658 *        Pointer to the second SpecFluxFrame.
659 *     status
660 *        Pointer to the inherited status variable.
661 
662 *  Returned Value:
663 *     A pointer to the required Mapping, or NULL if the Mapping cannot be
664 *     created. The Mapping will have 3 inputs and 3 outputs.
665 
666 *  Notes:
667 *     NULL is returned if this function is invoked with the global error
668 *     status set or if it should fail for any reason.
669 */
670 
671 /* Local Variables: */
672    AstFluxFrame *ff2;
673    AstFluxFrame *ff1;
674    AstFrameSet *fs;
675    AstMapping *fmap;
676    AstMapping *imap;
677    AstMapping *mapa;
678    AstMapping *mapb;
679    AstMapping *ret;
680    AstSpecFrame *sf2;
681    AstSpecFrame *sf1;
682 
683 /* Initialise */
684    ret = NULL;
685 
686 /* Check the global error status. */
687    if ( !astOK ) return ret;
688 
689 /* The first two inputs and outputs are related by a TranMap which
690    converts between standardised (v1,x1) and standardised (v2,x2). Get
691    pointers to the standardised SpecFrames and FluxFrames in the two
692    supplied SpecFluxFrames. */
693    ff1 = GetFluxFrame( target, 1, status );
694    sf1 = GetSpecFrame( target, 1, status );
695    ff2 = GetFluxFrame( result, 1, status );
696    sf2 = GetSpecFrame( result, 1, status );
697 
698 /* Create the Mapping which defines the forward transformation of the
699    required TranMap. The forward transformation of this Mapping goes from
700    (v1,x1) to (v2,x2). */
701    fmap = MakeMapF( ff1, sf1, ff2, sf2, status );
702 
703 /* Create the Mapping which defines the inverse transformation of the
704    required TranMap. The inverse transformation of this Mapping goes from
705    (v2,x2) to (v1,x1). */
706    imap = MakeMapI( ff1, sf1, ff2, sf2, status );
707 
708 /* Combine these into a TranMap */
709    if( fmap && imap ) {
710       mapa = (AstMapping *) astTranMap( fmap, imap, "", status );
711    } else {
712       mapa = NULL;
713    }
714 
715 /* Free resources. */
716    ff1 = astAnnul( ff1 );
717    sf1 = astAnnul( sf1 );
718    ff2 = astAnnul( ff2 );
719    sf2 = astAnnul( sf2 );
720    if( fmap ) fmap = astAnnul( fmap );
721    if( imap ) imap = astAnnul( imap );
722 
723 /* The third input and output are related by a Mapping which converts
724    between supplied (x1) and supplied (x2). Get pointers to the original
725    unmodified SpecFrames in the two supplied SpecFluxFrames. */
726    sf1 = GetSpecFrame( target, 0, status );
727    sf2 = GetSpecFrame( result, 0, status );
728 
729 /* Find the Mapping from the first to the second. */
730    fs = astConvert( sf1, sf2, "" );
731    if( fs ) {
732       mapb = astGetMapping( fs, AST__BASE, AST__CURRENT );
733       fs = astAnnul( fs );
734    } else {
735       mapb = NULL;
736    }
737 
738 /* Free resources. */
739    sf1 = astAnnul( sf1 );
740    sf2 = astAnnul( sf2 );
741 
742 /* Combine the two Mappings in parallel. */
743    if( mapa && mapb ) ret = (AstMapping *) astCmpMap( mapa, mapb, 0, "", status );
744    if( mapa ) mapa = astAnnul( mapa );
745    if( mapb ) mapb = astAnnul( mapb );
746 
747 /* If an error has occurred, return NULL. */
748    if( !astOK ) ret = astAnnul( ret );
749 
750 /* Return the result */
751    return ret;
752 }
753 
MakeMapF(AstFluxFrame * v1,AstSpecFrame * x1,AstFluxFrame * v2,AstSpecFrame * x2,int * status)754 static AstMapping *MakeMapF( AstFluxFrame *v1, AstSpecFrame *x1,
755                              AstFluxFrame *v2, AstSpecFrame *x2, int *status ){
756 /*
757 *  Name:
758 *     MakeMapF
759 
760 *  Purpose:
761 *     Generate the forward part of the third Mapping required by MakeSFMapping
762 
763 *  Type:
764 *     Private function.
765 
766 *  Synopsis:
767 *     #include "specfluxframe.h"
768 *     AstMapping *MakeMapF( AstFluxFrame *v1, AstSpecFrame *x1,
769 *                           AstFluxFrame *v2, AstSpecFrame *x2, int *status )
770 
771 *  Class Membership:
772 *     SpecFluxFrame member function.
773 
774 *  Description:
775 *     Theis creates a 2-input 2-output Mapping which transforms
776 *     input (v1,x1) in default units to output (v2,x2) in default units.
777 
778 *  Parameters:
779 *     v1
780 *        Pointer to the standardised input FluxFrame.
781 *     x1
782 *        Pointer to the standardised input SpecFrame.
783 *     v2
784 *        Pointer to the standardised output FluxFrame.
785 *     x2
786 *        Pointer to the standardised output SpecFrame.
787 *     status
788 *        Pointer to the inherited status variable.
789 
790 *  Returned Value:
791 *     A pointer to the required Mapping, or NULL if the Mapping cannot be
792 *     created.
793 
794 *  Notes:
795 *     NULL is returned if this function is invoked with the global error
796 *     status set or if it should fail for any reason.
797 */
798 
799 /* Local Variables: */
800    AstCmpMap *cmap1;
801    AstCmpMap *cmap2;
802    AstCmpMap *cmap3;
803    AstFrameSet *fs;
804    AstMapping *m;
805    AstMapping *ret;
806    AstMathMap *div;
807    AstPermMap *perm;
808    AstRateMap *rate;
809    AstUnitMap *unit;
810    const char *fwd[1];
811    const char *inv[2];
812    int inperm[ 2 ];
813    int outperm[ 3 ];
814 
815 /* Initialise */
816    ret = NULL;
817 
818 /* Check the global error status. */
819    if ( !astOK ) return ret;
820 
821 /* First create the required component Mappings.
822    --------------------------------------------- */
823 
824 /* A Mapping which maps input spectral position (x1) into output spectral
825    position (x2). */
826    fs = astConvert( x1, x2, "" );
827    if( fs ) {
828       m = astGetMapping( fs, AST__BASE, AST__CURRENT );
829 
830 /* A 1-input 1-output Mapping in which the input is spectral position (x1)
831    and the output is the rate of change of output spectral position (x2)
832    with respect to input spectral position (x1). */
833       rate = astRateMap( m, 0, 0, "", status );
834 
835 /* A MathMap which is used to divide the flux value (v1) by the absolute rate
836    of change of x2 wrt x1 */
837       fwd[ 0 ] = "out=in0/abs(in1)";
838       inv[ 0 ] = "in0";
839       inv[ 1 ] = "in1";
840       div = astMathMap( 2, 1, 1, fwd, 2, inv, "", status );
841 
842 /* A 1D UnitMap used to copy v1. */
843       unit = astUnitMap( 1, "", status );
844 
845 /* A PermMap which is used to produce an extra output copy of x1. */
846       inperm[ 0 ] = 0;
847       inperm[ 1 ] = 2;
848       outperm[ 0 ] = 0;
849       outperm[ 1 ] = 1;
850       outperm[ 2 ] = 1;
851       perm = astPermMap( 2, inperm, 3, outperm, NULL, "", status );
852 
853 /* Now combine these component Mappings together.
854    --------------------------------------------- */
855 
856 /* First put the UnitMap and the RateMap in parallel. This produces a 2-in
857    2-out Mapping in which the inputs are (v1,x1) and the outputs are
858    (v1,dx2/dx1). */
859       cmap1 = astCmpMap( unit, rate, 0, "", status );
860 
861 /* Now put this in series with the dividing MathMap. This results in a
862    2-in, 1-out Mapping in which the inputs are v1 and x1 and the single
863    output is v2. */
864       cmap2 = astCmpMap( cmap1, div, 1, "", status );
865 
866 /* Now put this in parallel with the x1->x2 Mapping. This results in a
867    3-in, 2-out Mapping in which the inputs are (v1,x1,x1) and the outputs
868    are (v2,x2). */
869       cmap3 = astCmpMap( cmap2, m, 0, "", status );
870 
871 /* Finally put this in series with the PermMap. This results in a 2-in,
872    2-out Mapping in which the inputs are (v1,x1) and the outputs are
873    (v2,x2). */
874       ret = (AstMapping *) astCmpMap( perm, cmap3, 1, "", status );
875 
876 /* Free resources. */
877       fs = astAnnul( fs );
878       m = astAnnul( m );
879       rate = astAnnul( rate );
880       div= astAnnul( div );
881       unit = astAnnul( unit );
882       perm = astAnnul( perm );
883       cmap1 = astAnnul( cmap1 );
884       cmap2 = astAnnul( cmap2 );
885       cmap3 = astAnnul( cmap3 );
886    }
887 
888 /* If an error has occurred, return NULL. */
889    if( !astOK ) ret = astAnnul( ret );
890 
891 /* Return the result */
892    return ret;
893 }
894 
MakeMapI(AstFluxFrame * v1,AstSpecFrame * x1,AstFluxFrame * v2,AstSpecFrame * x2,int * status)895 static AstMapping *MakeMapI( AstFluxFrame *v1, AstSpecFrame *x1,
896                              AstFluxFrame *v2, AstSpecFrame *x2, int *status ){
897 /*
898 *  Name:
899 *     MakeMapI
900 
901 *  Purpose:
902 *     Generate the inverse part of the third Mapping required by MakeSFMapping
903 
904 *  Type:
905 *     Private function.
906 
907 *  Synopsis:
908 *     #include "specfluxframe.h"
909 *     AstMapping *MakeMapI( AstFluxFrame *v1, AstSpecFrame *x1,
910 *                           AstFluxFrame *v2, AstSpecFrame *x2 )
911 
912 *  Class Membership:
913 *     SpecFluxFrame member function.
914 
915 *  Description:
916 *     This creates a 2-input 2-output Mapping in which the inverse
917 *     transformation transforms "outputs" representing (v2,x2) into
918 *     "inputs" representing (v1,x1).
919 
920 *  Parameters:
921 *     v1
922 *        Pointer to the standardised input FluxFrame.
923 *     x1
924 *        Pointer to the standardised input SpecFrame.
925 *     v2
926 *        Pointer to the standardised output FluxFrame.
927 *     x2
928 *        Pointer to the standardised output SpecFrame.
929 
930 *  Returned Value:
931 *     A pointer to the required Mapping, or NULL if the Mapping cannot be
932 *     created.
933 
934 *  Notes:
935 *     NULL is returned if this function is invoked with the global error
936 *     status set or if it should fail for any reason.
937 */
938 
939 /* Local Variables: */
940    AstCmpMap *cmap1;
941    AstCmpMap *cmap2;
942    AstCmpMap *cmap3;
943    AstCmpMap *cmap4;
944    AstCmpMap *cmap5;
945    AstFrameSet *fs;
946    AstMapping *m;
947    AstMapping *ret;
948    AstMathMap *mult;
949    AstPermMap *perm;
950    AstRateMap *rate;
951    AstUnitMap *unit;
952    const char *fwd[1];
953    const char *inv[2];
954    int inperm[ 2 ];
955    int outperm[ 3 ];
956 
957 /* Initialise */
958    ret = NULL;
959 
960 /* Check the global error status. */
961    if ( !astOK ) return ret;
962 
963 /* We create a CmpMap in which the forward transformation foes from
964    (v2,x2) to (v1,x1) and we finally invert this Mapping to get the
965    required Mapping in which the *inverse* transformation goes from
966    (v2,x2) to (v1,x1).
967 
968    First create the required component Mappings.
969    --------------------------------------------- */
970 
971 /* A Mapping which maps spectral position x1 into spectral position x2. */
972    fs = astConvert( x1, x2, "" );
973    if( fs ) {
974       m = astGetMapping( fs, AST__BASE, AST__CURRENT );
975 
976 /* A 1-input 1-output Mapping in which the input is spectral position x1
977    and the output is the rate of change of spectral position x2 with
978    respect to spectral position x1. */
979       rate = astRateMap( m, 0, 0, "", status );
980 
981 /* Now invert "m" so that its forward transformation goes from x2 to x1.
982    The RateMap created above retains a copy of the original Invert flag
983    for "m" and uses it in preference to the current value when transforming
984    points. */
985       astInvert( m );
986 
987 /* A MathMap which is used to multiple the flux value v2 by the
988    absolute rate of change of x2 wrt x1 */
989       fwd[ 0 ] = "out=in0*abs(in1)";
990       inv[ 0 ] = "in0";
991       inv[ 1 ] = "in1";
992       mult = astMathMap( 2, 1, 1, fwd, 2, inv, "", status );
993 
994 /* A 1D UnitMap used to copy various values. */
995       unit = astUnitMap( 1, "", status );
996 
997 /* A PermMap which is used to produce an extra copy of x1. */
998       inperm[ 0 ] = 0;
999       inperm[ 1 ] = 2;
1000       outperm[ 0 ] = 0;
1001       outperm[ 1 ] = 1;
1002       outperm[ 2 ] = 1;
1003       perm = astPermMap( 2, inperm, 3, outperm, NULL, "", status );
1004 
1005 /* Now combine these component Mappings together.
1006    --------------------------------------------- */
1007 
1008 /* First put the UnitMap and the RateMap in parallel. This produces a 2-in
1009    2-out Mapping in which the inputs are (v2,x1) and the outputs are
1010    (v2,dx2/dx1). */
1011       cmap1 = astCmpMap( unit, rate, 0, "", status );
1012 
1013 /* Now put this in series with the multiplying MathMap. This results in a
1014    2-in, 1-out Mapping in which the inputs are (v2,x1) and the single
1015    output is v1. */
1016       cmap2 = astCmpMap( cmap1, mult, 1, "", status );
1017 
1018 /* Now put this in parallel with the UnitMap to get a 3-in, 2-out Mapping
1019    in which the inputs are (v2,x1,x1) and the outputs are (v1,x1). */
1020       cmap3 = astCmpMap( cmap2, unit, 0, "", status );
1021 
1022 /* Now put this in series with the PermMap to get a 2-in, 2-out Mapping
1023    in which the inputs are (v2,x1) and the outputs are (v1,x1). */
1024       cmap4 = astCmpMap( perm, cmap3, 1, "", status );
1025 
1026 /* Now put the UnitMap in parallel with the (x2->x1 Mapping to get a
1027    2-in, 2-out Mapping in which the inputs are (v2,x2) and the outputs are
1028    (v2,x1). */
1029       cmap5 = astCmpMap( unit, m, 0, "", status );
1030 
1031 /* Finally put this in series with "cmap4" to get a 2-in 2-out Mapping
1032    from (v2,x2) to (v1,x1). */
1033       ret = (AstMapping *) astCmpMap( cmap5, cmap4, 1, "", status );
1034 
1035 /* Invert this so that the inverse transformation goes from (v2,x2) to
1036    (v1,x1). */
1037       astInvert( ret );
1038 
1039 /* Free resources. */
1040       fs = astAnnul( fs );
1041       m = astAnnul( m );
1042       rate = astAnnul( rate );
1043       mult = astAnnul( mult );
1044       unit = astAnnul( unit );
1045       perm = astAnnul( perm );
1046       cmap1 = astAnnul( cmap1 );
1047       cmap2 = astAnnul( cmap2 );
1048       cmap3 = astAnnul( cmap3 );
1049       cmap4 = astAnnul( cmap4 );
1050       cmap5 = astAnnul( cmap5 );
1051    }
1052 
1053 /* If an error has occurred, return NULL. */
1054    if( !astOK ) ret = astAnnul( ret );
1055 
1056 /* Return the result */
1057    return ret;
1058 }
1059 
MakeSFMapping(AstSpecFluxFrame * target,AstSpecFluxFrame * result,AstMapping ** map,int * status)1060 static int MakeSFMapping( AstSpecFluxFrame *target, AstSpecFluxFrame *result,
1061                           AstMapping **map, int *status ){
1062 /*
1063 *  Name:
1064 *     MakeSFMapping
1065 
1066 *  Purpose:
1067 *     Generate a Mapping between two SpecFluxFrames.
1068 
1069 *  Type:
1070 *     Private function.
1071 
1072 *  Synopsis:
1073 *     #include "specfluxframe.h"
1074 *     int MakeSFMapping( AstSpecFluxFrame *target, AstSpecFluxFrame *result,
1075 *                        AstMapping **map, int *status )
1076 
1077 *  Class Membership:
1078 *     SpecFluxFrame member function.
1079 
1080 *  Description:
1081 *     This function takes two SpecFluxFrames and generates a Mapping that
1082 *     converts between them, taking account of differences in their
1083 *     coordinate systems, systems, units, etc. (but not allowing for any
1084 *     axis permutations).
1085 
1086 *  Parameters:
1087 *     target
1088 *        Pointer to the first SpecFluxFrame.
1089 *     result
1090 *        Pointer to the second SpecFluxFrame.
1091 *     map
1092 *        Pointer to a location which is to receive a pointer to the
1093 *        returned Mapping. The forward transformation of this Mapping
1094 *        will convert from "target" coordinates to "result"
1095 *        coordinates, and the inverse transformation will convert in
1096 *        the opposite direction (all coordinate values in radians).
1097 *     status
1098 *        Pointer to the inherited status variable.
1099 
1100 *  Returned Value:
1101 *     Non-zero if the Mapping could be generated, or zero if the two
1102 *     SpecFluxFrames are sufficiently un-related that no meaningful Mapping
1103 *     can be produced.
1104 
1105 *  Notes:
1106 *     A value of zero is returned if this function is invoked with the
1107 *     global error status set or if it should fail for any reason.
1108 */
1109 
1110 /* Local Variables: */
1111    AstMapping *map1;
1112    AstMapping *map2;
1113    AstMapping *map3;
1114    AstMapping *map4;
1115    AstMapping *map5;
1116    AstMapping *tmap1;
1117    AstMapping *tmap2;
1118    AstMapping *tmap3;
1119    AstMapping *tmap4;
1120    int inperm[2];
1121    int match;
1122    int outperm[3];
1123 
1124 /* Check the global error status. */
1125    if ( !astOK ) return 0;
1126 
1127 /* Initialise the returned values. */
1128    match = 0;
1129    *map = NULL;
1130 
1131 /* Initialise other things. */
1132    map1 = NULL;
1133    map2 = NULL;
1134    map3 = NULL;
1135    map4 = NULL;
1136    map5 = NULL;
1137    tmap1 = NULL;
1138    tmap2 = NULL;
1139    tmap3 = NULL;
1140    tmap4 = NULL;
1141 
1142 /* At the top level, the required Mapping consists of five Mappings in
1143    series. Inputs 0 and 1 of the total Mapping correspond to the SpecFrame
1144    and FluxFrame in the target SpecFluxFrame. These are referred to as X1
1145    and V1. Outputs 0 and 1 of the total Mapping correspond to the SpecFrame
1146    and FluxFrame in the result SpecFluxFrame. These are referred to as X2
1147    and V2. */
1148 
1149 /* Map1 is a PermMap which copies v1 to its first output and x1 to its
1150    second and third outputs. The inverse transformation copies v1 from
1151    its first output and x1 from its third output. */
1152    inperm[ 0 ] = 2;
1153    inperm[ 1 ] = 0;
1154    outperm[ 0 ] = 1;
1155    outperm[ 1 ] = 0;
1156    outperm[ 2 ] = 0;
1157    map1 = (AstMapping *) astPermMap( 2, inperm, 3, outperm, NULL, "", status );
1158 
1159 /* Map2 contains three Mappings in parallel which converts v1 and x1 into
1160    default units, and passes the third axis unchanged. */
1161    map2 = MakeMap2( target, status );
1162 
1163 /* Map3 converts ( v1,x1) in default units to (v2,x2) in default units.
1164    The third axis (x1) in original units is convert to x2 in original
1165    units. */
1166    map3 = map2 ? MakeMap3( target, result, status ) : NULL;
1167 
1168 /* Map4 converts (v2,x2) in default units to (v2,x2) in original units
1169    and passes the third axis unchanged. This is similar to Map2 but based
1170    on the result ratherthan the target, and in the opposite direction. */
1171    if( map3 ) {
1172       map4 = MakeMap2( result, status );
1173       if( map4 ) astInvert( map4 );
1174    } else {
1175       map4 = NULL;
1176    }
1177 
1178 /* Map5 is a PermMap which is the inverse of Map1. */
1179    map5 = map4 ? astCopy( map1 ) : NULL;
1180    if( map5 ) astInvert( map5 );
1181 
1182 /* Combine all 6 Mappings in series. */
1183    if( map5 ) {
1184       tmap1 = (AstMapping *) astCmpMap( map1, map2, 1, "", status );
1185       tmap2 = (AstMapping *) astCmpMap( tmap1, map3, 1, "", status );
1186       tmap3 = (AstMapping *) astCmpMap( tmap2, map4, 1, "", status );
1187       tmap4 = (AstMapping *) astCmpMap( tmap3, map5, 1, "", status );
1188 
1189 /* Return the simplified total Mapping. */
1190       *map = astSimplify( tmap4 );
1191       match = 1;
1192    }
1193 
1194 /* Free resources. */
1195    if( map1 ) map1 = astAnnul( map1 );
1196    if( map2 ) map2 = astAnnul( map2 );
1197    if( map3 ) map3 = astAnnul( map3 );
1198    if( map4 ) map4 = astAnnul( map4 );
1199    if( map5 ) map5 = astAnnul( map5 );
1200    if( tmap1 ) tmap1 = astAnnul( tmap1 );
1201    if( tmap2 ) tmap2 = astAnnul( tmap2 );
1202    if( tmap3 ) tmap3 = astAnnul( tmap3 );
1203    if( tmap4 ) tmap4 = astAnnul( tmap4 );
1204 
1205 /* If an error occurred, annul the returned Mapping and clear the
1206    returned values. */
1207    if ( !astOK ) {
1208       *map = astAnnul( *map );
1209       match = 0;
1210    }
1211 
1212 /* Return the result. */
1213    return match;
1214 }
1215 
Match(AstFrame * template_frame,AstFrame * target,int matchsub,int ** template_axes,int ** target_axes,AstMapping ** map,AstFrame ** result,int * status)1216 static int Match( AstFrame *template_frame, AstFrame *target, int matchsub,
1217                   int **template_axes, int **target_axes,
1218                   AstMapping **map, AstFrame **result, int *status ) {
1219 /*
1220 *  Name:
1221 *     Match
1222 
1223 *  Purpose:
1224 *     Determine if conversion is possible between two coordinate systems.
1225 
1226 *  Type:
1227 *     Private function.
1228 
1229 *  Synopsis:
1230 *     #include "specfluxframe.h"
1231 *     int Match( AstFrame *template, AstFrame *target, int matchsub,
1232 *                int **template_axes, int **target_axes,
1233 *                AstMapping **map, AstFrame **result, int *status )
1234 
1235 *  Class Membership:
1236 *     SpecFluxFrame member function (over-rides the protected astMatch
1237 *     method inherited from the Frame class).
1238 
1239 *  Description:
1240 *     This function matches a "template" SpecFluxFrame to a "target" Frame
1241 *     and determines whether it is possible to convert coordinates
1242 *     between them.  If it is, a Mapping that performs the
1243 *     transformation is returned along with a new Frame that describes
1244 *     the coordinate system that results when this Mapping is applied
1245 *     to the "target" coordinate system. In addition, information is
1246 *     returned to allow the axes in this "result" Frame to be
1247 *     associated with the corresponding axes in the "target" Frame and
1248 *     "template" SpecFluxFrame from which they are derived.
1249 
1250 *  Parameters:
1251 *     template
1252 *        Pointer to the template SpecFluxFrame. This describes the
1253 *        coordinate system (or set of possible coordinate systems)
1254 *        into which we wish to convert our coordinates.
1255 *     target
1256 *        Pointer to the target Frame. This describes the coordinate
1257 *        system in which we already have coordinates.
1258 *     matchsub
1259 *        If zero then a match only occurs if the template is of the same
1260 *        class as the target, or of a more specialised class. If non-zero
1261 *        then a match can occur even if this is not the case.
1262 *     template_axes
1263 *        Address of a location where a pointer to int will be returned
1264 *        if the requested coordinate conversion is possible. This
1265 *        pointer will point at a dynamically allocated array of
1266 *        integers with one element for each axis of the "result" Frame
1267 *        (see below). It must be freed by the caller (using astFree)
1268 *        when no longer required.
1269 *
1270 *        For each axis in the result Frame, the corresponding element
1271 *        of this array will return the (zero-based) index of the
1272 *        template SpecFluxFrame axis from which it is derived. If it is not
1273 *        derived from any template axis, a value of -1 will be
1274 *        returned instead.
1275 *     target_axes
1276 *        Address of a location where a pointer to int will be returned
1277 *        if the requested coordinate conversion is possible. This
1278 *        pointer will point at a dynamically allocated array of
1279 *        integers with one element for each axis of the "result" Frame
1280 *        (see below). It must be freed by the caller (using astFree)
1281 *        when no longer required.
1282 *
1283 *        For each axis in the result Frame, the corresponding element
1284 *        of this array will return the (zero-based) index of the
1285 *        target Frame axis from which it is derived. If it is not
1286 *        derived from any target axis, a value of -1 will be returned
1287 *        instead.
1288 *     map
1289 *        Address of a location where a pointer to a new Mapping will
1290 *        be returned if the requested coordinate conversion is
1291 *        possible. If returned, the forward transformation of this
1292 *        Mapping may be used to convert coordinates between the
1293 *        "target" Frame and the "result" Frame (see below) and the
1294 *        inverse transformation will convert in the opposite
1295 *        direction.
1296 *     result
1297 *        Address of a location where a pointer to a new Frame will be
1298 *        returned if the requested coordinate conversion is
1299 *        possible. If returned, this Frame describes the coordinate
1300 *        system that results from applying the returned Mapping
1301 *        (above) to the "target" coordinate system. In general, this
1302 *        Frame will combine attributes from (and will therefore be
1303 *        more specific than) both the target Frame and the template
1304 *        SpecFluxFrame. In particular, when the template allows the
1305 *        possibility of transformaing to any one of a set of
1306 *        alternative coordinate systems, the "result" Frame will
1307 *        indicate which of the alternatives was used.
1308 *     status
1309 *        Pointer to the inherited status variable.
1310 
1311 *  Returned Value:
1312 *     A non-zero value is returned if the requested coordinate
1313 *     conversion is possible. Otherwise zero is returned (this will
1314 *     not in itself result in an error condition).
1315 
1316 *  Notes:
1317 *     - By default, the "result" Frame will have its number of axes
1318 *     and axis order determined by the "template" SpecFluxFrame. However,
1319 *     if the PreserveAxes attribute of the template SpecFluxFrame is
1320 *     non-zero, then the axis count and axis order of the "target"
1321 *     Frame will be used instead.
1322 *     - A value of zero will be returned if this function is invoked
1323 *     with the global error status set, or if it should fail for any
1324 *     reason.
1325 */
1326 
1327 /* Local Variables: */
1328    AstSpecFluxFrame *template;   /* Pointer to template SpecFluxFrame structure */
1329    int match;                    /* Coordinate conversion possible? */
1330    int swap1;                    /* Template axes swapped? */
1331    int swap2;                    /* Target axes swapped? */
1332    int swap;                     /* Additional axis swap needed? */
1333 
1334 /* Initialise the returned values. */
1335    *template_axes = NULL;
1336    *target_axes = NULL;
1337    *map = NULL;
1338    *result = NULL;
1339    match = 0;
1340 
1341 /* Check the global error status. */
1342    if ( !astOK ) return match;
1343 
1344 /* Obtain a pointer to the template SpecFluxFrame structure. */
1345    template = (AstSpecFluxFrame *) template_frame;
1346 
1347 /* If the target is not a SpecFluxFrame, use the results returned by the
1348    parent Match method inherited from the CmpFrame class. */
1349    if( !astIsASpecFluxFrame( target ) ) {
1350       match = (*parent_match)( template_frame, target, matchsub, template_axes,
1351                                target_axes, map, result, status );
1352 
1353 
1354 /* If the target is a SpecFluxFrame, see if we can convert between target
1355    and template */
1356    } else {
1357 
1358 /* We must now decide how the order of the axes in the result Frame relates to
1359    the order of axes in the target Frame. There are two factors involved. The
1360    first depends on whether the axis permutation array for the template
1361    SpecFluxFrame (whose method we are executing) causes an axis
1362    reversal. Determine this by permuting axis index zero. */
1363       swap1 = ( astValidateAxis( template, 0, 1, "astMatch" ) != 0 );
1364 
1365 /* The second factor depends on whether the axes of the target SpecFluxFrame
1366    causes an axis reversal. Determine this by permuting axis index zero. */
1367       swap2 = ( astValidateAxis( target, 0, 1, "astMatch" ) != 0 );
1368 
1369 /* Combine these to determine if an additional axis swap will be
1370    needed. */
1371       swap = ( swap1 != swap2 );
1372 
1373 /* Now check to see if this additional swap is permitted by the template's
1374    Permute attribute. */
1375       match = ( !swap || astGetPermute( template ) );
1376 
1377 /* Allocate the target and template axes arrays. */
1378       *template_axes = astMalloc( sizeof(int)*2 );
1379       *target_axes = astMalloc( sizeof(int)*2 );
1380 
1381 /* If the Frames still match, we next set up the axis association
1382    arrays. */
1383       if ( astOK && match ) {
1384 
1385 /* If the target axis order is to be preserved, then the target axis
1386    association involves no permutation but the template axis
1387    association may involve an axis swap. */
1388          if ( astGetPreserveAxes( template ) ) {
1389             (*template_axes)[ 0 ] = swap;
1390             (*template_axes)[ 1 ] = !swap;
1391             (*target_axes)[ 0 ] = 0;
1392             (*target_axes)[ 1 ] = 1;
1393 
1394 /* Otherwise, any swap applies to the target axis association
1395    instead. */
1396          } else {
1397             (*template_axes)[ 0 ] = 0;
1398             (*template_axes)[ 1 ] = 1;
1399             (*target_axes)[ 0 ] = swap;
1400             (*target_axes)[ 1 ] = !swap;
1401          }
1402 
1403 /* Use the target's "astSubFrame" method to create a new Frame (the
1404    result Frame) with copies of the target axes in the required
1405    order. This process also overlays the template attributes on to the
1406    target Frame and returns a Mapping between the target and result
1407    Frames which effects the required coordinate conversion. */
1408          match = astSubFrame( target, template, 2, *target_axes, *template_axes,
1409                               map, result );
1410 
1411 /* If an error occurred, or conversion to the result Frame's
1412    coordinate system was not possible, then free all memory, annul the
1413    returned objects, and reset the returned value. */
1414          if ( !astOK || !match ) {
1415             *template_axes = astFree( *template_axes );
1416             *target_axes = astFree( *target_axes );
1417             if( *map ) *map = astAnnul( *map );
1418             if( *result ) *result = astAnnul( *result );
1419             match = 0;
1420          }
1421       }
1422    }
1423 
1424 /* Return the result. */
1425    return match;
1426 }
1427 
SubFrame(AstFrame * target_frame,AstFrame * template,int result_naxes,const int * target_axes,const int * template_axes,AstMapping ** map,AstFrame ** result,int * status)1428 static int SubFrame( AstFrame *target_frame, AstFrame *template,
1429                      int result_naxes, const int *target_axes,
1430                      const int *template_axes, AstMapping **map,
1431                      AstFrame **result, int *status ) {
1432 /*
1433 *  Name:
1434 *     SubFrame
1435 
1436 *  Purpose:
1437 *     Select axes from a SpecFluxFrame and convert to the new coordinate system.
1438 
1439 *  Type:
1440 *     Private function.
1441 
1442 *  Synopsis:
1443 *     #include "specfluxframe.h"
1444 *     int SubFrame( AstFrame *target, AstFrame *template,
1445 *                   int result_naxes, const int *target_axes,
1446 *                   const int *template_axes, AstMapping **map,
1447 *                   AstFrame **result, int *status )
1448 
1449 *  Class Membership:
1450 *     SpecFluxFrame member function (over-rides the protected astSubFrame
1451 *     method inherited from the Frame class).
1452 
1453 *  Description:
1454 *     This function selects a requested sub-set (or super-set) of the
1455 *     axes from a "target" SpecFluxFrame and creates a new Frame with
1456 *     copies of the selected axes assembled in the requested order. It
1457 *     then optionally overlays the attributes of a "template" Frame on
1458 *     to the result. It returns both the resulting Frame and a Mapping
1459 *     that describes how to convert between the coordinate systems
1460 *     described by the target and result Frames. If necessary, this
1461 *     Mapping takes account of any differences in the Frames'
1462 *     attributes due to the influence of the template.
1463 
1464 *  Parameters:
1465 *     target
1466 *        Pointer to the target SpecFluxFrame, from which axes are to be selected.
1467 *     template
1468 *        Pointer to the template Frame, from which new attributes for
1469 *        the result Frame are to be obtained. Optionally, this may be
1470 *        NULL, in which case no overlaying of template attributes will
1471 *        be performed.
1472 *     result_naxes
1473 *        Number of axes to be selected from the target Frame. This
1474 *        number may be greater than or less than the number of axes in
1475 *        this Frame (or equal).
1476 *     target_axes
1477 *        Pointer to an array of int with result_naxes elements, giving
1478 *        a list of the (zero-based) axis indices of the axes to be
1479 *        selected from the target SpecFluxFrame. The order in which these
1480 *        are given determines the order in which the axes appear in
1481 *        the result Frame. If any of the values in this array is set
1482 *        to -1, the corresponding result axis will not be derived from
1483 *        the target Frame, but will be assigned default attributes
1484 *        instead.
1485 *     template_axes
1486 *        Pointer to an array of int with result_naxes elements. This
1487 *        should contain a list of the template axes (given as
1488 *        zero-based axis indices) with which the axes of the result
1489 *        Frame are to be associated. This array determines which axes
1490 *        are used when overlaying axis-dependent attributes of the
1491 *        template on to the result. If any element of this array is
1492 *        set to -1, the corresponding result axis will not receive any
1493 *        template attributes.
1494 *
1495 *        If the template argument is given as NULL, this array is not
1496 *        used and a NULL pointer may also be supplied here.
1497 *     map
1498 *        Address of a location to receive a pointer to the returned
1499 *        Mapping.  The forward transformation of this Mapping will
1500 *        describe how to convert coordinates from the coordinate
1501 *        system described by the target SpecFluxFrame to that described by
1502 *        the result Frame. The inverse transformation will convert in
1503 *        the opposite direction.
1504 *     result
1505 *        Address of a location to receive a pointer to the result Frame.
1506 *     status
1507 *        Pointer to the inherited status variable.
1508 
1509 *  Returned Value:
1510 *     A non-zero value is returned if coordinate conversion is
1511 *     possible between the target and the result Frame. Otherwise zero
1512 *     is returned and *map and *result are returned as NULL (but this
1513 *     will not in itself result in an error condition). In general,
1514 *     coordinate conversion should always be possible if no template
1515 *     Frame is supplied but may not always be possible otherwise.
1516 
1517 *  Notes:
1518 *     - A value of zero will be returned if this function is invoked
1519 *     with the global error status set, or if it should fail for any
1520 *     reason.
1521 
1522 *  Implementation Deficiencies:
1523 *     - It is not clear that the method of handling "extra" axes is
1524 *     the best one, nor is the method of setting the "following" flag
1525 *     necessarily correct.  However, it is also not obvious that this
1526 *     feature will ever be needed, so improvements have been left
1527 *     until the requirement is clearer.
1528 */
1529 
1530 /* Local Variables: */
1531    AstMapping *tmpmap;           /* Temporary Mapping pointer */
1532    AstPermMap *permmap;          /* Pointer to PermMap */
1533    AstSpecFluxFrame *target;     /* Pointer to target SpecFluxFrame structure */
1534    int match;                    /* Coordinate conversion is possible? */
1535    int perm[ 2 ];                /* Permutation array for axis swap */
1536    int result_swap;              /* Swap result SpecFluxFrame coordinates? */
1537    int target_swap;              /* Swap target SpecFluxFrame coordinates? */
1538 
1539 /* Initialise the returned values. */
1540    *map = NULL;
1541    *result = NULL;
1542    match = 0;
1543 
1544 /* Check the global error status. */
1545    if ( !astOK ) return match;
1546 
1547 /* If the template is not a SpecFluxFrame we use the parent SubFrame
1548    method inherited form the CmpFrame class. */
1549    if( !template || !astIsASpecFluxFrame( template ) || result_naxes != 2 ) {
1550       match = (*parent_subframe)( target_frame, template, result_naxes,
1551                                   target_axes, template_axes, map, result, status );
1552 
1553 /* Otherwise... */
1554    } else {
1555 
1556 /* Obtain a pointer to the target SpecFluxFrame structure. */
1557       target = (AstSpecFluxFrame *) target_frame;
1558 
1559 /* Form the result from a copy of the target and then permute its axes
1560    into the order required. */
1561       *result = astCopy( target );
1562       astPermAxes( *result, target_axes );
1563 
1564 /* Overlay the template attributes on to the result SpecFrame. */
1565       astOverlay( template, template_axes, *result );
1566 
1567 /* Generate a Mapping that takes account of changes in the coordinate
1568    system (system, units, etc.) between the target SpecFluxFrame and the
1569    result SpecFluxFrame. If this Mapping can be generated, set "match" to
1570    indicate that coordinate conversion is possible. */
1571       match = MakeSFMapping( target, (AstSpecFluxFrame *) *result, map, status );
1572 
1573 /* If a Mapping has been obtained, it will expect coordinate values to be
1574    supplied in (flux,spec) pairs. Test whether we need to swap the
1575    order of the target SpecFluxFrame coordinates to conform with this. */
1576       if ( astOK && match ) {
1577          target_swap = ( astValidateAxis( target, 0, 1, "astSubFrame" ) != 0 );
1578 
1579 /* Coordinates will also be delivered in (flux,spec) pairs, so check
1580    to see whether the result SpecFluxFrame coordinate order should be
1581    swapped. */
1582          result_swap = ( target_swap != ( target_axes[ 0 ] != 0 ) );
1583 
1584 /* If either set of coordinates needs swapping, create a PermMap that
1585    will swap a pair of coordinates. */
1586          permmap = NULL;
1587          if ( target_swap || result_swap ) {
1588             perm[ 0 ] = 1;
1589             perm[ 1 ] = 0;
1590             permmap = astPermMap( 2, perm, 2, perm, NULL, "", status );
1591          }
1592 
1593 /* If necessary, prefix this PermMap to the main Mapping. */
1594          if ( target_swap ) {
1595             tmpmap = (AstMapping *) astCmpMap( permmap, *map, 1, "", status );
1596             *map = astAnnul( *map );
1597             *map = tmpmap;
1598          }
1599 
1600 /* Also, if necessary, append it to the main Mapping. */
1601          if ( result_swap ) {
1602             tmpmap = (AstMapping *) astCmpMap( *map, permmap, 1, "", status );
1603             *map = astAnnul( *map );
1604             *map = tmpmap;
1605          }
1606 
1607 /* Annul the pointer to the PermMap (if created). */
1608          if ( permmap ) permmap = astAnnul( permmap );
1609       }
1610    }
1611 
1612 /* If an error occurred, clean up by annulling the result pointers and
1613    returning appropriate null values. */
1614    if ( !astOK ) {
1615       *map = astAnnul( *map );
1616       *result = astAnnul( *result );
1617       match = 0;
1618    }
1619 
1620 /* Return the result. */
1621    return match;
1622 }
1623 
1624 /* Functions which access class attributes. */
1625 /* ---------------------------------------- */
1626 /* Implement member functions to access the attributes associated with
1627    the axes of a SpecFluxFrame using the private macros defined for this
1628    purpose at the start of this file. */
1629 
1630 /* Copy constructor. */
1631 /* ----------------- */
1632 
1633 /* Destructor. */
1634 /* ----------- */
1635 
1636 /* Dump function. */
1637 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)1638 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
1639 /*
1640 *  Name:
1641 *     Dump
1642 
1643 *  Purpose:
1644 *     Dump function for SpecFluxFrame objects.
1645 
1646 *  Type:
1647 *     Private function.
1648 
1649 *  Synopsis:
1650 *     void Dump( AstObject *this, AstChannel *channel, int *status )
1651 
1652 *  Description:
1653 *     This function implements the Dump function which writes out data
1654 *     for the SpecFluxFrame class to an output Channel.
1655 
1656 *  Parameters:
1657 *     this
1658 *        Pointer to the SpecFluxFrame whose data are being written.
1659 *     channel
1660 *        Pointer to the Channel to which the data are being written.
1661 *     status
1662 *        Pointer to the inherited status variable.
1663 */
1664 
1665 /* Local Variables: */
1666    AstSpecFluxFrame *this;            /* Pointer to the SpecFluxFrame structure */
1667 
1668 /* Check the global error status. */
1669    if ( !astOK ) return;
1670 
1671 /* Obtain a pointer to the SpecFluxFrame structure. */
1672    this = (AstSpecFluxFrame *) this_object;
1673 
1674 /* Write out values representing the instance variables for the
1675    SpecFluxFrame class.  Accompany these with appropriate comment strings,
1676    possibly depending on the values being written.*/
1677 
1678 /* In the case of attributes, we first use the appropriate (private)
1679    Test...  member function to see if they are set. If so, we then use
1680    the (private) Get... function to obtain the value to be written
1681    out.
1682 
1683    For attributes which are not set, we use the astGet... method to
1684    obtain the value instead. This will supply a default value
1685    (possibly provided by a derived class which over-rides this method)
1686    which is more useful to a human reader as it corresponds to the
1687    actual default attribute value.  Since "set" will be zero, these
1688    values are for information only and will not be read back. */
1689 
1690 }
1691 
1692 /* Standard class functions. */
1693 /* ========================= */
1694 /* Implement the astIsASpecFluxFrame and astCheckSpecFluxFrame functions using
1695    the macros defined for this purpose in the "object.h" header file. */
astMAKE_ISA(SpecFluxFrame,CmpFrame)1696 astMAKE_ISA(SpecFluxFrame,CmpFrame)
1697 astMAKE_CHECK(SpecFluxFrame)
1698 
1699 AstSpecFluxFrame *astSpecFluxFrame_( void *frame1_void, void *frame2_void,
1700                                      const char *options, int *status, ...) {
1701 /*
1702 *++
1703 *  Name:
1704 c     astSpecFluxFrame
1705 f     AST_SPECFLUXFRAME
1706 
1707 *  Purpose:
1708 *     Create a SpecFluxFrame.
1709 
1710 *  Type:
1711 *     Public function.
1712 
1713 *  Synopsis:
1714 c     #include "specfluxframe.h"
1715 c     AstSpecFluxFrame *astSpecFluxFrame( AstSpecFrame *frame1, AstFluxFrame *frame2,
1716 c                                         const char *options, ... )
1717 f     RESULT = AST_SPECFLUXFRAME( FRAME1, FRAME2, OPTIONS, STATUS )
1718 
1719 *  Class Membership:
1720 *     SpecFluxFrame constructor.
1721 
1722 *  Description:
1723 *     This function creates a new SpecFluxFrame and optionally initialises
1724 *     its attributes.
1725 *
1726 *     A SpecFluxFrame combines a SpecFrame and a FluxFrame into a single
1727 *     2-dimensional compound Frame. Such a Frame can for instance be used
1728 *     to describe a Plot of a spectrum in which the first axis represents
1729 *     spectral position and the second axis represents flux.
1730 
1731 *  Parameters:
1732 c     frame1
1733 f     FRAME1 = INTEGER (Given)
1734 *        Pointer to the SpecFrame. This will form the first axis in the
1735 *        new SpecFluxFrame.
1736 c     frame2
1737 f     FRAME2 = INTEGER (Given)
1738 *        Pointer to the FluxFrame. This will form the second axis in the
1739 *        new SpecFluxFrame. The "SpecVal" attribute of this FluxFrame is
1740 *        not used by the SpecFluxFrame class and so may be set to AST__BAD
1741 *        when the FluxFrame is created.
1742 c     options
1743 f     OPTIONS = CHARACTER * ( * ) (Given)
1744 c        Pointer to a null-terminated string containing an optional
1745 c        comma-separated list of attribute assignments to be used for
1746 c        initialising the new SpecFluxFrame. The syntax used is identical to
1747 c        that for the astSet function and may include "printf" format
1748 c        specifiers identified by "%" symbols in the normal way.
1749 f        A character string containing an optional comma-separated
1750 f        list of attribute assignments to be used for initialising the
1751 f        new SpecFluxFrame. The syntax used is identical to that for the
1752 f        AST_SET routine.
1753 c     ...
1754 c        If the "options" string contains "%" format specifiers, then
1755 c        an optional list of additional arguments may follow it in
1756 c        order to supply values to be substituted for these
1757 c        specifiers. The rules for supplying these are identical to
1758 c        those for the astSet function (and for the C "printf"
1759 c        function).
1760 f     STATUS = INTEGER (Given and Returned)
1761 f        The global status.
1762 
1763 *  Returned Value:
1764 c     astSpecFluxFrame()
1765 f     AST_SPECFLUXFRAME = INTEGER
1766 *        A pointer to the new SpecFluxFrame.
1767 
1768 *  Notes:
1769 *     - The supplied Frame pointers are stored directly, rather than
1770 *     being used to create deep copies of the supplied Frames. This means
1771 *     that any subsequent changes made to the Frames via the supplied
1772 *     pointers will result in equivalent changes being visible in the
1773 *     SpecFluxFrame.
1774 *     - A null Object pointer (AST__NULL) will be returned if this
1775 c     function is invoked with the AST error status set, or if it
1776 f     function is invoked with STATUS set to an error value, or if it
1777 *     should fail for any reason.
1778 
1779 *  Status Handling:
1780 *     The protected interface to this function includes an extra
1781 *     parameter at the end of the parameter list descirbed above. This
1782 *     parameter is a pointer to the integer inherited status
1783 *     variable: "int *status".
1784 
1785 *--
1786 
1787 *  Implementation Notes:
1788 *     - This function implements the basic SpecFluxFrame constructor which
1789 *     is available via the protected interface to the SpecFluxFrame class.
1790 *     A public interface is provided by the astSpecFluxFrameId_ function.
1791 *     - Because this function has a variable argument list, it is
1792 *     invoked by a macro that evaluates to a function pointer (not a
1793 *     function invocation) and no checking or casting of arguments is
1794 *     performed before the function is invoked. Because of this, the
1795 *     "frame1" and "frame2" parameters are of type (void *) and are
1796 *     converted and validated within the function itself.
1797 */
1798 
1799 /* Local Variables: */
1800    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1801    AstSpecFluxFrame *new;        /* Pointer to new SpecFluxFrame */
1802    AstFluxFrame *frame2;         /* Pointer to FluxFrame structure */
1803    AstSpecFrame *frame1;         /* Pointer to SpecFrame structure */
1804    va_list args;                 /* Variable argument list */
1805 
1806 /* Get a pointer to the thread specific global data structure. */
1807    astGET_GLOBALS(NULL);
1808 
1809 /* Check the global status. */
1810    new = NULL;
1811    if ( !astOK ) return new;
1812 
1813 /* Obtain and validate pointers to the Frame structures provided. */
1814    frame1 = astCheckSpecFrame( frame1_void );
1815    frame2 = astCheckFluxFrame( frame2_void );
1816    if ( astOK ) {
1817 
1818 /* Initialise the SpecFluxFrame, allocating memory and initialising the
1819    virtual function table as well if necessary. */
1820       new = astInitSpecFluxFrame( NULL, sizeof( AstSpecFluxFrame ), !class_init,
1821                                   &class_vtab, "SpecFluxFrame", frame1, frame2 );
1822 
1823 /* If successful, note that the virtual function table has been
1824    initialised. */
1825       if ( astOK ) {
1826          class_init = 1;
1827 
1828 /* Obtain the variable argument list and pass it along with the
1829    options string to the astVSet method to initialise the new
1830    SpecFluxFrame's attributes. */
1831          va_start( args, status );
1832          astVSet( new, options, NULL, args );
1833          va_end( args );
1834 
1835 /* If an error occurred, clean up by deleting the new object. */
1836          if ( !astOK ) new = astDelete( new );
1837       }
1838    }
1839 
1840 /* Return a pointer to the new SpecFluxFrame. */
1841    return new;
1842 }
1843 
astSpecFluxFrameId_(void * frame1_void,void * frame2_void,const char * options,...)1844 AstSpecFluxFrame *astSpecFluxFrameId_( void *frame1_void, void *frame2_void,
1845                                        const char *options, ... ) {
1846 /*
1847 *  Name:
1848 *     astSpecFluxFrameId_
1849 
1850 *  Purpose:
1851 *     Create a SpecFluxFrame.
1852 
1853 *  Type:
1854 *     Private function.
1855 
1856 *  Synopsis:
1857 *     #include "specfluxframe.h"
1858 *     AstSpecFluxFrame *astSpecFluxFrameId_( void *frame1_void, void *frame2_void,
1859 *                                            const char *options, ... )
1860 
1861 *  Class Membership:
1862 *     SpecFluxFrame constructor.
1863 
1864 *  Description:
1865 *     This function implements the external (public) interface to the
1866 *     astSpecFluxFrame constructor function. It returns an ID value
1867 *     (instead of a true C pointer) to external users, and must be
1868 *     provided because astSpecFluxFrame_ has a variable argument list which
1869 *     cannot be encapsulated in a macro (where this conversion would
1870 *     otherwise occur). For the same reason, the "frame1" and "frame2"
1871 *     parameters are of type (void *) and are converted and validated
1872 *     within the function itself.
1873 *
1874 *     The variable argument list also prevents this function from
1875 *     invoking astSpecFluxFrame_ directly, so it must be a
1876 *     re-implementation of it in all respects, except for the final
1877 *     conversion of the result to an ID value.
1878 
1879 *  Parameters:
1880 *     As for astSpecFluxFrame_.
1881 
1882 *  Returned Value:
1883 *     The ID value associated with the new SpecFluxFrame.
1884 */
1885 
1886 /* Local Variables: */
1887    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1888    AstSpecFluxFrame *new;        /* Pointer to new SpecFluxFrame */
1889    AstSpecFrame *frame1;         /* Pointer to first Frame structure */
1890    AstFluxFrame *frame2;         /* Pointer to second Frame structure */
1891    va_list args;                 /* Variable argument list */
1892 
1893    int *status;                  /* Get a pointer to the thread specific global data structure. */
1894    astGET_GLOBALS(NULL);
1895 
1896 /* Pointer to inherited status value */
1897 
1898 /* Get a pointer to the inherited status value. */
1899    status = astGetStatusPtr;
1900 
1901 /* Check the global status. */
1902    new = NULL;
1903    if ( !astOK ) return new;
1904 
1905 /* Obtain the Frame pointers from the ID's supplied and validate the
1906    pointers to ensure they identify valid Frames. */
1907    frame1 = astVerifySpecFrame( astMakePointer( frame1_void ) );
1908    frame2 = astVerifyFluxFrame( astMakePointer( frame2_void ) );
1909    if ( astOK ) {
1910 
1911 /* Initialise the SpecFluxFrame, allocating memory and initialising the
1912    virtual function table as well if necessary. */
1913       new = astInitSpecFluxFrame( NULL, sizeof( AstSpecFluxFrame ), !class_init,
1914                                   &class_vtab, "SpecFluxFrame", frame1, frame2 );
1915 
1916 /* If successful, note that the virtual function table has been
1917    initialised. */
1918       if ( astOK ) {
1919          class_init = 1;
1920 
1921 /* Obtain the variable argument list and pass it along with the
1922    options string to the astVSet method to initialise the new
1923    SpecFluxFrame's attributes. */
1924          va_start( args, options );
1925          astVSet( new, options, NULL, args );
1926          va_end( args );
1927 
1928 /* If an error occurred, clean up by deleting the new object. */
1929          if ( !astOK ) new = astDelete( new );
1930       }
1931    }
1932 
1933 /* Return an ID value for the new SpecFluxFrame. */
1934    return astMakeId( new );
1935 }
1936 
astInitSpecFluxFrame_(void * mem,size_t size,int init,AstSpecFluxFrameVtab * vtab,const char * name,AstSpecFrame * frame1,AstFluxFrame * frame2,int * status)1937 AstSpecFluxFrame *astInitSpecFluxFrame_( void *mem, size_t size, int init,
1938                                AstSpecFluxFrameVtab *vtab, const char *name,
1939                                AstSpecFrame *frame1, AstFluxFrame *frame2, int *status ) {
1940 /*
1941 *+
1942 *  Name:
1943 *     astInitSpecFluxFrame
1944 
1945 *  Purpose:
1946 *     Initialise a SpecFluxFrame.
1947 
1948 *  Type:
1949 *     Protected function.
1950 
1951 *  Synopsis:
1952 *     #include "specfluxframe.h"
1953 *     AstSpecFluxFrame *astInitSpecFluxFrame( void *mem, size_t size, int init,
1954 *                                 AstSpecFluxFrameVtab *vtab, const char *name,
1955 *                                 AstSpecFrame *frame1, AstFluxFrame *frame2 )
1956 
1957 *  Class Membership:
1958 *     SpecFluxFrame initialiser.
1959 
1960 *  Description:
1961 *     This function is provided for use by class implementations to
1962 *     initialise a new SpecFluxFrame object. It allocates memory (if
1963 *     necessary) to accommodate the SpecFluxFrame plus any additional data
1964 *     associated with the derived class.  It then initialises a
1965 *     SpecFluxFrame structure at the start of this memory. If the "init"
1966 *     flag is set, it also initialises the contents of a virtual
1967 *     function table for a SpecFluxFrame at the start of the memory passed
1968 *     via the "vtab" parameter.
1969 
1970 *  Parameters:
1971 *     mem
1972 *        A pointer to the memory in which the SpecFluxFrame is to be
1973 *        created. This must be of sufficient size to accommodate the
1974 *        SpecFluxFrame data (sizeof(SpecFluxFrame)) plus any data used by the
1975 *        derived class. If a value of NULL is given, this function
1976 *        will allocate the memory itself using the "size" parameter to
1977 *        determine its size.
1978 *     size
1979 *        The amount of memory used by the SpecFluxFrame (plus derived class
1980 *        data).  This will be used to allocate memory if a value of
1981 *        NULL is given for the "mem" parameter. This value is also
1982 *        stored in the SpecFluxFrame structure, so a valid value must be
1983 *        supplied even if not required for allocating memory.
1984 *     init
1985 *        A logical flag indicating if the SpecFluxFrame's virtual function
1986 *        table is to be initialised. If this value is non-zero, the
1987 *        virtual function table will be initialised by this function.
1988 *     vtab
1989 *        Pointer to the start of the virtual function table to be
1990 *        associated with the new SpecFluxFrame.
1991 *     name
1992 *        Pointer to a constant null-terminated character string which
1993 *        contains the name of the class to which the new object
1994 *        belongs (it is this pointer value that will subsequently be
1995 *        returned by the Object astClass function).
1996 *     frame1
1997 *        Pointer to the SpecFrame
1998 *     frame2
1999 *        Pointer to the FluxFrame
2000 
2001 *  Returned Value:
2002 *     A pointer to the new SpecFluxFrame.
2003 
2004 *  Notes:
2005 *     - A null pointer will be returned if this function is invoked
2006 *     with the global error status set, or if it should fail for any
2007 *     reason.
2008 *-
2009 */
2010 
2011 /* Local Variables: */
2012    AstSpecFluxFrame *new;        /* Pointer to new SpecFluxFrame */
2013 
2014 /* Check the global status. */
2015    if ( !astOK ) return NULL;
2016 
2017 /* If necessary, initialise the virtual function table. */
2018    if ( init ) astInitSpecFluxFrameVtab( vtab, name );
2019 
2020 /* Initialise a Frame structure (the parent class) as the first
2021    component within the SpecFluxFrame structure, allocating memory if
2022    necessary. Set the number of Frame axes to zero, since all axis
2023    information is stored within the component Frames. */
2024    new = astInitCmpFrame( mem, size, 0, (AstCmpFrameVtab *) vtab, name,
2025                           frame1, frame2 );
2026    if ( astOK ) {
2027 
2028 
2029 /* If an error occurred, clean up by deleting the new object. */
2030       if ( !astOK ) new = astDelete( new );
2031    }
2032 
2033 /* Return a pointer to the new object. */
2034    return new;
2035 }
2036 
astLoadSpecFluxFrame_(void * mem,size_t size,AstSpecFluxFrameVtab * vtab,const char * name,AstChannel * channel,int * status)2037 AstSpecFluxFrame *astLoadSpecFluxFrame_( void *mem, size_t size,
2038                                  AstSpecFluxFrameVtab *vtab, const char *name,
2039                                  AstChannel *channel, int *status ) {
2040 /*
2041 *+
2042 *  Name:
2043 *     astLoadSpecFluxFrame
2044 
2045 *  Purpose:
2046 *     Load a SpecFluxFrame.
2047 
2048 *  Type:
2049 *     Protected function.
2050 
2051 *  Synopsis:
2052 *     #include "specfluxframe.h"
2053 *     AstSpecFluxFrame *astLoadSpecFluxFrame( void *mem, size_t size,
2054 *                                   AstSpecFluxFrameVtab *vtab, const char *name,
2055 *                                   AstChannel *channel )
2056 
2057 *  Class Membership:
2058 *     SpecFluxFrame loader.
2059 
2060 *  Description:
2061 *     This function is provided to load a new SpecFluxFrame using data read
2062 *     from a Channel. It first loads the data used by the parent class
2063 *     (which allocates memory if necessary) and then initialises a
2064 *     SpecFluxFrame structure in this memory, using data read from the
2065 *     input Channel.
2066 
2067 *  Parameters:
2068 *     mem
2069 *        A pointer to the memory into which the SpecFluxFrame is to be
2070 *        loaded.  This must be of sufficient size to accommodate the
2071 *        SpecFluxFrame data (sizeof(SpecFluxFrame)) plus any data used by
2072 *        derived classes. If a value of NULL is given, this function
2073 *        will allocate the memory itself using the "size" parameter to
2074 *        determine its size.
2075 *     size
2076 *        The amount of memory used by the SpecFluxFrame (plus derived class
2077 *        data).  This will be used to allocate memory if a value of
2078 *        NULL is given for the "mem" parameter. This value is also
2079 *        stored in the SpecFluxFrame structure, so a valid value must be
2080 *        supplied even if not required for allocating memory.
2081 *
2082 *        If the "vtab" parameter is NULL, the "size" value is ignored
2083 *        and sizeof(AstSpecFluxFrame) is used instead.
2084 *     vtab
2085 *        Pointer to the start of the virtual function table to be
2086 *        associated with the new SpecFluxFrame. If this is NULL, a pointer
2087 *        to the (static) virtual function table for the SpecFluxFrame class
2088 *        is used instead.
2089 *     name
2090 *        Pointer to a constant null-terminated character string which
2091 *        contains the name of the class to which the new object
2092 *        belongs (it is this pointer value that will subsequently be
2093 *        returned by the astGetClass method).
2094 *
2095 *        If the "vtab" parameter is NULL, the "name" value is ignored
2096 *        and a pointer to the string "SpecFluxFrame" is used instead.
2097 
2098 *  Returned Value:
2099 *     A pointer to the new SpecFluxFrame.
2100 
2101 *  Notes:
2102 *     - A null pointer will be returned if this function is invoked
2103 *     with the global error status set, or if it should fail for any
2104 *     reason.
2105 *-
2106 */
2107 
2108 /* Local Constants: */
2109    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2110 #define KEY_LEN 50               /* Maximum length of a keyword */
2111 
2112 /* Local Variables: */
2113    AstSpecFluxFrame *new;        /* Pointer to the new SpecFluxFrame */
2114 
2115 /* Initialise. */
2116    new = NULL;
2117 
2118 /* Get a pointer to the thread specific global data structure. */
2119    astGET_GLOBALS(channel);
2120 
2121 /* Check the global error status. */
2122    if ( !astOK ) return new;
2123 
2124 /* If a NULL virtual function table has been supplied, then this is
2125    the first loader to be invoked for this SpecFluxFrame. In this case the
2126    SpecFluxFrame belongs to this class, so supply appropriate values to be
2127    passed to the parent class loader (and its parent, etc.). */
2128    if ( !vtab ) {
2129       size = sizeof( AstSpecFluxFrame );
2130       vtab = &class_vtab;
2131       name = "SpecFluxFrame";
2132 
2133 /* If required, initialise the virtual function table for this class. */
2134       if ( !class_init ) {
2135          astInitSpecFluxFrameVtab( vtab, name );
2136          class_init = 1;
2137       }
2138    }
2139 
2140 /* Invoke the parent class loader to load data for all the ancestral
2141    classes of the current one, returning a pointer to the resulting
2142    partly-built SpecFluxFrame. */
2143    new = astLoadCmpFrame( mem, size, (AstCmpFrameVtab *) vtab, name,
2144                           channel );
2145 
2146    if ( astOK ) {
2147 
2148 /* Read input data. */
2149 /* ================ */
2150 /* Request the input Channel to read all the input data appropriate to
2151    this class into the internal "values list". */
2152       astReadClassData( channel, "SpecFluxFrame" );
2153 
2154 /* Now read each individual data item from this list and use it to
2155    initialise the appropriate instance variable(s) for this class. */
2156 
2157 /* In the case of attributes, we first read the "raw" input value,
2158    supplying the "unset" value as the default. If a "set" value is
2159    obtained, we then use the appropriate (private) Set... member
2160    function to validate and set the value properly. */
2161 /*  (none)  */
2162 
2163 /* If an error occurred, clean up by deleting the new SpecFluxFrame. */
2164       if ( !astOK ) new = astDelete( new );
2165    }
2166 
2167 /* Return the new SpecFluxFrame pointer. */
2168    return new;
2169 
2170 /* Undefine macros local to this function. */
2171 #undef KEY_LEN
2172 }
2173 
2174 /* Virtual function interfaces. */
2175 /* ============================ */
2176 /* These provide the external interface to the virtual functions defined by
2177    this class. Each simply checks the global error status and then locates and
2178    executes the appropriate member function, using the function pointer stored
2179    in the object's virtual function table (this pointer is located using the
2180    astMEMBER macro defined in "object.h").
2181 
2182    Note that the member function may not be the one defined here, as it may
2183    have been over-ridden by a derived class. However, it should still have the
2184    same interface. */
2185 
2186 
2187 
2188 
2189 
2190