1 /*
2 *class++
3 *  Name:
4 *     SwitchMap
5 
6 *  Purpose:
7 *     A Mapping that encapsulates a set of alternate Mappings.
8 
9 *  Constructor Function:
10 c     astSwitchMap
11 f     AST_SWITCHMAP
12 
13 *  Description:
14 *     A SwitchMap is a Mapping which represents a set of alternate
15 *     Mappings, each of which is used to transform positions within a
16 *     particular region of the input or output coordinate system of the
17 *     SwitchMap.
18 *
19 *     A SwitchMap can encapsulate any number of Mappings, but they must
20 *     all have the same number of inputs (Nin attribute value) and the
21 *     same number of outputs (Nout attribute value). The SwitchMap itself
22 *     inherits these same values for its Nin and Nout attributes. Each of
23 *     these Mappings represents a "route" through the switch, and are
24 *     referred to as "route" Mappings below. Each route Mapping transforms
25 *     positions between the input and output coordinate space of the entire
26 *     SwitchMap, but only one Mapping will be used to transform any given
27 *     position. The selection of the appropriate route Mapping to use with
28 *     any given input position is made by another Mapping, called the
29 *     "selector" Mapping. Each SwitchMap encapsulates two selector
30 *     Mappings in addition to its route Mappings; one for use with the
31 *     SwitchMap's forward transformation (called the "forward selector
32 *     Mapping"), and one for use with the SwitchMap's inverse transformation
33 *     (called the "inverse selector Mapping"). The forward selector Mapping
34 *     must have the same number of inputs as the route Mappings, but
35 *     should have only one output. Likewise, the inverse selector Mapping
36 *     must have the same number of outputs as the route Mappings, but
37 *     should have only one input.
38 *
39 *     When the SwitchMap is used to transform a position in the forward
40 *     direction (from input to output), each supplied input position is
41 *     first transformed by the forward transformation of the forward selector
42 *     Mapping. This produces a single output value for each input position
43 *     referred to as the selector value. The nearest integer to the selector
44 *     value is found, and is used to index the array of route Mappings (the
45 *     first supplied route Mapping has index 1, the second route Mapping has
46 *     index 2, etc). If the nearest integer to the selector value is less
47 *     than 1 or greater than the number of route Mappings, then the SwitchMap
48 *     output position is set to a value of AST__BAD on every axis. Otherwise,
49 *     the forward transformation of the selected route Mapping is used to
50 *     transform the supplied input position to produce the SwitchMap output
51 *     position.
52 *
53 *     When the SwitchMap is used to transform a position in the inverse
54 *     direction (from "output" to "input"), each supplied "output" position
55 *     is first transformed by the inverse transformation of the inverse
56 *     selector Mapping. This produces a selector value for each "output"
57 *     position. Again, the nearest integer to the selector value is found,
58 *     and is used to index the array of route Mappings. If this selector
59 *     index value is within the bounds of the array of route Mappings, then
60 *     the inverse transformation of the selected route Mapping is used to
61 *     transform the supplied "output" position to produce the SwitchMap
62 *     "input" position. If the selector index value is outside the bounds
63 *     of the array of route Mappings, then the SwitchMap "input" position is
64 *     set to a value of AST__BAD on every axis.
65 *
66 *     In practice, appropriate selector Mappings should be chosen to
67 *     associate a different route Mapping with each region of coordinate
68 *     space. Note that the SelectorMap class of Mapping is particularly
69 *     appropriate for this purpose.
70 *
71 *     If a compound Mapping contains a SwitchMap in series with its own
72 *     inverse, the combination of the two adjacent SwitchMaps will be
73 *     replaced by a UnitMap when the compound Mapping is simplified using
74 c     astSimplify.
75 f     AST_SIMPLIFY.
76 
77 *  Inheritance:
78 *     The SwitchMap class inherits from the Mapping class.
79 
80 *  Attributes:
81 *     The SwitchMap class does not define any new attributes beyond those
82 *     which are applicable to all Mappings.
83 
84 *  Functions:
85 c     The SwitchMap class does not define any new functions beyond those
86 f     The SwitchMap class does not define any new routines beyond those
87 *     which are applicable to all Mappings.
88 
89 *  Copyright:
90 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the Research Councils
91 
92 *  Licence:
93 *     This program is free software: you can redistribute it and/or
94 *     modify it under the terms of the GNU Lesser General Public
95 *     License as published by the Free Software Foundation, either
96 *     version 3 of the License, or (at your option) any later
97 *     version.
98 *
99 *     This program is distributed in the hope that it will be useful,
100 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
101 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
102 *     GNU Lesser General Public License for more details.
103 *
104 *     You should have received a copy of the GNU Lesser General
105 *     License along with this program.  If not, see
106 *     <http://www.gnu.org/licenses/>.
107 
108 *  Authors:
109 *     DSB: David S. Berry (Starlink)
110 
111 *  History:
112 *     13-MAR-2006 (DSB):
113 *        Original version.
114 *     17-MAR-2006 (DSB):
115 *        Guard against AST__BAD selector values.
116 *     9-MAY-2006 (DSB):
117 *        Check selector Mapping pointers are not NULL before calling
118 *        astEqual in Equal.
119 *class--
120 */
121 
122 /* Module Macros. */
123 /* ============== */
124 /* Set the name of the class we are implementing. This indicates to
125    the header files that define class interfaces that they should make
126    "protected" symbols available. */
127 #define astCLASS SwitchMap
128 
129 /* Include files. */
130 /* ============== */
131 /* Interface definitions. */
132 /* ---------------------- */
133 
134 #include "globals.h"             /* Thread-safe global data access */
135 #include "error.h"               /* Error reporting facilities */
136 #include "memory.h"              /* Memory allocation facilities */
137 #include "object.h"              /* Base Object class */
138 #include "pointset.h"            /* Sets of points/coordinates */
139 #include "mapping.h"             /* Coordinate Mappings (parent class) */
140 #include "unitmap.h"             /* Unit Mappings */
141 #include "channel.h"             /* I/O channels */
142 #include "switchmap.h"           /* Interface definition for this class */
143 #include "frame.h"               /* Frames */
144 
145 /* Error code definitions. */
146 /* ----------------------- */
147 #include "ast_err.h"             /* AST error codes */
148 
149 /* C header files. */
150 /* --------------- */
151 #include <stdarg.h>
152 #include <stddef.h>
153 #include <string.h>
154 #include <stdio.h>
155 
156 /* Module Variables. */
157 /* ================= */
158 
159 /* Address of this static variable is used as a unique identifier for
160    member of this class. */
161 static int class_check;
162 
163 /* Pointers to parent class methods which are extended by this class. */
164 static int (* parent_getobjsize)( AstObject *, int * );
165 static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
166 
167 #if defined(THREAD_SAFE)
168 static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
169 #endif
170 
171 
172 
173 #ifdef THREAD_SAFE
174 /* Define how to initialise thread-specific globals. */
175 #define GLOBAL_inits \
176    globals->Class_Init = 0;
177 
178 /* Create the function that initialises global data for this module. */
179 astMAKE_INITGLOBALS(SwitchMap)
180 
181 /* Define macros for accessing each item of thread specific global data. */
182 #define class_init astGLOBAL(SwitchMap,Class_Init)
183 #define class_vtab astGLOBAL(SwitchMap,Class_Vtab)
184 
185 
186 #include <pthread.h>
187 
188 
189 #else
190 
191 
192 /* Define the class virtual function table and its initialisation flag
193    as static variables. */
194 static AstSwitchMapVtab class_vtab;   /* Virtual function table */
195 static int class_init = 0;       /* Virtual function table initialised? */
196 
197 #endif
198 
199 /* External Interface Function Prototypes. */
200 /* ======================================= */
201 /* The following functions have public prototypes only (i.e. no
202    protected prototypes), so we must provide local prototypes for use
203    within this module. */
204 AstSwitchMap *astSwitchMapId_( void *, void *, int, void **, const char *, ... );
205 
206 /* Prototypes for Private Member Functions. */
207 /* ======================================== */
208 static AstMapping *RemoveRegions( AstMapping *, int * );
209 static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
210 static double Rate( AstMapping *, double *, int, int, int * );
211 static int Equal( AstObject *, AstObject *, int * );
212 static int GetObjSize( AstObject *, int * );
213 static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * );
214 static void Copy( const AstObject *, AstObject *, int * );
215 static void Delete( AstObject *, int * );
216 static void Dump( AstObject *, AstChannel *, int * );
217 static AstMapping *GetSelector( AstSwitchMap *, int, int *, int * );
218 static AstMapping *GetRoute( AstSwitchMap *, double, int *, int * );
219 
220 #if defined(THREAD_SAFE)
221 static int ManageLock( AstObject *, int, int, AstObject **, int * );
222 #endif
223 
224 /* Member functions. */
225 /* ================= */
Equal(AstObject * this_object,AstObject * that_object,int * status)226 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
227 /*
228 *  Name:
229 *     Equal
230 
231 *  Purpose:
232 *     Test if two SwitchMaps are equivalent.
233 
234 *  Type:
235 *     Private function.
236 
237 *  Synopsis:
238 *     #include "switchmap.h"
239 *     int Equal( AstObject *this, AstObject *that, int *status )
240 
241 *  Class Membership:
242 *     SwitchMap member function (over-rides the astEqual protected
243 *     method inherited from the astMapping class).
244 
245 *  Description:
246 *     This function returns a boolean result (0 or 1) to indicate whether
247 *     two SwitchMaps are equivalent.
248 
249 *  Parameters:
250 *     this
251 *        Pointer to the first Object (a SwitchMap).
252 *     that
253 *        Pointer to the second Object.
254 *     status
255 *        Pointer to the inherited status variable.
256 
257 *  Returned Value:
258 *     One if the SwitchMaps are equivalent, zero otherwise.
259 
260 *  Notes:
261 *     - A value of zero will be returned if this function is invoked
262 *     with the global status set, or if it should fail for any reason.
263 */
264 
265 /* Local Variables: */
266    AstMapping *fsmap1;
267    AstMapping *fsmap2;
268    AstMapping *ismap1;
269    AstMapping *ismap2;
270    AstMapping *rmap1;
271    AstMapping *rmap2;
272    AstSwitchMap *that;
273    AstSwitchMap *this;
274    int fsinv1;
275    int fsinv2;
276    int isinv1;
277    int i;
278    int isinv2;
279    int nroute;
280    int result;
281    int rinv1;
282    int rinv2;
283 
284 /* Initialise. */
285    result = 0;
286 
287 /* Check the global error status. */
288    if ( !astOK ) return result;
289 
290 /* Obtain pointers to the two SwitchMap structures. */
291    this = (AstSwitchMap *) this_object;
292    that = (AstSwitchMap *) that_object;
293 
294 /* Check the second object is a SwitchMap. We know the first is a
295    SwitchMap since we have arrived at this implementation of the virtual
296    function. */
297    if( astIsASwitchMap( that ) ) {
298 
299 /* Check they have the same number of route mappings. */
300       nroute = this->nroute;
301       if( that->nroute == nroute ) {
302 
303 /* Get the forward selector Mappings from the two SwitchMaps. */
304          fsmap1 = GetSelector( this, 1, &fsinv1, status );
305          fsmap2 = GetSelector( that, 1, &fsinv2, status );
306 
307 /* Are they equal? */
308          if( ( !fsmap1 && !fsmap2 ) ||
309              ( fsmap1 && fsmap2 && astEqual( fsmap1, fsmap2 ) ) ) {
310 
311 /* Get the inverse selector Mappings from the two SwitchMaps. */
312             ismap1 = GetSelector( this, 0, &isinv1, status );
313             ismap2 = GetSelector( that, 0, &isinv2, status );
314 
315 /* Are they equal? */
316             if( ( !ismap1 && !ismap2 ) ||
317                 ( ismap1 && ismap2 && astEqual( ismap1, ismap2 ) ) ) {
318 
319 /* Loop over the route mappings, breaking as soon as two unequal route
320    Mappings are found. Re-instate the original values for the route
321    Mapping Invert flag after testing the route Mappings for equality. */
322                result = 1;
323                for( i = 0; result && i < nroute; i++ ) {
324                   rmap1 = GetRoute( this, (double) ( i + 1 ), &rinv1, status );
325                   rmap2 = GetRoute( that, (double) ( i + 1 ), &rinv2, status );
326                   if( !astEqual( rmap1, rmap2 ) ) result = 0;
327                   astSetInvert( rmap2, rinv2 );
328                   astSetInvert( rmap1, rinv1 );
329                }
330             }
331 
332 /* Reinstate the invert flags for the inverse selector Mappings. Ensure
333    this is done in the opposite order to which the selector Mappings were
334    obtained (in case they are in fact the same Mapping). */
335             if( ismap2 ) astSetInvert( ismap2, isinv2 );
336             if( ismap1 ) astSetInvert( ismap1, isinv1 );
337          }
338 
339 /* Reinstate the invert flags for the forward selector Mappings. Ensure
340    this is done in the oppsote order to which the selector Mappings were
341    obtained (in case they are in fact the same Mapping). */
342          if( fsmap2 ) astSetInvert( fsmap2, fsinv2 );
343          if( fsmap1 ) astSetInvert( fsmap1, fsinv1 );
344       }
345    }
346 
347 /* If an error occurred, clear the result value. */
348    if ( !astOK ) result = 0;
349 
350 /* Return the result, */
351    return result;
352 }
353 
GetObjSize(AstObject * this_object,int * status)354 static int GetObjSize( AstObject *this_object, int *status ) {
355 /*
356 *  Name:
357 *     GetObjSize
358 
359 *  Purpose:
360 *     Return the in-memory size of an Object.
361 
362 *  Type:
363 *     Private function.
364 
365 *  Synopsis:
366 *     #include "switchmap.h"
367 *     int GetObjSize( AstObject *this, int *status )
368 
369 *  Class Membership:
370 *     SwitchMap member function (over-rides the astGetObjSize protected
371 *     method inherited from the parent class).
372 
373 *  Description:
374 *     This function returns the in-memory size of the supplied SwitchMap,
375 *     in bytes.
376 
377 *  Parameters:
378 *     this
379 *        Pointer to the SwitchMap.
380 *     status
381 *        Pointer to the inherited status variable.
382 
383 *  Returned Value:
384 *     The Object size, in bytes.
385 
386 *  Notes:
387 *     - A value of zero will be returned if this function is invoked
388 *     with the global status set, or if it should fail for any reason.
389 */
390 
391 /* Local Variables: */
392    AstSwitchMap *this;
393    int i;
394    int result;
395 
396 /* Initialise. */
397    result = 0;
398 
399 /* Check the global error status. */
400    if ( !astOK ) return result;
401 
402 /* Obtain a pointers to the SwitchMap structure. */
403    this = (AstSwitchMap *) this_object;
404 
405 /* Invoke the GetObjSize method inherited from the parent class, and then
406    add on any components of the class structure defined by this class
407    which are stored in dynamically allocated memory. */
408    result = (*parent_getobjsize)( this_object, status );
409 
410    result += astGetObjSize( this->fsmap );
411    result += astGetObjSize( this->ismap );
412 
413    for( i = 0; i < this->nroute; i++ ) {
414       result += astGetObjSize( this->routemap[ i ] );
415    }
416 
417    result += astGetObjSize( this->routeinv );
418 
419 /* If an error occurred, clear the result value. */
420    if ( !astOK ) result = 0;
421 
422 /* Return the result, */
423    return result;
424 }
425 
GetRoute(AstSwitchMap * this,double sel,int * inv,int * status)426 static AstMapping *GetRoute( AstSwitchMap *this, double sel, int *inv, int *status ){
427 /*
428 *  Name:
429 *     GetRoute
430 
431 *  Purpose:
432 *     Return a pointer to a route Mapping, handling all Invert flags.
433 
434 *  Type:
435 *     Private function.
436 
437 *  Synopsis:
438 *     #include "switchmap.h"
439 *     AstMapping *GetRoute( AstSwitchMap *this, double sel, int *inv, int *status )
440 
441 *  Class Membership:
442 *     SwitchMap method.
443 
444 *  Description:
445 *     This function returns a pointer to a route Mapping (specified by a
446 *     floating point selector value) for the given SwitchMap, taking account
447 *     of the state of the Invert flag of both the route Mapping and the
448 *     SwitchMap.
449 
450 *  Parameters:
451 *     this
452 *        Pointer to the SwitchMap.
453 *     sel
454 *        The selector value. The nearest integer value (minus 1) is used
455 *        to index the array of route Mappings stored in the SwitchMap. A
456 *        NULL pointer is returned if the selector value is out of range.
457 *     inv
458 *        Pointer to an int in which to return the original value of the
459 *        Invert flag of the returned Mapping. The astSetInvert method
460 *        should be used to re-instate this value once all use of the Mapping
461 *        has been completed.
462 *     status
463 *        Pointer to the inherited status variable.
464 
465 *  Returns:
466 *     A pointer to the route Mapping to use. Note, the returned pointer
467 *     should NOT be annulled when no longer needed. NULL is returned
468 *     (without error) if the SwitchMap does not have a route Mapping for the
469 *     requested selector value. The forward transformation of the
470 *     returned Mapping will implenment the forward transformation of the
471 *     required route Mapping (and vice-versa).
472 
473 */
474 
475 /* Local Variables: */
476    AstMapping *ret;
477    int rindex;
478 
479 /* Initialise */
480    ret = NULL;
481 
482 /* Check the global error status. */
483    if ( !astOK ) return ret;
484 
485 /* Check selector value is good. */
486    if( sel != AST__BAD ) {
487 
488 /* Convert the supplied floating point selector value into an integer
489    index into the array of route Mappings held in the supplied SwitchMap. */
490       rindex = (int)( sel + 0.5 ) - 1;
491 
492 /* Return the null pointer if the index is out of range. */
493       if( rindex >= 0 && rindex < this->nroute ) {
494 
495 /* Get the required route Mapping. */
496          ret = ( this->routemap )[ rindex ];
497 
498 /* Return its original invert flag. */
499          *inv = astGetInvert( ret );
500 
501 /* Set the Invert flag back to the value it had when the SwitchMap was
502    created. */
503          astSetInvert( ret, this->routeinv[ rindex ] );
504 
505 /* If the SwitchMap has since been inverted, also invert the returned
506    route Mapping, so that the forward transformation of the returned
507    Mapping implements the forward transformation of the supplied
508    SwitchMap (and vice-versa). */
509          if( astGetInvert( this ) ) astInvert( ret );
510       }
511    }
512 
513 /* Return the pointer. */
514    return ret;
515 
516 }
517 
GetSelector(AstSwitchMap * this,int fwd,int * inv,int * status)518 static AstMapping *GetSelector( AstSwitchMap *this, int fwd, int *inv, int *status ){
519 /*
520 *  Name:
521 *     GetSelector
522 
523 *  Purpose:
524 *     Return a pointer to a selector Mapping, handling all Invert flags.
525 
526 *  Type:
527 *     Private function.
528 
529 *  Synopsis:
530 *     #include "switchmap.h"
531 *     AstMapping *GetSelector( AstSwitchMap *this, int fwd, int *inv, int *status )
532 
533 *  Class Membership:
534 *     SwitchMap method.
535 
536 *  Description:
537 *     This function returns a pointer to either the forward or inverse
538 *     selector Mapping for the given SwitchMap, taking account of the
539 *     state of the Invert flag of bothe the selector Mapping and the
540 *     SwitchMap.
541 
542 *  Parameters:
543 *     this
544 *        Pointer to the SwitchMap.
545 *     fwd
546 *        If non-zero, return the forward selector Mapping. Otherwise,
547 *        return the inverse selector Mapping.
548 *     inv
549 *        Pointer to an int in which to return the original value of the
550 *        Invert flag of the returned Mapping. The astSetInvert method
551 *        should be used to re-instate this value once all use of the Mapping
552 *        has been completed.
553 *     status
554 *        Pointer to the inherited status variable.
555 
556 *  Returns:
557 *     A pointer to the selector Mapping to use. Note, the returned pointer
558 *     should NOT be annulled when no longer needed. NULL is returned
559 *     (without error) if the SwitchMap does not have a Mapping for the
560 *     requested selector.
561 
562 */
563 
564 /* Local Variables: */
565    AstMapping *ret;
566    int swinv;
567 
568 /* Initialise */
569    ret = NULL;
570 
571 /* Check the global error status. */
572    if ( !astOK ) return ret;
573 
574 /* See if the SwitchMap has been inverted. */
575    swinv = astGetInvert( this );
576 
577 /* If the SwitchMap has been inverted, the forward and inverse selector
578    Mappings should be reversed. */
579    if( ( !swinv && !fwd ) || ( swinv && fwd ) ){
580       ret = this->ismap;
581       if( ret ) {
582          *inv = astGetInvert( ret );
583          astSetInvert( ret, this->isinv );
584       }
585 
586    } else {
587       ret = this->fsmap;
588       if( ret ) {
589          *inv = astGetInvert( ret );
590          astSetInvert( ret, this->fsinv );
591       }
592    }
593 
594    if( ret && swinv ) astInvert( ret );
595 
596 /* Return the pointer. */
597    return ret;
598 
599 }
600 
astInitSwitchMapVtab_(AstSwitchMapVtab * vtab,const char * name,int * status)601 void astInitSwitchMapVtab_(  AstSwitchMapVtab *vtab, const char *name, int *status ) {
602 /*
603 *+
604 *  Name:
605 *     astInitSwitchMapVtab
606 
607 *  Purpose:
608 *     Initialise a virtual function table for a SwitchMap.
609 
610 *  Type:
611 *     Protected function.
612 
613 *  Synopsis:
614 *     #include "switchmap.h"
615 *     void astInitSwitchMapVtab( AstSwitchMapVtab *vtab, const char *name )
616 
617 *  Class Membership:
618 *     SwitchMap vtab initialiser.
619 
620 *  Description:
621 *     This function initialises the component of a virtual function
622 *     table which is used by the SwitchMap class.
623 
624 *  Parameters:
625 *     vtab
626 *        Pointer to the virtual function table. The components used by
627 *        all ancestral classes will be initialised if they have not already
628 *        been initialised.
629 *     name
630 *        Pointer to a constant null-terminated character string which contains
631 *        the name of the class to which the virtual function table belongs (it
632 *        is this pointer value that will subsequently be returned by the Object
633 *        astClass function).
634 *-
635 */
636 
637 /* Local Variables: */
638    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
639    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
640    AstMappingVtab *mapping;      /* Pointer to Mapping component of Vtab */
641 
642 /* Check the local error status. */
643    if ( !astOK ) return;
644 
645 /* Get a pointer to the thread specific global data structure. */
646    astGET_GLOBALS(NULL);
647 
648 /* Initialize the component of the virtual function table used by the
649    parent class. */
650    astInitMappingVtab( (AstMappingVtab *) vtab, name );
651 
652 /* Store a unique "magic" value in the virtual function table. This
653    will be used (by astIsASwitchMap) to determine if an object belongs to
654    this class.  We can conveniently use the address of the (static)
655    class_check variable to generate this unique value. */
656    vtab->id.check = &class_check;
657    vtab->id.parent = &(((AstMappingVtab *) vtab)->id);
658 
659 /* Initialise member function pointers. */
660 /* ------------------------------------ */
661 /* Store pointers to the member functions (implemented here) that
662    provide virtual methods for this class. */
663 
664 /* None. */
665 
666 /* Save the inherited pointers to methods that will be extended, and
667    replace them with pointers to the new member functions. */
668    object = (AstObjectVtab *) vtab;
669    mapping = (AstMappingVtab *) vtab;
670    parent_getobjsize = object->GetObjSize;
671    object->GetObjSize = GetObjSize;
672 
673 #if defined(THREAD_SAFE)
674    parent_managelock = object->ManageLock;
675    object->ManageLock = ManageLock;
676 #endif
677 
678    parent_transform = mapping->Transform;
679    mapping->Transform = Transform;
680 
681 /* Store replacement pointers for methods which will be over-ridden by
682    new member functions implemented here. */
683    object->Equal = Equal;
684    mapping->MapMerge = MapMerge;
685    mapping->Rate = Rate;
686    mapping->RemoveRegions = RemoveRegions;
687 
688 /* Declare the copy constructor, destructor and class dump function. */
689    astSetCopy( vtab, Copy );
690    astSetDelete( vtab, Delete );
691    astSetDump( vtab, Dump, "SwitchMap", "Alternate regionalised Mapping" );
692 
693 /* If we have just initialised the vtab for the current class, indicate
694    that the vtab is now initialised, and store a pointer to the class
695    identifier in the base "object" level of the vtab. */
696    if( vtab == &class_vtab ) {
697       class_init = 1;
698       astSetVtabClassIdentifier( vtab, &(vtab->id) );
699    }
700 }
701 
702 #if defined(THREAD_SAFE)
ManageLock(AstObject * this_object,int mode,int extra,AstObject ** fail,int * status)703 static int ManageLock( AstObject *this_object, int mode, int extra,
704                        AstObject **fail, int *status ) {
705 /*
706 *  Name:
707 *     ManageLock
708 
709 *  Purpose:
710 *     Manage the thread lock on an Object.
711 
712 *  Type:
713 *     Private function.
714 
715 *  Synopsis:
716 *     #include "object.h"
717 *     AstObject *ManageLock( AstObject *this, int mode, int extra,
718 *                            AstObject **fail, int *status )
719 
720 *  Class Membership:
721 *     SwitchMap member function (over-rides the astManageLock protected
722 *     method inherited from the parent class).
723 
724 *  Description:
725 *     This function manages the thread lock on the supplied Object. The
726 *     lock can be locked, unlocked or checked by this function as
727 *     deteremined by parameter "mode". See astLock for details of the way
728 *     these locks are used.
729 
730 *  Parameters:
731 *     this
732 *        Pointer to the Object.
733 *     mode
734 *        An integer flag indicating what the function should do:
735 *
736 *        AST__LOCK: Lock the Object for exclusive use by the calling
737 *        thread. The "extra" value indicates what should be done if the
738 *        Object is already locked (wait or report an error - see astLock).
739 *
740 *        AST__UNLOCK: Unlock the Object for use by other threads.
741 *
742 *        AST__CHECKLOCK: Check that the object is locked for use by the
743 *        calling thread (report an error if not).
744 *     extra
745 *        Extra mode-specific information.
746 *     fail
747 *        If a non-zero function value is returned, a pointer to the
748 *        Object that caused the failure is returned at "*fail". This may
749 *        be "this" or it may be an Object contained within "this". Note,
750 *        the Object's reference count is not incremented, and so the
751 *        returned pointer should not be annulled. A NULL pointer is
752 *        returned if this function returns a value of zero.
753 *     status
754 *        Pointer to the inherited status variable.
755 
756 *  Returned Value:
757 *    A local status value:
758 *        0 - Success
759 *        1 - Could not lock or unlock the object because it was already
760 *            locked by another thread.
761 *        2 - Failed to lock a POSIX mutex
762 *        3 - Failed to unlock a POSIX mutex
763 *        4 - Bad "mode" value supplied.
764 
765 *  Notes:
766 *     - This function attempts to execute even if an error has already
767 *     occurred.
768 */
769 
770 /* Local Variables: */
771    AstSwitchMap *this;       /* Pointer to SwitchMap structure */
772    int i;                      /* Loop count */
773    int result;                 /* Returned status value */
774 
775 /* Initialise */
776    result = 0;
777 
778 /* Check the supplied pointer is not NULL. */
779    if( !this_object ) return result;
780 
781 /* Obtain a pointers to the SwitchMap structure. */
782    this = (AstSwitchMap *) this_object;
783 
784 /* Invoke the ManageLock method inherited from the parent class. */
785    if( !result ) result = (*parent_managelock)( this_object, mode, extra,
786                                                 fail, status );
787 
788 /* Invoke the astManageLock method on any Objects contained within
789    the supplied Object. */
790    if( !result ) result = astManageLock( this->fsmap, mode, extra, fail );
791    if( !result ) result = astManageLock( this->ismap, mode, extra, fail );
792    for( i = 0; i < this->nroute; i++ ) {
793       if( !result ) result = astManageLock( this->routemap[ i ], mode,
794                                             extra, fail );
795    }
796 
797    return result;
798 
799 }
800 #endif
801 
MapMerge(AstMapping * this,int where,int series,int * nmap,AstMapping *** map_list,int ** invert_list,int * status)802 static int MapMerge( AstMapping *this, int where, int series, int *nmap,
803                      AstMapping ***map_list, int **invert_list, int *status ) {
804 /*
805 *  Name:
806 *     MapMerge
807 
808 *  Purpose:
809 *     Simplify a sequence of Mappings containing a SwitchMap.
810 
811 *  Type:
812 *     Private function.
813 
814 *  Synopsis:
815 *     #include "mapping.h"
816 *     int MapMerge( AstMapping *this, int where, int series, int *nmap,
817 *                   AstMapping ***map_list, int **invert_list, int *status )
818 
819 *  Class Membership:
820 *     SwitchMap method (over-rides the protected astMapMerge method
821 *     inherited from the Mapping class).
822 
823 *  Description:
824 *     This function attempts to simplify a sequence of Mappings by
825 *     merging a nominated SwitchMap in the sequence with its neighbours,
826 *     so as to shorten the sequence if possible.
827 *
828 *     In many cases, simplification will not be possible and the
829 *     function will return -1 to indicate this, without further
830 *     action.
831 *
832 *     In most cases of interest, however, this function will either
833 *     attempt to replace the nominated SwitchMap with one which it
834 *     considers simpler, or to merge it with the Mappings which
835 *     immediately precede it or follow it in the sequence (both will
836 *     normally be considered). This is sufficient to ensure the
837 *     eventual simplification of most Mapping sequences by repeated
838 *     application of this function.
839 *
840 *     In some cases, the function may attempt more elaborate
841 *     simplification, involving any number of other Mappings in the
842 *     sequence. It is not restricted in the type or scope of
843 *     simplification it may perform, but will normally only attempt
844 *     elaborate simplification in cases where a more straightforward
845 *     approach is not adequate.
846 
847 *  Parameters:
848 *     this
849 *        Pointer to the nominated SwitchMap which is to be merged with
850 *        its neighbours. This should be a cloned copy of the SwitchMap
851 *        pointer contained in the array element "(*map_list)[where]"
852 *        (see below). This pointer will not be annulled, and the
853 *        SwitchMap it identifies will not be modified by this function.
854 *     where
855 *        Index in the "*map_list" array (below) at which the pointer
856 *        to the nominated SwitchMap resides.
857 *     series
858 *        A non-zero value indicates that the sequence of Mappings to
859 *        be simplified will be applied in series (i.e. one after the
860 *        other), whereas a zero value indicates that they will be
861 *        applied in parallel (i.e. on successive sub-sets of the
862 *        input/output coordinates).
863 *     nmap
864 *        Address of an int which counts the number of Mappings in the
865 *        sequence. On entry this should be set to the initial number
866 *        of Mappings. On exit it will be updated to record the number
867 *        of Mappings remaining after simplification.
868 *     map_list
869 *        Address of a pointer to a dynamically allocated array of
870 *        Mapping pointers (produced, for example, by the astMapList
871 *        method) which identifies the sequence of Mappings. On entry,
872 *        the initial sequence of Mappings to be simplified should be
873 *        supplied.
874 *
875 *        On exit, the contents of this array will be modified to
876 *        reflect any simplification carried out. Any form of
877 *        simplification may be performed. This may involve any of: (a)
878 *        removing Mappings by annulling any of the pointers supplied,
879 *        (b) replacing them with pointers to new Mappings, (c)
880 *        inserting additional Mappings and (d) changing their order.
881 *
882 *        The intention is to reduce the number of Mappings in the
883 *        sequence, if possible, and any reduction will be reflected in
884 *        the value of "*nmap" returned. However, simplifications which
885 *        do not reduce the length of the sequence (but improve its
886 *        execution time, for example) may also be performed, and the
887 *        sequence might conceivably increase in length (but normally
888 *        only in order to split up a Mapping into pieces that can be
889 *        more easily merged with their neighbours on subsequent
890 *        invocations of this function).
891 *
892 *        If Mappings are removed from the sequence, any gaps that
893 *        remain will be closed up, by moving subsequent Mapping
894 *        pointers along in the array, so that vacated elements occur
895 *        at the end. If the sequence increases in length, the array
896 *        will be extended (and its pointer updated) if necessary to
897 *        accommodate any new elements.
898 *
899 *        Note that any (or all) of the Mapping pointers supplied in
900 *        this array may be annulled by this function, but the Mappings
901 *        to which they refer are not modified in any way (although
902 *        they may, of course, be deleted if the annulled pointer is
903 *        the final one).
904 *     invert_list
905 *        Address of a pointer to a dynamically allocated array which,
906 *        on entry, should contain values to be assigned to the Invert
907 *        attributes of the Mappings identified in the "*map_list"
908 *        array before they are applied (this array might have been
909 *        produced, for example, by the astMapList method). These
910 *        values will be used by this function instead of the actual
911 *        Invert attributes of the Mappings supplied, which are
912 *        ignored.
913 *
914 *        On exit, the contents of this array will be updated to
915 *        correspond with the possibly modified contents of the
916 *        "*map_list" array.  If the Mapping sequence increases in
917 *        length, the "*invert_list" array will be extended (and its
918 *        pointer updated) if necessary to accommodate any new
919 *        elements.
920 *     status
921 *        Pointer to the inherited status variable.
922 
923 *  Returned Value:
924 *     If simplification was possible, the function returns the index
925 *     in the "map_list" array of the first element which was
926 *     modified. Otherwise, it returns -1 (and makes no changes to the
927 *     arrays supplied).
928 
929 *  Notes:
930 *     - A value of -1 will be returned if this function is invoked
931 *     with the global error status set, or if it should fail for any
932 *     reason.
933 */
934 
935 /* Local Variables: */
936    AstSwitchMap *map;
937    AstMapping *new;
938    int i;
939    int nroute;
940    int result;
941    int fsinv_old;
942    int isinv_old;
943    int *rinv_old;
944    AstMapping *sfsmap;
945    AstMapping *sismap;
946    int simp;
947    AstMapping **srmap;
948    AstSwitchMap *swneb;
949    int ilo;
950    int equal;
951 
952 /* Initialise.*/
953    result = -1;
954 
955 /* Check the inherited status. */
956    if ( !astOK ) return result;
957 
958 /* Get a pointer to this SwitchMap, and note the number of route Mappings. */
959    map = (AstSwitchMap *) this;
960    nroute = map->nroute;
961 
962 /* Temporarily put the Invert flag of all encapsulated Mappings (both
963    route and selector) back to the values they had when the SwitchMap was
964    created, noting their current values so that they can be re-instated
965    later. If the SwitchMap itself has been inverted, swap all the original
966    invert flags. */
967    if( map->fsmap ) {
968       fsinv_old = astGetInvert( map->fsmap );
969       astSetInvert( map->fsmap, map->fsinv );
970    } else {
971       fsinv_old = 0;
972    }
973 
974    if( map->ismap ) {
975       isinv_old = astGetInvert( map->ismap );
976       astSetInvert( map->ismap, map->isinv );
977    } else {
978       isinv_old = 0;
979    }
980 
981    rinv_old = astMalloc( sizeof( int )*nroute );
982    if( astOK ) {
983       for( i = 0; i < nroute; i++ ) {
984          rinv_old[ i ] = astGetInvert( map->routemap[ i ] );
985          astSetInvert( map->routemap[ i ], map->routeinv[ i ] );
986       }
987    }
988 
989 /* If possible, merge the SwitchMap with a neighbouring SwitchMap. */
990 /* =============================================================== */
991 /* Only do this if we are combining the Mappings in series. */
992    if( series ) {
993 
994 /* Is the higher neighbour a SwitchMap? If so get a pointer to it, and
995    note the index of the lower of the two adjacent SwitchMaps. */
996       if( where < ( *nmap - 1 ) &&
997           astIsASwitchMap( ( *map_list )[ where + 1 ] ) ){
998          swneb = (AstSwitchMap *) ( *map_list )[ where + 1 ];
999          ilo = where;
1000 
1001 /* If not, is the lower neighbour a SwitchMap? If so get a pointer to it, and
1002    note the index of the lower of the two adjacent SwitchMaps. */
1003       } else if( where > 0 &&
1004                  astIsASwitchMap( ( *map_list )[ where - 1 ] ) ){
1005          swneb = (AstSwitchMap *) ( *map_list )[ where - 1 ];
1006          ilo =  where - 1;
1007 
1008       } else {
1009          swneb = NULL;
1010       }
1011 
1012 /* If a neighbouring SwitchMap was found, we can replace the pair by a
1013    UnitMap if the two SwitchMaps are equal but have opposite values for
1014    their Invert flags. Temporarily invert the neighbour, then compare
1015    the two SwitchMaps for equality, then re-invert the neighbour. */
1016       if( swneb ) {
1017          astInvert( swneb );
1018          equal = astEqual( map, swneb );
1019          astInvert( swneb );
1020 
1021 /* If the two SwitchMaps are equal but opposite, annul the first of the two
1022    Mappings, and replace it with a UnitMap. Also set the invert flag. */
1023          if( equal ) {
1024             new = (AstMapping *) astUnitMap( astGetNin( ( *map_list )[ ilo ] ), "", status );
1025             (void) astAnnul( ( *map_list )[ ilo ] );
1026             ( *map_list )[ ilo ] = new;
1027             ( *invert_list )[ ilo ] = 0;
1028 
1029 /* Annul the second of the two Mappings, and shuffle down the rest of the
1030    list to fill the gap. */
1031             (void) astAnnul( ( *map_list )[ ilo + 1 ] );
1032             for ( i = ilo + 2; i < *nmap; i++ ) {
1033                ( *map_list )[ i - 1 ] = ( *map_list )[ i ];
1034                ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ];
1035             }
1036 
1037 /* Clear the vacated element at the end. */
1038             ( *map_list )[ *nmap - 1 ] = NULL;
1039             ( *invert_list )[ *nmap - 1 ] = 0;
1040 
1041 /* Decrement the Mapping count and return the index of the first
1042    modified element. */
1043             ( *nmap )--;
1044             result = where;
1045          }
1046       }
1047    }
1048 
1049 /* Attempt to simplify the SwitchMap on its own. */
1050 /* ============================================= */
1051 /* Only do this if no change was made above. */
1052    if( result == -1 ) {
1053 
1054 /* If the SwitchMap is inverted, create an equal SwitchMap which is not
1055    inverted. To do this, invert and swap the selector Mappings, and
1056    invert all the route Mappings. We use astSetInvert rather than astInvert
1057    because two or more more stored pointers may point to the same Mapping
1058    in which case that Mapping would be inverted more than once with
1059    unpredictable results. */
1060       if( ( *invert_list )[ where ] ) {
1061          if( map->fsmap ) astSetInvert( map->fsmap, !(map->fsinv) );
1062          if( map->ismap ) astSetInvert( map->ismap, !(map->isinv) );
1063          for( i = 0; i < nroute; i++ ) {
1064             astSetInvert( map->routemap[ i ], !(map->routeinv[ i ]) );
1065          }
1066 
1067          new = (AstMapping *) astSwitchMap( map->ismap, map->fsmap, nroute, (void **) map->routemap, "", status );
1068 
1069          (void) astAnnul( ( *map_list )[ where ] );
1070          ( *map_list )[ where ] = (AstMapping *) new;
1071          ( *invert_list )[ where ] = 0;
1072          result = where;
1073 
1074 /* Otherwise, try to simplify each of the encapsulated Mappings, noting
1075    if any simplification takes place. */
1076       } else {
1077          sfsmap = ( map->fsmap ) ? astSimplify( map->fsmap ) : NULL;
1078          sismap = ( map->ismap ) ? astSimplify( map->ismap ) : NULL;
1079          simp = ( sfsmap != map->fsmap ) || ( sismap != map->ismap );
1080 
1081          srmap = astMalloc( sizeof( AstMapping * )*nroute );
1082          if( astOK ) {
1083             for( i = 0; i < nroute; i++ ) {
1084                srmap[ i ] = astSimplify( map->routemap[ i ] );
1085                simp = simp || ( srmap[ i ] != map->routemap[ i ] );
1086             }
1087          }
1088 
1089 /* If any simplification took place, construct a new SwitchMap from these
1090     simplified Mappings. */
1091          if( simp ) {
1092             (void) astAnnul( ( *map_list )[ where ] );
1093             ( *map_list )[ where ] = (AstMapping *) astSwitchMap( sfsmap, sismap,
1094                                                     nroute, (void **) srmap, "", status );
1095             result = where;
1096          }
1097 
1098 /* Release resources. */
1099          if( sfsmap ) sfsmap = astAnnul( sfsmap );
1100          if( sismap ) sismap = astAnnul( sismap );
1101          if( srmap ) {
1102             for( i = 0; i < nroute; i++ ) srmap[ i ] = astAnnul( srmap[ i ] );
1103             srmap = astFree( srmap );
1104          }
1105       }
1106    }
1107 
1108 /* Re-instate the original Invert values for the encapsulated Mappings. */
1109    if( map->fsmap ) astSetInvert( map->fsmap, fsinv_old );
1110    if( map->ismap ) astSetInvert( map->ismap, isinv_old );
1111    if( rinv_old ) {
1112       for( i = 0; i < nroute; i++ ) {
1113          astSetInvert( map->routemap[ i ], rinv_old[ i ] );
1114       }
1115       rinv_old = astFree( rinv_old );
1116    }
1117 
1118 /* If an error occurred, clear the result value. */
1119    if ( !astOK ) result = -1;
1120 
1121 /* Return the result. */
1122    return result;
1123 }
1124 
Rate(AstMapping * this,double * at,int ax1,int ax2,int * status)1125 static double Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ){
1126 /*
1127 *  Name:
1128 *     Rate
1129 
1130 *  Purpose:
1131 *     Calculate the rate of change of a Mapping output.
1132 
1133 *  Type:
1134 *     Private function.
1135 
1136 *  Synopsis:
1137 *     #include "switchmap.h"
1138 *     result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status )
1139 
1140 *  Class Membership:
1141 *     SwitchMap member function (overrides the astRate method inherited
1142 *     from the Mapping class ).
1143 
1144 *  Description:
1145 *     This function returns the rate of change of a specified output of
1146 *     the supplied Mapping with respect to a specified input, at a
1147 *     specified input position. Also evaluates the second derivative.
1148 
1149 *  Parameters:
1150 *     this
1151 *        Pointer to the Mapping to be applied.
1152 *     at
1153 *        The address of an array holding the axis values at the position
1154 *        at which the rate of change is to be evaluated. The number of
1155 *        elements in this array should equal the number of inputs to the
1156 *        Mapping.
1157 *     ax1
1158 *        The index of the Mapping output for which the rate of change is to
1159 *        be found (output numbering starts at 0 for the first output).
1160 *     ax2
1161 *        The index of the Mapping input which is to be varied in order to
1162 *        find the rate of change (input numbering starts at 0 for the first
1163 *        input).
1164 *     status
1165 *        Pointer to the inherited status variable.
1166 
1167 *  Returned Value:
1168 *     The rate of change of Mapping output "ax1" with respect to input
1169 *     "ax2", evaluated at "at", or AST__BAD if the value cannot be
1170 *     calculated.
1171 
1172 */
1173 
1174 /* Local Variables: */
1175    AstSwitchMap *map;
1176    AstMapping *smap;
1177    AstMapping *rmap;
1178    double result;
1179    double sel;
1180    int fsinv;
1181    int rinv;
1182    int nin;
1183 
1184 /* Initialise. */
1185    result = AST__BAD;
1186 
1187 /* Check inherited status */
1188    if( !astOK ) return result;
1189 
1190 /* Get a pointer to the SwitchMap structure. */
1191    map = (AstSwitchMap *) this;
1192 
1193 /* Get a pointer to the effective foward selector Mapping, and its current
1194    invert flag (this takes account of whether the SwtichMap has been
1195    inverted or not). This call resets the selector's invert flag temporarily
1196    back to the value it had when the SwitchMap was created. */
1197    smap = GetSelector( map, 1, &fsinv, status );
1198 
1199 /* If the SwitchMap has no forward selector Mapping, return AST__BAD. */
1200    if( smap ) {
1201 
1202 /* Get the number of inputs */
1203       nin = astGetNin( smap );
1204 
1205 /* Transform the supplied position using the selector Mapping. The output
1206    value is the selector value that indicates which route Mapping to use. */
1207       astTranN( smap, 1, nin, 1, at, 1, 1, 1, &sel );
1208 
1209 /* Get the index of the route Mapping to use, and check it is valid (if
1210    not, return AST__BAD if not). This takes account of whether the
1211    SwitchMap has been inverted, and also temporarily re-instates the
1212    original value of the route Mapping's Invert flag . */
1213       rmap = GetRoute( map, sel, &rinv, status );
1214       if( rmap ) {
1215 
1216 /* Use the astRate method of the route Mapping. */
1217          result = astRate( rmap, at, ax1, ax2 );
1218 
1219 /* Reset the Invert flag for the route Mapping. */
1220          astSetInvert( rmap, rinv );
1221       }
1222 
1223 /* Reset the Invert flag for the selector Mapping. */
1224       astSetInvert( smap, fsinv );
1225    }
1226 
1227 /* Return the result. */
1228    return result;
1229 }
1230 
RemoveRegions(AstMapping * this_mapping,int * status)1231 static AstMapping *RemoveRegions( AstMapping *this_mapping, int *status ) {
1232 /*
1233 *  Name:
1234 *     RemoveRegions
1235 
1236 *  Purpose:
1237 *     Remove any Regions from a Mapping.
1238 
1239 *  Type:
1240 *     Private function.
1241 
1242 *  Synopsis:
1243 *     #include "switchmap.h"
1244 *     AstMapping *RemoveRegions( AstMapping *this, int *status )
1245 
1246 *  Class Membership:
1247 *     SwitchMap method (over-rides the astRemoveRegions method inherited
1248 *     from the Mapping class).
1249 
1250 *  Description:
1251 *     This function searches the supplied Mapping (which may be a
1252 *     compound Mapping such as a SwitchMap) for any component Mappings
1253 *     that are instances of the AST Region class. It then creates a new
1254 *     Mapping from which all Regions have been removed. If a Region
1255 *     cannot simply be removed (for instance, if it is a component of a
1256 *     parallel SwitchMap), then it is replaced with an equivalent UnitMap
1257 *     in the returned Mapping.
1258 *
1259 *     The implementation provided by the SwitchMap class invokes the
1260 *     astRemoveRegions method on all the component Mappings, and joins
1261 *     the results together into a new SwitchMap.
1262 
1263 *  Parameters:
1264 *     this
1265 *        Pointer to the original Region.
1266 *     status
1267 *        Pointer to the inherited status variable.
1268 
1269 *  Returned Value:
1270 *     A pointer to the modified mapping.
1271 
1272 *  Notes:
1273 *     - A NULL pointer value will be returned if this function is
1274 *     invoked with the AST error status set, or if it should fail for
1275 *     any reason.
1276 */
1277 
1278 /* Local Variables: */
1279    AstMapping **temp;            /* Array of new route Mappings */
1280    AstMapping *newfsmap;         /* New forward selector Mapping */
1281    AstMapping *newismap;         /* New inverse selector Mapping */
1282    AstMapping *result;           /* Result pointer to return */
1283    AstSwitchMap *new;            /* Pointer to new SwitchMap */
1284    AstSwitchMap *this;           /* Pointer to SwitchMap structure */
1285    int changed;                  /* Has any mapping been changed? */
1286    int i;                        /* Loop count */
1287    int nax;                      /* Number of Frame axes */
1288 
1289 /* Initialise. */
1290    result = NULL;
1291 
1292 /* Check the global error status. */
1293    if ( !astOK ) return result;
1294 
1295 /* Get a pointer to the SwitchMap. */
1296    this = (AstSwitchMap *) this_mapping;
1297 
1298 /* Allocate an array to hold the modified Mapping pointers. */
1299    temp = astMalloc( sizeof( AstMapping *)*( this->nroute ) );
1300    if( astOK ) {
1301 
1302 /* Invoke the astRemoveRegions method on all the component Mappings. */
1303       changed = 0;
1304       for( i = 0; i < this->nroute; i++ ) {
1305          temp[ i ] = astRemoveRegions( this->routemap[ i ] );
1306 
1307 /* Note if any Mapping was changed. */
1308          if( temp[ i ] != this->routemap[ i ] ) {
1309             changed = 1;
1310 
1311 /* The implementation of the astRemoveRegions method provided by the
1312    Region class returns a Frame rather than a UnitMap. But we need
1313    Mappings here, not Frames. So if the new Mapping is a Frame, replace
1314    it with an equivalent UnitMap. */
1315             if( astIsAFrame( temp[ i ] ) ) {
1316                nax = astGetNin( temp[ i ] );
1317                (void) astAnnul( temp[ i ] );
1318                temp[ i ] = (AstMapping *) astUnitMap( nax, " ", status );
1319             }
1320          }
1321       }
1322 
1323 /* And on the other ancillary Mappings */
1324       if( this->fsmap ) {
1325          newfsmap = astRemoveRegions( this->fsmap );
1326          if( newfsmap != this->fsmap ) {
1327             changed = 1;
1328             if( astIsAFrame( newfsmap ) ) {
1329                nax = astGetNin( newfsmap );
1330                (void) astAnnul( newfsmap );
1331                newfsmap = (AstMapping *) astUnitMap( nax, " ", status );
1332             }
1333          }
1334 
1335       } else {
1336          newfsmap = NULL;
1337       }
1338 
1339       if( this->ismap ) {
1340          newismap = astRemoveRegions( this->ismap );
1341          if( newismap != this->ismap ) {
1342             changed = 1;
1343             if( astIsAFrame( newismap ) ) {
1344                nax = astGetNin( newismap );
1345                (void) astAnnul( newismap );
1346                newismap = (AstMapping *) astUnitMap( nax, " ", status );
1347             }
1348          }
1349 
1350       } else {
1351          newismap = NULL;
1352       }
1353 
1354 /* If no component was modified, just return a clone of the supplied
1355    pointer. */
1356       if( ! changed ) {
1357          result = astClone( this );
1358 
1359 /* Otherwise, we need to create a new Mapping to return. We take a deep
1360    copy of the supplied SwitchMap and then modify the Mappings so that
1361    we retain any extra information in the supplied SwitchMap. */
1362       } else {
1363          new = astCopy( this );
1364 
1365          for( i = 0; i < this->nroute; i++ ) {
1366             (void) astAnnul( new->routemap[ i ] );
1367             new->routemap[ i ] = astClone( temp[ i ] );
1368          }
1369 
1370          if( newfsmap ) {
1371             (void) astAnnul( new->fsmap );
1372             new->fsmap = astClone( newfsmap );
1373          }
1374 
1375          if( newismap ) {
1376             (void) astAnnul( new->ismap );
1377             new->ismap = astClone( newismap );
1378          }
1379 
1380          result = (AstMapping *) new;
1381       }
1382 
1383 /* Free resources. */
1384       for( i = 0; i < this->nroute; i++ ) {
1385          temp[ i ] = astAnnul( temp[ i ] );
1386       }
1387 
1388       if( newfsmap ) newfsmap = astAnnul( newfsmap );
1389       if( newismap ) newismap = astAnnul( newismap );
1390    }
1391 
1392    temp = astFree( temp );
1393 
1394 /* Annul the returned Mapping if an error has occurred. */
1395    if( !astOK ) result = astAnnul( result );
1396 
1397 /* Return the result. */
1398    return result;
1399 }
1400 
astSwitchList_(AstSwitchMap * this,int invert,int * nmap,AstMapping *** map_list,int ** invert_list,int * status)1401 int astSwitchList_( AstSwitchMap *this, int invert, int *nmap,
1402                     AstMapping ***map_list, int **invert_list, int *status ) {
1403 /*
1404 *+
1405 *  Name:
1406 *     astSwitchList
1407 
1408 *  Purpose:
1409 *     Extract the selector and route Mappings from a SwitchMap.
1410 
1411 *  Type:
1412 *     Protected function.
1413 
1414 *  Synopsis:
1415 *     #include "switchmap.h"
1416 *     int astSwitchList( AstSwitchMap *this, int invert, int *nmap,
1417 *                        AstMapping ***map_list, int **invert_list )
1418 
1419 *  Class Membership:
1420 *     SwitchMap member function.
1421 
1422 *  Description:
1423 *     This function extracts the route and selector Mappings form a
1424 *     SwitchMap.
1425 
1426 *  Parameters:
1427 *     this
1428 *        Pointer to the SwitchMap to be decomposed (it is not actually
1429 *        modified by this function).
1430 *     invert
1431 *        The value to which the SwitchMap's Invert attribute is to be
1432 *        (notionally) set before performing the decomposition. Normally,
1433 *        the value supplied here will be the actual Invert value obtained
1434 *        from the SwitchMap (e.g. using astGetInvert).  Sometimes, however,
1435 *        when a SwitchMap is encapsulated within another structure, that
1436 *        structure may retain an Invert value (in order to prevent external
1437 *        interference) which should be used instead.
1438 *
1439 *        Note that the actual Invert value of the SwitchMap supplied is
1440 *        not used (or modified) by this function.
1441 *     nmap
1442 *        The address of an int in which to return a count of the number of
1443 *        individual Mappings in the decomposition. The supplied value is
1444 *        ignored.
1445 *     map_list
1446 *        Address of a pointer to an array of Mapping pointers. The value
1447 *        supplied on entry is ignored. On exit, it points at a dynamically
1448 *        allocated array containing Mapping pointers ("*nmap" in number) that
1449 *        result from the decomposition requested.
1450 *
1451 *        The returned Mapping pointers returned will identify the following
1452 *        sequence of Mappings; forward selector mapping (or NULL if the
1453 *        SwitchMap has no forward selector Mapping), inverse selector
1454 *        mapping (or NULL if the SwitchMap has no inverse selector Mapping),
1455 *        the route Mappings in the order they were supplied when the
1456 *        SwitchMap was constructed.
1457 *
1458 *        All the Mapping pointers returned by this function should be
1459 *        annulled by the caller, using astAnnul, when no longer
1460 *        required. The dynamic array holding these pointers should
1461 *        also be freed, using astFree.
1462 *     invert_list
1463 *        Address of a pointer to an array of int. The value supplied on
1464 *        entry is ignored. On exit, it points at a dynamically allocated
1465 *        array containing Invert attribute values ("*nmap" in number) that
1466 *        result from the decomposition requested.
1467 *
1468 *        The returned Invert values returned identify the values which must
1469 *        be assigned to the Invert attributes of the corresponding
1470 *        Mappings (whose pointers are in the "*map_list" array) before
1471 *        they are applied. Note that these values may differ from the
1472 *        actual Invert attribute values of these Mappings, which are
1473 *        not relevant.
1474 *
1475 *        The dynamic array holding these values should be freed by the
1476 *        caller, using astFree, when no longer required.
1477 
1478 *  Returned Value:
1479 *     The number of route Mappings stored in the SwitchMap.
1480 
1481 *  Notes:
1482 *     - It is unspecified to what extent the original SwitchMap and the
1483 *     individual (decomposed) Mappings are inter-dependent. Consequently,
1484 *     the individual Mappings cannot be modified without risking
1485 *     modification of the original SwitchMap.
1486 *     - If this function is invoked with the global error status set,
1487 *     or if it should fail for any reason, then the *nmap value, the
1488 *     list of Mapping pointers and the list of Invert values will all
1489 *     be returned unchanged.
1490 *-
1491 */
1492 
1493 /* Local Variables: */
1494    AstMapping *map;              /* Pointer to Mapping to return */
1495    int inv;                      /* Original Invert flag for Mapping */
1496    int i;                        /* Route Mapping index */
1497    int oldinv;                   /* Original Invert flag for SwitchMap */
1498    int result;                   /* Returned value */
1499 
1500 /* Check the global error status. */
1501    if ( !astOK ) return 0;
1502 
1503 /* Store the numbe of route Mappings */
1504    result = this->nroute;
1505    *nmap = result + 2;
1506 
1507 /* Allocate the required arrays. */
1508    *map_list = astMalloc( sizeof( AstMapping * )*(size_t) *nmap );
1509    *invert_list = astMalloc( sizeof( int )*(size_t) *nmap );
1510 
1511 /* Check the pointers can be used safely. */
1512    if( astOK ) {
1513 
1514 /* Temporaily set the requested Invert flag for the SwitchMap. */
1515       oldinv = astGetInvert( this );
1516       astSetInvert( this, invert );
1517 
1518 /* Get the forward selector Mapping. */
1519       map = GetSelector( this, 1, &inv, status );
1520 
1521 /* If the SwitchMap has a forward selector Mapping, return a clone of the
1522    Mapping pointer, and the invert flag to be used with it, then
1523    re-instate the original invert flag value (which was modified by
1524    GetSelector). */
1525       if( map ) {
1526          ( *map_list )[ 0 ] = astClone( map );
1527          ( *invert_list )[ 0 ] = astGetInvert( map );
1528          astSetInvert( map, inv );
1529 
1530 /* If the SwitchMap does not has a forward selector Mapping, return a
1531    NULL pointer. */
1532       } else {
1533          ( *map_list )[ 0 ] = NULL;
1534          ( *invert_list )[ 0 ] = 0;
1535       }
1536 
1537 /* Likewise, get and return the inverse selector Mapping.*/
1538       map = GetSelector( this, 0, &inv, status );
1539       if( map ) {
1540          ( *map_list )[ 1 ] = astClone( map );
1541          ( *invert_list )[ 1 ] = astGetInvert( map );
1542          astSetInvert( map, inv );
1543       } else {
1544          ( *map_list )[ 1 ] = NULL;
1545          ( *invert_list )[ 1 ] = 0;
1546       }
1547 
1548 /* Loop round all route Mappings. */
1549       for( i = 0; i < result; i++ ){
1550 
1551 /* Get the next route Mapping. */
1552          map = GetRoute( this, (double) i + 1.0, &inv, status );
1553 
1554 /* If the SwitchMap has a route Mapping for the current selector value,
1555    return a clone of the Mapping pointer, and the invert flag to be used
1556    with it, then re-instate the original invert flag value (which was
1557    modified by GetRoute). */
1558          if( map ) {
1559             ( *map_list )[ i + 2 ] = astClone( map );
1560             ( *invert_list )[ i + 2 ] = astGetInvert( map );
1561             astSetInvert( map, inv );
1562 
1563 /* If the SwitchMap does not has a route Mapping for the current selector
1564    value, return a NULL pointer. */
1565          } else {
1566             ( *map_list )[ i + 2 ] = NULL;
1567             ( *invert_list )[ i + 2 ] = 0;
1568          }
1569 
1570       }
1571 
1572 /* Re-instate the original Ivert flag for the SwitchMap. */
1573       astSetInvert( this, oldinv );
1574 
1575    }
1576 
1577 /* If an error has occurred, free the returned arrays. */
1578    if( !astOK ) {
1579       *map_list = astFree( *map_list );
1580       *invert_list= astFree( *invert_list );
1581       result= 0;
1582       *nmap = 0;
1583    }
1584 
1585 /* Return the result */
1586    return result;
1587 }
1588 
Transform(AstMapping * this,AstPointSet * in,int forward,AstPointSet * out,int * status)1589 static AstPointSet *Transform( AstMapping *this, AstPointSet *in,
1590                                int forward, AstPointSet *out, int *status ) {
1591 /*
1592 *  Name:
1593 *     Transform
1594 
1595 *  Purpose:
1596 *     Apply a SwitchMap to transform a set of points.
1597 
1598 *  Type:
1599 *     Private function.
1600 
1601 *  Synopsis:
1602 *     #include "switchmap.h"
1603 *     AstPointSet *Transform( AstMapping *this, AstPointSet *in,
1604 *                             int forward, AstPointSet *out, int *status )
1605 
1606 *  Class Membership:
1607 *     SwitchMap member function (over-rides the astTransform method inherited
1608 *     from the Mapping class).
1609 
1610 *  Description:
1611 *     This function takes a SwitchMap and a set of points encapsulated in a
1612 *     PointSet and transforms the points so as to apply the required Mapping.
1613 *     This implies applying each of the SwitchMap's component Mappings in turn,
1614 *     either in series or in parallel.
1615 
1616 *  Parameters:
1617 *     this
1618 *        Pointer to the SwitchMap.
1619 *     in
1620 *        Pointer to the PointSet associated with the input coordinate values.
1621 *     forward
1622 *        A non-zero value indicates that the forward coordinate transformation
1623 *        should be applied, while a zero value requests the inverse
1624 *        transformation.
1625 *     out
1626 *        Pointer to a PointSet which will hold the transformed (output)
1627 *        coordinate values. A NULL value may also be given, in which case a
1628 *        new PointSet will be created by this function.
1629 *     status
1630 *        Pointer to the inherited status variable.
1631 
1632 *  Returned Value:
1633 *     Pointer to the output (possibly new) PointSet.
1634 
1635 *  Notes:
1636 *     -  A null pointer will be returned if this function is invoked with the
1637 *     global error status set, or if it should fail for any reason.
1638 *     -  The number of coordinate values per point in the input PointSet must
1639 *     match the number of coordinates for the SwitchMap being applied.
1640 *     -  If an output PointSet is supplied, it must have space for sufficient
1641 *     number of points and coordinate values per point to accommodate the
1642 *     result. Any excess space will be ignored.
1643 */
1644 
1645 /* Local Variables: */
1646    AstMapping *rmap;
1647    AstMapping *selmap;
1648    AstPointSet *ps1;
1649    AstPointSet *ps1a;
1650    AstPointSet *ps2;
1651    AstPointSet *ps2a;
1652    AstPointSet *result;
1653    AstPointSet *selps;
1654    AstSwitchMap *map;
1655    double **in_ptr;
1656    double **out_ptr;
1657    double **ptr1;
1658    double **ptr2;
1659    double **sel_ptr;
1660    double *outv;
1661    double *sel;
1662    int *popmap;
1663    int iroute;
1664    int ipoint;
1665    int j;
1666    int k;
1667    int maxpop;
1668    int ncin;
1669    int ncout;
1670    int npoint;
1671    int nroute;
1672    int rindex;
1673    int rinv;
1674    int selinv;
1675    int totpop;
1676 
1677 /* Check the global error status. */
1678    if ( !astOK ) return NULL;
1679 
1680 /* Obtain a pointer to the SwitchMap. */
1681    map = (AstSwitchMap *) this;
1682 
1683 /* Apply the parent Mapping using the stored pointer to the Transform member
1684    function inherited from the parent Mapping class. This function validates
1685    all arguments and generates an output PointSet if necessary, but does not
1686    actually transform any coordinate values. */
1687    result = (*parent_transform)( this, in, forward, out, status );
1688 
1689 /* We now extend the parent astTransform method by applying the component
1690    Mappings of the SwitchMap to generate the output coordinate values. */
1691 
1692 /* Get the number of input and output coords. */
1693    if( forward ) {
1694       ncin = astGetNin( this );
1695       ncout = astGetNout( this );
1696    } else {
1697       ncin = astGetNout( this );
1698       ncout = astGetNin( this );
1699    }
1700 
1701 /* Get the appropriate selector Mapping. */
1702    selmap = GetSelector( map, forward, &selinv, status );
1703 
1704 /* Transform the supplied positions using the above selector Mapping. */
1705    selps = astTransform( selmap, in, forward, NULL );
1706 
1707 /* Get a pointer to the array holding the selector value. */
1708    sel_ptr = astGetPoints( selps );
1709 
1710 /* Get a pointer to the array holding the input values. */
1711    in_ptr = astGetPoints( in );
1712 
1713 /* Get a pointer to the array in which to store the results, and the total
1714    number of points being transformed. */
1715    out_ptr = astGetPoints( result );
1716    npoint = astGetNpoint( result );
1717 
1718 /* We now count how many positions are to be tranformed by each of the
1719    route Mappings. */
1720    nroute = map->nroute;
1721    popmap = astMalloc( sizeof( int )*nroute );
1722    if( astOK ) {
1723       for( iroute = 0; iroute < nroute; iroute++ ) popmap[ iroute ] = 0;
1724 
1725       sel = sel_ptr[ 0 ];
1726       for( ipoint = 0; ipoint < npoint; ipoint++,sel++ ) {
1727          if( *sel != AST__BAD ) {
1728             rindex = (int)( *sel + 0.5 ) - 1;
1729             if( rindex >= 0 && rindex < nroute ) ( popmap[ rindex ] )++;
1730          }
1731       }
1732 
1733 /* Find the number of points transformed by the most popular route Mapping.
1734    Also find the total number of points transformed by any route Mapping. */
1735       totpop = 0;
1736       maxpop = 0;
1737       for( iroute = 0; iroute < nroute; iroute++ ) {
1738          if( popmap[ iroute ] > maxpop ) maxpop = popmap[ iroute ];
1739          totpop += popmap[ iroute ];
1740       }
1741       if( maxpop == 0 ) maxpop = 1;
1742 
1743 /* If some of the points are not transformed by any route Mapping.
1744    Initialise the whole output array to hold AST__BAD at every point. */
1745       if( totpop < npoint ) {
1746          for( j = 0; j < ncout; j++ ) {
1747             outv = out_ptr[ j ];
1748             for( ipoint = 0; ipoint < npoint; ipoint++ ) *(outv++) = AST__BAD;
1749          }
1750       }
1751 
1752 /* Create a PointSet large enough to hold all the supplied positions
1753    which are to be transformed by the most popular route Mapping. */
1754       ps1 = astPointSet( maxpop, ncin, "", status );
1755       ptr1 = astGetPoints( ps1 );
1756 
1757 /* Create a PointSet large enough to hold all the output positions
1758    created by the most popular route Mapping. */
1759       ps2 = astPointSet( maxpop, ncout, "", status );
1760       ptr2 = astGetPoints( ps2 );
1761       if( astOK ) {
1762 
1763 /* Loop round each route Mapping which is used by at least 1 point. */
1764          for( iroute = 0; iroute < nroute; iroute++ ) {
1765             if( popmap[ iroute ] >0 ) {
1766                rmap = GetRoute( map, (double)( iroute + 1 ), &rinv, status );
1767 
1768 /* Construct two PointSets of the correct size to hold the input and
1769    output points to be processed with the current route Mapping. We
1770    re-use the memory allocated for the largest route Mapping's PointSet. */
1771                if( popmap[ iroute ] != maxpop ) {
1772                   ps1a = astPointSet( popmap[ iroute ], ncin, "", status );
1773                   astSetPoints( ps1a, ptr1 );
1774                   ps2a = astPointSet( popmap[ iroute ], ncout, "", status );
1775                   astSetPoints( ps2a, ptr2 );
1776                } else {
1777                   ps1a = astClone( ps1 );
1778                   ps2a = astClone( ps2 );
1779                }
1780 
1781 /* Fill the input PointSet with the input positions which are to be
1782    transformed using the current route Mapping. */
1783                sel = sel_ptr[ 0 ];
1784                k = 0;
1785                for( ipoint = 0; ipoint < npoint; ipoint++,sel++ ) {
1786                   if( *sel != AST__BAD ) {
1787                      rindex = (int)( *sel + 0.5 ) - 1;
1788                      if( rindex == iroute ) {
1789                         for( j = 0; j < ncin; j++ ) {
1790                            ptr1[ j ][ k ] = in_ptr[ j ][ ipoint ];
1791                         }
1792                         k++;
1793                      }
1794                   }
1795                }
1796 
1797 /* Use the route Mapping to transform this PointSet. */
1798                (void) astTransform( rmap, ps1a, forward, ps2a );
1799 
1800 /* Copy the axis values from the resulting PointSet back into the results
1801    array. */
1802                sel = sel_ptr[ 0 ];
1803                k = 0;
1804                for( ipoint = 0; ipoint < npoint; ipoint++,sel++ ) {
1805                   if( *sel != AST__BAD ) {
1806                      rindex = (int)( *sel + 0.5 ) - 1;
1807                      if( rindex == iroute ) {
1808                         for( j = 0; j < ncout; j++ ) {
1809                            out_ptr[ j ][ ipoint ] = ptr2[ j ][ k ];
1810                         }
1811                         k++;
1812                      }
1813                   }
1814                }
1815 
1816 /* Free resources. */
1817                ps1a = astAnnul( ps1a );
1818                ps2a = astAnnul( ps2a );
1819 
1820 /* Re-instate the Invert flag for the route Mapping. */
1821                astSetInvert( rmap, rinv );
1822             }
1823          }
1824       }
1825 
1826 /* Free resources. */
1827       ps1 = astAnnul( ps1 );
1828       ps2 = astAnnul( ps2 );
1829    }
1830 
1831    selps = astAnnul( selps );
1832    popmap = astFree( popmap );
1833 
1834 /* Re-instate the Invert flag of the selector Mapping. */
1835    astSetInvert( selmap, selinv );
1836 
1837 /* If an error occurred, clean up by deleting the output PointSet (if
1838    allocated by this function) and setting a NULL result pointer. */
1839    if ( !astOK ) {
1840       if ( !out ) result = astDelete( result );
1841       result = NULL;
1842    }
1843 
1844 /* Return a pointer to the output PointSet. */
1845    return result;
1846 }
1847 
1848 /* Copy constructor. */
1849 /* ----------------- */
Copy(const AstObject * objin,AstObject * objout,int * status)1850 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
1851 /*
1852 *  Name:
1853 *     Copy
1854 
1855 *  Purpose:
1856 *     Copy constructor for SwitchMap objects.
1857 
1858 *  Type:
1859 *     Private function.
1860 
1861 *  Synopsis:
1862 *     void Copy( const AstObject *objin, AstObject *objout, int *status )
1863 
1864 *  Description:
1865 *     This function implements the copy constructor for SwitchMap objects.
1866 
1867 *  Parameters:
1868 *     objin
1869 *        Pointer to the object to be copied.
1870 *     objout
1871 *        Pointer to the object being constructed.
1872 *     status
1873 *        Pointer to the inherited status variable.
1874 
1875 *  Returned Value:
1876 *     void
1877 
1878 *  Notes:
1879 *     -  This constructor makes a deep copy, including a copy of the component
1880 *     Mappings within the SwitchMap.
1881 */
1882 
1883 /* Local Variables: */
1884    AstSwitchMap *in;                /* Pointer to input SwitchMap */
1885    AstSwitchMap *out;               /* Pointer to output SwitchMap */
1886    int i;                           /* Loop count */
1887 
1888 /* Check the global error status. */
1889    if ( !astOK ) return;
1890 
1891 /* Obtain pointers to the input and output SwitchMaps. */
1892    in = (AstSwitchMap *) objin;
1893    out = (AstSwitchMap *) objout;
1894 
1895 /* For safety, start by clearing any references to the input component
1896    Mappings,etc, from the output SwitchMap. */
1897    out->fsmap = NULL;
1898    out->ismap = NULL;
1899    out->routemap = NULL;
1900    out->routeinv = NULL;
1901 
1902 /* Make copies of these Mappings, etc, and store pointers to them in the output
1903    SwitchMap structure. */
1904    if( in->fsmap ) out->fsmap = astCopy( in->fsmap );
1905    if( in->ismap ) out->ismap = astCopy( in->ismap );
1906 
1907    out->routemap = astMalloc( sizeof( AstMapping * )*( in->nroute ) );
1908    out->routeinv = astMalloc( sizeof( int )*( in->nroute ) );
1909    if( astOK ) {
1910       for( i = 0; i < in->nroute; i++ ) {
1911          out->routemap[ i ] = astCopy( in->routemap[ i ] );
1912          out->routeinv[ i ] = in->routeinv[ i ];
1913       }
1914    }
1915 
1916 }
1917 
1918 /* Destructor. */
1919 /* ----------- */
Delete(AstObject * obj,int * status)1920 static void Delete( AstObject *obj, int *status ) {
1921 /*
1922 *  Name:
1923 *     Delete
1924 
1925 *  Purpose:
1926 *     Destructor for SwitchMap objects.
1927 
1928 *  Type:
1929 *     Private function.
1930 
1931 *  Synopsis:
1932 *     void Delete( AstObject *obj, int *status )
1933 
1934 *  Description:
1935 *     This function implements the destructor for SwitchMap objects.
1936 
1937 *  Parameters:
1938 *     obj
1939 *        Pointer to the object to be deleted.
1940 *     status
1941 *        Pointer to the inherited status variable.
1942 
1943 *  Returned Value:
1944 *     void
1945 
1946 *  Notes:
1947 *     This function attempts to execute even if the global error status is
1948 *     set.
1949 */
1950 
1951 /* Local Variables: */
1952    AstSwitchMap *this;              /* Pointer to SwitchMap */
1953    int i;
1954 
1955 /* Obtain a pointer to the SwitchMap structure. */
1956    this = (AstSwitchMap *) obj;
1957 
1958 /* Free dynamically allocated resources. */
1959    if( this->fsmap ) this->fsmap = astAnnul( this->fsmap );
1960    if( this->ismap ) this->ismap = astAnnul( this->ismap );
1961    for( i = 0; i < this->nroute; i++ ) {
1962       this->routemap[ i ] = astAnnul( this->routemap[ i ] );
1963    }
1964    this->routemap = astFree( this->routemap );
1965    this->routeinv = astFree( this->routeinv );
1966 
1967 /* Clear the remaining SwitchMap variables. */
1968    this->nroute = 0;
1969    this->fsinv = 0;
1970    this->isinv = 0;
1971 }
1972 
1973 /* Dump function. */
1974 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)1975 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
1976 /*
1977 *  Name:
1978 *     Dump
1979 
1980 *  Purpose:
1981 *     Dump function for SwitchMap objects.
1982 
1983 *  Type:
1984 *     Private function.
1985 
1986 *  Synopsis:
1987 *     void Dump( AstObject *this, AstChannel *channel, int *status )
1988 
1989 *  Description:
1990 *     This function implements the Dump function which writes out data
1991 *     for the SwitchMap class to an output Channel.
1992 
1993 *  Parameters:
1994 *     this
1995 *        Pointer to the SwitchMap whose data are being written.
1996 *     channel
1997 *        Pointer to the Channel to which the data are being written.
1998 *     status
1999 *        Pointer to the inherited status variable.
2000 */
2001 
2002 /* Local Variables: */
2003    AstSwitchMap *this;
2004    int ival;
2005    int set;
2006    int i;
2007    char buf[ 20 ];
2008 
2009 /* Check the global error status. */
2010    if ( !astOK ) return;
2011 
2012 /* Obtain a pointer to the SwitchMap structure. */
2013    this = (AstSwitchMap *) this_object;
2014 
2015 /* Write out values representing the instance variables for the SwitchMap
2016    class.  Accompany these with appropriate comment strings, possibly
2017    depending on the values being written.*/
2018 
2019 /* In the case of attributes, we first use the appropriate (private)
2020    Test...  member function to see if they are set. If so, we then use
2021    the (private) Get... function to obtain the value to be written
2022    out.
2023 
2024    For attributes which are not set, we use the astGet... method to
2025    obtain the value instead. This will supply a default value
2026    (possibly provided by a derived class which over-rides this method)
2027    which is more useful to a human reader as it corresponds to the
2028    actual default attribute value.  Since "set" will be zero, these
2029    values are for information only and will not be read back. */
2030 
2031 /* Forward selector Mapping */
2032 /* ------------------------ */
2033    if( this->fsmap ) {
2034       astWriteObject( channel, "FSMap", 1, 1, this->fsmap,
2035                       "Forward selector Mapping" );
2036 
2037 /* Forward selector Invert flag. */
2038 /* ----------------------------- */
2039       ival = this->fsinv;
2040       set = ( ival != 0 );
2041       astWriteInt( channel, "FSInv", set, 0, ival,
2042                    ival ? "Fwd selector used in inverse direction" :
2043                           "Fwd selector used in forward direction" );
2044    }
2045 
2046 
2047 /* Inverse selector Mapping */
2048 /* ------------------------ */
2049    if( this->ismap ) {
2050       astWriteObject( channel, "ISMap", 1, 1, this->ismap,
2051                       "Inverse selector Mapping" );
2052 
2053 /* Forward selector Invert flag. */
2054 /* ----------------------------- */
2055       ival = this->isinv;
2056       set = ( ival != 0 );
2057       astWriteInt( channel, "ISInv", set, 0, ival,
2058                    ival ? "Inv selector used in inverse direction" :
2059                           "Inv selector used in forward direction" );
2060    }
2061 
2062 /* Loop to dump each route Mapping and its invert flag. */
2063 /* ---------------------------------------------------- */
2064    for( i = 0; i < this->nroute; i++ ) {
2065       sprintf( buf, "RMap%d", i + 1 );
2066       astWriteObject( channel, buf, 1, 1, this->routemap[ i ],
2067                       "Route Mapping" );
2068 
2069       ival = this->routeinv[ i ];
2070       set = ( ival != 0 );
2071       sprintf( buf, "RInv%d", i + 1 );
2072       astWriteInt( channel, buf, set, 0, ival,
2073                    ival ? "Route Mapping used in inverse direction" :
2074                           "Route Mapping used in forward direction" );
2075    }
2076 
2077 }
2078 
2079 /* Standard class functions. */
2080 /* ========================= */
2081 /* Implement the astIsASwitchMap and astCheckSwitchMap functions using the
2082    macros defined for this purpose in the "object.h" header file. */
astMAKE_ISA(SwitchMap,Mapping)2083 astMAKE_ISA(SwitchMap,Mapping)
2084 astMAKE_CHECK(SwitchMap)
2085 
2086 AstSwitchMap *astSwitchMap_( void *fsmap_void, void *ismap_void, int nroute,
2087                              void **routemaps_void, const char *options, int *status, ...) {
2088 /*
2089 *+
2090 *  Name:
2091 *     astSwitchMap
2092 
2093 *  Purpose:
2094 *     Create a SwitchMap.
2095 
2096 *  Type:
2097 *     Protected function.
2098 
2099 *  Synopsis:
2100 *     #include "switchmap.h"
2101 *     AstSwitchMap *astSwitchMap( AstMapping *fsmap, AstMapping *ismap,
2102 *                                 int nroute, AstMapping **routemaps,
2103 *                                 const char *options, ... )
2104 
2105 *  Class Membership:
2106 *     SwitchMap constructor.
2107 
2108 *  Description:
2109 *     This function creates a new SwitchMap and optionally initialises its
2110 *     attributes.
2111 
2112 *  Parameters:
2113 *     fsmap
2114 *        Pointer to the forward selector Mapping
2115 *     ismap
2116 *        Pointer to the inverse selector Mapping
2117 *     nroute
2118 *        The number of route Mappings.
2119 *     routemaps
2120 *        An array of pointers to the route Mappings.
2121 *     options
2122 *        Pointer to a null terminated string containing an optional
2123 *        comma-separated list of attribute assignments to be used for
2124 *        initialising the new SwitchMap. The syntax used is the same as for the
2125 *        astSet method and may include "printf" format specifiers identified
2126 *        by "%" symbols in the normal way.
2127 *     ...
2128 *        If the "options" string contains "%" format specifiers, then an
2129 *        optional list of arguments may follow it in order to supply values to
2130 *        be substituted for these specifiers. The rules for supplying these
2131 *        are identical to those for the astSet method (and for the C "printf"
2132 *        function).
2133 
2134 *  Returned Value:
2135 *     A pointer to the new SwitchMap.
2136 
2137 *  Notes:
2138 *     - A null pointer will be returned if this function is invoked
2139 *     with the global error status set, or if it should fail for any
2140 *     reason.
2141 *-
2142 
2143 *  Implementation Notes:
2144 *     - This function implements the basic SwitchMap constructor which is
2145 *     available via the protected interface to the SwitchMap class.  A
2146 *     public interface is provided by the astSwitchMapId_ function.
2147 *     - Because this function has a variable argument list, it is
2148 *     invoked by a macro that evaluates to a function pointer (not a
2149 *     function invocation) and no checking or casting of arguments is
2150 *     performed before the function is invoked. Because of this, the
2151 *     "map1" and "map2" parameters are of type (void *) and are
2152 *     converted and validated within the function itself.
2153 */
2154 
2155 /* Local Variables: */
2156    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2157    AstSwitchMap *new;            /* Pointer to new SwitchMap */
2158    AstMapping *fsmap;            /* Pointer to fwd selector Mapping */
2159    AstMapping *ismap;            /* Pointer to inv selector Mapping */
2160    AstMapping **routemaps;       /* Array of route Mapping pointers */
2161    int i;                        /* Route Mappings index */
2162    va_list args;                 /* Variable argument list */
2163 
2164 /* Initialise. */
2165    new = NULL;
2166 
2167 /* Get a pointer to the thread specific global data structure. */
2168    astGET_GLOBALS(NULL);
2169 
2170 /* Check the global status. */
2171    if ( !astOK ) return new;
2172 
2173 /* Report an error if no route Mappings have been supplied. */
2174    if( nroute <= 0 ) astError( AST__BDPAR, "astSwitchMap(SwitchMap): "
2175                                "Bad number of route Mappings (%d) specified.", status,
2176                                nroute );
2177 
2178 /* Otherwise create an array to hold the route Mapping pointers. */
2179    routemaps = astMalloc( sizeof( AstMapping * )*nroute );
2180 
2181 /* Obtain and validate pointers to the Mapping structures provided. */
2182    if( astOK ) {
2183       fsmap = fsmap_void ? astCheckMapping( fsmap_void ) : NULL;
2184       ismap = ismap_void ? astCheckMapping( ismap_void ) : NULL;
2185       for( i = 0; i < nroute; i++ ) {
2186          routemaps[ i ] = astCheckMapping( routemaps_void[ i ] );
2187       }
2188    }
2189 
2190    if ( astOK ) {
2191 
2192 /* Initialise the SwitchMap, allocating memory and initialising the
2193    virtual function table as well if necessary. */
2194       new = astInitSwitchMap( NULL, sizeof( AstSwitchMap ), !class_init, &class_vtab,
2195                               "SwitchMap", fsmap, ismap, nroute, routemaps );
2196 
2197 /* If successful, note that the virtual function table has been
2198    initialised. */
2199       if ( astOK ) {
2200          class_init = 1;
2201 
2202 /* Obtain the variable argument list and pass it along with the
2203    options string to the astVSet method to initialise the new SwitchMap's
2204    attributes. */
2205          va_start( args, status );
2206          astVSet( new, options, NULL, args );
2207          va_end( args );
2208 
2209 /* If an error occurred, clean up by deleting the new object. */
2210          if ( !astOK ) new = astDelete( new );
2211       }
2212    }
2213 
2214 /* Free memory used to hold the route Mapping pointers. */
2215    routemaps = astFree( routemaps );
2216 
2217 /* Return a pointer to the new SwitchMap. */
2218    return new;
2219 }
2220 
astSwitchMapId_(void * fsmap_void,void * ismap_void,int nroute,void ** routemaps_void,const char * options,...)2221 AstSwitchMap *astSwitchMapId_( void *fsmap_void, void *ismap_void, int nroute,
2222                                void **routemaps_void, const char *options, ... ) {
2223 /*
2224 *++
2225 *  Name:
2226 c     astSwitchMap
2227 f     AST_SWITCHMAP
2228 
2229 *  Purpose:
2230 *     Create a SwitchMap.
2231 
2232 *  Type:
2233 *     Public function.
2234 
2235 *  Synopsis:
2236 c     #include "switchmap.h"
2237 c     AstSwitchMap *astSwitchMap( AstMapping *fsmap, AstMapping *ismap,
2238 c                                 int nroute, AstMapping *routemaps[],
2239 c                                 const char *options, ... )
2240 f     RESULT = AST_SWITCHMAP( FSMAP, ISMAP, NROUTE, ROUTEMAPS, OPTIONS,
2241 f                             STATUS )
2242 
2243 *  Class Membership:
2244 *     SwitchMap constructor.
2245 
2246 *  Description:
2247 *     This function creates a new SwitchMap and optionally initialises
2248 *     its attributes.
2249 *
2250 *     A SwitchMap is a Mapping which represents a set of alternate
2251 *     Mappings, each of which is used to transform positions within a
2252 *     particular region of the input or output coordinate system of the
2253 *     SwitchMap.
2254 *
2255 *     A SwitchMap can encapsulate any number of Mappings, but they must
2256 *     all have the same number of inputs (Nin attribute value) and the
2257 *     same number of outputs (Nout attribute value). The SwitchMap itself
2258 *     inherits these same values for its Nin and Nout attributes. Each of
2259 *     these Mappings represents a "route" through the switch, and are
2260 *     referred to as "route" Mappings below. Each route Mapping transforms
2261 *     positions between the input and output coordinate space of the entire
2262 *     SwitchMap, but only one Mapping will be used to transform any given
2263 *     position. The selection of the appropriate route Mapping to use with
2264 *     any given input position is made by another Mapping, called the
2265 *     "selector" Mapping. Each SwitchMap encapsulates two selector
2266 *     Mappings in addition to its route Mappings; one for use with the
2267 *     SwitchMap's forward transformation (called the "forward selector
2268 *     Mapping"), and one for use with the SwitchMap's inverse transformation
2269 *     (called the "inverse selector Mapping"). The forward selector Mapping
2270 *     must have the same number of inputs as the route Mappings, but
2271 *     should have only one output. Likewise, the inverse selector Mapping
2272 *     must have the same number of outputs as the route Mappings, but
2273 *     should have only one input.
2274 *
2275 *     When the SwitchMap is used to transform a position in the forward
2276 *     direction (from input to output), each supplied input position is
2277 *     first transformed by the forward transformation of the forward selector
2278 *     Mapping. This produces a single output value for each input position
2279 *     referred to as the selector value. The nearest integer to the selector
2280 *     value is found, and is used to index the array of route Mappings (the
2281 *     first supplied route Mapping has index 1, the second route Mapping has
2282 *     index 2, etc). If the nearest integer to the selector value is less
2283 *     than 1 or greater than the number of route Mappings, then the SwitchMap
2284 *     output position is set to a value of AST__BAD on every axis. Otherwise,
2285 *     the forward transformation of the selected route Mapping is used to
2286 *     transform the supplied input position to produce the SwitchMap output
2287 *     position.
2288 *
2289 *     When the SwitchMap is used to transform a position in the inverse
2290 *     direction (from "output" to "input"), each supplied "output" position
2291 *     is first transformed by the inverse transformation of the inverse
2292 *     selector Mapping. This produces a selector value for each "output"
2293 *     position. Again, the nearest integer to the selector value is found,
2294 *     and is used to index the array of route Mappings. If this selector
2295 *     index value is within the bounds of the array of route Mappings, then
2296 *     the inverse transformation of the selected route Mapping is used to
2297 *     transform the supplied "output" position to produce the SwitchMap
2298 *     "input" position. If the selector index value is outside the bounds
2299 *     of the array of route Mappings, then the SwitchMap "input" position is
2300 *     set to a value of AST__BAD on every axis.
2301 *
2302 *     In practice, appropriate selector Mappings should be chosen to
2303 *     associate a different route Mapping with each region of coordinate
2304 *     space. Note that the SelectorMap class of Mapping is particularly
2305 *     appropriate for this purpose.
2306 *
2307 *     If a compound Mapping contains a SwitchMap in series with its own
2308 *     inverse, the combination of the two adjacent SwitchMaps will be
2309 *     replaced by a UnitMap when the compound Mapping is simplified using
2310 c     astSimplify.
2311 f     AST_SIMPLIFY.
2312 
2313 *  Parameters:
2314 c     fsmap
2315 f     FSMAP = INTEGER (Given)
2316 *        Pointer to the forward selector Mapping. This must have a
2317 *        defined forward transformation, but need not have a defined
2318 *        inverse transformation. It must have one output, and the number of
2319 *        inputs must match the number of inputs of each of the supplied
2320 *        route Mappings.
2321 c        NULL
2322 f        AST__NULL
2323 *        may be supplied, in which case the SwitchMap will have an undefined
2324 *        forward Mapping.
2325 c     ismap
2326 f     ISMAP = INTEGER (Given)
2327 *        Pointer to the inverse selector Mapping. This must have a
2328 *        defined inverse transformation, but need not have a defined
2329 *        forward transformation. It must have one input, and the number of
2330 *        outputs must match the number of outputs of each of the supplied
2331 *        route Mappings.
2332 c        NULL
2333 f        AST__NULL
2334 *        may be supplied, in which case the SwitchMap will have an undefined
2335 *        inverse Mapping.
2336 c     nroute
2337 f     NROUTE = INTEGER (Given)
2338 *        The number of supplied route Mappings.
2339 c     routemaps
2340 f     ROUTEMAPS( NROUTE ) = INTEGER (Given)
2341 *        An array of pointers to the route Mappings. All the supplied
2342 *        route Mappings must have common values for the Nin and Nout
2343 *        attributes, and these values define the number of inputs and
2344 *        outputs of the SwitchMap.
2345 c     options
2346 f     OPTIONS = CHARACTER * ( * ) (Given)
2347 c        Pointer to a null-terminated string containing an optional
2348 c        comma-separated list of attribute assignments to be used for
2349 c        initialising the new SwitchMap. The syntax used is identical to
2350 c        that for the astSet function and may include "printf" format
2351 c        specifiers identified by "%" symbols in the normal way.
2352 f        A character string containing an optional comma-separated
2353 f        list of attribute assignments to be used for initialising the
2354 f        new SwitchMap. The syntax used is identical to that for the
2355 f        AST_SET routine.
2356 c     ...
2357 c        If the "options" string contains "%" format specifiers, then
2358 c        an optional list of additional arguments may follow it in
2359 c        order to supply values to be substituted for these
2360 c        specifiers. The rules for supplying these are identical to
2361 c        those for the astSet function (and for the C "printf"
2362 c        function).
2363 f     STATUS = INTEGER (Given and Returned)
2364 f        The global status.
2365 
2366 *  Returned Value:
2367 c     astSwitchMap()
2368 f     AST_SWITCHMAP = INTEGER
2369 *        A pointer to the new SwitchMap.
2370 
2371 *  Notes:
2372 c     - Note that the component Mappings supplied are not copied by
2373 c     astSwitchMap (the new SwitchMap simply retains a reference to
2374 c     them). They may continue to be used for other purposes, but
2375 c     should not be deleted. If a SwitchMap containing a copy of its
2376 c     component Mappings is required, then a copy of the SwitchMap should
2377 c     be made using astCopy.
2378 f     - Note that the component Mappings supplied are not copied by
2379 f     AST_SWITCHMAP (the new SwitchMap simply retains a reference to
2380 f     them). They may continue to be used for other purposes, but
2381 f     should not be deleted. If a SwitchMap containing a copy of its
2382 f     component Mappings is required, then a copy of the SwitchMap should
2383 f     be made using AST_COPY.
2384 *     - A null Object pointer (AST__NULL) will be returned if this
2385 c     function is invoked with the AST error status set, or if it
2386 f     function is invoked with STATUS set to an error value, or if it
2387 *     should fail for any reason.
2388 *--
2389 
2390 *  Implementation Notes:
2391 *     - This function implements the external (public) interface to
2392 *     the astSwitchMap constructor function. It returns an ID value
2393 *     (instead of a true C pointer) to external users, and must be
2394 *     provided because astSwitchMap_ has a variable argument list which
2395 *     cannot be encapsulated in a macro (where this conversion would
2396 *     otherwise occur).
2397 *     - Because no checking or casting of arguments is performed
2398 *     before the function is invoked, the "map1" and "map2" parameters
2399 *     are of type (void *) and are converted from an ID value to a
2400 *     pointer and validated within the function itself.
2401 *     - The variable argument list also prevents this function from
2402 *     invoking astSwitchMap_ directly, so it must be a re-implementation
2403 *     of it in all respects, except for the conversions between IDs
2404 *     and pointers on input/output of Objects.
2405 */
2406 
2407 /* Local Variables: */
2408    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2409    AstSwitchMap *new;            /* Pointer to new SwitchMap */
2410    AstMapping *fsmap;            /* Pointer to fwd selector Mapping */
2411    AstMapping *ismap;            /* Pointer to inv selector Mapping */
2412    AstMapping **routemaps;       /* Array of route Mapping pointers */
2413    int i;                        /* Route Mappings index */
2414    va_list args;                 /* Variable argument list */
2415 
2416    int *status;                  /* Pointer to inherited status value */
2417 
2418 /* Get a pointer to the thread specific global data structure. */
2419    astGET_GLOBALS(NULL);
2420 
2421 /* Initialise. */
2422    new = NULL;
2423 
2424 /* Get a pointer to the inherited status value. */
2425    status = astGetStatusPtr;
2426 
2427 /* Check the global status. */
2428    if ( !astOK ) return new;
2429 
2430 /* Report an error if no route Mappings have been supplied. */
2431    if( nroute <= 0 ) astError( AST__BDPAR, "astSwitchMap(SwitchMap): "
2432                                " Bad number of route Mappings (%d) specified.", status,
2433                                nroute );
2434 
2435 /* Otherwise create an array to hold the route Mapping pointers. */
2436    routemaps = astMalloc( sizeof( AstMapping * )*nroute );
2437 
2438 /* Obtain and validate pointers to the Mapping structures provided. */
2439    if( astOK ) {
2440       fsmap = fsmap_void ? astCheckMapping( astMakePointer(fsmap_void) ) : NULL;
2441       ismap = ismap_void ? astCheckMapping( astMakePointer(ismap_void) ) : NULL;
2442       for( i = 0; i < nroute; i++ ) {
2443          routemaps[ i ] = astVerifyMapping( astMakePointer(routemaps_void[ i ]) );
2444       }
2445    }
2446 
2447    if ( astOK ) {
2448 
2449 /* Initialise the SwitchMap, allocating memory and initialising the
2450    virtual function table as well if necessary. */
2451       new = astInitSwitchMap( NULL, sizeof( AstSwitchMap ), !class_init, &class_vtab,
2452                               "SwitchMap", fsmap, ismap, nroute, routemaps );
2453 
2454 /* If successful, note that the virtual function table has been
2455    initialised. */
2456       if ( astOK ) {
2457          class_init = 1;
2458 
2459 /* Obtain the variable argument list and pass it along with the
2460    options string to the astVSet method to initialise the new SwitchMap's
2461    attributes. */
2462          va_start( args, options );
2463          astVSet( new, options, NULL, args );
2464          va_end( args );
2465 
2466 /* If an error occurred, clean up by deleting the new object. */
2467          if ( !astOK ) new = astDelete( new );
2468       }
2469    }
2470 
2471 /* Free memory used to hold the route Mapping pointers. */
2472    routemaps = astFree( routemaps );
2473 
2474 /* Return an ID value for the new SwitchMap. */
2475    return astMakeId( new );
2476 }
2477 
astInitSwitchMap_(void * mem,size_t size,int init,AstSwitchMapVtab * vtab,const char * name,AstMapping * fsmap,AstMapping * ismap,int nroute,AstMapping ** routemaps,int * status)2478 AstSwitchMap *astInitSwitchMap_( void *mem, size_t size, int init,
2479                                  AstSwitchMapVtab *vtab, const char *name,
2480                                  AstMapping *fsmap, AstMapping *ismap,
2481                                  int nroute, AstMapping **routemaps, int *status ) {
2482 /*
2483 *+
2484 *  Name:
2485 *     astInitSwitchMap
2486 
2487 *  Purpose:
2488 *     Initialise a SwitchMap.
2489 
2490 *  Type:
2491 *     Protected function.
2492 
2493 *  Synopsis:
2494 *     #include "switchmap.h"
2495 *     AstSwitchMap *astInitSwitchMap( void *mem, size_t size, int init,
2496 *                                     AstSwitchMapVtab *vtab, const char *name,
2497 *                                     AstMapping *fsmap, AstMapping *ismap,
2498 *                                     int nroute, AstMapping **routemaps )
2499 
2500 *  Class Membership:
2501 *     SwitchMap initialiser.
2502 
2503 *  Description:
2504 *     This function is provided for use by class implementations to initialise
2505 *     a new SwitchMap object. It allocates memory (if necessary) to
2506 *     accommodate the SwitchMap plus any additional data associated with the
2507 *     derived class. It then initialises a SwitchMap structure at the start
2508 *     of this memory. If the "init" flag is set, it also initialises the
2509 *     contents of a virtual function table for a SwitchMap at the start of
2510 *     the memory passed via the "vtab" parameter.
2511 
2512 *  Parameters:
2513 *     mem
2514 *        A pointer to the memory in which the SwitchMap is to be initialised.
2515 *        This must be of sufficient size to accommodate the SwitchMap data
2516 *        (sizeof(SwitchMap)) plus any data used by the derived class. If a
2517 *        value of NULL is given, this function will allocate the memory itself
2518 *        using the "size" parameter to determine its size.
2519 *     size
2520 *        The amount of memory used by the SwitchMap (plus derived class
2521 *        data). This will be used to allocate memory if a value of NULL is
2522 *        given for the "mem" parameter. This value is also stored in the
2523 *        SwitchMap structure, so a valid value must be supplied even if not
2524 *        required for allocating memory.
2525 *     init
2526 *        A logical flag indicating if the SwitchMap's virtual function table
2527 *        is to be initialised. If this value is non-zero, the virtual function
2528 *        table will be initialised by this function.
2529 *     vtab
2530 *        Pointer to the start of the virtual function table to be associated
2531 *        with the new SwitchMap.
2532 *     name
2533 *        Pointer to a constant null-terminated character string which contains
2534 *        the name of the class to which the new object belongs (it is this
2535 *        pointer value that will subsequently be returned by the Object
2536 *        astClass function).
2537 *     fsmap
2538 *        Pointer to the forward selector Mapping.
2539 *     ismap
2540 *        Pointer to the inverse selector Mapping.
2541 *     nroute
2542 *        The number of route Mappings supplied.
2543 *     routemaps
2544 *        An array holdiong pointers to the route Mappings.
2545 
2546 *  Returned Value:
2547 *     A pointer to the new SwitchMap.
2548 
2549 *  Notes:
2550 *     -  A null pointer will be returned if this function is invoked with the
2551 *     global error status set, or if it should fail for any reason.
2552 *-
2553 */
2554 
2555 /* Local Variables: */
2556    AstSwitchMap *new;            /* Pointer to new SwitchMap */
2557    int i;                        /* Loop count */
2558    int nin;                      /* No. input coordinates for SwitchMap */
2559    int nout;                     /* No. output coordinates for SwitchMap */
2560 
2561 /* Check the global status. */
2562    if ( !astOK ) return NULL;
2563 
2564 /* If necessary, initialise the virtual function table. */
2565    if ( init ) astInitSwitchMapVtab( vtab, name );
2566 
2567 /* Initialise. */
2568    new = NULL;
2569 
2570 /* Check that all route Mappings have common values for Nin and Nout.*/
2571    nin = astGetNin( routemaps[ 0 ] );
2572    nout = astGetNout( routemaps[ 0 ] );
2573    for( i = 1; i < nroute; i++ ) {
2574       if( nin != astGetNin( routemaps[ i ] ) ){
2575          if( astOK ) {
2576             astError( AST__BADNI, "astInitSwitchMap(%s): Route Mapping "
2577                       "number %d has %d input(s) but the first route "
2578                       "Mapping has %d input(s).", status, name, i + 1,
2579                       astGetNin( routemaps[ i ] ), nin );
2580          }
2581 
2582       } else if( nout != astGetNout( routemaps[ i ] ) ){
2583          if( astOK ) {
2584             astError( AST__BADNO, "astInitSwitchMap(%s): Route Mapping "
2585                       "number %d has %d output(s) but the first route "
2586                       "Mapping has %d output(s).", status, name, i + 1,
2587                       astGetNin( routemaps[ i ] ), nin );
2588          }
2589       }
2590    }
2591 
2592 /* If supplied, report an error if fsmap has no forward transformation,
2593    or if it has an incorrect number of inputs or output. */
2594    if( fsmap && astOK ) {
2595       if( !astGetTranForward( fsmap ) ) {
2596          astError( AST__INTRD, "astInitSwitchMap(%s): The forward selector Mapping "
2597               "is not able to transform coordinates in the forward direction.", status,
2598               name );
2599 
2600       } else if( astGetNin( fsmap ) != nin ){
2601          astError( AST__BADNI, "astInitSwitchMap(%s): The forward selector "
2602                    "Mapping has %d input(s) but the SwitchMap has %d "
2603                    "input(s).", status, name, astGetNin( fsmap ), nin );
2604 
2605       } else if( astGetNout( fsmap ) != 1 ){
2606          astError( AST__BADNO, "astInitSwitchMap(%s): The forward selector "
2607                    "Mapping has %d outputs but should only have 1.", status, name,
2608                    astGetNout( fsmap ) );
2609       }
2610    }
2611 
2612 /* If supplied, report an error if ismap has no inverse transformation,
2613    or if it has an incorrect number of inputs or outputs. */
2614    if( ismap && astOK ) {
2615       if( !astGetTranInverse( ismap ) ) {
2616          astError( AST__INTRD, "astInitSwitchMap(%s): The inverse selector Mapping "
2617               "is not able to transform coordinates in the inverse direction.", status,
2618               name );
2619       } else if( nout != astGetNout( ismap ) ){
2620          astError( AST__BADNO, "astInitSwitchMap(%s): The inverse selector "
2621                    "Mapping has %d output(s) but the SwitchMap has %d "
2622                    "output(s).", status, name, astGetNout( ismap ), nout );
2623 
2624       } else if( astGetNin( ismap ) != 1 ){
2625          astError( AST__BADNI, "astInitSwitchMap(%s): The inverse selector "
2626                    "Mapping has %d inputs but should only have 1.", status, name,
2627                    astGetNin( ismap ) );
2628 
2629       }
2630    }
2631 
2632 /* Report an error if neither ismap nor fsmap were supplied. */
2633    if( !fsmap && !ismap && astOK ) {
2634       astError( AST__INTRD, "astInitSwitchMap(%s): No selector Mappings "
2635                 "supplied.", status, name );
2636    }
2637 
2638 /* Initialise a Mapping structure (the parent class) as the first component
2639    within the SwitchMap structure, allocating memory if necessary. Specify
2640    the number of input and output coordinates and in which directions the
2641    Mapping should be defined. */
2642    if ( astOK ) {
2643       new = (AstSwitchMap *) astInitMapping( mem, size, 0,
2644                                              (AstMappingVtab *) vtab, name,
2645                                              nin, nout,
2646                                              ( fsmap != NULL ),
2647                                              ( ismap != NULL ) );
2648       if ( astOK ) {
2649 
2650 /* Initialise the SwitchMap data. */
2651 /* --------------------------- */
2652 /* Store pointers to the selector Mappings. */
2653          new->fsmap = fsmap ? astClone( fsmap ) : NULL;
2654          new->ismap = ismap ? astClone( ismap ) : NULL;
2655 
2656 /* Save the initial values of the inversion flags for these Mappings. */
2657          new->fsinv = fsmap ? astGetInvert( fsmap ) : 0;
2658          new->isinv = ismap ? astGetInvert( ismap ) : 0;
2659 
2660 /* Create arrays for the route Mappings. */
2661          new->routemap = astMalloc( sizeof( AstMapping * )*nroute );
2662          new->routeinv = astMalloc( sizeof( int )*nroute );
2663 
2664 /* Store pointers to the route Mappings and their invert flags. */
2665          if( astOK ) {
2666             new->nroute = nroute;
2667             for( i = 0; i < nroute; i++ ) {
2668                new->routemap[ i ] = astClone( routemaps[ i ] );
2669                new->routeinv[ i ] = astGetInvert( routemaps[ i ] );
2670             }
2671          } else {
2672             new->nroute = 0;
2673          }
2674 
2675 /* If an error occurred, clean up by deleting the new object. */
2676          if ( !astOK ) new = astDelete( new );
2677       }
2678    }
2679 
2680 /* Return a pointer to the new object. */
2681    return new;
2682 }
2683 
astLoadSwitchMap_(void * mem,size_t size,AstSwitchMapVtab * vtab,const char * name,AstChannel * channel,int * status)2684 AstSwitchMap *astLoadSwitchMap_( void *mem, size_t size,
2685                                  AstSwitchMapVtab *vtab, const char *name,
2686                                  AstChannel *channel, int *status ) {
2687 /*
2688 *+
2689 *  Name:
2690 *     astLoadSwitchMap
2691 
2692 *  Purpose:
2693 *     Load a SwitchMap.
2694 
2695 *  Type:
2696 *     Protected function.
2697 
2698 *  Synopsis:
2699 *     #include "switchmap.h"
2700 *     AstSwitchMap *astLoadSwitchMap( void *mem, size_t size,
2701 *                                     AstSwitchMapVtab *vtab, const char *name,
2702 *                                     AstChannel *channel )
2703 
2704 *  Class Membership:
2705 *     SwitchMap loader.
2706 
2707 *  Description:
2708 *     This function is provided to load a new SwitchMap using data read
2709 *     from a Channel. It first loads the data used by the parent class
2710 *     (which allocates memory if necessary) and then initialises a
2711 *     SwitchMap structure in this memory, using data read from the input
2712 *     Channel.
2713 *
2714 *     If the "init" flag is set, it also initialises the contents of a
2715 *     virtual function table for a SwitchMap at the start of the memory
2716 *     passed via the "vtab" parameter.
2717 
2718 
2719 *  Parameters:
2720 *     mem
2721 *        A pointer to the memory into which the SwitchMap is to be
2722 *        loaded.  This must be of sufficient size to accommodate the
2723 *        SwitchMap data (sizeof(SwitchMap)) plus any data used by derived
2724 *        classes. If a value of NULL is given, this function will
2725 *        allocate the memory itself using the "size" parameter to
2726 *        determine its size.
2727 *     size
2728 *        The amount of memory used by the SwitchMap (plus derived class
2729 *        data).  This will be used to allocate memory if a value of
2730 *        NULL is given for the "mem" parameter. This value is also
2731 *        stored in the SwitchMap structure, so a valid value must be
2732 *        supplied even if not required for allocating memory.
2733 *
2734 *        If the "vtab" parameter is NULL, the "size" value is ignored
2735 *        and sizeof(AstSwitchMap) is used instead.
2736 *     vtab
2737 *        Pointer to the start of the virtual function table to be
2738 *        associated with the new SwitchMap. If this is NULL, a pointer to
2739 *        the (static) virtual function table for the SwitchMap class is
2740 *        used instead.
2741 *     name
2742 *        Pointer to a constant null-terminated character string which
2743 *        contains the name of the class to which the new object
2744 *        belongs (it is this pointer value that will subsequently be
2745 *        returned by the astGetClass method).
2746 *
2747 *        If the "vtab" parameter is NULL, the "name" value is ignored
2748 *        and a pointer to the string "SwitchMap" is used instead.
2749 
2750 *  Returned Value:
2751 *     A pointer to the new SwitchMap.
2752 
2753 *  Notes:
2754 *     - A null pointer will be returned if this function is invoked
2755 *     with the global error status set, or if it should fail for any
2756 *     reason.
2757 *-
2758 */
2759 
2760 /* Local Variables: */
2761    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2762    AstSwitchMap *new;
2763    AstMapping *rmap;
2764    int i;
2765    char buf[ 20 ];
2766 
2767 /* Initialise. */
2768    new = NULL;
2769 
2770 /* Check the global error status. */
2771    if ( !astOK ) return new;
2772 
2773 /* Get a pointer to the thread specific global data structure. */
2774    astGET_GLOBALS(channel);
2775 
2776 /* If a NULL virtual function table has been supplied, then this is
2777    the first loader to be invoked for this SwitchMap. In this case the
2778    SwitchMap belongs to this class, so supply appropriate values to be
2779    passed to the parent class loader (and its parent, etc.). */
2780    if ( !vtab ) {
2781       size = sizeof( AstSwitchMap );
2782       vtab = &class_vtab;
2783       name = "SwitchMap";
2784 
2785 /* If required, initialise the virtual function table for this class. */
2786       if ( !class_init ) {
2787          astInitSwitchMapVtab( vtab, name );
2788          class_init = 1;
2789       }
2790    }
2791 
2792 /* Invoke the parent class loader to load data for all the ancestral
2793    classes of the current one, returning a pointer to the resulting
2794    partly-built SwitchMap. */
2795    new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name,
2796                          channel );
2797    if ( astOK ) {
2798 
2799 /* Read input data. */
2800 /* ================ */
2801 /* Request the input Channel to read all the input data appropriate to
2802    this class into the internal "values list". */
2803       astReadClassData( channel, "SwitchMap" );
2804 
2805 /* Now read each individual data item from this list and use it to
2806    initialise the appropriate instance variable(s) for this class. */
2807 
2808 /* In the case of attributes, we first read the "raw" input value,
2809    supplying the "unset" value as the default. If a "set" value is
2810    obtained, we then use the appropriate (private) Set... member
2811    function to validate and set the value properly. */
2812 
2813 /* Forward Selector Mapping and its Invert flag. */
2814 /* --------------------------------------------- */
2815       new->fsmap = astReadObject( channel, "fsmap", NULL );
2816       new->fsinv = astReadInt( channel, "fsinv", 0 );
2817       new->fsinv = ( new->fsinv != 0 );
2818 
2819 /* Inverse Selector Mapping and its Invert flag. */
2820 /* --------------------------------------------- */
2821       new->ismap = astReadObject( channel, "ismap", NULL );
2822       new->isinv = astReadInt( channel, "isinv", new->fsinv );
2823       new->isinv = ( new->isinv != 0 );
2824 
2825 /* Loop to load each route Mapping and its invert flag. */
2826 /* ---------------------------------------------------- */
2827       new->routemap = NULL;
2828       new->routeinv = NULL;
2829       i = 0;
2830       while( astOK ) {
2831          sprintf( buf, "rmap%d", i + 1 );
2832          rmap = astReadObject( channel, buf, NULL );
2833          if( rmap ) {
2834             new->routemap = astGrow( new->routemap, i + 1, sizeof( AstMapping *) );
2835             new->routeinv = astGrow( new->routeinv, i + 1, sizeof( int ) );
2836             if( astOK ) {
2837                new->routemap[ i ] = rmap;
2838                sprintf( buf, "rinv%d", i + 1 );
2839                new->routeinv[ i ] = astReadInt( channel, buf, 0 );
2840                new->routeinv[ i ] = ( new->routeinv[ i ] != 0 );
2841                i++;
2842             }
2843          } else {
2844             break;
2845          }
2846       }
2847 
2848 /* Number of route Mappings. */
2849       new->nroute = i;
2850 
2851 /* If an error occurred, clean up by deleting the new SwitchMap. */
2852       if ( !astOK ) new = astDelete( new );
2853    }
2854 
2855 /* Return the new SwitchMap pointer. */
2856    return new;
2857 }
2858 
2859 /* Virtual function interfaces. */
2860 /* ============================ */
2861 /* These provide the external interface to the virtual functions defined by
2862    this class. Each simply checks the global error status and then locates and
2863    executes the appropriate member function, using the function pointer stored
2864    in the object's virtual function table (this pointer is located using the
2865    astMEMBER macro defined in "object.h").
2866 
2867    Note that the member function may not be the one defined here, as it may
2868    have been over-ridden by a derived class. However, it should still have the
2869    same interface. */
2870 
2871 /* None. */
2872 
2873 
2874 
2875 
2876