1 /*
2 *class++
3 *  Name:
4 *     TranMap
5 
6 *  Purpose:
7 *     Mapping with specified forward and inverse transformations.
8 
9 *  Constructor Function:
10 c     astTranMap
11 f     AST_TRANMAP
12 
13 *  Description:
14 *     A TranMap is a Mapping which combines the forward transformation of
15 *     a supplied Mapping with the inverse transformation of another
16 *     supplied Mapping, ignoring the un-used transformation in each
17 *     Mapping (indeed the un-used transformation need not exist).
18 *
19 *     When the forward transformation of the TranMap is referred to, the
20 *     transformation actually used is the forward transformation of the
21 *     first Mapping supplied when the TranMap was constructed. Likewise,
22 *     when the inverse transformation of the TranMap is referred to, the
23 *     transformation actually used is the inverse transformation of the
24 *     second Mapping supplied when the TranMap was constructed.
25 
26 *  Inheritance:
27 *     The TranMap class inherits from the Mapping class.
28 
29 *  Attributes:
30 *     The TranMap class does not define any new attributes beyond those
31 *     which are applicable to all Mappings.
32 
33 *  Functions:
34 c     The TranMap class does not define any new functions beyond those
35 f     The TranMap class does not define any new routines beyond those
36 *     which are applicable to all Mappings.
37 
38 *  Copyright:
39 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
40 *     Research Councils
41 
42 *  Licence:
43 *     This program is free software: you can redistribute it and/or
44 *     modify it under the terms of the GNU Lesser General Public
45 *     License as published by the Free Software Foundation, either
46 *     version 3 of the License, or (at your option) any later
47 *     version.
48 *
49 *     This program is distributed in the hope that it will be useful,
50 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
51 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
52 *     GNU Lesser General Public License for more details.
53 *
54 *     You should have received a copy of the GNU Lesser General
55 *     License along with this program.  If not, see
56 *     <http://www.gnu.org/licenses/>.
57 
58 *  Authors:
59 *     DSB: David S. Berry (Starlink)
60 
61 *  History:
62 *     10-FEB-2004 (DSB):
63 *        Original version.
64 *     19-JAN-2005 (DSB):
65 *        Fix memory leak.
66 *     14-FEB-2006 (DSB):
67 *        - Over-ride the astDecompose method.
68 *        - Fix bug in MapSplit related to use of invert flags.
69 *     14-FEB-2006 (DSB):
70 *        Override astGetObjSize.
71 *     10-MAY-2006 (DSB):
72 *        Override astEqual.
73 *class--
74 */
75 
76 /* Module Macros. */
77 /* ============== */
78 /* Set the name of the class we are implementing. This indicates to
79    the header files that define class interfaces that they should make
80    "protected" symbols available. */
81 #define astCLASS TranMap
82 
83 /* Include files. */
84 /* ============== */
85 /* Interface definitions. */
86 /* ---------------------- */
87 
88 #include "globals.h"             /* Thread-safe global data access */
89 #include "error.h"               /* Error reporting facilities */
90 #include "memory.h"              /* Memory allocation facilities */
91 #include "object.h"              /* Base Object class */
92 #include "pointset.h"            /* Sets of points/coordinates */
93 #include "mapping.h"             /* Coordinate Mappings (parent class) */
94 #include "channel.h"             /* I/O channels */
95 #include "permmap.h"             /* Coordinate permutation Mappings */
96 #include "cmpmap.h"              /* Compound Mappings */
97 #include "unitmap.h"             /* Unit Mappings */
98 #include "tranmap.h"             /* Interface definition for this class */
99 #include "frame.h"               /* Frames */
100 
101 /* Error code definitions. */
102 /* ----------------------- */
103 #include "ast_err.h"             /* AST error codes */
104 
105 /* C header files. */
106 /* --------------- */
107 #include <stdarg.h>
108 #include <stddef.h>
109 #include <string.h>
110 #include <stdio.h>
111 
112 /* Module Variables. */
113 /* ================= */
114 
115 /* Address of this static variable is used as a unique identifier for
116    member of this class. */
117 static int class_check;
118 
119 /* Pointers to parent class methods which are extended by this class. */
120 static int (* parent_getobjsize)( AstObject *, int * );
121 static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
122 static int *(* parent_mapsplit)( AstMapping *, int, const int *, AstMapping **, int * );
123 
124 #if defined(THREAD_SAFE)
125 static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
126 #endif
127 
128 
129 
130 #ifdef THREAD_SAFE
131 /* Define how to initialise thread-specific globals. */
132 #define GLOBAL_inits \
133    globals->Class_Init = 0;
134 
135 /* Create the function that initialises global data for this module. */
136 astMAKE_INITGLOBALS(TranMap)
137 
138 /* Define macros for accessing each item of thread specific global data. */
139 #define class_init astGLOBAL(TranMap,Class_Init)
140 #define class_vtab astGLOBAL(TranMap,Class_Vtab)
141 
142 
143 #include <pthread.h>
144 
145 
146 #else
147 
148 
149 /* Define the class virtual function table and its initialisation flag
150    as static variables. */
151 static AstTranMapVtab class_vtab;   /* Virtual function table */
152 static int class_init = 0;       /* Virtual function table initialised? */
153 
154 #endif
155 
156 /* External Interface Function Prototypes. */
157 /* ======================================= */
158 /* The following functions have public prototypes only (i.e. no
159    protected prototypes), so we must provide local prototypes for use
160    within this module. */
161 AstTranMap *astTranMapId_( void *, void *, const char *, ... );
162 
163 /* Prototypes for Private Member Functions. */
164 /* ======================================== */
165 static AstMapping *RemoveRegions( AstMapping *, int * );
166 static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
167 static double Rate( AstMapping *, double *, int, int, int * );
168 static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * );
169 static int Equal( AstObject *, AstObject *, int * );
170 static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * );
171 static void Copy( const AstObject *, AstObject *, int * );
172 static void Delete( AstObject *, int * );
173 static void Dump( AstObject *, AstChannel *, int * );
174 static void Decompose( AstMapping *, AstMapping **, AstMapping **, int *, int *, int *, int * );
175 static int GetObjSize( AstObject *, int * );
176 
177 #if defined(THREAD_SAFE)
178 static int ManageLock( AstObject *, int, int, AstObject **, int * );
179 #endif
180 
181 
182 /* Member functions. */
183 /* ================= */
Equal(AstObject * this_object,AstObject * that_object,int * status)184 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
185 /*
186 *  Name:
187 *     Equal
188 
189 *  Purpose:
190 *     Test if two TranMaps are equivalent.
191 
192 *  Type:
193 *     Private function.
194 
195 *  Synopsis:
196 *     #include "tranmap.h"
197 *     int Equal( AstObject *this, AstObject *that, int *status )
198 
199 *  Class Membership:
200 *     TranMap member function (over-rides the astEqual protected
201 *     method inherited from the astMapping class).
202 
203 *  Description:
204 *     This function returns a boolean result (0 or 1) to indicate whether
205 *     two TranMaps are equivalent.
206 
207 *  Parameters:
208 *     this
209 *        Pointer to the first Object (a TranMap).
210 *     that
211 *        Pointer to the second Object.
212 *     status
213 *        Pointer to the inherited status variable.
214 
215 *  Returned Value:
216 *     One if the TranMaps are equivalent, zero otherwise.
217 
218 *  Notes:
219 *     - A value of zero will be returned if this function is invoked
220 *     with the global status set, or if it should fail for any reason.
221 */
222 
223 /* Local Variables: */
224    AstTranMap *that;
225    AstTranMap *this;
226    int nin;
227    int nout;
228    int result;
229    int that_inv1;
230    int that_inv2;
231    int this_inv1;
232    int this_inv2;
233 
234 /* Initialise. */
235    result = 0;
236 
237 /* Check the global error status. */
238    if ( !astOK ) return result;
239 
240 /* Obtain pointers to the two TranMap structures. */
241    this = (AstTranMap *) this_object;
242    that = (AstTranMap *) that_object;
243 
244 /* Check the second object is a TranMap. We know the first is a
245    TranMap since we have arrived at this implementation of the virtual
246    function. */
247    if( astIsATranMap( that ) ) {
248 
249 /* Get the number of inputs and outputs and check they are the same for both. */
250       nin = astGetNin( this );
251       nout = astGetNout( this );
252       if( astGetNin( that ) == nin && astGetNout( that ) == nout ) {
253 
254 /* Temporarily re-instate the original Invert flag values. */
255          that_inv1 = astGetInvert( that->map1 );
256          that_inv2 = astGetInvert( that->map2 );
257          this_inv1 = astGetInvert( this->map1 );
258          this_inv2 = astGetInvert( this->map2 );
259 
260          astSetInvert( this->map1, this->invert1 );
261          astSetInvert( this->map2, this->invert2 );
262          astSetInvert( that->map1, that->invert1 );
263          astSetInvert( that->map2, that->invert2 );
264 
265 /* If the Invert flags for the two TranMaps differ, it may still be possible
266    for them to be equivalent. First compare the TranMaps if their Invert
267    flags are the same. In this case all the attributes of the two TranMaps
268    must be identical. */
269          if( astGetInvert( this ) == astGetInvert( that ) ) {
270             if( astEqual( this->map1, that->map1 ) &&
271                 astEqual( this->map2, that->map2 ) ) {
272                result = 1;
273             }
274 
275 /* If the Invert flags for the two TranMaps differ, the attributes of the two
276    TranMaps must be inversely related to each other. */
277          } else {
278 
279             astInvert( that->map1 );
280             astInvert( that->map2 );
281 
282             if( astEqual( this->map1, that->map2 ) &&
283                 astEqual( this->map2, that->map1 ) ) {
284                result = 1;
285             }
286 
287          }
288 
289 /* Restore the original Invert flag values. */
290          astSetInvert( this->map1, this_inv1 );
291          astSetInvert( this->map2, this_inv2 );
292          astSetInvert( that->map1, that_inv1 );
293          astSetInvert( that->map2, that_inv2 );
294       }
295    }
296 
297 /* If an error occurred, clear the result value. */
298    if ( !astOK ) result = 0;
299 
300 /* Return the result, */
301    return result;
302 }
303 
GetObjSize(AstObject * this_object,int * status)304 static int GetObjSize( AstObject *this_object, int *status ) {
305 /*
306 *  Name:
307 *     GetObjSize
308 
309 *  Purpose:
310 *     Return the in-memory size of an Object.
311 
312 *  Type:
313 *     Private function.
314 
315 *  Synopsis:
316 *     #include "tranmap.h"
317 *     int GetObjSize( AstObject *this, int *status )
318 
319 *  Class Membership:
320 *     TranMap member function (over-rides the astGetObjSize protected
321 *     method inherited from the parent class).
322 
323 *  Description:
324 *     This function returns the in-memory size of the supplied TranMap,
325 *     in bytes.
326 
327 *  Parameters:
328 *     this
329 *        Pointer to the TranMap.
330 *     status
331 *        Pointer to the inherited status variable.
332 
333 *  Returned Value:
334 *     The Object size, in bytes.
335 
336 *  Notes:
337 *     - A value of zero will be returned if this function is invoked
338 *     with the global status set, or if it should fail for any reason.
339 */
340 
341 /* Local Variables: */
342    AstTranMap *this;         /* Pointer to TranMap structure */
343    int result;                /* Result value to return */
344 
345 /* Initialise. */
346    result = 0;
347 
348 /* Check the global error status. */
349    if ( !astOK ) return result;
350 
351 /* Obtain a pointers to the TranMap structure. */
352    this = (AstTranMap *) this_object;
353 
354 /* Invoke the GetObjSize method inherited from the parent class, and then
355    add on any components of the class structure defined by thsi class
356    which are stored in dynamically allocated memory. */
357    result = (*parent_getobjsize)( this_object, status );
358    result += astGetObjSize( this->map1 );
359    result += astGetObjSize( this->map2 );
360 
361 /* If an error occurred, clear the result value. */
362    if ( !astOK ) result = 0;
363 
364 /* Return the result, */
365    return result;
366 }
367 
Decompose(AstMapping * this_mapping,AstMapping ** map1,AstMapping ** map2,int * series,int * invert1,int * invert2,int * status)368 static void Decompose( AstMapping *this_mapping, AstMapping **map1,
369                        AstMapping **map2, int *series, int *invert1,
370                        int *invert2, int *status ) {
371 /*
372 *
373 *  Name:
374 *     Decompose
375 
376 *  Purpose:
377 *     Decompose a Mapping into two component Mappings.
378 
379 *  Type:
380 *     Private function.
381 
382 *  Synopsis:
383 *     #include "tranmap.h"
384 *     void Decompose( AstMapping *this, AstMapping **map1,
385 *                     AstMapping **map2, int *series,
386 *                     int *invert1, int *invert2, int *status )
387 
388 *  Class Membership:
389 *     TranMap member function (over-rides the protected astDecompose
390 *     method inherited from the Mapping class).
391 
392 *  Description:
393 *     This function returns pointers to the two Mappings encapsulated by
394 *     a TranMap.
395 
396 *  Parameters:
397 *     this
398 *        Pointer to the Mapping.
399 *     map1
400 *        Address of a location to receive a pointer to first component
401 *        Mapping (the forward Mapping).
402 *     map2
403 *        Address of a location to receive a pointer to second component
404 *        Mapping (the inverse Mapping).
405 *     series
406 *        Address of a location to receive a value indicating if the
407 *        component Mappings are applied in series or parallel. A non-zero
408 *        value means that the supplied Mapping is equivalent to applying map1
409 *        followed by map2 in series. A zero value means that the supplied
410 *        Mapping is equivalent to applying map1 to the lower numbered axes
411 *        and map2 to the higher numbered axes, in parallel. Zero is
412 *        returned for a TranMap.
413 *     invert1
414 *        The value of the Invert attribute to be used with map1.
415 *     invert2
416 *        The value of the Invert attribute to be used with map2.
417 *     status
418 *        Pointer to the inherited status variable.
419 
420 *  Notes:
421 *     - Any changes made to the component Mappings using the returned
422 *     pointers will be reflected in the supplied Mapping.
423 
424 *-
425 */
426 
427 
428 /* Local Variables: */
429    AstTranMap *this;             /* Pointer to TranMap structure */
430 
431 /* Check the global error status. */
432    if ( !astOK ) return;
433 
434 /* Obtain a pointer to the TranMap structure. */
435    this = (AstTranMap *) this_mapping;
436 
437 /* If the TranMap has been inverted, return the Mappings in reverse
438    order with inverted Invert falgs. */
439    if( astGetInvert( this ) ) {
440       if( map1 ) *map1 = astClone( this->map2 );
441       if( map2 ) *map2 = astClone( this->map1 );
442       if( invert1 ) *invert1 = this->invert2 ? 0 : 1;
443       if( invert2 ) *invert2 = this->invert1 ? 0 : 1;
444 
445 /* If the TranMap has not been inverted, return the Mappings in their
446    original order with their original Invert flags. */
447    } else {
448       if( map1 ) *map1 = astClone( this->map1 );
449       if( map2 ) *map2 = astClone( this->map2 );
450       if( invert1 ) *invert1 = this->invert1;
451       if( invert2 ) *invert2 = this->invert2;
452    }
453 }
454 
astInitTranMapVtab_(AstTranMapVtab * vtab,const char * name,int * status)455 void astInitTranMapVtab_(  AstTranMapVtab *vtab, const char *name, int *status ) {
456 /*
457 *+
458 *  Name:
459 *     astInitTranMapVtab
460 
461 *  Purpose:
462 *     Initialise a virtual function table for a TranMap.
463 
464 *  Type:
465 *     Protected function.
466 
467 *  Synopsis:
468 *     #include "tranmap.h"
469 *     void astInitTranMapVtab( AstTranMapVtab *vtab, const char *name )
470 
471 *  Class Membership:
472 *     TranMap vtab initialiser.
473 
474 *  Description:
475 *     This function initialises the component of a virtual function
476 *     table which is used by the TranMap class.
477 
478 *  Parameters:
479 *     vtab
480 *        Pointer to the virtual function table. The components used by
481 *        all ancestral classes will be initialised if they have not already
482 *        been initialised.
483 *     name
484 *        Pointer to a constant null-terminated character string which contains
485 *        the name of the class to which the virtual function table belongs (it
486 *        is this pointer value that will subsequently be returned by the Object
487 *        astClass function).
488 *-
489 */
490 
491 /* Local Variables: */
492    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
493    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
494    AstMappingVtab *mapping;      /* Pointer to Mapping component of Vtab */
495 
496 /* Check the local error status. */
497    if ( !astOK ) return;
498 
499 /* Get a pointer to the thread specific global data structure. */
500    astGET_GLOBALS(NULL);
501 
502 /* Initialize the component of the virtual function table used by the
503    parent class. */
504    astInitMappingVtab( (AstMappingVtab *) vtab, name );
505 
506 /* Store a unique "magic" value in the virtual function table. This
507    will be used (by astIsATranMap) to determine if an object belongs to
508    this class.  We can conveniently use the address of the (static)
509    class_check variable to generate this unique value. */
510    vtab->id.check = &class_check;
511    vtab->id.parent = &(((AstMappingVtab *) vtab)->id);
512 
513 /* Initialise member function pointers. */
514 /* ------------------------------------ */
515 /* Store pointers to the member functions (implemented here) that
516    provide virtual methods for this class. */
517 
518 /* None. */
519 
520 /* Save the inherited pointers to methods that will be extended, and
521    replace them with pointers to the new member functions. */
522    object = (AstObjectVtab *) vtab;
523    mapping = (AstMappingVtab *) vtab;
524    parent_getobjsize = object->GetObjSize;
525    object->GetObjSize = GetObjSize;
526 
527    mapping->RemoveRegions = RemoveRegions;
528 
529 #if defined(THREAD_SAFE)
530    parent_managelock = object->ManageLock;
531    object->ManageLock = ManageLock;
532 #endif
533 
534    parent_transform = mapping->Transform;
535    mapping->Transform = Transform;
536 
537    parent_mapsplit = mapping->MapSplit;
538    mapping->MapSplit = MapSplit;
539 
540 /* Store replacement pointers for methods which will be over-ridden by
541    new member functions implemented here. */
542    object->Equal = Equal;
543    mapping->Decompose = Decompose;
544    mapping->MapMerge = MapMerge;
545    mapping->Rate = Rate;
546 
547 /* Declare the copy constructor, destructor and class dump function. */
548    astSetCopy( vtab, Copy );
549    astSetDelete( vtab, Delete );
550    astSetDump( vtab, Dump, "TranMap", "Compound Transformation Mapping" );
551 
552 /* If we have just initialised the vtab for the current class, indicate
553    that the vtab is now initialised, and store a pointer to the class
554    identifier in the base "object" level of the vtab. */
555    if( vtab == &class_vtab ) {
556       class_init = 1;
557       astSetVtabClassIdentifier( vtab, &(vtab->id) );
558    }
559 }
560 
561 #if defined(THREAD_SAFE)
ManageLock(AstObject * this_object,int mode,int extra,AstObject ** fail,int * status)562 static int ManageLock( AstObject *this_object, int mode, int extra,
563                        AstObject **fail, int *status ) {
564 /*
565 *  Name:
566 *     ManageLock
567 
568 *  Purpose:
569 *     Manage the thread lock on an Object.
570 
571 *  Type:
572 *     Private function.
573 
574 *  Synopsis:
575 *     #include "object.h"
576 *     AstObject *ManageLock( AstObject *this, int mode, int extra,
577 *                            AstObject **fail, int *status )
578 
579 *  Class Membership:
580 *     TranMap member function (over-rides the astManageLock protected
581 *     method inherited from the parent class).
582 
583 *  Description:
584 *     This function manages the thread lock on the supplied Object. The
585 *     lock can be locked, unlocked or checked by this function as
586 *     deteremined by parameter "mode". See astLock for details of the way
587 *     these locks are used.
588 
589 *  Parameters:
590 *     this
591 *        Pointer to the Object.
592 *     mode
593 *        An integer flag indicating what the function should do:
594 *
595 *        AST__LOCK: Lock the Object for exclusive use by the calling
596 *        thread. The "extra" value indicates what should be done if the
597 *        Object is already locked (wait or report an error - see astLock).
598 *
599 *        AST__UNLOCK: Unlock the Object for use by other threads.
600 *
601 *        AST__CHECKLOCK: Check that the object is locked for use by the
602 *        calling thread (report an error if not).
603 *     extra
604 *        Extra mode-specific information.
605 *     fail
606 *        If a non-zero function value is returned, a pointer to the
607 *        Object that caused the failure is returned at "*fail". This may
608 *        be "this" or it may be an Object contained within "this". Note,
609 *        the Object's reference count is not incremented, and so the
610 *        returned pointer should not be annulled. A NULL pointer is
611 *        returned if this function returns a value of zero.
612 *     status
613 *        Pointer to the inherited status variable.
614 
615 *  Returned Value:
616 *    A local status value:
617 *        0 - Success
618 *        1 - Could not lock or unlock the object because it was already
619 *            locked by another thread.
620 *        2 - Failed to lock a POSIX mutex
621 *        3 - Failed to unlock a POSIX mutex
622 *        4 - Bad "mode" value supplied.
623 
624 *  Notes:
625 *     - This function attempts to execute even if an error has already
626 *     occurred.
627 */
628 
629 /* Local Variables: */
630    AstTranMap *this;       /* Pointer to TranMap structure */
631    int result;             /* Returned status value */
632 
633 /* Initialise */
634    result = 0;
635 
636 /* Check the supplied pointer is not NULL. */
637    if( !this_object ) return result;
638 
639 /* Obtain a pointers to the TranMap structure. */
640    this = (AstTranMap *) this_object;
641 
642 /* Invoke the ManageLock method inherited from the parent class. */
643    if( !result ) result = (*parent_managelock)( this_object, mode, extra,
644                                                 fail, status );
645 
646 /* Invoke the astManageLock method on any Objects contained within
647    the supplied Object. */
648    if( !result ) result = astManageLock( this->map1, mode, extra, fail );
649    if( !result ) result = astManageLock( this->map2, mode, extra, fail );
650 
651    return result;
652 
653 }
654 #endif
655 
MapMerge(AstMapping * this,int where,int series,int * nmap,AstMapping *** map_list,int ** invert_list,int * status)656 static int MapMerge( AstMapping *this, int where, int series, int *nmap,
657                      AstMapping ***map_list, int **invert_list, int *status ) {
658 /*
659 *  Name:
660 *     MapMerge
661 
662 *  Purpose:
663 *     Simplify a sequence of Mappings containing a TranMap.
664 
665 *  Type:
666 *     Private function.
667 
668 *  Synopsis:
669 *     #include "mapping.h"
670 *     int MapMerge( AstMapping *this, int where, int series, int *nmap,
671 *                   AstMapping ***map_list, int **invert_list, int *status )
672 
673 *  Class Membership:
674 *     TranMap method (over-rides the protected astMapMerge method
675 *     inherited from the Mapping class).
676 
677 *  Description:
678 *     This function attempts to simplify a sequence of Mappings by
679 *     merging a nominated TranMap in the sequence with its neighbours,
680 *     so as to shorten the sequence if possible.
681 *
682 *     In many cases, simplification will not be possible and the
683 *     function will return -1 to indicate this, without further
684 *     action.
685 *
686 *     In most cases of interest, however, this function will either
687 *     attempt to replace the nominated TranMap with one which it
688 *     considers simpler, or to merge it with the Mappings which
689 *     immediately precede it or follow it in the sequence (both will
690 *     normally be considered). This is sufficient to ensure the
691 *     eventual simplification of most Mapping sequences by repeated
692 *     application of this function.
693 *
694 *     In some cases, the function may attempt more elaborate
695 *     simplification, involving any number of other Mappings in the
696 *     sequence. It is not restricted in the type or scope of
697 *     simplification it may perform, but will normally only attempt
698 *     elaborate simplification in cases where a more straightforward
699 *     approach is not adequate.
700 
701 *  Parameters:
702 *     this
703 *        Pointer to the nominated TranMap which is to be merged with
704 *        its neighbours. This should be a cloned copy of the TranMap
705 *        pointer contained in the array element "(*map_list)[where]"
706 *        (see below). This pointer will not be annulled, and the
707 *        TranMap it identifies will not be modified by this function.
708 *     where
709 *        Index in the "*map_list" array (below) at which the pointer
710 *        to the nominated TranMap resides.
711 *     series
712 *        A non-zero value indicates that the sequence of Mappings to
713 *        be simplified will be applied in series (i.e. one after the
714 *        other), whereas a zero value indicates that they will be
715 *        applied in parallel (i.e. on successive sub-sets of the
716 *        input/output coordinates).
717 *     nmap
718 *        Address of an int which counts the number of Mappings in the
719 *        sequence. On entry this should be set to the initial number
720 *        of Mappings. On exit it will be updated to record the number
721 *        of Mappings remaining after simplification.
722 *     map_list
723 *        Address of a pointer to a dynamically allocated array of
724 *        Mapping pointers (produced, for example, by the astMapList
725 *        method) which identifies the sequence of Mappings. On entry,
726 *        the initial sequence of Mappings to be simplified should be
727 *        supplied.
728 *
729 *        On exit, the contents of this array will be modified to
730 *        reflect any simplification carried out. Any form of
731 *        simplification may be performed. This may involve any of: (a)
732 *        removing Mappings by annulling any of the pointers supplied,
733 *        (b) replacing them with pointers to new Mappings, (c)
734 *        inserting additional Mappings and (d) changing their order.
735 *
736 *        The intention is to reduce the number of Mappings in the
737 *        sequence, if possible, and any reduction will be reflected in
738 *        the value of "*nmap" returned. However, simplifications which
739 *        do not reduce the length of the sequence (but improve its
740 *        execution time, for example) may also be performed, and the
741 *        sequence might conceivably increase in length (but normally
742 *        only in order to split up a Mapping into pieces that can be
743 *        more easily merged with their neighbours on subsequent
744 *        invocations of this function).
745 *
746 *        If Mappings are removed from the sequence, any gaps that
747 *        remain will be closed up, by moving subsequent Mapping
748 *        pointers along in the array, so that vacated elements occur
749 *        at the end. If the sequence increases in length, the array
750 *        will be extended (and its pointer updated) if necessary to
751 *        accommodate any new elements.
752 *
753 *        Note that any (or all) of the Mapping pointers supplied in
754 *        this array may be annulled by this function, but the Mappings
755 *        to which they refer are not modified in any way (although
756 *        they may, of course, be deleted if the annulled pointer is
757 *        the final one).
758 *     invert_list
759 *        Address of a pointer to a dynamically allocated array which,
760 *        on entry, should contain values to be assigned to the Invert
761 *        attributes of the Mappings identified in the "*map_list"
762 *        array before they are applied (this array might have been
763 *        produced, for example, by the astMapList method). These
764 *        values will be used by this function instead of the actual
765 *        Invert attributes of the Mappings supplied, which are
766 *        ignored.
767 *
768 *        On exit, the contents of this array will be updated to
769 *        correspond with the possibly modified contents of the
770 *        "*map_list" array.  If the Mapping sequence increases in
771 *        length, the "*invert_list" array will be extended (and its
772 *        pointer updated) if necessary to accommodate any new
773 *        elements.
774 *     status
775 *        Pointer to the inherited status variable.
776 
777 *  Returned Value:
778 *     If simplification was possible, the function returns the index
779 *     in the "map_list" array of the first element which was
780 *     modified. Otherwise, it returns -1 (and makes no changes to the
781 *     arrays supplied).
782 
783 *  Notes:
784 *     - A value of -1 will be returned if this function is invoked
785 *     with the global error status set, or if it should fail for any
786 *     reason.
787 */
788 
789 /* Local Variables: */
790    AstCmpMap *cmap;              /* Pointer to compound Mapping */
791    AstMapping *cmap_f;           /* Pointer to compound Mapping */
792    AstMapping *cmap_i;           /* Pointer to compound Mapping */
793    AstMapping *hmap1;            /* Pointer to 1st comp of higher TranMap */
794    AstMapping *hmap2;            /* Pointer to 2nd comp of higher TranMap */
795    AstMapping *hmap_f;           /* Pointer to fwd Mapping of higher TranMap */
796    AstMapping *hmap_i;           /* Pointer to inv Mapping of higher TranMap */
797    AstMapping *map1;             /* Pointer to 1st comp of nominated TranMap */
798    AstMapping *map2;             /* Pointer to 2nd comp of nominated TranMap */
799    AstMapping *map_f;            /* Pointer to fwd Mapping of nominated TranMap */
800    AstMapping *map_i;            /* Pointer to inv Mapping of nominated TranMap */
801    AstMapping *smap;             /* Pointer to simplified Mapping */
802    AstMapping *smap_f;           /* Pointer to simplified Mapping */
803    AstMapping *smap_i;           /* Pointer to simplified Mapping */
804    AstTranMap *hmap;             /* Pointer to higher TranMap */
805    AstTranMap *map;              /* Pointer to this TranMap */
806    AstTranMap *new;              /* Pointer to merged TranMap */
807    int i;                        /* Loop count */
808    int old_hinv1;                /* Original Invert flag for hmap->map1 */
809    int old_hinv2;                /* Original Invert flag for hmap->map2 */
810    int old_inv1;                 /* Original Invert flag for this->map1 */
811    int old_inv2;                 /* Original Invert flag for this->map2 */
812    int result;                   /* The value to return */
813 
814 /* Initialise.*/
815    result = -1;
816 
817 /* Check the inherited status. */
818    if ( !astOK ) return result;
819 
820 /* Get a pointer to this TranMap. */
821    map = (AstTranMap *) this;
822 
823 /* Get the two component Mappings,and temporarily set their Invert
824    attributes back to the values they had when the TranMap was created,
825    saving their current Invert values so that they can be re-instated later. */
826    map1 = map->map1;
827    old_inv1 = astGetInvert( map1 );
828    astSetInvert( map1, map->invert1 );
829 
830    map2 = map->map2;
831    old_inv2 = astGetInvert( map2 );
832    astSetInvert( map2, map->invert2 );
833 
834 /* Simplify the TranMap on its own. */
835 /* ================================ */
836 
837 /* If the TranMap is inverted, creat an equal TranMap which is not inverted.
838    To do this, invert and swap the component Mappings. */
839    if( ( *invert_list )[ where ] ) {
840       astInvert( map1 );
841       astInvert( map2 );
842       new = astTranMap( map2, map1, "", status );
843       astInvert( map1 );
844       astInvert( map2 );
845 
846       (void) astAnnul( ( *map_list )[ where ] );
847       ( *map_list )[ where ] = (AstMapping *) new;
848       ( *invert_list )[ where ] = 0;
849       result = where;
850 
851 /* Otherwise, try to simplify each of the component Mappings. */
852    } else {
853       smap_f = astSimplify( map1 );
854       smap_i = astSimplify( map2 );
855 
856 /* Assume some simplification took place if the pointers have changed. */
857       if( smap_f != map1 || smap_i != map2 ) {
858 
859 /* Construct a new TranMap from these simplifgied Mappings. */
860          (void) astAnnul( ( *map_list )[ where ] );
861          ( *map_list )[ where ] = (AstMapping *) astTranMap( smap_f, smap_i, "", status );
862          result = where;
863 
864 /* Otherwise, if the both component Mappings are defined in both directions... */
865       } else if( astGetTranForward( map1 ) && astGetTranInverse( map1 ) &&
866                  astGetTranForward( map2 ) && astGetTranInverse( map2 ) ) {
867 
868 /* Form a series CmpMap from the two component Mappings, with the second
869    Mapping inverted. */
870          astInvert( map2 );
871          cmap = astCmpMap( map1, map2, 1, "", status );
872          astInvert( map2 );
873 
874 /* If this CmpMap simplifies to a UnitMap, then the two components of the
875    TranMap are equal, and so we can replace the entire TranMap with either
876    of its components. Note, we leave the supplied invert flag unchanged,
877    since the copycreated below refers to the Mapping as it was when the
878    TranMap was created. However, we invert the returned Mapping if
879    necessary. */
880          smap = astSimplify( cmap );
881          if( astIsAUnitMap( smap ) ) {
882             (void) astAnnul( ( *map_list )[ where ] );
883             ( *map_list )[ where ] = astCopy( map1 );
884             if( ( *invert_list )[ where ] ) astInvert( ( *map_list )[ where ] );
885             result = where;
886          }
887 
888 /* Release resources. */
889          smap = astAnnul( smap );
890          cmap = astAnnul( cmap );
891       }
892 
893 /* Release resources. */
894       smap_f = astAnnul( smap_f );
895       smap_i = astAnnul( smap_i );
896    }
897 
898 /* Merge the TranMap with a neighbouring TranMap. */
899 /* ============================================== */
900 /* Only do this if no change was made above, and we are combining the
901    Mappings in series. */
902    if( result == -1 && series ) {
903 
904 /* Is the higher neighbour a TranMap? */
905       if( where < ( *nmap - 1 ) &&
906           astIsATranMap( ( *map_list )[ where + 1 ] ) ){
907 
908 /* Get the two component Mappings of the higher TranMap, and temporarily set
909    their Invert attributes back to the values they had when the TranMap was
910    created, saving their current Invert values so that they can be re-instated
911    later. */
912          hmap = (AstTranMap *) ( *map_list )[ where + 1 ];
913 
914          hmap1 = hmap->map1;
915          old_hinv1 = astGetInvert( hmap1 );
916          astSetInvert( hmap1, hmap->invert1 );
917 
918          hmap2 = hmap->map2;
919          old_hinv2 = astGetInvert( hmap2 );
920          astSetInvert( hmap2, hmap->invert2 );
921 
922 /* Get the Mappings which defines the forward and inverse transformation of
923    the lower TranMap ("this"). Then, map_f and map_i are pointers to
924    Mappings which could be used to construct a new TranMap which would be
925    equivalent to "this" with the supplied invert setting. */
926          if( ( *invert_list )[ where ] ) {
927             map_f = map2;
928             map_i = map1;
929             astInvert( map_f );
930             astInvert( map_i );
931          } else {
932             map_f = map1;
933             map_i = map2;
934          }
935 
936 /* Likewise, get the Mappings which defines the forward and inverse
937    transformation of the higher TranMap. */
938          if( ( *invert_list )[ where + 1 ] ) {
939             hmap_f = hmap2;
940             hmap_i = hmap1;
941             astInvert( hmap_f );
942             astInvert( hmap_i );
943          } else {
944             hmap_f = hmap1;
945             hmap_i = hmap2;
946          }
947 
948 /* Combine the two forward Mappings together into a series CmpMap, and
949    simplify it. */
950          cmap_f = (AstMapping *) astCmpMap( map_f,  hmap_f, 1, "", status );
951          smap_f = astSimplify( cmap_f );
952 
953 /* Do the same for the inverse Mappings */
954          cmap_i = (AstMapping *) astCmpMap( map_i,  hmap_i, 1, "", status );
955          smap_i = astSimplify( cmap_i );
956 
957 /* Was any simplification performed? We assume this is the case if the
958    either of the simplied pointer differs from the original pointer. */
959          if( cmap_f != smap_f || cmap_i != smap_i ) {
960 
961 /* In which case,construct a new TranMap from the simplified Mappings. */
962             new = astTranMap( smap_f, smap_i, "", status );
963 
964          } else {
965             new = NULL;
966          }
967 
968 /* Free resources.*/
969          cmap_f = astAnnul( cmap_f );
970          smap_f = astAnnul( smap_f );
971          cmap_i = astAnnul( cmap_i );
972          smap_i = astAnnul( smap_i );
973 
974 /* Re-instate the original Invert values for the component Mappings of
975    the higher TranMap. */
976          astSetInvert( hmap1, old_hinv1 );
977          astSetInvert( hmap2, old_hinv2 );
978 
979 /* If we have a new TranMap, annul the first of the two Mappings, and replace
980    it with the merged TranMap. Also set the invert flag. */
981          if( new ) {
982             (void) astAnnul( ( *map_list )[ where ] );
983             ( *map_list )[ where ] = (AstMapping *) new;
984             ( *invert_list )[ where ] = 0;
985 
986 /* Annul the second of the two Mappings, and shuffle down the rest of the
987    list to fill the gap. */
988             (void) astAnnul( ( *map_list )[ where + 1 ] );
989             for ( i = where + 2; i < *nmap; i++ ) {
990                ( *map_list )[ i - 1 ] = ( *map_list )[ i ];
991                ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ];
992             }
993 
994 /* Clear the vacated element at the end. */
995             ( *map_list )[ *nmap - 1 ] = NULL;
996             ( *invert_list )[ *nmap - 1 ] = 0;
997 
998 /* Decrement the Mapping count and return the index of the first
999    modified element. */
1000             ( *nmap )--;
1001             result = where;
1002          }
1003       }
1004    }
1005 
1006 /* Re-instate the original Invert values for the component Mappings. */
1007    astSetInvert( map1, old_inv1 );
1008    astSetInvert( map2, old_inv2 );
1009 
1010 /* If an error occurred, clear the result value. */
1011    if ( !astOK ) result = -1;
1012 
1013 /* Return the result. */
1014    return result;
1015 }
1016 
MapSplit(AstMapping * this_map,int nin,const int * in,AstMapping ** map,int * status)1017 static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){
1018 /*
1019 *  Name:
1020 *     MapSplit
1021 
1022 *  Purpose:
1023 *     Create a Mapping representing a subset of the inputs of an existing
1024 *     TranMap.
1025 
1026 *  Type:
1027 *     Private function.
1028 
1029 *  Synopsis:
1030 *     #include "tranmap.h"
1031 *     int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status )
1032 
1033 *  Class Membership:
1034 *     TranMap method (over-rides the protected astMapSplit method
1035 *     inherited from the Mapping class).
1036 
1037 *  Description:
1038 *     This function creates a new Mapping by picking specified inputs from
1039 *     an existing TranMap. This is only possible if the specified inputs
1040 *     correspond to some subset of the TranMap outputs. That is, there
1041 *     must exist a subset of the TranMap outputs for which each output
1042 *     depends only on the selected TranMap inputs, and not on any of the
1043 *     inputs which have not been selected. If this condition is not met
1044 *     by the supplied TranMap, then a NULL Mapping is returned.
1045 
1046 *  Parameters:
1047 *     this
1048 *        Pointer to the TranMap to be split (the TranMap is not actually
1049 *        modified by this function).
1050 *     nin
1051 *        The number of inputs to pick from "this".
1052 *     in
1053 *        Pointer to an array of indices (zero based) for the inputs which
1054 *        are to be picked. This array should have "nin" elements. If "Nin"
1055 *        is the number of inputs of the supplied TranMap, then each element
1056 *        should have a value in the range zero to Nin-1.
1057 *     map
1058 *        Address of a location at which to return a pointer to the new
1059 *        Mapping. This Mapping will have "nin" inputs (the number of
1060 *        outputs may be different to "nin"). A NULL pointer will be
1061 *        returned if the supplied TranMap has no subset of outputs which
1062 *        depend only on the selected inputs.
1063 *     status
1064 *        Pointer to the inherited status variable.
1065 
1066 *  Returned Value:
1067 *     A pointer to a dynamically allocated array of ints. The number of
1068 *     elements in this array will equal the number of outputs for the
1069 *     returned Mapping. Each element will hold the index of the
1070 *     corresponding output in the supplied TranMap. The array should be
1071 *     freed using astFree when no longer needed. A NULL pointer will
1072 *     be returned if no output Mapping can be created.
1073 
1074 *  Notes:
1075 *     - If this function is invoked with the global error status set,
1076 *     or if it should fail for any reason, then NULL values will be
1077 *     returned as the function value and for the "map" pointer.
1078 */
1079 
1080 /* Local Variables: */
1081    AstMapping *fmap;          /* Pointer to forward Mapping in supplied TranMap */
1082    AstMapping *imap;          /* Pointer to inverse Mapping in supplied TranMap */
1083    AstMapping *rfmap;         /* Pointer to split forward Mapping */
1084    AstMapping *rimap;         /* Pointer to split inverse Mapping */
1085    AstTranMap *this;          /* Pointer to TranMap structure */
1086    int *ires;                 /* I/ps of inv Mapping dependent on selected o/ps */
1087    int *out;                  /* O/ps of fwd Mapping dependent on selected i/ps */
1088    int *result;               /* Pointer to returned array */
1089    int finv;                  /* Invert flag to use with fmap */
1090    int i;                     /* Loop count */
1091    int iinv;                  /* Invert flag to use with imap */
1092    int nout;                  /* No. of outputs dependent on selected inputs */
1093    int ok;                    /* Can required Mapping be created? */
1094    int old_finv;              /* Original Invert flag for fmap */
1095    int old_iinv;              /* Original Invert flag for imap */
1096 
1097 /* Initialise */
1098    result = NULL;
1099    *map = NULL;
1100 
1101 /* Check the global error status. */
1102    if ( !astOK ) return result;
1103 
1104 /* Invoke the parent astMapSplit method to see if it can do the job. */
1105    result = (*parent_mapsplit)( this_map, nin, in, map, status );
1106 
1107 /* If not, we provide a special implementation here. */
1108    if( !result ) {
1109 
1110 /* Get a pointer to the TranMap structure. */
1111       this = (AstTranMap *) this_map;
1112 
1113 /* Get pointers to the forward and inverse Mappings, taking into account
1114    whether the TranMap has been inverted. */
1115       if( !astGetInvert( this ) ) {
1116          fmap = this->map1;
1117          finv = this->invert1;
1118          imap = this->map2;
1119          iinv = this->invert2;
1120       } else {
1121          imap = this->map1;
1122          iinv = !( this->invert1 );
1123          fmap = this->map2;
1124          finv = !( this->invert2 );
1125       }
1126 
1127 /* Temporarily set the Invert flag of both Mappings back to their
1128    original values. */
1129       old_finv = astGetInvert( fmap );
1130       astSetInvert( fmap, finv );
1131       old_iinv = astGetInvert( imap );
1132       astSetInvert( imap, iinv );
1133 
1134 /* Try to split the forward Mapping. */
1135       out = astMapSplit( fmap, nin, in, &rfmap );
1136 
1137 /* Check the split could be done. */
1138       if( out ) {
1139 
1140 /* Get the number of outputs which are fed by the selected inputs. */
1141          nout = astGetNout( rfmap );
1142 
1143 /* See if the inverse Mapping can be split using these outputs as inputs. */
1144          astInvert( imap );
1145          ires = astMapSplit( imap, nout, out, &rimap );
1146          astInvert( imap );
1147          if( ires ) {
1148             astInvert( rimap );
1149 
1150 /* Check that the resulting inputs are the same as the supplied inputs. */
1151             if( astGetNin( rimap ) == nin ) {
1152                ok = 1;
1153                for( i = 0; i < nin; i++ ) {
1154                   if( in[ i ] != ires[ i ] ) {
1155                      ok = 0;
1156                      break;
1157                   }
1158                }
1159 
1160 /* If so create the required new TranMap. */
1161                if( ok ) {
1162                   *map = (AstMapping *) astTranMap( rfmap, rimap, "", status );
1163                   result = out;
1164                }
1165             }
1166 
1167 /* Free resources. */
1168             ires = astFree( ires );
1169             rimap = astAnnul( rimap );
1170          }
1171 
1172          if( !result ) out = astFree( out );
1173          rfmap = astAnnul( rfmap );
1174       }
1175 
1176 /* Re-instate the Invert flags of the component Mappings. */
1177       astSetInvert( fmap, old_finv );
1178       astSetInvert( imap, old_iinv );
1179    }
1180 
1181 /* Free returned resources if an error has occurred. */
1182    if( !astOK ) {
1183       result = astFree( result );
1184       *map = astAnnul( *map );
1185    }
1186 
1187 /* Return the list of output indices. */
1188    return result;
1189 }
1190 
Rate(AstMapping * this,double * at,int ax1,int ax2,int * status)1191 static double Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ){
1192 /*
1193 *  Name:
1194 *     Rate
1195 
1196 *  Purpose:
1197 *     Calculate the rate of change of a Mapping output.
1198 
1199 *  Type:
1200 *     Private function.
1201 
1202 *  Synopsis:
1203 *     #include "tranmap.h"
1204 *     result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status )
1205 
1206 *  Class Membership:
1207 *     TranMap member function (overrides the astRate method inherited
1208 *     from the Mapping class ).
1209 
1210 *  Description:
1211 *     This function returns the rate of change of a specified output of
1212 *     the supplied Mapping with respect to a specified input, at a
1213 *     specified input position. Also evaluates the second derivative.
1214 
1215 *  Parameters:
1216 *     this
1217 *        Pointer to the Mapping to be applied.
1218 *     at
1219 *        The address of an array holding the axis values at the position
1220 *        at which the rate of change is to be evaluated. The number of
1221 *        elements in this array should equal the number of inputs to the
1222 *        Mapping.
1223 *     ax1
1224 *        The index of the Mapping output for which the rate of change is to
1225 *        be found (output numbering starts at 0 for the first output).
1226 *     ax2
1227 *        The index of the Mapping input which is to be varied in order to
1228 *        find the rate of change (input numbering starts at 0 for the first
1229 *        input).
1230 *     status
1231 *        Pointer to the inherited status variable.
1232 
1233 *  Returned Value:
1234 *     The rate of change of Mapping output "ax1" with respect to input
1235 *     "ax2", evaluated at "at", or AST__BAD if the value cannot be
1236 *     calculated.
1237 
1238 */
1239 
1240 /* Local Variables: */
1241    AstTranMap *map;
1242    AstMapping *cmap;
1243    double result;
1244    int cinv;
1245    int old_inv;
1246 
1247 /* Check inherited status */
1248    if( !astOK ) return AST__BAD;
1249 
1250 /* Get a pointer to the TranMap structure. */
1251    map = (AstTranMap *) this;
1252 
1253 /* Choose the component Mapping to use, and get its original Invert
1254    value. Invert this if the TranMap itself has been inverted (this is
1255    because the astRate function has no "invert" argument so we need to
1256    invert the Mapping before calling astRate). */
1257    if( astGetInvert( this ) ) {
1258       cmap = map->map2;
1259       cinv = !(map->invert2);
1260    } else {
1261       cmap = map->map1;
1262       cinv = map->invert1;
1263    }
1264 
1265 /* Temporarily set the Invert flag of the component Mapping back to its
1266    original value. */
1267    old_inv = astGetInvert( cmap );
1268    astSetInvert( cmap, cinv );
1269 
1270 /* Use the astRate method of the component Mapping. */
1271    result = astRate( cmap, at, ax1, ax2 );
1272 
1273 /* Re-instate the Invert flag of the component Mapping. */
1274    astSetInvert( cmap, old_inv );
1275 
1276 /* Return the result. */
1277    return result;
1278 }
1279 
RemoveRegions(AstMapping * this_mapping,int * status)1280 static AstMapping *RemoveRegions( AstMapping *this_mapping, int *status ) {
1281 /*
1282 *  Name:
1283 *     RemoveRegions
1284 
1285 *  Purpose:
1286 *     Remove any Regions from a Mapping.
1287 
1288 *  Type:
1289 *     Private function.
1290 
1291 *  Synopsis:
1292 *     #include "tranmap.h"
1293 *     AstMapping *RemoveRegions( AstMapping *this, int *status )
1294 
1295 *  Class Membership:
1296 *     TranMap method (over-rides the astRemoveRegions method inherited
1297 *     from the Mapping class).
1298 
1299 *  Description:
1300 *     This function searches the supplied Mapping (which may be a
1301 *     compound Mapping such as a TranMap) for any component Mappings
1302 *     that are instances of the AST Region class. It then creates a new
1303 *     Mapping from which all Regions have been removed. If a Region
1304 *     cannot simply be removed (for instance, if it is a component of a
1305 *     parallel TranMap), then it is replaced with an equivalent UnitMap
1306 *     in the returned Mapping.
1307 *
1308 *     The implementation provided by the TranMap class invokes the
1309 *     astRemoveRegions method on the two component Mappings, and joins
1310 *     the results together into a new TranMap.
1311 
1312 *  Parameters:
1313 *     this
1314 *        Pointer to the original Region.
1315 *     status
1316 *        Pointer to the inherited status variable.
1317 
1318 *  Returned Value:
1319 *     A pointer to the modified mapping.
1320 
1321 *  Notes:
1322 *     - A NULL pointer value will be returned if this function is
1323 *     invoked with the AST error status set, or if it should fail for
1324 *     any reason.
1325 */
1326 
1327 /* Local Variables: */
1328    AstTranMap *new;              /* Pointer to new TranMap */
1329    AstTranMap *this;             /* Pointer to TranMap structure */
1330    AstMapping *newmap1;          /* New first component Mapping */
1331    AstMapping *newmap2;          /* New second component Mapping */
1332    AstMapping *result;           /* Result pointer to return */
1333    int nax;                      /* Number of Frame axes */
1334    int unit1;                    /* Is new first Mapping a UnitMap? */
1335    int unit2;                    /* Is new second Mapping a UnitMap? */
1336 
1337 /* Initialise. */
1338    result = NULL;
1339 
1340 /* Check the global error status. */
1341    if ( !astOK ) return result;
1342 
1343 /* Get a pointer to the TranMap. */
1344    this = (AstTranMap *) this_mapping;
1345 
1346 /* Invoke the astRemoveRegions method on the two component Mappings. */
1347    newmap1 = astRemoveRegions( this->map1 );
1348    newmap2 = astRemoveRegions( this->map2 );
1349 
1350 /* If neither component was modified, just return a clone of the supplied
1351    pointer. */
1352    if( this->map1 == newmap1 && this->map2 == newmap2 ) {
1353       result = astClone( this );
1354 
1355 /* Otherwise, we need to create a new Mapping to return. */
1356    } else {
1357 
1358 /* The implementation of the astRemoveRegions method provided by the
1359    Region class returns a Frame rather than a UnitMap. But we need
1360    Mappings here, not Frames. So if either of these new Mappings is
1361    a Frame, replace it with an equivalent UnitMap. Also, get flags
1362    indicating if either Mapping is a UnitMap.*/
1363       if( astIsAFrame( newmap1 ) ) {
1364          nax = astGetNin( newmap1 );
1365          (void) astAnnul( newmap1 );
1366          newmap1 = (AstMapping *) astUnitMap( nax, " ", status );
1367          unit1 = 1;
1368       } else {
1369          unit1 = astIsAUnitMap( newmap1 );
1370       }
1371 
1372       if( astIsAFrame( newmap2 ) ) {
1373          nax = astGetNin( newmap2 );
1374          (void) astAnnul( newmap2 );
1375          newmap2 = (AstMapping *) astUnitMap( nax, " ", status );
1376          unit2 = 1;
1377       } else {
1378          unit2 = astIsAUnitMap( newmap2 );
1379       }
1380 
1381 /* If both new Mappings are UnitMaps, return an equivalent UnitMap. */
1382       if( unit1 && unit2 ) {
1383          result = (AstMapping *) astUnitMap( astGetNin( newmap1 ) +
1384                                              astGetNin( newmap2 ), " ",
1385                                              status );
1386 
1387 /* Otherwise, return a new TranMap containing the two new Mappings. */
1388       } else {
1389          new = astCopy( this );
1390          (void) astAnnul( new->map1 );
1391          (void) astAnnul( new->map2 );
1392          new->map1 = astClone( newmap1 );
1393          new->map2 = astClone( newmap2 );
1394          result = (AstMapping *) new;
1395       }
1396    }
1397 
1398 /* Free resources. */
1399    newmap1 = astAnnul( newmap1 );
1400    newmap2 = astAnnul( newmap2 );
1401 
1402 /* Annul the returned Mapping if an error has occurred. */
1403    if( !astOK ) result = astAnnul( result );
1404 
1405 /* Return the result. */
1406    return result;
1407 }
1408 
Transform(AstMapping * this,AstPointSet * in,int forward,AstPointSet * out,int * status)1409 static AstPointSet *Transform( AstMapping *this, AstPointSet *in,
1410                                int forward, AstPointSet *out, int *status ) {
1411 /*
1412 *  Name:
1413 *     Transform
1414 
1415 *  Purpose:
1416 *     Apply a TranMap to transform a set of points.
1417 
1418 *  Type:
1419 *     Private function.
1420 
1421 *  Synopsis:
1422 *     #include "tranmap.h"
1423 *     AstPointSet *Transform( AstMapping *this, AstPointSet *in,
1424 *                             int forward, AstPointSet *out, int *status )
1425 
1426 *  Class Membership:
1427 *     TranMap member function (over-rides the astTransform method inherited
1428 *     from the Mapping class).
1429 
1430 *  Description:
1431 *     This function takes a TranMap and a set of points encapsulated in a
1432 *     PointSet and transforms the points so as to apply the required Mapping.
1433 *     This implies applying each of the TranMap's component Mappings in turn,
1434 *     either in series or in parallel.
1435 
1436 *  Parameters:
1437 *     this
1438 *        Pointer to the TranMap.
1439 *     in
1440 *        Pointer to the PointSet associated with the input coordinate values.
1441 *     forward
1442 *        A non-zero value indicates that the forward coordinate transformation
1443 *        should be applied, while a zero value requests the inverse
1444 *        transformation.
1445 *     out
1446 *        Pointer to a PointSet which will hold the transformed (output)
1447 *        coordinate values. A NULL value may also be given, in which case a
1448 *        new PointSet will be created by this function.
1449 *     status
1450 *        Pointer to the inherited status variable.
1451 
1452 *  Returned Value:
1453 *     Pointer to the output (possibly new) PointSet.
1454 
1455 *  Notes:
1456 *     -  A null pointer will be returned if this function is invoked with the
1457 *     global error status set, or if it should fail for any reason.
1458 *     -  The number of coordinate values per point in the input PointSet must
1459 *     match the number of coordinates for the TranMap being applied.
1460 *     -  If an output PointSet is supplied, it must have space for sufficient
1461 *     number of points and coordinate values per point to accommodate the
1462 *     result. Any excess space will be ignored.
1463 */
1464 
1465 /* Local Variables: */
1466    AstMapping *cmap;             /* Mapping which defines the required transformation */
1467    AstPointSet *result;          /* Pointer to output PointSet */
1468    AstTranMap *map;              /* Pointer to TranMap to be applied */
1469    int cinv;                     /* Invert flag when TranMap was created */
1470    int old_inv;                  /* Invert flag on entry to this function */
1471 
1472 /* Check the global error status. */
1473    if ( !astOK ) return NULL;
1474 
1475 /* Obtain a pointer to the TranMap. */
1476    map = (AstTranMap *) this;
1477 
1478 /* Apply the parent Mapping using the stored pointer to the Transform member
1479    function inherited from the parent Mapping class. This function validates
1480    all arguments and generates an output PointSet if necessary, but does not
1481    actually transform any coordinate values. */
1482    result = (*parent_transform)( this, in, forward, out, status );
1483 
1484 /* We now extend the parent astTransform method by applying the component
1485    Mappings of the TranMap to generate the output coordinate values. */
1486 
1487 /* Determine whether to apply the forward or inverse Mapping, according to the
1488    direction specified and whether the Mapping has been inverted. */
1489    if ( astGetInvert( map ) ) forward = !forward;
1490 
1491 /* Choose the component Mapping to use, and get its original Invert value. */
1492    if( forward ) {
1493       cmap = map->map1;
1494       cinv = map->invert1;
1495    }else {
1496       cmap = map->map2;
1497       cinv = map->invert2;
1498    }
1499 
1500 /* Temporarily set the Invert flag of the component Mapping back to its
1501    original value. */
1502    old_inv = astGetInvert( cmap );
1503    astSetInvert( cmap, cinv );
1504 
1505 /* Use the Transform method of the component Mapping. */
1506    result = astTransform( cmap, in, forward, out );
1507 
1508 /* Re-instate the Invert flag of the component Mapping. */
1509    astSetInvert( cmap, old_inv );
1510 
1511 /* If an error occurred, clean up by deleting the output PointSet (if
1512    allocated by this function) and setting a NULL result pointer. */
1513    if ( !astOK ) {
1514       if ( !out ) result = astDelete( result );
1515       result = NULL;
1516    }
1517 
1518 /* Return a pointer to the output PointSet. */
1519    return result;
1520 }
1521 
1522 /* Copy constructor. */
1523 /* ----------------- */
Copy(const AstObject * objin,AstObject * objout,int * status)1524 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
1525 /*
1526 *  Name:
1527 *     Copy
1528 
1529 *  Purpose:
1530 *     Copy constructor for TranMap objects.
1531 
1532 *  Type:
1533 *     Private function.
1534 
1535 *  Synopsis:
1536 *     void Copy( const AstObject *objin, AstObject *objout, int *status )
1537 
1538 *  Description:
1539 *     This function implements the copy constructor for TranMap objects.
1540 
1541 *  Parameters:
1542 *     objin
1543 *        Pointer to the object to be copied.
1544 *     objout
1545 *        Pointer to the object being constructed.
1546 *     status
1547 *        Pointer to the inherited status variable.
1548 
1549 *  Returned Value:
1550 *     void
1551 
1552 *  Notes:
1553 *     -  This constructor makes a deep copy, including a copy of the component
1554 *     Mappings within the TranMap.
1555 */
1556 
1557 /* Local Variables: */
1558    AstTranMap *in;                /* Pointer to input TranMap */
1559    AstTranMap *out;               /* Pointer to output TranMap */
1560 
1561 /* Check the global error status. */
1562    if ( !astOK ) return;
1563 
1564 /* Obtain pointers to the input and output TranMaps. */
1565    in = (AstTranMap *) objin;
1566    out = (AstTranMap *) objout;
1567 
1568 /* For safety, start by clearing any references to the input component
1569    Mappings from the output TranMap. */
1570    out->map1 = NULL;
1571    out->map2 = NULL;
1572 
1573 /* Make copies of these Mappings and store pointers to them in the output
1574    TranMap structure. */
1575    out->map1 = astCopy( in->map1 );
1576    out->map2 = astCopy( in->map2 );
1577 }
1578 
1579 /* Destructor. */
1580 /* ----------- */
Delete(AstObject * obj,int * status)1581 static void Delete( AstObject *obj, int *status ) {
1582 /*
1583 *  Name:
1584 *     Delete
1585 
1586 *  Purpose:
1587 *     Destructor for TranMap objects.
1588 
1589 *  Type:
1590 *     Private function.
1591 
1592 *  Synopsis:
1593 *     void Delete( AstObject *obj, int *status )
1594 
1595 *  Description:
1596 *     This function implements the destructor for TranMap objects.
1597 
1598 *  Parameters:
1599 *     obj
1600 *        Pointer to the object to be deleted.
1601 *     status
1602 *        Pointer to the inherited status variable.
1603 
1604 *  Returned Value:
1605 *     void
1606 
1607 *  Notes:
1608 *     This function attempts to execute even if the global error status is
1609 *     set.
1610 */
1611 
1612 /* Local Variables: */
1613    AstTranMap *this;              /* Pointer to TranMap */
1614 
1615 /* Obtain a pointer to the TranMap structure. */
1616    this = (AstTranMap *) obj;
1617 
1618 /* Annul the pointers to the component Mappings. */
1619    this->map1 = astAnnul( this->map1 );
1620    this->map2 = astAnnul( this->map2 );
1621 
1622 /* Clear the remaining TranMap variables. */
1623    this->invert1 = 0;
1624    this->invert2 = 0;
1625 }
1626 
1627 /* Dump function. */
1628 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)1629 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
1630 /*
1631 *  Name:
1632 *     Dump
1633 
1634 *  Purpose:
1635 *     Dump function for TranMap objects.
1636 
1637 *  Type:
1638 *     Private function.
1639 
1640 *  Synopsis:
1641 *     void Dump( AstObject *this, AstChannel *channel, int *status )
1642 
1643 *  Description:
1644 *     This function implements the Dump function which writes out data
1645 *     for the TranMap class to an output Channel.
1646 
1647 *  Parameters:
1648 *     this
1649 *        Pointer to the TranMap whose data are being written.
1650 *     channel
1651 *        Pointer to the Channel to which the data are being written.
1652 *     status
1653 *        Pointer to the inherited status variable.
1654 */
1655 
1656 /* Local Variables: */
1657    AstTranMap *this;              /* Pointer to the TranMap structure */
1658    int ival;                     /* Integer value */
1659    int set;                      /* Attribute value set? */
1660 
1661 /* Check the global error status. */
1662    if ( !astOK ) return;
1663 
1664 /* Obtain a pointer to the TranMap structure. */
1665    this = (AstTranMap *) this_object;
1666 
1667 /* Write out values representing the instance variables for the TranMap
1668    class.  Accompany these with appropriate comment strings, possibly
1669    depending on the values being written.*/
1670 
1671 /* In the case of attributes, we first use the appropriate (private)
1672    Test...  member function to see if they are set. If so, we then use
1673    the (private) Get... function to obtain the value to be written
1674    out.
1675 
1676    For attributes which are not set, we use the astGet... method to
1677    obtain the value instead. This will supply a default value
1678    (possibly provided by a derived class which over-rides this method)
1679    which is more useful to a human reader as it corresponds to the
1680    actual default attribute value.  Since "set" will be zero, these
1681    values are for information only and will not be read back. */
1682 
1683 /* First Invert flag. */
1684 /* ------------------ */
1685    ival = this->invert1;
1686    set = ( ival != 0 );
1687    astWriteInt( channel, "InvA", set, 0, ival,
1688                 ival ? "First Mapping used in inverse direction" :
1689                        "First Mapping used in forward direction" );
1690 
1691 /* Second Invert flag. */
1692 /* ------------------- */
1693    ival = this->invert2;
1694    set = ( ival != 0 );
1695    astWriteInt( channel, "InvB", set, 0, ival,
1696                 ival ? "Second Mapping used in inverse direction" :
1697                        "Second Mapping used in forward direction" );
1698 
1699 /* First Mapping. */
1700 /* -------------- */
1701    astWriteObject( channel, "MapA", 1, 1, this->map1,
1702                    "Mapping for forward transformation" );
1703 
1704 /* Second Mapping. */
1705 /* --------------- */
1706    astWriteObject( channel, "MapB", 1, 1, this->map2,
1707                    "Mapping for inverse transformation" );
1708 }
1709 
1710 /* Standard class functions. */
1711 /* ========================= */
1712 /* Implement the astIsATranMap and astCheckTranMap functions using the
1713    macros defined for this purpose in the "object.h" header file. */
astMAKE_ISA(TranMap,Mapping)1714 astMAKE_ISA(TranMap,Mapping)
1715 astMAKE_CHECK(TranMap)
1716 
1717 AstTranMap *astTranMap_( void *map1_void, void *map2_void, const char *options, int *status, ...) {
1718 /*
1719 *+
1720 *  Name:
1721 *     astTranMap
1722 
1723 *  Purpose:
1724 *     Create a TranMap.
1725 
1726 *  Type:
1727 *     Protected function.
1728 
1729 *  Synopsis:
1730 *     #include "tranmap.h"
1731 *     AstTranMap *astTranMap( AstMapping *map1, AstMapping *map2, const char *options, int *status, ... )
1732 
1733 *  Class Membership:
1734 *     TranMap constructor.
1735 
1736 *  Description:
1737 *     This function creates a new TranMap and optionally initialises its
1738 *     attributes.
1739 
1740 *  Parameters:
1741 *     map1
1742 *        Pointer to the first Mapping (which deinfes the forward
1743 *        transformation).
1744 *     map2
1745 *        Pointer to the second Mapping (which deinfes the inverse
1746 *        transformation).
1747 *     options
1748 *        Pointer to a null terminated string containing an optional
1749 *        comma-separated list of attribute assignments to be used for
1750 *        initialising the new TranMap. The syntax used is the same as for the
1751 *        astSet method and may include "printf" format specifiers identified
1752 *        by "%" symbols in the normal way.
1753 *     status
1754 *        Pointer to the inherited status variable.
1755 *     ...
1756 *        If the "options" string contains "%" format specifiers, then an
1757 *        optional list of arguments may follow it in order to supply values to
1758 *        be substituted for these specifiers. The rules for supplying these
1759 *        are identical to those for the astSet method (and for the C "printf"
1760 *        function).
1761 
1762 *  Returned Value:
1763 *     A pointer to the new TranMap.
1764 
1765 *  Notes:
1766 *     - A null pointer will be returned if this function is invoked
1767 *     with the global error status set, or if it should fail for any
1768 *     reason.
1769 *-
1770 
1771 *  Implementation Notes:
1772 *     - This function implements the basic TranMap constructor which is
1773 *     available via the protected interface to the TranMap class.  A
1774 *     public interface is provided by the astTranMapId_ function.
1775 *     - Because this function has a variable argument list, it is
1776 *     invoked by a macro that evaluates to a function pointer (not a
1777 *     function invocation) and no checking or casting of arguments is
1778 *     performed before the function is invoked. Because of this, the
1779 *     "map1" and "map2" parameters are of type (void *) and are
1780 *     converted and validated within the function itself.
1781 */
1782 
1783 /* Local Variables: */
1784    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1785    AstTranMap *new;              /* Pointer to new TranMap */
1786    AstMapping *map1;             /* Pointer to first Mapping structure */
1787    AstMapping *map2;             /* Pointer to second Mapping structure */
1788    va_list args;                 /* Variable argument list */
1789 
1790 /* Initialise. */
1791    new = NULL;
1792 
1793 /* Get a pointer to the thread specific global data structure. */
1794    astGET_GLOBALS(NULL);
1795 
1796 /* Check the global status. */
1797    if ( !astOK ) return new;
1798 
1799 /* Obtain and validate pointers to the Mapping structures provided. */
1800    map1 = astCheckMapping( map1_void );
1801    map2 = astCheckMapping( map2_void );
1802    if ( astOK ) {
1803 
1804 /* Initialise the TranMap, allocating memory and initialising the
1805    virtual function table as well if necessary. */
1806       new = astInitTranMap( NULL, sizeof( AstTranMap ), !class_init, &class_vtab,
1807                            "TranMap", map1, map2 );
1808 
1809 /* If successful, note that the virtual function table has been
1810    initialised. */
1811       if ( astOK ) {
1812          class_init = 1;
1813 
1814 /* Obtain the variable argument list and pass it along with the
1815    options string to the astVSet method to initialise the new TranMap's
1816    attributes. */
1817          va_start( args, status );
1818          astVSet( new, options, NULL, args );
1819          va_end( args );
1820 
1821 /* If an error occurred, clean up by deleting the new object. */
1822          if ( !astOK ) new = astDelete( new );
1823       }
1824    }
1825 
1826 /* Return a pointer to the new TranMap. */
1827    return new;
1828 }
1829 
astTranMapId_(void * map1_void,void * map2_void,const char * options,...)1830 AstTranMap *astTranMapId_( void *map1_void, void *map2_void,
1831                            const char *options, ... ) {
1832 /*
1833 *++
1834 *  Name:
1835 c     astTranMap
1836 f     AST_TRANMAP
1837 
1838 *  Purpose:
1839 *     Create a TranMap.
1840 
1841 *  Type:
1842 *     Public function.
1843 
1844 *  Synopsis:
1845 c     #include "tranmap.h"
1846 c     AstTranMap *astTranMap( AstMapping *map1, AstMapping *map2,
1847 c                           const char *options, ... )
1848 f     RESULT = AST_TRANMAP( MAP1, MAP2, OPTIONS, STATUS )
1849 
1850 *  Class Membership:
1851 *     TranMap constructor.
1852 
1853 *  Description:
1854 *     This function creates a new TranMap and optionally initialises
1855 *     its attributes.
1856 *
1857 *     A TranMap is a Mapping which combines the forward transformation of
1858 *     a supplied Mapping with the inverse transformation of another
1859 *     supplied Mapping, ignoring the un-used transformation in each
1860 *     Mapping (indeed the un-used transformation need not exist).
1861 *
1862 *     When the forward transformation of the TranMap is referred to, the
1863 *     transformation actually used is the forward transformation of the
1864 *     first Mapping supplied when the TranMap was constructed. Likewise,
1865 *     when the inverse transformation of the TranMap is referred to, the
1866 *     transformation actually used is the inverse transformation of the
1867 *     second Mapping supplied when the TranMap was constructed.
1868 
1869 *  Parameters:
1870 c     map1
1871 f     MAP1 = INTEGER (Given)
1872 *        Pointer to the first component Mapping, which defines the
1873 *        forward transformation.
1874 c     map2
1875 f     MAP2 = INTEGER (Given)
1876 *        Pointer to the second component Mapping, which defines the
1877 *        inverse transformation.
1878 c     options
1879 f     OPTIONS = CHARACTER * ( * ) (Given)
1880 c        Pointer to a null-terminated string containing an optional
1881 c        comma-separated list of attribute assignments to be used for
1882 c        initialising the new TranMap. The syntax used is identical to
1883 c        that for the astSet function and may include "printf" format
1884 c        specifiers identified by "%" symbols in the normal way.
1885 f        A character string containing an optional comma-separated
1886 f        list of attribute assignments to be used for initialising the
1887 f        new TranMap. The syntax used is identical to that for the
1888 f        AST_SET routine.
1889 c     ...
1890 c        If the "options" string contains "%" format specifiers, then
1891 c        an optional list of additional arguments may follow it in
1892 c        order to supply values to be substituted for these
1893 c        specifiers. The rules for supplying these are identical to
1894 c        those for the astSet function (and for the C "printf"
1895 c        function).
1896 f     STATUS = INTEGER (Given and Returned)
1897 f        The global status.
1898 
1899 *  Returned Value:
1900 c     astTranMap()
1901 f     AST_TRANMAP = INTEGER
1902 *        A pointer to the new TranMap.
1903 
1904 *  Notes:
1905 *     - The number of output coordinates generated by the two Mappings
1906 *     (their Nout attribute) must be equal, as must the number of input
1907 *     coordinates accepted by each Mapping (their Nin attribute).
1908 *     - The forward transformation of the first Mapping must exist.
1909 *     - The inverse transformation of the second Mapping must exist.
1910 c     - Note that the component Mappings supplied are not copied by
1911 c     astTranMap (the new TranMap simply retains a reference to
1912 c     them). They may continue to be used for other purposes, but
1913 c     should not be deleted. If a TranMap containing a copy of its
1914 c     component Mappings is required, then a copy of the TranMap should
1915 c     be made using astCopy.
1916 f     - Note that the component Mappings supplied are not copied by
1917 f     AST_TRANMAP (the new TranMap simply retains a reference to
1918 f     them). They may continue to be used for other purposes, but
1919 f     should not be deleted. If a TranMap containing a copy of its
1920 f     component Mappings is required, then a copy of the TranMap should
1921 f     be made using AST_COPY.
1922 *     - A null Object pointer (AST__NULL) will be returned if this
1923 c     function is invoked with the AST error status set, or if it
1924 f     function is invoked with STATUS set to an error value, or if it
1925 *     should fail for any reason.
1926 
1927 *  Status Handling:
1928 *     The protected interface to this function includes an extra
1929 *     parameter at the end of the parameter list descirbed above. This
1930 *     parameter is a pointer to the integer inherited status
1931 *     variable: "int *status".
1932 
1933 *--
1934 
1935 *  Implementation Notes:
1936 *     - This function implements the external (public) interface to
1937 *     the astTranMap constructor function. It returns an ID value
1938 *     (instead of a true C pointer) to external users, and must be
1939 *     provided because astTranMap_ has a variable argument list which
1940 *     cannot be encapsulated in a macro (where this conversion would
1941 *     otherwise occur).
1942 *     - Because no checking or casting of arguments is performed
1943 *     before the function is invoked, the "map1" and "map2" parameters
1944 *     are of type (void *) and are converted from an ID value to a
1945 *     pointer and validated within the function itself.
1946 *     - The variable argument list also prevents this function from
1947 *     invoking astTranMap_ directly, so it must be a re-implementation
1948 *     of it in all respects, except for the conversions between IDs
1949 *     and pointers on input/output of Objects.
1950 */
1951 
1952 /* Local Variables: */
1953    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1954    AstTranMap *new;               /* Pointer to new TranMap */
1955    AstMapping *map1;             /* Pointer to first Mapping structure */
1956    AstMapping *map2;             /* Pointer to second Mapping structure */
1957    va_list args;                 /* Variable argument list */
1958 
1959    int *status;                  /* Pointer to inherited status value */
1960 
1961 /* Get a pointer to the thread specific global data structure. */
1962    astGET_GLOBALS(NULL);
1963 
1964 /* Initialise. */
1965    new = NULL;
1966 
1967 /* Get a pointer to the inherited status value. */
1968    status = astGetStatusPtr;
1969 
1970 /* Check the global status. */
1971    if ( !astOK ) return new;
1972 
1973 /* Obtain the Mapping pointers from the ID's supplied and validate the
1974    pointers to ensure they identify valid Mappings. */
1975    map1 = astVerifyMapping( astMakePointer( map1_void ) );
1976    map2 = astVerifyMapping( astMakePointer( map2_void ) );
1977    if ( astOK ) {
1978 
1979 /* Initialise the TranMap, allocating memory and initialising the
1980    virtual function table as well if necessary. */
1981       new = astInitTranMap( NULL, sizeof( AstTranMap ), !class_init, &class_vtab,
1982                            "TranMap", map1, map2 );
1983 
1984 /* If successful, note that the virtual function table has been initialised. */
1985       if ( astOK ) {
1986          class_init = 1;
1987 
1988 /* Obtain the variable argument list and pass it along with the
1989    options string to the astVSet method to initialise the new TranMap's
1990    attributes. */
1991          va_start( args, options );
1992          astVSet( new, options, NULL, args );
1993          va_end( args );
1994 
1995 /* If an error occurred, clean up by deleting the new object. */
1996          if ( !astOK ) new = astDelete( new );
1997       }
1998    }
1999 
2000 /* Return an ID value for the new TranMap. */
2001    return astMakeId( new );
2002 }
2003 
astInitTranMap_(void * mem,size_t size,int init,AstTranMapVtab * vtab,const char * name,AstMapping * map1,AstMapping * map2,int * status)2004 AstTranMap *astInitTranMap_( void *mem, size_t size, int init,
2005                            AstTranMapVtab *vtab, const char *name,
2006                            AstMapping *map1, AstMapping *map2, int *status ) {
2007 /*
2008 *+
2009 *  Name:
2010 *     astInitTranMap
2011 
2012 *  Purpose:
2013 *     Initialise a TranMap.
2014 
2015 *  Type:
2016 *     Protected function.
2017 
2018 *  Synopsis:
2019 *     #include "tranmap.h"
2020 *     AstTranMap *astInitTranMap( void *mem, size_t size, int init,
2021 *                               AstTranMapVtab *vtab, const char *name,
2022 *                               AstMapping *map1, AstMapping *map2 )
2023 
2024 *  Class Membership:
2025 *     TranMap initialiser.
2026 
2027 *  Description:
2028 *     This function is provided for use by class implementations to initialise
2029 *     a new TranMap object. It allocates memory (if necessary) to
2030 *     accommodate the TranMap plus any additional data associated with the
2031 *     derived class. It then initialises a TranMap structure at the start
2032 *     of this memory. If the "init" flag is set, it also initialises the
2033 *     contents of a virtual function table for a TranMap at the start of
2034 *     the memory passed via the "vtab" parameter.
2035 
2036 *  Parameters:
2037 *     mem
2038 *        A pointer to the memory in which the TranMap is to be initialised.
2039 *        This must be of sufficient size to accommodate the TranMap data
2040 *        (sizeof(TranMap)) plus any data used by the derived class. If a
2041 *        value of NULL is given, this function will allocate the memory itself
2042 *        using the "size" parameter to determine its size.
2043 *     size
2044 *        The amount of memory used by the TranMap (plus derived class
2045 *        data). This will be used to allocate memory if a value of NULL is
2046 *        given for the "mem" parameter. This value is also stored in the
2047 *        TranMap structure, so a valid value must be supplied even if not
2048 *        required for allocating memory.
2049 *     init
2050 *        A logical flag indicating if the TranMap's virtual function table
2051 *        is to be initialised. If this value is non-zero, the virtual function
2052 *        table will be initialised by this function.
2053 *     vtab
2054 *        Pointer to the start of the virtual function table to be associated
2055 *        with the new TranMap.
2056 *     name
2057 *        Pointer to a constant null-terminated character string which contains
2058 *        the name of the class to which the new object belongs (it is this
2059 *        pointer value that will subsequently be returned by the Object
2060 *        astClass function).
2061 *     map1
2062 *        Pointer to the first Mapping.
2063 *     map2
2064 *        Pointer to the second Mapping.
2065 
2066 *  Returned Value:
2067 *     A pointer to the new TranMap.
2068 
2069 *  Notes:
2070 *     -  A null pointer will be returned if this function is invoked with the
2071 *     global error status set, or if it should fail for any reason.
2072 *-
2073 */
2074 
2075 /* Local Variables: */
2076    AstTranMap *new;               /* Pointer to new TranMap */
2077    int nin;                      /* No. input coordinates for TranMap */
2078    int nout;                     /* No. output coordinates for TranMap */
2079 
2080 /* Check the global status. */
2081    if ( !astOK ) return NULL;
2082 
2083 /* If necessary, initialise the virtual function table. */
2084    if ( init ) astInitTranMapVtab( vtab, name );
2085 
2086 /* Initialise. */
2087    new = NULL;
2088 
2089 /* Report an error if map1 has no forward transformation. */
2090    if( !astGetTranForward( map1 ) && astOK ) {
2091       astError( AST__INTRD, "astInitTranMap(%s): The first supplied Mapping "
2092               "is not able to transform coordinates in the forward direction.", status,
2093               name );
2094    }
2095 
2096 /* Report an error if map2 has no inverse transformation. */
2097    if( !astGetTranInverse( map2 ) && astOK ) {
2098       astError( AST__INTRD, "astInitTranMap(%s): The second supplied Mapping "
2099               "is not able to transform coordinates in the inverse direction.", status,
2100               name );
2101    }
2102 
2103 /* Check that the number of coordinates are compatible and report an error if
2104    they are not. */
2105    nout = astGetNout( map1 );
2106    if ( astGetNout( map2 ) != nout && astOK ) {
2107       astError( AST__INNCO, "astInitTranMap(%s): The number of output "
2108                       "coordinates per point (%d) for the first Mapping "
2109                       "supplied does not match the number of output "
2110                       "coordinates (%d) for the second Mapping.", status, name, nout,
2111                       astGetNout( map2 ) );
2112    }
2113 
2114    nin = astGetNin( map1 );
2115    if ( astGetNin( map2 ) != nin && astOK ) {
2116       astError( AST__INNCO, "astInitTranMap(%s): The number of input "
2117                       "coordinates per point (%d) for the first Mapping "
2118                       "supplied does not match the number of input "
2119                       "coordinates (%d) for the second Mapping.", status, name, nin,
2120                       astGetNin( map2 ) );
2121    }
2122 
2123 /* Initialise a Mapping structure (the parent class) as the first component
2124    within the TranMap structure, allocating memory if necessary. Specify
2125    the number of input and output coordinates and in which directions the
2126    Mapping should be defined. */
2127    if ( astOK ) {
2128       new = (AstTranMap *) astInitMapping( mem, size, 0,
2129                                           (AstMappingVtab *) vtab, name,
2130                                           nin, nout, 1, 1 );
2131 
2132       if ( astOK ) {
2133 
2134 /* Initialise the TranMap data. */
2135 /* --------------------------- */
2136 /* Store pointers to the component Mappings. */
2137          new->map1 = astClone( map1 );
2138          new->map2 = astClone( map2 );
2139 
2140 /* Save the initial values of the inversion flags for these Mappings. */
2141          new->invert1 = astGetInvert( map1 );
2142          new->invert2 = astGetInvert( map2 );
2143 
2144 /* If an error occurred, clean up by annulling the Mapping pointers and
2145    deleting the new object. */
2146          if ( !astOK ) {
2147             new->map1 = astAnnul( new->map1 );
2148             new->map2 = astAnnul( new->map2 );
2149             new = astDelete( new );
2150          }
2151       }
2152    }
2153 
2154 /* Return a pointer to the new object. */
2155    return new;
2156 }
2157 
astLoadTranMap_(void * mem,size_t size,AstTranMapVtab * vtab,const char * name,AstChannel * channel,int * status)2158 AstTranMap *astLoadTranMap_( void *mem, size_t size,
2159                            AstTranMapVtab *vtab, const char *name,
2160                            AstChannel *channel, int *status ) {
2161 /*
2162 *+
2163 *  Name:
2164 *     astLoadTranMap
2165 
2166 *  Purpose:
2167 *     Load a TranMap.
2168 
2169 *  Type:
2170 *     Protected function.
2171 
2172 *  Synopsis:
2173 *     #include "tranmap.h"
2174 *     AstTranMap *astLoadTranMap( void *mem, size_t size,
2175 *                               AstTranMapVtab *vtab, const char *name,
2176 *                               AstChannel *channel )
2177 
2178 *  Class Membership:
2179 *     TranMap loader.
2180 
2181 *  Description:
2182 *     This function is provided to load a new TranMap using data read
2183 *     from a Channel. It first loads the data used by the parent class
2184 *     (which allocates memory if necessary) and then initialises a
2185 *     TranMap structure in this memory, using data read from the input
2186 *     Channel.
2187 *
2188 *     If the "init" flag is set, it also initialises the contents of a
2189 *     virtual function table for a TranMap at the start of the memory
2190 *     passed via the "vtab" parameter.
2191 
2192 
2193 *  Parameters:
2194 *     mem
2195 *        A pointer to the memory into which the TranMap is to be
2196 *        loaded.  This must be of sufficient size to accommodate the
2197 *        TranMap data (sizeof(TranMap)) plus any data used by derived
2198 *        classes. If a value of NULL is given, this function will
2199 *        allocate the memory itself using the "size" parameter to
2200 *        determine its size.
2201 *     size
2202 *        The amount of memory used by the TranMap (plus derived class
2203 *        data).  This will be used to allocate memory if a value of
2204 *        NULL is given for the "mem" parameter. This value is also
2205 *        stored in the TranMap structure, so a valid value must be
2206 *        supplied even if not required for allocating memory.
2207 *
2208 *        If the "vtab" parameter is NULL, the "size" value is ignored
2209 *        and sizeof(AstTranMap) is used instead.
2210 *     vtab
2211 *        Pointer to the start of the virtual function table to be
2212 *        associated with the new TranMap. If this is NULL, a pointer to
2213 *        the (static) virtual function table for the TranMap class is
2214 *        used instead.
2215 *     name
2216 *        Pointer to a constant null-terminated character string which
2217 *        contains the name of the class to which the new object
2218 *        belongs (it is this pointer value that will subsequently be
2219 *        returned by the astGetClass method).
2220 *
2221 *        If the "vtab" parameter is NULL, the "name" value is ignored
2222 *        and a pointer to the string "TranMap" is used instead.
2223 
2224 *  Returned Value:
2225 *     A pointer to the new TranMap.
2226 
2227 *  Notes:
2228 *     - A null pointer will be returned if this function is invoked
2229 *     with the global error status set, or if it should fail for any
2230 *     reason.
2231 *-
2232 */
2233 
2234 /* Local Variables: */
2235    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2236    AstTranMap *new;               /* Pointer to the new TranMap */
2237 
2238 /* Initialise. */
2239    new = NULL;
2240 
2241 /* Check the global error status. */
2242    if ( !astOK ) return new;
2243 
2244 /* Get a pointer to the thread specific global data structure. */
2245    astGET_GLOBALS(channel);
2246 
2247 /* If a NULL virtual function table has been supplied, then this is
2248    the first loader to be invoked for this TranMap. In this case the
2249    TranMap belongs to this class, so supply appropriate values to be
2250    passed to the parent class loader (and its parent, etc.). */
2251    if ( !vtab ) {
2252       size = sizeof( AstTranMap );
2253       vtab = &class_vtab;
2254       name = "TranMap";
2255 
2256 /* If required, initialise the virtual function table for this class. */
2257       if ( !class_init ) {
2258          astInitTranMapVtab( vtab, name );
2259          class_init = 1;
2260       }
2261    }
2262 
2263 /* Invoke the parent class loader to load data for all the ancestral
2264    classes of the current one, returning a pointer to the resulting
2265    partly-built TranMap. */
2266    new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name,
2267                          channel );
2268 
2269    if ( astOK ) {
2270 
2271 /* Read input data. */
2272 /* ================ */
2273 /* Request the input Channel to read all the input data appropriate to
2274    this class into the internal "values list". */
2275       astReadClassData( channel, "TranMap" );
2276 
2277 /* Now read each individual data item from this list and use it to
2278    initialise the appropriate instance variable(s) for this class. */
2279 
2280 /* In the case of attributes, we first read the "raw" input value,
2281    supplying the "unset" value as the default. If a "set" value is
2282    obtained, we then use the appropriate (private) Set... member
2283    function to validate and set the value properly. */
2284 
2285 /* First Invert flag. */
2286 /* ------------------ */
2287       new->invert1 = astReadInt( channel, "inva", 0 );
2288       new->invert1 = ( new->invert1 != 0 );
2289 
2290 /* Second Invert flag. */
2291 /* ------------------- */
2292       new->invert2 = astReadInt( channel, "invb", 0 );
2293       new->invert2 = ( new->invert2 != 0 );
2294 
2295 /* First Mapping. */
2296 /* -------------- */
2297       new->map1 = astReadObject( channel, "mapa", NULL );
2298 
2299 /* Second Mapping. */
2300 /* --------------- */
2301       new->map2 = astReadObject( channel, "mapb", NULL );
2302 
2303 /* If an error occurred, clean up by deleting the new TranMap. */
2304       if ( !astOK ) new = astDelete( new );
2305    }
2306 
2307 /* Return the new TranMap pointer. */
2308    return new;
2309 }
2310 
2311 /* Virtual function interfaces. */
2312 /* ============================ */
2313 /* These provide the external interface to the virtual functions defined by
2314    this class. Each simply checks the global error status and then locates and
2315    executes the appropriate member function, using the function pointer stored
2316    in the object's virtual function table (this pointer is located using the
2317    astMEMBER macro defined in "object.h").
2318 
2319    Note that the member function may not be the one defined here, as it may
2320    have been over-ridden by a derived class. However, it should still have the
2321    same interface. */
2322 
2323 /* None. */
2324 
2325 
2326 
2327 
2328