1 /*
2 *class++
3 *  Name:
4 *     UnitMap
5 
6 *  Purpose:
7 *     Unit (null) Mapping.
8 
9 *  Constructor Function:
10 c     astUnitMap
11 f     AST_UNITMAP
12 
13 *  Description:
14 *     A UnitMap is a unit (null) Mapping that has no effect on the
15 *     coordinates supplied to it. They are simply copied. This can be
16 *     useful if a Mapping is required (e.g. to pass to another
17 c     function) but you do not want it to have any effect.
18 f     routine) but you do not want it to have any effect.
19 *     The Nin and Nout attributes of a UnitMap are always equal and
20 *     are specified when it is created.
21 
22 *  Inheritance:
23 *     The UnitMap class inherits from the Mapping class.
24 
25 *  Attributes:
26 *     The UnitMap class does not define any new attributes beyond
27 *     those which are applicable to all Mappings.
28 
29 *  Functions:
30 c     The UnitMap class does not define any new functions beyond those
31 f     The UnitMap class does not define any new routines beyond those
32 *     which are applicable to all Mappings.
33 
34 *  Copyright:
35 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
36 *     Research Councils
37 
38 *  Licence:
39 *     This program is free software: you can redistribute it and/or
40 *     modify it under the terms of the GNU Lesser General Public
41 *     License as published by the Free Software Foundation, either
42 *     version 3 of the License, or (at your option) any later
43 *     version.
44 *
45 *     This program is distributed in the hope that it will be useful,
46 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
47 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
48 *     GNU Lesser General Public License for more details.
49 *
50 *     You should have received a copy of the GNU Lesser General
51 *     License along with this program.  If not, see
52 *     <http://www.gnu.org/licenses/>.
53 
54 *  Authors:
55 *     RFWS: R.F. Warren-Smith (Starlink)
56 *     DSB: David S Berry (JAC, Hawaii)
57 
58 *  History:
59 *     7-FEB-1996 (RFWS):
60 *        Original version.
61 *     13-DEC-1996 (RFWS):
62 *        Over-ride the astMapMerge method.
63 *     8-JAN-2003 (DSB):
64 *        Changed private InitVtab method to protected astInitUnitMapVtab
65 *        method.
66 *     10-MAY-2006 (DSB):
67 *        Override astEqual.
68 *     17-FEB-2012 (DSB):
69 *        In Transform, do not copy the coordinate values if the input and
70 *        output array are the same.
71 *class--
72 */
73 
74 /* Module Macros. */
75 /* ============== */
76 /* Set the name of the class we are implementing. This indicates to
77    the header files that define class interfaces that they should make
78    "protected" symbols available. */
79 #define astCLASS UnitMap
80 
81 /* Include files. */
82 /* ============== */
83 /* Interface definitions. */
84 /* ---------------------- */
85 
86 #include "globals.h"             /* Thread-safe global data access */
87 #include "error.h"               /* Error reporting facilities */
88 #include "object.h"              /* Base Object class */
89 #include "memory.h"              /* AST memory management */
90 #include "pointset.h"            /* Sets of points/coordinates */
91 #include "mapping.h"             /* Coordinate mappings (parent class) */
92 #include "unitmap.h"             /* Interface definition for this class */
93 
94 /* Error code definitions. */
95 /* ----------------------- */
96 #include "ast_err.h"             /* AST error codes */
97 
98 /* C header files. */
99 /* --------------- */
100 #include <stdarg.h>
101 #include <stddef.h>
102 #include <string.h>
103 
104 /* Module Variables. */
105 /* ================= */
106 
107 /* Address of this static variable is used as a unique identifier for
108    member of this class. */
109 static int class_check;
110 
111 /* Pointers to parent class methods which are extended by this class. */
112 static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
113 
114 
115 #ifdef THREAD_SAFE
116 /* Define how to initialise thread-specific globals. */
117 #define GLOBAL_inits \
118    globals->Class_Init = 0;
119 
120 /* Create the function that initialises global data for this module. */
121 astMAKE_INITGLOBALS(UnitMap)
122 
123 /* Define macros for accessing each item of thread specific global data. */
124 #define class_init astGLOBAL(UnitMap,Class_Init)
125 #define class_vtab astGLOBAL(UnitMap,Class_Vtab)
126 
127 
128 #include <pthread.h>
129 
130 
131 #else
132 
133 
134 /* Define the class virtual function table and its initialisation flag
135    as static variables. */
136 static AstUnitMapVtab class_vtab;   /* Virtual function table */
137 static int class_init = 0;       /* Virtual function table initialised? */
138 
139 #endif
140 
141 /* External Interface Function Prototypes. */
142 /* ======================================= */
143 /* The following functions have public prototypes only (i.e. no
144    protected prototypes), so we must provide local prototypes for use
145    within this module. */
146 AstUnitMap *astUnitMapId_( int, const char *, ... );
147 
148 /* Prototypes for Private Member Functions. */
149 /* ======================================== */
150 static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
151 static double Rate( AstMapping *, double *, int, int, int * );
152 static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * );
153 static int Equal( AstObject *, AstObject *, int * );
154 static int GetIsLinear( AstMapping *, int * );
155 static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * );
156 static void Dump( AstObject *, AstChannel *, int * );
157 
158 /* Member functions. */
159 /* ================= */
Equal(AstObject * this_object,AstObject * that_object,int * status)160 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
161 /*
162 *  Name:
163 *     Equal
164 
165 *  Purpose:
166 *     Test if two UnitMaps are equivalent.
167 
168 *  Type:
169 *     Private function.
170 
171 *  Synopsis:
172 *     #include "unitmap.h"
173 *     int Equal( AstObject *this, AstObject *that, int *status )
174 
175 *  Class Membership:
176 *     UnitMap member function (over-rides the astEqual protected
177 *     method inherited from the astMapping class).
178 
179 *  Description:
180 *     This function returns a boolean result (0 or 1) to indicate whether
181 *     two UnitMaps are equivalent.
182 
183 *  Parameters:
184 *     this
185 *        Pointer to the first Object (a UnitMap).
186 *     that
187 *        Pointer to the second Object.
188 *     status
189 *        Pointer to the inherited status variable.
190 
191 *  Returned Value:
192 *     One if the UnitMaps are equivalent, zero otherwise.
193 
194 *  Notes:
195 *     - A value of zero will be returned if this function is invoked
196 *     with the global status set, or if it should fail for any reason.
197 */
198 
199 /* Local Variables: */
200    AstUnitMap *that;
201    AstUnitMap *this;
202    int result;
203 
204 /* Initialise. */
205    result = 0;
206 
207 /* Check the global error status. */
208    if ( !astOK ) return result;
209 
210 /* Obtain pointers to the two UnitMap structures. */
211    this = (AstUnitMap *) this_object;
212    that = (AstUnitMap *) that_object;
213 
214 /* Check the second object is a UnitMap. We know the first is a
215    UnitMap since we have arrived at this implementation of the virtual
216    function. */
217    if( astIsAUnitMap( that ) ) {
218 
219 /* Get the number of inputs check they are the same for both. */
220       result = ( astGetNin( this ) == astGetNin( that ) );
221 
222    }
223 
224 /* If an error occurred, clear the result value. */
225    if ( !astOK ) result = 0;
226 
227 /* Return the result, */
228    return result;
229 }
230 
GetIsLinear(AstMapping * this_mapping,int * status)231 static int GetIsLinear( AstMapping *this_mapping, int *status ){
232 /*
233 *  Name:
234 *     GetIsLinear
235 
236 *  Purpose:
237 *     Return the value of the IsLinear attribute for a UnitMap.
238 
239 *  Type:
240 *     Private function.
241 
242 *  Synopsis:
243 *     #include "mapping.h"
244 *     void GetIsLinear( AstMapping *this, int *status )
245 
246 *  Class Membership:
247 *     UnitMap member function (over-rides the protected astGetIsLinear
248 *     method inherited from the Mapping class).
249 
250 *  Description:
251 *     This function returns the value of the IsLinear attribute for a
252 *     Frame, which is always one.
253 
254 *  Parameters:
255 *     this
256 *        Pointer to the UnitMap.
257 *     status
258 *        Pointer to the inherited status variable.
259 */
260    return 1;
261 }
262 
astInitUnitMapVtab_(AstUnitMapVtab * vtab,const char * name,int * status)263 void astInitUnitMapVtab_(  AstUnitMapVtab *vtab, const char *name, int *status ) {
264 /*
265 *+
266 *  Name:
267 *     astInitUnitMapVtab
268 
269 *  Purpose:
270 *     Initialise a virtual function table for a UnitMap.
271 
272 *  Type:
273 *     Protected function.
274 
275 *  Synopsis:
276 *     #include "unitmap.h"
277 *     void astInitUnitMapVtab( AstUnitMapVtab *vtab, const char *name )
278 
279 *  Class Membership:
280 *     UnitMap vtab initialiser.
281 
282 *  Description:
283 *     This function initialises the component of a virtual function
284 *     table which is used by the UnitMap class.
285 
286 *  Parameters:
287 *     vtab
288 *        Pointer to the virtual function table. The components used by
289 *        all ancestral classes will be initialised if they have not already
290 *        been initialised.
291 *     name
292 *        Pointer to a constant null-terminated character string which contains
293 *        the name of the class to which the virtual function table belongs (it
294 *        is this pointer value that will subsequently be returned by the Object
295 *        astClass function).
296 *-
297 */
298 
299 /* Local Variables: */
300    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
301    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
302    AstMappingVtab *mapping;      /* Pointer to Mapping component of Vtab */
303 
304 /* Check the local error status. */
305    if ( !astOK ) return;
306 
307 /* Get a pointer to the thread specific global data structure. */
308    astGET_GLOBALS(NULL);
309 
310 /* Initialize the component of the virtual function table used by the
311    parent class. */
312    astInitMappingVtab( (AstMappingVtab *) vtab, name );
313 
314 /* Store a unique "magic" value in the virtual function table. This
315    will be used (by astIsAUnitMap) to determine if an object belongs
316    to this class.  We can conveniently use the address of the (static)
317    class_check variable to generate this unique value. */
318    vtab->id.check = &class_check;
319    vtab->id.parent = &(((AstMappingVtab *) vtab)->id);
320 
321 /* Initialise member function pointers. */
322 /* ------------------------------------ */
323 /* Store pointers to the member functions (implemented here) that
324    provide virtual methods for this class. */
325 
326 /* None. */
327 
328 /* Save the inherited pointers to methods that will be extended, and
329    replace them with pointers to the new member functions. */
330    object = (AstObjectVtab *) vtab;
331    mapping = (AstMappingVtab *) vtab;
332 
333    parent_transform = mapping->Transform;
334    mapping->Transform = Transform;
335 
336 /* Store replacement pointers for methods which will be over-ridden by
337    new member functions implemented here. */
338    object->Equal = Equal;
339    mapping->MapMerge = MapMerge;
340    mapping->MapSplit = MapSplit;
341    mapping->Rate = Rate;
342    mapping->GetIsLinear = GetIsLinear;
343 
344 /* Declare the class dump function. There is no copy constructor or
345    destructor. */
346    astSetDump( vtab, Dump, "UnitMap", "Unit (null) Mapping" );
347 
348 /* If we have just initialised the vtab for the current class, indicate
349    that the vtab is now initialised, and store a pointer to the class
350    identifier in the base "object" level of the vtab. */
351    if( vtab == &class_vtab ) {
352       class_init = 1;
353       astSetVtabClassIdentifier( vtab, &(vtab->id) );
354    }
355 }
356 
MapMerge(AstMapping * this,int where,int series,int * nmap,AstMapping *** map_list,int ** invert_list,int * status)357 static int MapMerge( AstMapping *this, int where, int series, int *nmap,
358                      AstMapping ***map_list, int **invert_list, int *status ) {
359 /*
360 *  Name:
361 *     MapMerge
362 
363 *  Purpose:
364 *     Simplify a sequence of Mappings containing a UnitMap.
365 
366 *  Type:
367 *     Private function.
368 
369 *  Synopsis:
370 *     #include "mapping.h"
371 *     int MapMerge( AstMapping *this, int where, int series, int *nmap,
372 *                   AstMapping ***map_list, int **invert_list, int *status )
373 
374 *  Class Membership:
375 *     UnitMap method (over-rides the protected astMapMerge method
376 *     inherited from the Mapping class).
377 
378 *  Description:
379 *     This function attempts to simplify a sequence of Mappings by
380 *     merging a nominated UnitMap in the sequence with its neighbours,
381 *     so as to shorten the sequence if possible.
382 *
383 *     In many cases, simplification will not be possible and the
384 *     function will return -1 to indicate this, without further
385 *     action.
386 *
387 *     In most cases of interest, however, this function will either
388 *     attempt to replace the nominated UnitMap with one which it
389 *     considers simpler, or to merge it with the Mappings which
390 *     immediately precede it or follow it in the sequence (both will
391 *     normally be considered). This is sufficient to ensure the
392 *     eventual simplification of most Mapping sequences by repeated
393 *     application of this function.
394 *
395 *     In some cases, the function may attempt more elaborate
396 *     simplification, involving any number of other Mappings in the
397 *     sequence. It is not restricted in the type or scope of
398 *     simplification it may perform, but will normally only attempt
399 *     elaborate simplification in cases where a more straightforward
400 *     approach is not adequate.
401 
402 *  Parameters:
403 *     this
404 *        Pointer to the nominated UnitMap which is to be merged with
405 *        its neighbours. This should be a cloned copy of the UnitMap
406 *        pointer contained in the array element "(*map_list)[where]"
407 *        (see below). This pointer will not be annulled, and the
408 *        UnitMap it identifies will not be modified by this function.
409 *     where
410 *        Index in the "*map_list" array (below) at which the pointer
411 *        to the nominated UnitMap resides.
412 *     series
413 *        A non-zero value indicates that the sequence of Mappings to
414 *        be simplified will be applied in series (i.e. one after the
415 *        other), whereas a zero value indicates that they will be
416 *        applied in parallel (i.e. on successive sub-sets of the
417 *        input/output coordinates).
418 *     nmap
419 *        Address of an int which counts the number of Mappings in the
420 *        sequence. On entry this should be set to the initial number
421 *        of Mappings. On exit it will be updated to record the number
422 *        of Mappings remaining after simplification.
423 *     map_list
424 *        Address of a pointer to a dynamically allocated array of
425 *        Mapping pointers (produced, for example, by the astMapList
426 *        method) which identifies the sequence of Mappings. On entry,
427 *        the initial sequence of Mappings to be simplified should be
428 *        supplied.
429 *
430 *        On exit, the contents of this array will be modified to
431 *        reflect any simplification carried out. Any form of
432 *        simplification may be performed. This may involve any of: (a)
433 *        removing Mappings by annulling any of the pointers supplied,
434 *        (b) replacing them with pointers to new Mappings, (c)
435 *        inserting additional Mappings and (d) changing their order.
436 *
437 *        The intention is to reduce the number of Mappings in the
438 *        sequence, if possible, and any reduction will be reflected in
439 *        the value of "*nmap" returned. However, simplifications which
440 *        do not reduce the length of the sequence (but improve its
441 *        execution time, for example) may also be performed, and the
442 *        sequence might conceivably increase in length (but normally
443 *        only in order to split up a Mapping into pieces that can be
444 *        more easily merged with their neighbours on subsequent
445 *        invocations of this function).
446 *
447 *        If Mappings are removed from the sequence, any gaps that
448 *        remain will be closed up, by moving subsequent Mapping
449 *        pointers along in the array, so that vacated elements occur
450 *        at the end. If the sequence increases in length, the array
451 *        will be extended (and its pointer updated) if necessary to
452 *        accommodate any new elements.
453 *
454 *        Note that any (or all) of the Mapping pointers supplied in
455 *        this array may be annulled by this function, but the Mappings
456 *        to which they refer are not modified in any way (although
457 *        they may, of course, be deleted if the annulled pointer is
458 *        the final one).
459 *     invert_list
460 *        Address of a pointer to a dynamically allocated array which,
461 *        on entry, should contain values to be assigned to the Invert
462 *        attributes of the Mappings identified in the "*map_list"
463 *        array before they are applied (this array might have been
464 *        produced, for example, by the astMapList method). These
465 *        values will be used by this function instead of the actual
466 *        Invert attributes of the Mappings supplied, which are
467 *        ignored.
468 *
469 *        On exit, the contents of this array will be updated to
470 *        correspond with the possibly modified contents of the
471 *        "*map_list" array.  If the Mapping sequence increases in
472 *        length, the "*invert_list" array will be extended (and its
473 *        pointer updated) if necessary to accommodate any new
474 *        elements.
475 *     status
476 *        Pointer to the inherited status variable.
477 
478 *  Returned Value:
479 *     If simplification was possible, the function returns the index
480 *     in the "map_list" array of the first element which was
481 *     modified. Otherwise, it returns -1 (and makes no changes to the
482 *     arrays supplied).
483 
484 *  Notes:
485 *     - A value of -1 will be returned if this function is invoked
486 *     with the global error status set, or if it should fail for any
487 *     reason.
488 */
489 
490 /* Local Variables: */
491    AstMapping *new;              /* Pointer to replacement UnitMap */
492    const char *class;            /* Pointer to Mapping class string */
493    int i1;                       /* Index of first UnitMap to merge */
494    int i2;                       /* Index of last UnitMap to merge */
495    int i;                        /* Loop counter for Mappings */
496    int ngone;                    /* Number of UnitMaps eliminated */
497    int nin;                      /* Number of coordinates for UnitMap */
498    int result;                   /* Result value to return */
499 
500 /* Initialise. */
501    result = -1;
502 
503 /* Check the global error status. */
504    if ( !astOK ) return result;
505 
506 /* If the Mapping sequence consists of a single UnitMap, simply check
507    if the asociated Invert flag is set, and clear it if necessary. */
508    if ( *nmap == 1 ) {
509       if ( ( *invert_list )[ 0 ] ) {
510          ( *invert_list )[ 0 ] = 0;
511 
512 /* Note if the Mapping sequence was modified. */
513          result = 0;
514       }
515 
516 /* In series. */
517 /* ========== */
518 /* If a UnitMap occurs in series with any other Mapping, it can simply
519    be eliminated, so annul its Mapping pointer. */
520    } else if ( *nmap > 1 ) {
521       if ( series ) {
522          ( *map_list )[ where ] = astAnnul( ( *map_list )[ where ] );
523 
524 /* Loop to move any following pointers and their Invert flags down in
525    the array to fill the gap, and clear the vacated elements at the
526    end of the arrays. */
527          for ( i = where + 1; i < *nmap; i++ ) {
528             ( *map_list )[ i - 1 ] = ( *map_list )[ i ];
529             ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ];
530          }
531          ( *map_list )[ *nmap - 1 ] = NULL;
532          ( *invert_list )[ *nmap - 1 ] = 0;
533 
534 /* Decrement the Mapping count and return the index of the first
535    modified element. */
536          ( *nmap )--;
537          result = where;
538 
539 /* In parallel. */
540 /* ============ */
541 /* If a UnitMap occurs in parallel with other Mappings, it can be
542    merged with any UnitMaps on either side of itself. */
543       } else {
544 
545 /* Initialise indices to identify any adjacent UnitMaps and the number
546    of coordinates to be handled by the replacement. */
547          i1 = i2 = where;
548          nin = astGetNin( ( *map_list )[ where ] );
549 
550 /* Loop to inspect earlier Mappings, obtaining the Mapping Class name
551    and checking it is "UnitMap". Quit looping as soon as any other
552    class of Mapping is found. */
553          while ( i1 - 1 >= 0 ) {
554             class = astGetClass( ( *map_list )[ i1 - 1 ] );
555             if ( !astOK || strcmp( class, "UnitMap" ) ) break;
556 
557 /* Update the index of the earliest UnitMap that is to be merged and
558    increment the total number of coordinates involved. */
559             i1--;
560             nin += astGetNin( ( *map_list )[ i1 ] );
561          }
562 
563 /* Repeat the above process to inspect any later Mappings in the
564    sequence. */
565          while ( i2 + 1 < *nmap ) {
566             class = astGetClass( ( *map_list )[ i2 + 1 ] );
567             if ( !astOK || strcmp( class, "UnitMap" ) ) break;
568             i2++;
569             nin += astGetNin( ( *map_list )[ i2 ] );
570          }
571 
572 /* Calculate the net number of Mappings that can be removed from the
573    sequence and check if this is zero, meaning that there were no
574    adjacent UnitMaps to merge with. */
575          if ( astOK ) {
576             ngone = i2 - i1;
577             if ( !ngone ) {
578 
579 /* If so, simply check if the nominated UnitMap's Invert flag is set,
580    and clear it if necessary. */
581                if ( ( *invert_list )[ where ] ) {
582                   ( *invert_list )[ where ] = 0;
583 
584 /* Note if the Mapping sequence was modified. */
585                   result = where;
586                }
587 
588 /* If UnitMaps can be merged, create the replacement UnitMap. */
589             } else {
590                new = (AstMapping *) astUnitMap( nin, "", status );
591                if ( astOK ) {
592 
593 /* Annul the pointers to all the UnitMaps that are being replaced. */
594                   for ( i = i1; i <= i2; i++ ) {
595                      ( *map_list )[ i ] = astAnnul( ( *map_list )[ i ] );
596                   }
597 
598 /* Insert the new pointer and the associated Invert flag. */
599                   ( *map_list )[ i1 ] = new;
600                   ( *invert_list )[ i1 ] = 0;
601 
602 /* Loop to close the resulting gap by moving subsequent elements down
603    in the arrays. */
604                   for ( i = i2 + 1; i < *nmap; i++ ) {
605                      ( *map_list )[ i - ngone ] = ( *map_list )[ i ];
606                      ( *invert_list )[ i - ngone ] = ( *invert_list )[ i ];
607                   }
608 
609 /* Clear the vacated elements at the end. */
610                   for ( i = *nmap - ngone; i < *nmap; i++ ) {
611                      ( *map_list )[ i ] = NULL;
612                      ( *invert_list )[ i ] = 0;
613                   }
614 
615 /* Decrement the Mapping count and return the index of the first
616    modified element. */
617                   ( *nmap ) -= ngone;
618                   result = i1;
619                }
620             }
621          }
622       }
623    }
624 
625 /* Return the result. */
626    return result;
627 }
628 
MapSplit(AstMapping * this_map,int nin,const int * in,AstMapping ** map,int * status)629 static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){
630 /*
631 *  Name:
632 *     MapSplit
633 
634 *  Purpose:
635 *     Create a Mapping representing a subset of the inputs of an existing
636 *     UnitMap.
637 
638 *  Type:
639 *     Private function.
640 
641 *  Synopsis:
642 *     #include "unitmap.h"
643 *     int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status )
644 
645 *  Class Membership:
646 *     UnitMap method (over-rides the protected astMapSplit method
647 *     inherited from the Mapping class).
648 
649 *  Description:
650 *     This function creates a new Mapping by picking specified inputs from
651 *     an existing UnitMap. This is only possible if the specified inputs
652 *     correspond to some subset of the UnitMap outputs. That is, there
653 *     must exist a subset of the UnitMap outputs for which each output
654 *     depends only on the selected UnitMap inputs, and not on any of the
655 *     inputs which have not been selected. If this condition is not met
656 *     by the supplied UnitMap, then a NULL Mapping is returned.
657 
658 *  Parameters:
659 *     this
660 *        Pointer to the UnitMap to be split (the UnitMap is not actually
661 *        modified by this function).
662 *     nin
663 *        The number of inputs to pick from "this".
664 *     in
665 *        Pointer to an array of indices (zero based) for the inputs which
666 *        are to be picked. This array should have "nin" elements. If "Nin"
667 *        is the number of inputs of the supplied UnitMap, then each element
668 *        should have a value in the range zero to Nin-1.
669 *     map
670 *        Address of a location at which to return a pointer to the new
671 *        Mapping. This Mapping will have "nin" inputs (the number of
672 *        outputs may be different to "nin"). A NULL pointer will be
673 *        returned if the supplied UnitMap has no subset of outputs which
674 *        depend only on the selected inputs.
675 *     status
676 *        Pointer to the inherited status variable.
677 
678 *  Returned Value:
679 *     A pointer to a dynamically allocated array of ints. The number of
680 *     elements in this array will equal the number of outputs for the
681 *     returned Mapping. Each element will hold the index of the
682 *     corresponding output in the supplied UnitMap. The array should be
683 *     freed using astFree when no longer needed. A NULL pointer will
684 *     be returned if no output Mapping can be created.
685 
686 *  Notes:
687 *     - If this function is invoked with the global error status set,
688 *     or if it should fail for any reason, then NULL values will be
689 *     returned as the function value and for the "map" pointer.
690 */
691 
692 /* Local Variables: */
693    AstUnitMap *this;          /* Pointer to UnitMap structure */
694    int *result;               /* Pointer to returned array */
695    int i;                     /* Loop count */
696    int iin;                   /* Mapping input index */
697    int mnin;                  /* No. of Mapping inputs */
698    int ok;                    /* Are input indices OK? */
699 
700 /* Initialise */
701    result = NULL;
702    *map = NULL;
703 
704 /* Check the global error status. */
705    if ( !astOK ) return result;
706 
707 /* Get a pointer to the UnitMap structure. */
708    this = (AstUnitMap *) this_map;
709 
710 /* Allocate memory for the returned array and create a UnitMap with the
711    required number of axes. */
712    result = astMalloc( sizeof( int )*(size_t) nin );
713    *map = (AstMapping *) astUnitMap( nin, "", status );
714 
715 /* Check pointers can be used safely. */
716    if( astOK ) {
717 
718 /* Store the required output axis indices. At the same time check that each
719    axis is valid. */
720       mnin = astGetNin( this );
721       ok = 1;
722       for( i = 0; i < nin; i++ ) {
723          iin = in[ i ];
724          if( iin >= 0 && iin < mnin ) {
725             result[ i ] = iin;
726          } else {
727             ok = 0;
728             break;
729          }
730       }
731 
732 /* If the "in" array contained any invalid values, free the returned
733    resources. */
734       if( !ok ) {
735          result = astFree( result );
736          *map = astAnnul( *map );
737       }
738    }
739 
740 /* Free returned resources if an error has occurred. */
741    if( !astOK ) {
742       result = astFree( result );
743       *map = astAnnul( *map );
744    }
745 
746 /* Return the list of output indices. */
747    return result;
748 }
749 
Rate(AstMapping * this,double * at,int ax1,int ax2,int * status)750 static double Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ){
751 /*
752 *  Name:
753 *     Rate
754 
755 *  Purpose:
756 *     Calculate the rate of change of a Mapping output.
757 
758 *  Type:
759 *     Private function.
760 
761 *  Synopsis:
762 *     #include "unitmap.h"
763 *     result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status )
764 
765 *  Class Membership:
766 *     UnitMap member function (overrides the astRate method inherited
767 *     from the Mapping class ).
768 
769 *  Description:
770 *     This function returns the rate of change of a specified output of
771 *     the supplied Mapping with respect to a specified input, at a
772 *     specified input position.
773 
774 *  Parameters:
775 *     this
776 *        Pointer to the Mapping to be applied.
777 *     at
778 *        The address of an array holding the axis values at the position
779 *        at which the rate of change is to be evaluated. The number of
780 *        elements in this array should equal the number of inputs to the
781 *        Mapping.
782 *     ax1
783 *        The index of the Mapping output for which the rate of change is to
784 *        be found (output numbering starts at 0 for the first output).
785 *     ax2
786 *        The index of the Mapping input which is to be varied in order to
787 *        find the rate of change (input numbering starts at 0 for the first
788 *        input).
789 *     status
790 *        Pointer to the inherited status variable.
791 
792 *  Returned Value:
793 *     The rate of change of Mapping output "ax1" with respect to input
794 *     "ax2", evaluated at "at", or AST__BAD if the value cannot be
795 *     calculated.
796 
797 */
798 
799    return ( ax1 == ax2 ) ? 1.0 : 0.0;
800 }
801 
Transform(AstMapping * this,AstPointSet * in,int forward,AstPointSet * out,int * status)802 static AstPointSet *Transform( AstMapping *this, AstPointSet *in,
803                                int forward, AstPointSet *out, int *status ) {
804 /*
805 *  Name:
806 *     Transform
807 
808 *  Purpose:
809 *     Apply a UnitMap to transform a set of points.
810 
811 *  Type:
812 *     Private function.
813 
814 *  Synopsis:
815 *     #include "unitmap.h"
816 *     AstPointSet *Transform( AstMapping *this, AstPointSet *in,
817 *                             int forward, AstPointSet *out, int *status )
818 
819 *  Class Membership:
820 *     UnitMap member function (over-rides the astTransform method inherited
821 *     from the Mapping class).
822 
823 *  Description:
824 *     This function takes a UnitMap and a set of points encapsulated in a
825 *     PointSet and transforms the points so as to perform the identity
826 *     transformation (i.e. simply copies the coordinate values).
827 
828 *  Parameters:
829 *     this
830 *        Pointer to the UnitMap.
831 *     in
832 *        Pointer to the PointSet holding the input coordinate data.
833 *     forward
834 *        A non-zero value indicates that the forward coordinate transformation
835 *        should be applied, while a zero value requests the inverse
836 *        transformation. In this case, both transformations are equivalent.
837 *     out
838 *        Pointer to a PointSet which will hold the transformed (output)
839 *        coordinate values. A NULL value may also be given, in which case a
840 *        new PointSet will be created by this function.
841 *     status
842 *        Pointer to the inherited status variable.
843 
844 *  Returned Value:
845 *     Pointer to the output (possibly new) PointSet.
846 
847 *  Notes:
848 *     -  A null pointer will be returned if this function is invoked with the
849 *     global error status set, or if it should fail for any reason.
850 *     -  The number of coordinate values per point in the input PointSet must
851 *     match the number of coordinates for the UnitMap being applied.
852 *     -  If an output PointSet is supplied, it must have space for sufficient
853 *     number of points and coordinate values per point to accommodate the
854 *     result. Any excess space will be ignored.
855 */
856 
857 /* Local Variables: */
858    AstPointSet *result;          /* Pointer to output PointSet */
859    AstUnitMap *map;              /* Pointer to UnitMap to be applied */
860    double **ptr_in;              /* Pointer to input coordinate data */
861    double **ptr_out;             /* Pointer to output coordinate data */
862    int coord;                    /* Loop counter for coordinates */
863    int ncoord_in;                /* Number of coordinates per input point */
864    int npoint;                   /* Number of points */
865 
866 /* Check the global error status. */
867    if ( !astOK ) return NULL;
868 
869 /* Obtain a pointer to the UnitMap. */
870    map = (AstUnitMap *) this;
871 
872 /* Apply the parent mapping using the stored pointer to the Transform member
873    function inherited from the parent Mapping class. This function validates
874    all arguments and generates an output PointSet if necessary, but does not
875    actually transform any coordinate values. */
876    result = (*parent_transform)( this, in, forward, out, status );
877 
878 /* We will now extend the parent astTransform method by performing the
879    coordinate copy needed to generate the output coordinate values. */
880 
881 /* Determine the numbers of points and coordinates per point from the input
882    PointSet and obtain pointers for accessing the input and output coordinate
883    values. */
884    ncoord_in = astGetNcoord( in );
885    npoint = astGetNpoint( in );
886    ptr_in = astGetPoints( in );
887    ptr_out = astGetPoints( result );
888 
889 /* We need not determine whether to apply the forward or inverse
890    transformation, as they are both the same. */
891 
892 /* Copy the coordinate values. */
893 /* --------------------------- */
894    if ( astOK ) {
895 
896 /* Loop to copy the values for each coordinate. Use a memory copy for speed.
897    Do not do the copy if the input and output arrays are the same. */
898       for ( coord = 0; coord < ncoord_in; coord++ ) {
899          if( ptr_out[ coord ] != ptr_in[ coord ] ) {
900             (void) memcpy( (void *) ptr_out[ coord ],
901                            (const void *) ptr_in[ coord ],
902                            sizeof( double ) * (size_t) npoint );
903          }
904       }
905    }
906 
907 /* Return a pointer to the output PointSet. */
908    return result;
909 }
910 
911 /* Copy constructor. */
912 /* ----------------- */
913 /* No copy constructor is needed, as a byte-by-byte copy suffices. */
914 
915 /* Destructor. */
916 /* ----------- */
917 /* No destructor is needed as no memory, etc. needs freeing. */
918 
919 /* Dump function. */
920 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)921 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
922 /*
923 *  Name:
924 *     Dump
925 
926 *  Purpose:
927 *     Dump function for UnitMap objects.
928 
929 *  Type:
930 *     Private function.
931 
932 *  Synopsis:
933 *     void Dump( AstObject *this, AstChannel *channel, int *status )
934 
935 *  Description:
936 *     This function implements the Dump function which writes out data
937 *     for the UnitMap class to an output Channel.
938 
939 *  Parameters:
940 *     this
941 *        Pointer to the UnitMap whose data are being written.
942 *     channel
943 *        Pointer to the Channel to which the data are being written.
944 *     status
945 *        Pointer to the inherited status variable.
946 */
947 
948 /* Local Variables: */
949    AstUnitMap *this;             /* Pointer to the UnitMap structure */
950 
951 /* Check the global error status. */
952    if ( !astOK ) return;
953 
954 /* Obtain a pointer to the UnitMap structure. */
955    this = (AstUnitMap *) this_object;
956 
957 /* Write out values representing the instance variables for the
958    UnitMap class.  Accompany these with appropriate comment strings,
959    possibly depending on the values being written.*/
960 
961 /* In the case of attributes, we first use the appropriate (private)
962    Test...  member function to see if they are set. If so, we then use
963    the (private) Get... function to obtain the value to be written
964    out.
965 
966    For attributes which are not set, we use the astGet... method to
967    obtain the value instead. This will supply a default value
968    (possibly provided by a derived class which over-rides this method)
969    which is more useful to a human reader as it corresponds to the
970    actual default attribute value.  Since "set" will be zero, these
971    values are for information only and will not be read back. */
972 
973 /* There are no values to write, so return without further action. */
974 }
975 
976 /* Standard class functions. */
977 /* ========================= */
978 /* Implement the astIsAUnitMap and astCheckUnitMap functions using the macros
979    defined for this purpose in the "object.h" header file. */
astMAKE_ISA(UnitMap,Mapping)980 astMAKE_ISA(UnitMap,Mapping)
981 astMAKE_CHECK(UnitMap)
982 
983 AstUnitMap *astUnitMap_( int ncoord, const char *options, int *status, ...) {
984 /*
985 *++
986 *  Name:
987 c     astUnitMap
988 f     AST_UNITMAP
989 
990 *  Purpose:
991 *     Create a UnitMap.
992 
993 *  Type:
994 *     Public function.
995 
996 *  Synopsis:
997 c     #include "unitmap.h"
998 c     AstUnitMap *astUnitMap( int ncoord, const char *options, ... )
999 f     RESULT = AST_UNITMAP( NCOORD, OPTIONS, STATUS )
1000 
1001 *  Class Membership:
1002 *     UnitMap constructor.
1003 
1004 *  Description:
1005 *     This function creates a new UnitMap and optionally initialises
1006 *     its attributes.
1007 *
1008 *     A UnitMap is a unit (null) Mapping that has no effect on the
1009 *     coordinates supplied to it. They are simply copied. This can be
1010 *     useful if a Mapping is required (e.g. to pass to another
1011 c     function) but you do not want it to have any effect.
1012 f     routine) but you do not want it to have any effect.
1013 
1014 *  Parameters:
1015 c     ncoord
1016 f     NCOORD = INTEGER (Given)
1017 *        The number of input and output coordinates (these numbers are
1018 *        necessarily the same).
1019 c     options
1020 f     OPTIONS = CHARACTER * ( * ) (Given)
1021 c        Pointer to a null-terminated string containing an optional
1022 c        comma-separated list of attribute assignments to be used for
1023 c        initialising the new UnitMap. The syntax used is identical to
1024 c        that for the astSet function and may include "printf" format
1025 c        specifiers identified by "%" symbols in the normal way.
1026 f        A character string containing an optional comma-separated
1027 f        list of attribute assignments to be used for initialising the
1028 f        new UnitMap. The syntax used is identical to that for the
1029 f        AST_SET routine.
1030 c     ...
1031 c        If the "options" string contains "%" format specifiers, then
1032 c        an optional list of additional arguments may follow it in
1033 c        order to supply values to be substituted for these
1034 c        specifiers. The rules for supplying these are identical to
1035 c        those for the astSet function (and for the C "printf"
1036 c        function).
1037 f     STATUS = INTEGER (Given and Returned)
1038 f        The global status.
1039 
1040 *  Returned Value:
1041 c     astUnitMap()
1042 f     AST_UNITMAP = INTEGER
1043 *        A pointer to the new UnitMap.
1044 
1045 *  Notes:
1046 *     - A null Object pointer (AST__NULL) will be returned if this
1047 c     function is invoked with the AST error status set, or if it
1048 f     function is invoked with STATUS set to an error value, or if it
1049 *     should fail for any reason.
1050 *--
1051 */
1052 
1053 /* Local Variables: */
1054    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1055    AstUnitMap *new;              /* Pointer to new UnitMap */
1056    va_list args;                 /* Variable argument list */
1057 
1058 /* Get a pointer to the thread specific global data structure. */
1059    astGET_GLOBALS(NULL);
1060 
1061 /* Check the global status. */
1062    if ( !astOK ) return NULL;
1063 
1064 /* Initialise the UnitMap, allocating memory and initialising the
1065    virtual function table as well if necessary. */
1066    new = astInitUnitMap( NULL, sizeof( AstUnitMap ), !class_init, &class_vtab,
1067                          "UnitMap", ncoord );
1068 
1069 /* If successful, note that the virtual function table has been
1070    initialised. */
1071    if ( astOK ) {
1072       class_init = 1;
1073 
1074 /* Obtain the variable argument list and pass it along with the
1075    options string to the astVSet method to initialise the new
1076    UnitMap's attributes. */
1077       va_start( args, status );
1078       astVSet( new, options, NULL, args );
1079       va_end( args );
1080 
1081 /* If an error occurred, clean up by deleting the new object. */
1082       if ( !astOK ) new = astDelete( new );
1083    }
1084 
1085 /* Return a pointer to the new UnitMap. */
1086    return new;
1087 }
1088 
astUnitMapId_(int ncoord,const char * options,...)1089 AstUnitMap *astUnitMapId_( int ncoord, const char *options, ... ) {
1090 /*
1091 *  Name:
1092 *     astUnitMapId_
1093 
1094 *  Purpose:
1095 *     Create a UnitMap.
1096 
1097 *  Type:
1098 *     Private function.
1099 
1100 *  Synopsis:
1101 *     #include "unitmap.h"
1102 *     AstUnitMap *astUnitMapId_( int ncoord, const char *options, ... )
1103 
1104 *  Class Membership:
1105 *     UnitMap constructor.
1106 
1107 *  Description:
1108 *     This function implements the external (public) interface to the
1109 *     astUnitMap constructor function. It returns an ID value (instead
1110 *     of a true C pointer) to external users, and must be provided
1111 *     because astUnitMap_ has a variable argument list which cannot be
1112 *     encapsulated in a macro (where this conversion would otherwise
1113 *     occur).
1114 *
1115 *     The variable argument list also prevents this function from
1116 *     invoking astUnitMap_ directly, so it must be a re-implementation
1117 *     of it in all respects, except for the final conversion of the
1118 *     result to an ID value.
1119 
1120 *  Parameters:
1121 *     As for astUnitMap_.
1122 
1123 *  Returned Value:
1124 *     The ID value associated with the new UnitMap.
1125 */
1126 
1127 /* Local Variables: */
1128    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1129    AstUnitMap *new;              /* Pointer to new UnitMap */
1130    va_list args;                 /* Variable argument list */
1131 
1132    int *status;                  /* Pointer to inherited status value */
1133 
1134 /* Get a pointer to the inherited status value. */
1135    status = astGetStatusPtr;
1136 
1137 /* Get a pointer to the thread specific global data structure. */
1138    astGET_GLOBALS(NULL);
1139 
1140 /* Check the global status. */
1141    if ( !astOK ) return NULL;
1142 
1143 /* Initialise the UnitMap, allocating memory and initialising the
1144    virtual function table as well if necessary. */
1145    new = astInitUnitMap( NULL, sizeof( AstUnitMap ), !class_init, &class_vtab,
1146                          "UnitMap", ncoord );
1147 
1148 /* If successful, note that the virtual function table has been
1149    initialised. */
1150    if ( astOK ) {
1151       class_init = 1;
1152 
1153 /* Obtain the variable argument list and pass it along with the
1154    options string to the astVSet method to initialise the new
1155    UnitMap's attributes. */
1156       va_start( args, options );
1157       astVSet( new, options, NULL, args );
1158       va_end( args );
1159 
1160 /* If an error occurred, clean up by deleting the new object. */
1161       if ( !astOK ) new = astDelete( new );
1162    }
1163 
1164 /* Return an ID value for the new UnitMap. */
1165    return astMakeId( new );
1166 }
1167 
astInitUnitMap_(void * mem,size_t size,int init,AstUnitMapVtab * vtab,const char * name,int ncoord,int * status)1168 AstUnitMap *astInitUnitMap_( void *mem, size_t size, int init,
1169                              AstUnitMapVtab *vtab, const char *name,
1170                              int ncoord, int *status ) {
1171 /*
1172 *+
1173 *  Name:
1174 *     astInitUnitMap
1175 
1176 *  Purpose:
1177 *     Initialise a UnitMap.
1178 
1179 *  Type:
1180 *     Protected function.
1181 
1182 *  Synopsis:
1183 *     #include "unitmap.h"
1184 *     AstUnitMap *astInitUnitMap( void *mem, size_t size, int init,
1185 *                                 AstUnitMapVtab *vtab, const char *name,
1186 *                                 int ncoord )
1187 
1188 *  Class Membership:
1189 *     UnitMap initialiser.
1190 
1191 *  Description:
1192 *     This function is provided for use by class implementations to initialise
1193 *     a new UnitMap object. It allocates memory (if necessary) to accommodate
1194 *     the UnitMap plus any additional data associated with the derived class.
1195 *     It then initialises a UnitMap structure at the start of this memory. If
1196 *     the "init" flag is set, it also initialises the contents of a virtual
1197 *     function table for a UnitMap at the start of the memory passed via the
1198 *     "vtab" parameter.
1199 
1200 *  Parameters:
1201 *     mem
1202 *        A pointer to the memory in which the UnitMap is to be initialised.
1203 *        This must be of sufficient size to accommodate the UnitMap data
1204 *        (sizeof(UnitMap)) plus any data used by the derived class. If a value
1205 *        of NULL is given, this function will allocate the memory itself using
1206 *        the "size" parameter to determine its size.
1207 *     size
1208 *        The amount of memory used by the UnitMap (plus derived class data).
1209 *        This will be used to allocate memory if a value of NULL is given for
1210 *        the "mem" parameter. This value is also stored in the UnitMap
1211 *        structure, so a valid value must be supplied even if not required for
1212 *        allocating memory.
1213 *     init
1214 *        A logical flag indicating if the UnitMap's virtual function table is
1215 *        to be initialised. If this value is non-zero, the virtual function
1216 *        table will be initialised by this function.
1217 *     vtab
1218 *        Pointer to the start of the virtual function table to be associated
1219 *        with the new UnitMap.
1220 *     name
1221 *        Pointer to a constant null-terminated character string which contains
1222 *        the name of the class to which the new object belongs (it is this
1223 *        pointer value that will subsequently be returned by the Object
1224 *        astClass function).
1225 *     ncoord
1226 *        The number of coordinate values per point.
1227 
1228 *  Returned Value:
1229 *     A pointer to the new UnitMap.
1230 
1231 *  Notes:
1232 *     -  A null pointer will be returned if this function is invoked with the
1233 *     global error status set, or if it should fail for any reason.
1234 *-
1235 */
1236 
1237 /* Local Variables: */
1238    AstUnitMap *new;              /* Pointer to new UnitMap */
1239 
1240 /* Check the global status. */
1241    if ( !astOK ) return NULL;
1242 
1243 /* If necessary, initialise the virtual function table. */
1244    if ( init ) astInitUnitMapVtab( vtab, name );
1245 
1246 /* Initialise. */
1247    new = NULL;
1248 
1249 /* Initialise a Mapping structure (the parent class) as the first component
1250    within the UnitMap structure, allocating memory if necessary. Specify that
1251    the Mapping should be defined in both the forward and inverse directions. */
1252    new = (AstUnitMap *) astInitMapping( mem, size, 0,
1253                                         (AstMappingVtab *) vtab, name,
1254                                         ncoord, ncoord, 1, 1 );
1255 
1256       if ( astOK ) {
1257 
1258 /* Initialise the UnitMap data. */
1259 /* ---------------------------- */
1260 /* There is nothing else to store. */
1261 
1262 /* If an error occurred, clean up by deleting the new object (if any other
1263    resources had been allocated, we would free these first). */
1264       if ( !astOK ) new = astDelete( new );
1265    }
1266 
1267 /* Return a pointer to the new object. */
1268    return new;
1269 }
1270 
astLoadUnitMap_(void * mem,size_t size,AstUnitMapVtab * vtab,const char * name,AstChannel * channel,int * status)1271 AstUnitMap *astLoadUnitMap_( void *mem, size_t size,
1272                              AstUnitMapVtab *vtab, const char *name,
1273                              AstChannel *channel, int *status ) {
1274 /*
1275 *+
1276 *  Name:
1277 *     astLoadUnitMap
1278 
1279 *  Purpose:
1280 *     Load a UnitMap.
1281 
1282 *  Type:
1283 *     Protected function.
1284 
1285 *  Synopsis:
1286 *     #include "unitmap.h"
1287 *     AstUnitMap *astLoadUnitMap( void *mem, size_t size,
1288 *                                 AstUnitMapVtab *vtab, const char *name,
1289 *                                 AstChannel *channel )
1290 
1291 *  Class Membership:
1292 *     UnitMap loader.
1293 
1294 *  Description:
1295 *     This function is provided to load a new UnitMap using data read
1296 *     from a Channel. It first loads the data used by the parent class
1297 *     (which allocates memory if necessary) and then initialises a
1298 *     UnitMap structure in this memory, using data read from the input
1299 *     Channel.
1300 *
1301 *     If the "init" flag is set, it also initialises the contents of a
1302 *     virtual function table for a UnitMap at the start of the memory
1303 *     passed via the "vtab" parameter.
1304 
1305 
1306 *  Parameters:
1307 *     mem
1308 *        A pointer to the memory into which the UnitMap is to be
1309 *        loaded.  This must be of sufficient size to accommodate the
1310 *        UnitMap data (sizeof(UnitMap)) plus any data used by derived
1311 *        classes. If a value of NULL is given, this function will
1312 *        allocate the memory itself using the "size" parameter to
1313 *        determine its size.
1314 *     size
1315 *        The amount of memory used by the UnitMap (plus derived class
1316 *        data).  This will be used to allocate memory if a value of
1317 *        NULL is given for the "mem" parameter. This value is also
1318 *        stored in the UnitMap structure, so a valid value must be
1319 *        supplied even if not required for allocating memory.
1320 *
1321 *        If the "vtab" parameter is NULL, the "size" value is ignored
1322 *        and sizeof(AstUnitMap) is used instead.
1323 *     vtab
1324 *        Pointer to the start of the virtual function table to be
1325 *        associated with the new UnitMap. If this is NULL, a pointer
1326 *        to the (static) virtual function table for the UnitMap class
1327 *        is used instead.
1328 *     name
1329 *        Pointer to a constant null-terminated character string which
1330 *        contains the name of the class to which the new object
1331 *        belongs (it is this pointer value that will subsequently be
1332 *        returned by the astGetClass method).
1333 *
1334 *        If the "vtab" parameter is NULL, the "name" value is ignored
1335 *        and a pointer to the string "UnitMap" is used instead.
1336 
1337 *  Returned Value:
1338 *     A pointer to the new UnitMap.
1339 
1340 *  Notes:
1341 *     - A null pointer will be returned if this function is invoked
1342 *     with the global error status set, or if it should fail for any
1343 *     reason.
1344 *-
1345 */
1346 
1347 /* Local Variables: */
1348    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1349    AstUnitMap *new;              /* Pointer to the new UnitMap */
1350 
1351 /* Initialise. */
1352    new = NULL;
1353 
1354 /* Check the global error status. */
1355    if ( !astOK ) return new;
1356 
1357 /* Get a pointer to the thread specific global data structure. */
1358    astGET_GLOBALS(channel);
1359 
1360 /* If a NULL virtual function table has been supplied, then this is
1361    the first loader to be invoked for this UnitMap. In this case the
1362    UnitMap belongs to this class, so supply appropriate values to be
1363    passed to the parent class loader (and its parent, etc.). */
1364    if ( !vtab ) {
1365       size = sizeof( AstUnitMap );
1366       vtab = &class_vtab;
1367       name = "UnitMap";
1368 
1369 /* If required, initialise the virtual function table for this class. */
1370       if ( !class_init ) {
1371          astInitUnitMapVtab( vtab, name );
1372          class_init = 1;
1373       }
1374    }
1375 
1376 /* Invoke the parent class loader to load data for all the ancestral
1377    classes of the current one, returning a pointer to the resulting
1378    partly-built UnitMap. */
1379    new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name,
1380                          channel );
1381 
1382    if ( astOK ) {
1383 
1384 /* Read input data. */
1385 /* ================ */
1386 /* Request the input Channel to read all the input data appropriate to
1387    this class into the internal "values list". */
1388       astReadClassData( channel, "UnitMap" );
1389 
1390 /* Now read each individual data item from this list and use it to
1391    initialise the appropriate instance variable(s) for this class. */
1392 
1393 /* In the case of attributes, we first read the "raw" input value,
1394    supplying the "unset" value as the default. If a "set" value is
1395    obtained, we then use the appropriate (private) Set... member
1396    function to validate and set the value properly. */
1397 
1398 /* There are no values to read. */
1399 /* ---------------------------- */
1400 
1401 /* If an error occurred, clean up by deleting the new UnitMap. */
1402       if ( !astOK ) new = astDelete( new );
1403    }
1404 
1405 /* Return the new UnitMap pointer. */
1406    return new;
1407 }
1408 
1409 /* Virtual function interfaces. */
1410 /* ============================ */
1411 /* These provide the external interface to the virtual functions defined by
1412    this class. Each simply checks the global error status and then locates and
1413    executes the appropriate member function, using the function pointer stored
1414    in the object's virtual function table (this pointer is located using the
1415    astMEMBER macro defined in "object.h").
1416 
1417    Note that the member function may not be the one defined here, as it may
1418    have been over-ridden by a derived class. However, it should still have the
1419    same interface. */
1420 
1421 /* There are none of these. */
1422 
1423 
1424 
1425 
1426