1 /*
2 *class++
3 * Name:
4 * SphMap
5
6 * Purpose:
7 * Map 3-d Cartesian to 2-d spherical coordinates
8
9 * Constructor Function:
10 c astSphMap
11 f AST_SPHMAP
12
13 * Description:
14 * A SphMap is a Mapping which transforms points from a
15 * 3-dimensional Cartesian coordinate system into a 2-dimensional
16 * spherical coordinate system (longitude and latitude on a unit
17 * sphere centred at the origin). It works by regarding the input
18 * coordinates as position vectors and finding their intersection
19 * with the sphere surface. The inverse transformation always
20 * produces points which are a unit distance from the origin
21 * (i.e. unit vectors).
22
23 * Inheritance:
24 * The SphMap class inherits from the Mapping class.
25
26 * Attributes:
27 * In addition to those attributes common to all Mappings, every
28 * SphMap also has the following attributes:
29 *
30 * - UnitRadius: SphMap input vectors lie on a unit sphere?
31 * - PolarLong: The longitude value to assign to either pole
32
33 * Functions:
34 c The SphMap class does not define any new functions beyond those
35 f The SphMap 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 Berry (Starlink)
60 * RFWS: R.F. Warren-Smith (Starlink)
61
62 * History:
63 * 24-OCT-1996 (DSB):
64 * Original version.
65 * 5-MAR-1997 (RFWS):
66 * Tidied public prologues.
67 * 24-MAR-1998 (RFWS):
68 * Override the astMapMerge method.
69 * 4-SEP-1998 (DSB):
70 * Added UnitRadius attribute.
71 * 8-JAN-2003 (DSB):
72 * Changed private InitVtab method to protected astInitSphMapVtab
73 * method.
74 * 11-JUN-2003 (DSB):
75 * Added PolarLong attribute.
76 * 10-MAY-2006 (DSB):
77 * Override astEqual.
78 * 5-NOV-2013 (DSB):
79 * Modify MapMerge so that it can spot and simplify an
80 * (inverted SphMap,MatrixMap,SphMap) sequence in which the
81 * MatrixMap just magnifies or reflects the radius vector.
82 * 25-MAR-2014 (DSB):
83 * Correct 5-NOV-2013 MapMerge change.
84 *class--
85 */
86
87 /* Module Macros. */
88 /* ============== */
89 /* Set the name of the class we are implementing. This indicates to
90 the header files that define class interfaces that they should make
91 "protected" symbols available. */
92 #define astCLASS SphMap
93
94 /* Include files. */
95 /* ============== */
96 /* Interface definitions. */
97 /* ---------------------- */
98
99 #include "globals.h" /* Thread-safe global data access */
100 #include "error.h" /* Error reporting facilities */
101 #include "memory.h" /* Memory management facilities */
102 #include "globals.h" /* Thread-safe global data access */
103 #include "object.h" /* Base Object class */
104 #include "pointset.h" /* Sets of points/coordinates */
105 #include "mapping.h" /* Coordinate mappings (parent class) */
106 #include "channel.h" /* I/O channels */
107 #include "unitmap.h" /* Unit (identity) Mappings */
108 #include "sphmap.h" /* Interface definition for this class */
109 #include "pal.h" /* SLA transformations */
110 #include "wcsmap.h" /* For the AST__DPIBY2 (etc) constants */
111 #include "matrixmap.h" /* Matrix mappings */
112 #include "winmap.h" /* Shift and scale mappings */
113 #include "zoommap.h" /* Scale mappings */
114
115 /* Error code definitions. */
116 /* ----------------------- */
117 #include "ast_err.h" /* AST error codes */
118
119 /* C header files. */
120 /* --------------- */
121 #include <float.h>
122 #include <stdarg.h>
123 #include <stddef.h>
124 #include <stdio.h>
125 #include <string.h>
126
127 /* Module Variables. */
128 /* ================= */
129
130 /* Address of this static variable is used as a unique identifier for
131 member of this class. */
132 static int class_check;
133
134 /* Pointers to parent class methods which are extended by this class. */
135 static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
136 static const char *(* parent_getattrib)( AstObject *, const char *, int * );
137 static int (* parent_testattrib)( AstObject *, const char *, int * );
138 static void (* parent_clearattrib)( AstObject *, const char *, int * );
139 static void (* parent_setattrib)( AstObject *, const char *, int * );
140
141 /* Define macros for accessing each item of thread specific global data. */
142 #ifdef THREAD_SAFE
143
144 /* Define how to initialise thread-specific globals. */
145 #define GLOBAL_inits \
146 globals->Class_Init = 0; \
147 globals->GetAttrib_Buff[ 0 ] = 0;
148
149 /* Create the function that initialises global data for this module. */
150 astMAKE_INITGLOBALS(SphMap)
151
152 /* Define macros for accessing each item of thread specific global data. */
153 #define class_init astGLOBAL(SphMap,Class_Init)
154 #define class_vtab astGLOBAL(SphMap,Class_Vtab)
155 #define getattrib_buff astGLOBAL(SphMap,GetAttrib_Buff)
156
157
158
159 /* If thread safety is not needed, declare and initialise globals at static
160 variables. */
161 #else
162
163 static char getattrib_buff[ 101 ];
164
165
166 /* Define the class virtual function table and its initialisation flag
167 as static variables. */
168 static AstSphMapVtab class_vtab; /* Virtual function table */
169 static int class_init = 0; /* Virtual function table initialised? */
170
171 #endif
172
173 /* External Interface Function Prototypes. */
174 /* ======================================= */
175 /* The following functions have public prototypes only (i.e. no
176 protected prototypes), so we must provide local prototypes for use
177 within this module. */
178 AstSphMap *astSphMapId_( const char *, ...);
179
180 /* Prototypes for Private Member Functions. */
181 /* ======================================== */
182 static int GetUnitRadius( AstSphMap *, int * );
183 static int TestUnitRadius( AstSphMap *, int * );
184 static void ClearUnitRadius( AstSphMap *, int * );
185 static void SetUnitRadius( AstSphMap *, int, int * );
186
187 static double GetPolarLong( AstSphMap *, int * );
188 static int TestPolarLong( AstSphMap *, int * );
189 static void ClearPolarLong( AstSphMap *, int * );
190 static void SetPolarLong( AstSphMap *, double, int * );
191
192 static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
193 static const char *GetAttrib( AstObject *, const char *, int * );
194 static int Equal( AstObject *, AstObject *, int * );
195 static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * );
196 static int TestAttrib( AstObject *, const char *, int * );
197 static void ClearAttrib( AstObject *, const char *, int * );
198 static void Copy( const AstObject *, AstObject *, int * );
199 static void Delete( AstObject *, int * );
200 static void Dump( AstObject *, AstChannel *, int * );
201 static void SetAttrib( AstObject *, const char *, int * );
202
203 /* Member functions. */
204 /* ================= */
ClearAttrib(AstObject * this_object,const char * attrib,int * status)205 static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
206 /*
207 * Name:
208 * ClearAttrib
209
210 * Purpose:
211 * Clear an attribute value for a SphMap.
212
213 * Type:
214 * Private function.
215
216 * Synopsis:
217 * #include "sphmap.h"
218 * void ClearAttrib( AstObject *this, const char *attrib, int *status, int *status )
219
220 * Class Membership:
221 * SphMap member function (over-rides the astClearAttrib protected
222 * method inherited from the Mapping class).
223
224 * Description:
225 * This function clears the value of a specified attribute for a
226 * SphMap, so that the default value will subsequently be used.
227
228 * Parameters:
229 * this
230 * Pointer to the SphMap.
231 * attrib
232 * Pointer to a null-terminated string specifying the attribute
233 * name. This should be in lower case with no surrounding white
234 * space.
235 * status
236 * Pointer to the inherited status variable.
237 * status
238 * Pointer to the inherited status variable.
239 */
240
241 /* Local Variables: */
242 AstSphMap *this; /* Pointer to the SphMap structure */
243
244 /* Check the global error status. */
245 if ( !astOK ) return;
246
247 /* Obtain a pointer to the SphMap structure. */
248 this = (AstSphMap *) this_object;
249
250 /* UnitRadius */
251 /* ---------- */
252 if ( !strcmp( attrib, "unitradius" ) ) {
253 astClearUnitRadius( this );
254
255 /* PolarLong */
256 /* --------- */
257 } else if ( !strcmp( attrib, "polarlong" ) ) {
258 astClearPolarLong( this );
259
260 /* If the attribute is still not recognised, pass it on to the parent
261 method for further interpretation. */
262 } else {
263 (*parent_clearattrib)( this_object, attrib, status );
264 }
265 }
266
Equal(AstObject * this_object,AstObject * that_object,int * status)267 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
268 /*
269 * Name:
270 * Equal
271
272 * Purpose:
273 * Test if two SphMaps are equivalent.
274
275 * Type:
276 * Private function.
277
278 * Synopsis:
279 * #include "sphmap.h"
280 * int Equal( AstObject *this, AstObject *that, int *status, int *status )
281
282 * Class Membership:
283 * SphMap member function (over-rides the astEqual protected
284 * method inherited from the astMapping class).
285
286 * Description:
287 * This function returns a boolean result (0 or 1) to indicate whether
288 * two SphMaps are equivalent.
289
290 * Parameters:
291 * this
292 * Pointer to the first Object (a SphMap).
293 * that
294 * Pointer to the second Object.
295 * status
296 * Pointer to the inherited status variable.
297 * status
298 * Pointer to the inherited status variable.
299
300 * Returned Value:
301 * One if the SphMaps are equivalent, zero otherwise.
302
303 * Notes:
304 * - A value of zero will be returned if this function is invoked
305 * with the global status set, or if it should fail for any reason.
306 */
307
308 /* Local Variables: */
309 AstSphMap *that;
310 AstSphMap *this;
311 int nin;
312 int nout;
313 int result;
314
315 /* Initialise. */
316 result = 0;
317
318 /* Check the global error status. */
319 if ( !astOK ) return result;
320
321 /* Obtain pointers to the two SphMap structures. */
322 this = (AstSphMap *) this_object;
323 that = (AstSphMap *) that_object;
324
325 /* Check the second object is a SphMap. We know the first is a
326 SphMap since we have arrived at this implementation of the virtual
327 function. */
328 if( astIsASphMap( that ) ) {
329
330 /* Get the number of inputs and outputs and check they are the same for both. */
331 nin = astGetNin( this );
332 nout = astGetNout( this );
333 if( astGetNin( that ) == nin && astGetNout( that ) == nout ) {
334
335 /* If the Invert flags for the two SphMaps differ, it may still be possible
336 for them to be equivalent. First compare the SphMaps if their Invert
337 flags are the same. In this case all the attributes of the two SphMaps
338 must be identical. */
339 if( astGetInvert( this ) == astGetInvert( that ) ) {
340
341 if( astEQUAL( this->polarlong, that->polarlong ) &&
342 this->unitradius == that->unitradius ){
343 result = 1;
344 }
345
346 /* If the Invert flags for the two SphMaps differ, the attributes of the two
347 SphMaps must be inversely related to each other. */
348 } else {
349
350 /* In the specific case of a SphMap, Invert flags must be equal. */
351 result = 0;
352
353 }
354 }
355 }
356
357 /* If an error occurred, clear the result value. */
358 if ( !astOK ) result = 0;
359
360 /* Return the result, */
361 return result;
362 }
363
GetAttrib(AstObject * this_object,const char * attrib,int * status)364 static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
365 /*
366 * Name:
367 * GetAttrib
368
369 * Purpose:
370 * Get the value of a specified attribute for a SphMap.
371
372 * Type:
373 * Private function.
374
375 * Synopsis:
376 * #include "sphmap.h"
377 * const char *GetAttrib( AstObject *this, const char *attrib, int *status, int *status )
378
379 * Class Membership:
380 * SphMap member function (over-rides the protected astGetAttrib
381 * method inherited from the Mapping class).
382
383 * Description:
384 * This function returns a pointer to the value of a specified
385 * attribute for a SphMap, formatted as a character string.
386
387 * Parameters:
388 * this
389 * Pointer to the SphMap.
390 * attrib
391 * Pointer to a null-terminated string containing the name of
392 * the attribute whose value is required. This name should be in
393 * lower case, with all white space removed.
394 * status
395 * Pointer to the inherited status variable.
396 * status
397 * Pointer to the inherited status variable.
398
399 * Returned Value:
400 * - Pointer to a null-terminated string containing the attribute
401 * value.
402
403 * Notes:
404 * - The returned string pointer may point at memory allocated
405 * within the SphMap, or at static memory. The contents of the
406 * string may be over-written or the pointer may become invalid
407 * following a further invocation of the same function or any
408 * modification of the SphMap. A copy of the string should
409 * therefore be made if necessary.
410 * - A NULL pointer will be returned if this function is invoked
411 * with the global error status set, or if it should fail for any
412 * reason.
413 */
414
415 /* Local Variables: */
416 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
417 AstSphMap *this; /* Pointer to the SphMap structure */
418 const char *result; /* Pointer value to return */
419 double dval; /* Double precision attribute value */
420 int ival; /* Int attribute value */
421
422 /* Initialise. */
423 result = NULL;
424
425 /* Check the global error status. */
426 if ( !astOK ) return result;
427
428 /* Get a pointer to the thread specific global data structure. */
429 astGET_GLOBALS(this_object);
430
431 /* Obtain a pointer to the SphMap structure. */
432 this = (AstSphMap *) this_object;
433
434 /* UnitRadius. */
435 /* ----------- */
436 if ( !strcmp( attrib, "unitradius" ) ) {
437 ival = astGetUnitRadius( this );
438 if ( astOK ) {
439 (void) sprintf( getattrib_buff, "%d", ival );
440 result = getattrib_buff;
441 }
442
443 /* PolarLong */
444 /* --------- */
445 } else if ( !strcmp( attrib, "polarlong" ) ) {
446 dval = astGetPolarLong( this );
447 if ( astOK ) {
448 (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
449 result = getattrib_buff;
450 }
451
452 /* If the attribute name was not recognised, pass it on to the parent
453 method for further interpretation. */
454 } else {
455 result = (*parent_getattrib)( this_object, attrib, status );
456 }
457
458 /* Return the result. */
459 return result;
460 }
461
astInitSphMapVtab_(AstSphMapVtab * vtab,const char * name,int * status)462 void astInitSphMapVtab_( AstSphMapVtab *vtab, const char *name, int *status ) {
463 /*
464 *+
465 * Name:
466 * astInitSphMapVtab
467
468 * Purpose:
469 * Initialise a virtual function table for a SphMap.
470
471 * Type:
472 * Protected function.
473
474 * Synopsis:
475 * #include "sphmap.h"
476 * void astInitSphMapVtab( AstSphMapVtab *vtab, const char *name )
477
478 * Class Membership:
479 * SphMap vtab initialiser.
480
481 * Description:
482 * This function initialises the component of a virtual function
483 * table which is used by the SphMap class.
484
485 * Parameters:
486 * vtab
487 * Pointer to the virtual function table. The components used by
488 * all ancestral classes will be initialised if they have not already
489 * been initialised.
490 * name
491 * Pointer to a constant null-terminated character string which contains
492 * the name of the class to which the virtual function table belongs (it
493 * is this pointer value that will subsequently be returned by the Object
494 * astClass function).
495 *-
496 */
497
498 /* Local Variables: */
499 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
500 AstObjectVtab *object; /* Pointer to Object component of Vtab */
501 AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */
502
503 /* Check the local error status. */
504 if ( !astOK ) return;
505
506 /* Get a pointer to the thread specific global data structure. */
507 astGET_GLOBALS(NULL);
508
509 /* Initialize the component of the virtual function table used by the
510 parent class. */
511 astInitMappingVtab( (AstMappingVtab *) vtab, name );
512
513 /* Store a unique "magic" value in the virtual function table. This
514 will be used (by astIsASphMap) to determine if an object belongs
515 to this class. We can conveniently use the address of the (static)
516 class_check variable to generate this unique value. */
517 vtab->id.check = &class_check;
518 vtab->id.parent = &(((AstMappingVtab *) vtab)->id);
519
520 /* Initialise member function pointers. */
521 /* ------------------------------------ */
522 /* Store pointers to the member functions (implemented here) that provide
523 virtual methods for this class. */
524 vtab->ClearUnitRadius = ClearUnitRadius;
525 vtab->SetUnitRadius = SetUnitRadius;
526 vtab->GetUnitRadius = GetUnitRadius;
527 vtab->TestUnitRadius = TestUnitRadius;
528
529 vtab->ClearPolarLong = ClearPolarLong;
530 vtab->SetPolarLong = SetPolarLong;
531 vtab->GetPolarLong = GetPolarLong;
532 vtab->TestPolarLong = TestPolarLong;
533
534 /* Save the inherited pointers to methods that will be extended, and
535 replace them with pointers to the new member functions. */
536 object = (AstObjectVtab *) vtab;
537 mapping = (AstMappingVtab *) vtab;
538
539 parent_clearattrib = object->ClearAttrib;
540 object->ClearAttrib = ClearAttrib;
541 parent_getattrib = object->GetAttrib;
542 object->GetAttrib = GetAttrib;
543 parent_setattrib = object->SetAttrib;
544 object->SetAttrib = SetAttrib;
545 parent_testattrib = object->TestAttrib;
546 object->TestAttrib = TestAttrib;
547
548 parent_transform = mapping->Transform;
549 mapping->Transform = Transform;
550
551 /* Store replacement pointers for methods which will be over-ridden by
552 new member functions implemented here. */
553 object->Equal = Equal;
554 mapping->MapMerge = MapMerge;
555
556 /* Declare the class dump, copy and delete functions.*/
557 astSetDump( vtab, Dump, "SphMap", "Cartesian to Spherical mapping" );
558 astSetCopy( (AstObjectVtab *) vtab, Copy );
559 astSetDelete( (AstObjectVtab *) vtab, Delete );
560
561 /* If we have just initialised the vtab for the current class, indicate
562 that the vtab is now initialised, and store a pointer to the class
563 identifier in the base "object" level of the vtab. */
564 if( vtab == &class_vtab ) {
565 class_init = 1;
566 astSetVtabClassIdentifier( vtab, &(vtab->id) );
567 }
568 }
569
MapMerge(AstMapping * this,int where,int series,int * nmap,AstMapping *** map_list,int ** invert_list,int * status)570 static int MapMerge( AstMapping *this, int where, int series, int *nmap,
571 AstMapping ***map_list, int **invert_list, int *status ) {
572 /*
573 * Name:
574 * MapMerge
575
576 * Purpose:
577 * Simplify a sequence of Mappings containing a SphMap.
578
579 * Type:
580 * Private function.
581
582 * Synopsis:
583 * #include "sphmap.h"
584 * int MapMerge( AstMapping *this, int where, int series, int *nmap,
585 * AstMapping ***map_list, int **invert_list, int *status, int *status )
586
587 * Class Membership:
588 * SphMap method (over-rides the protected astMapMerge method
589 * inherited from the Mapping class).
590
591 * Description:
592 * This function attempts to simplify a sequence of Mappings by
593 * merging a nominated SphMap in the sequence with its neighbours,
594 * so as to shorten the sequence if possible.
595 *
596 * In many cases, simplification will not be possible and the
597 * function will return -1 to indicate this, without further
598 * action.
599 *
600 * In most cases of interest, however, this function will either
601 * attempt to replace the nominated SphMap with one which it
602 * considers simpler, or to merge it with the Mappings which
603 * immediately precede it or follow it in the sequence (both will
604 * normally be considered). This is sufficient to ensure the
605 * eventual simplification of most Mapping sequences by repeated
606 * application of this function.
607 *
608 * In some cases, the function may attempt more elaborate
609 * simplification, involving any number of other Mappings in the
610 * sequence. It is not restricted in the type or scope of
611 * simplification it may perform, but will normally only attempt
612 * elaborate simplification in cases where a more straightforward
613 * approach is not adequate.
614
615 * Parameters:
616 * this
617 * Pointer to the nominated SphMap which is to be merged with
618 * its neighbours. This should be a cloned copy of the SphMap
619 * pointer contained in the array element "(*map_list)[where]"
620 * (see below). This pointer will not be annulled, and the
621 * SphMap it identifies will not be modified by this function.
622 * where
623 * Index in the "*map_list" array (below) at which the pointer
624 * to the nominated SphMap resides.
625 * series
626 * A non-zero value indicates that the sequence of Mappings to
627 * be simplified will be applied in series (i.e. one after the
628 * other), whereas a zero value indicates that they will be
629 * applied in parallel (i.e. on successive sub-sets of the
630 * input/output coordinates).
631 * nmap
632 * Address of an int which counts the number of Mappings in the
633 * sequence. On entry this should be set to the initial number
634 * of Mappings. On exit it will be updated to record the number
635 * of Mappings remaining after simplification.
636 * map_list
637 * Address of a pointer to a dynamically allocated array of
638 * Mapping pointers (produced, for example, by the astMapList
639 * method) which identifies the sequence of Mappings. On entry,
640 * the initial sequence of Mappings to be simplified should be
641 * supplied.
642 *
643 * On exit, the contents of this array will be modified to
644 * reflect any simplification carried out. Any form of
645 * simplification may be performed. This may involve any of: (a)
646 * removing Mappings by annulling any of the pointers supplied,
647 * (b) replacing them with pointers to new Mappings, (c)
648 * inserting additional Mappings and (d) changing their order.
649 *
650 * The intention is to reduce the number of Mappings in the
651 * sequence, if possible, and any reduction will be reflected in
652 * the value of "*nmap" returned. However, simplifications which
653 * do not reduce the length of the sequence (but improve its
654 * execution time, for example) may also be performed, and the
655 * sequence might conceivably increase in length (but normally
656 * only in order to split up a Mapping into pieces that can be
657 * more easily merged with their neighbours on subsequent
658 * invocations of this function).
659 *
660 * If Mappings are removed from the sequence, any gaps that
661 * remain will be closed up, by moving subsequent Mapping
662 * pointers along in the array, so that vacated elements occur
663 * at the end. If the sequence increases in length, the array
664 * will be extended (and its pointer updated) if necessary to
665 * accommodate any new elements.
666 *
667 * Note that any (or all) of the Mapping pointers supplied in
668 * this array may be annulled by this function, but the Mappings
669 * to which they refer are not modified in any way (although
670 * they may, of course, be deleted if the annulled pointer is
671 * the final one).
672 * invert_list
673 * Address of a pointer to a dynamically allocated array which,
674 * on entry, should contain values to be assigned to the Invert
675 * attributes of the Mappings identified in the "*map_list"
676 * array before they are applied (this array might have been
677 * produced, for example, by the astMapList method). These
678 * values will be used by this function instead of the actual
679 * Invert attributes of the Mappings supplied, which are
680 * ignored.
681 *
682 * On exit, the contents of this array will be updated to
683 * correspond with the possibly modified contents of the
684 * "*map_list" array. If the Mapping sequence increases in
685 * length, the "*invert_list" array will be extended (and its
686 * pointer updated) if necessary to accommodate any new
687 * elements.
688 * status
689 * Pointer to the inherited status variable.
690 * status
691 * Pointer to the inherited status variable.
692
693 * Returned Value:
694 * If simplification was possible, the function returns the index
695 * in the "map_list" array of the first element which was
696 * modified. Otherwise, it returns -1 (and makes no changes to the
697 * arrays supplied).
698
699 * Notes:
700 * - A value of -1 will be returned if this function is invoked
701 * with the global error status set, or if it should fail for any
702 * reason.
703 */
704
705 /* Local Variables: */
706 AstMapping *new; /* Pointer to replacement Mapping */
707 AstMatrixMap *mm; /* Pointer to MatrixMap */
708 AstWinMap *wm; /* The new WinMap */
709 const char *class; /* Pointer to Mapping class string */
710 double absval; /* Absolute value fo each diagonal element */
711 double diag[ 3 ]; /* The diagonal matrix elements */
712 double polarlong; /* Value of PolarLong attribute */
713 int imap1; /* Index of first SphMap */
714 int imap2; /* Index of second SphMap */
715 int imap; /* Loop counter for Mappings */
716 int result; /* Result value to return */
717 int simpler; /* Mappings simplified? */
718
719 /* Initialise the returned result. */
720 result = -1;
721
722 /* Check the global error status. */
723 if ( !astOK ) return result;
724
725 /* Further initialisation. */
726 new = NULL;
727 simpler = 0;
728
729 /* We will only handle the case of SphMaps in series and will consider
730 merging the nominated SphMap with the Mapping which follows
731 it. Check that there is such a Mapping. */
732 if ( series && ( ( where + 1 ) < *nmap ) ) {
733
734 /* Obtain the indices of the two potential SphMaps to be merged. */
735 imap1 = where;
736 imap2 = where + 1;
737
738 /* Obtain the Class string of the second Mapping and determine if it
739 is a SphMap. */
740 class = astGetClass( ( *map_list )[ imap2 ] );
741 if ( astOK && !strcmp( class, "SphMap" ) ) {
742
743 /* Check if the first SphMap is applied in the inverse direction and
744 the second in the forward direction. This combination can be
745 simplified if the PolarLongitude attributes are equal.. */
746 if( ( *invert_list )[ imap1 ] && !( *invert_list )[ imap2 ] ) {
747 simpler = astEQUAL( astGetPolarLong( ( *map_list )[ imap1 ] ),
748 astGetPolarLong( ( *map_list )[ imap2 ] ) );
749
750 /* If the first SphMap is applied in the forward direction and the second in
751 the inverse direction, the combination can only be simplified if the
752 input vectors to the first SphMap all have unit length (as indicated by
753 the UnitRadius attribute). */
754 } else if( !( *invert_list )[ imap1 ] && ( *invert_list )[ imap2 ] ) {
755 simpler = astGetUnitRadius( ( *map_list )[ imap1 ] );
756 }
757 }
758
759 /* If the two SphMaps can be simplified, create a UnitMap to replace
760 them. */
761 if ( simpler ) {
762 new = (AstMapping *) astUnitMap( 2, "", status );
763
764 /* Annul the pointers to the SphMaps. */
765 if ( astOK ) {
766 ( *map_list )[ imap1 ] = astAnnul( ( *map_list )[ imap1 ] );
767 ( *map_list )[ imap2 ] = astAnnul( ( *map_list )[ imap2 ] );
768
769 /* Insert the pointer to the replacement Mapping and initialise its
770 invert flag. */
771 ( *map_list )[ imap1 ] = new;
772 ( *invert_list )[ imap1 ] = 0;
773
774 /* Loop to close the resulting gap by moving subsequent elements down
775 in the arrays. */
776 for ( imap = imap2 + 1; imap < *nmap; imap++ ) {
777 ( *map_list )[ imap - 1 ] = ( *map_list )[ imap ];
778 ( *invert_list )[ imap - 1 ] = ( *invert_list )[ imap ];
779 }
780
781 /* Clear the vacated elements at the end. */
782 ( *map_list )[ *nmap - 1 ] = NULL;
783 ( *invert_list )[ *nmap - 1 ] = 0;
784
785 /* Decrement the Mapping count and return the index of the first
786 modified element. */
787 ( *nmap )--;
788 result = imap1;
789 }
790 }
791 }
792
793 /* Another possible simplification is if the nominated Mapping is an inverted
794 SphMap followed in series by a ZoomMap or diagonal MatrixMap that has
795 diagonal elements of equal magnitude, which is then followed by a
796 non-inverted SphMap. This is equivalent to a 3D rotation of a pair of
797 (longitude,latitude) angles. The MatrixMap/ZoomMap may magnify the
798 radius vector, but this will not alter the angles. Any difference in
799 signs amongst the diagonal elements will cause a reflection or reversal
800 of the corresponbding angles, which can be represented by a WinMap. We
801 do not need to consider the other possibility (that the nominated
802 SphMap is the *last* Mapping in such a sequence of three), since we
803 will already have discovered such a sequence on an earlier invocation
804 of this function. */
805 if( series && !simpler && ( *invert_list )[ where ] &&
806 where + 2 < *nmap ) {
807
808 /* Check the third Mapping is a non-inverted SphMap. */
809 class = astGetClass( ( *map_list )[ where + 2 ] );
810 if( astOK && !strcmp( class, "SphMap" ) &&
811 !( *invert_list )[ where + 2 ] ) {
812
813 /* Check the second Mapping is a ZoomMap, or a diagonal MatrixMap that
814 has diagonal elements of equal magnitude. Since the Mapping is
815 sandwiched between the two SphMaps, we know it must have 3 inputs and
816 3 outputs. Record the corresponding diagonal values. The state of the
817 Invert flag does not matter since it will only affect the degree to
818 which the radius vector is magnified - it will not change the signs of
819 any diagonal elements. */
820 class = astGetClass( ( *map_list )[ where + 1 ] );
821 if( astOK && !strcmp( class, "ZoomMap" ) ) {
822 diag[ 0 ] = astGetZoom( ( *map_list )[ where + 1 ] );
823 if( diag[ 0 ] != 0.0 ) {
824 diag[ 1 ] = diag[ 0 ];
825 diag[ 2 ] = diag[ 0 ];
826 } else {
827 class = NULL;
828 }
829
830 } else if( astOK && !strcmp( class, "MatrixMap" ) ) {
831 mm = (AstMatrixMap *) ( *map_list )[ where + 1 ];
832 if( mm->form == 1 && mm->f_matrix ) {
833 diag[ 0 ] = mm->f_matrix[ 0 ];
834 if( diag[ 0 ] != 0.0 ) {
835 diag[ 1 ] = mm->f_matrix[ 1 ];
836 diag[ 2 ] = mm->f_matrix[ 2 ];
837
838 absval = fabs( diag[ 0 ] );
839 if( !astEQUAL( fabs( diag[ 1 ] ), absval ) ||
840 !astEQUAL( fabs( diag[ 2 ] ), absval ) ) {
841 class = NULL;
842 }
843
844 } else {
845 class = NULL;
846 }
847
848 } else {
849 class = NULL;
850 }
851
852 } else {
853 class = NULL;
854 }
855
856 } else {
857 class = NULL;
858 }
859
860 /* We can only make changes if above conditions were met. */
861 if( class ) {
862
863 /* Create a WinMap that modifies the (longitude,latitude) values, initially
864 with undefined corners. */
865 wm = astWinMap( 2, NULL, NULL, NULL, NULL, "", status );
866
867 /* Store appropriate scales and offsets in the WinMap. These just depend on
868 the signs of the matrix diagonal elements since we know the magnitudes of
869 these elements are all equal. */
870 if( diag[ 0 ] < 0.0 ) {
871 if( diag[ 1 ] < 0.0 ) {
872 wm->a[ 0 ] = AST__DPI;
873 wm->b[ 0 ] = 1.0;
874 } else {
875 wm->a[ 0 ] = AST__DPI;
876 wm->b[ 0 ] = -1.0;
877 }
878
879 } else {
880 if( diag[ 1 ] < 0.0 ) {
881 wm->a[ 0 ] = 0.0;
882 wm->b[ 0 ] = -1.0;
883 } else {
884 wm->a[ 0 ] = 0.0;
885 wm->b[ 0 ] = 1.0;
886 }
887 }
888
889 if( diag[ 2 ] < 0.0 ) {
890 wm->a[ 1 ] = 0.0;
891 wm->b[ 1 ] = -1.0;
892 } else {
893 wm->a[ 1 ] = 0.0;
894 wm->b[ 1 ] = 1.0;
895 }
896
897 /* We are aiming to replace the supplied (SphMap,MatrixMap,SphMap)
898 combination with (WinMap,SphMap,SphMap), leaving us with an inverted
899 and non-inverted SphMap side by side. This is on the understanding
900 that a subsequent call to this function will combine these two
901 adjacent SphMaps into a UnitMap. But this will only happen if the
902 adjacent SphMaps have equal values for their PolarLong attributes. The
903 change of (SphMap,MatrixMap) to (WinMap,SphMap) will change the value
904 of the PolarLong attribute in the first SphMap, so we need to work out
905 this changed value and check that it is the same as the PolarLong
906 value of the second SphMap. If they are different, there is no point
907 making any changes since the two SphMaps cannot be merged into a
908 UnitMap. So get the PolarLong value from the supplied first SphMap. */
909 polarlong = astGetPolarLong( ( *map_list )[ where ] );
910
911 /* Modified the PolarLong value to take account of the change from
912 (SphMap,MatrixMap) to (WinMap,SphMap). */
913 polarlong = wm->a[ 0 ] + wm->b[ 0 ]*polarlong;
914
915 /* Check this is the same as the PolarLong value in the second SphMap. */
916 if( astEQUAL( polarlong, astGetPolarLong( ( *map_list )[ where + 2 ] ) ) ) {
917
918 /* All is good, so we can now change the supplied Mappings list. First
919 change the PolarLong value in the first SphMap. */
920 astSetPolarLong( ( *map_list )[ where ], polarlong );
921
922 /* Annul The MatrixMap or ZoomMap. */
923 (void) astAnnul( ( *map_list )[ where + 1 ] );
924
925 /* Move the first SphMap to the slot left vacant by the annulled
926 MatrixMap or ZoomMap. */
927 ( *map_list )[ where + 1 ] = ( *map_list )[ where ];
928 ( *invert_list )[ where + 1 ] = ( *invert_list )[ where ];
929
930 /* Store the new WinMap in the place of the SphMap. */
931 ( *map_list )[ where ] = astClone( wm );
932 ( *invert_list )[ where ] = 0;
933
934 /* Return the index of the first modified element. */
935 result = where;
936 }
937
938 /* Free resources. */
939 wm = astAnnul( wm );
940 }
941 }
942
943 /* If an error occurred, clear the returned result. */
944 if ( !astOK ) result = -1;
945
946 /* Return the result. */
947 return result;
948 }
949
SetAttrib(AstObject * this_object,const char * setting,int * status)950 static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
951 /*
952 * Name:
953 * SetAttrib
954
955 * Purpose:
956 * Set an attribute value for a SphMap.
957
958 * Type:
959 * Private function.
960
961 * Synopsis:
962 * #include "sphmap.h"
963 * void SetAttrib( AstObject *this, const char *setting )
964
965 * Class Membership:
966 * SphMap member function (over-rides the astSetAttrib protected
967 * method inherited from the Mapping class).
968
969 * Description:
970 * This function assigns an attribute value for a SphMap, the
971 * attribute and its value being specified by means of a string of
972 * the form:
973 *
974 * "attribute= value "
975 *
976 * Here, "attribute" specifies the attribute name and should be in
977 * lower case with no white space present. The value to the right
978 * of the "=" should be a suitable textual representation of the
979 * value to be assigned and this will be interpreted according to
980 * the attribute's data type. White space surrounding the value is
981 * only significant for string attributes.
982
983 * Parameters:
984 * this
985 * Pointer to the SphMap.
986 * setting
987 * Pointer to a null-terminated string specifying the new attribute
988 * value.
989 */
990
991 /* Local Variables: */
992 AstSphMap *this; /* Pointer to the SphMap structure */
993 double dval; /* Double precision attribute value */
994 int len; /* Length of setting string */
995 int ival; /* Int attribute value */
996 int nc; /* Number of characters read by astSscanf */
997
998 /* Check the global error status. */
999 if ( !astOK ) return;
1000
1001 /* Obtain a pointer to the SphMap structure. */
1002 this = (AstSphMap *) this_object;
1003
1004 /* Obtain the length of the setting string. */
1005 len = (int) strlen( setting );
1006
1007 /* UnitRadius */
1008 /* ---------- */
1009 if ( nc = 0,
1010 ( 1 == astSscanf( setting, "unitradius= %d %n", &ival, &nc ) )
1011 && ( nc >= len ) ) {
1012 astSetUnitRadius( this, ival );
1013
1014 /* PolarLong */
1015 /* --------- */
1016 } else if ( nc = 0,
1017 ( 1 == astSscanf( setting, "polarlong= %lf %n", &dval, &nc ) )
1018 && ( nc >= len ) ) {
1019 astSetPolarLong( this, dval );
1020
1021 /* If the attribute is still not recognised, pass it on to the parent
1022 method for further interpretation. */
1023 } else {
1024 (*parent_setattrib)( this_object, setting, status );
1025 }
1026 }
1027
TestAttrib(AstObject * this_object,const char * attrib,int * status)1028 static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
1029 /*
1030 * Name:
1031 * TestAttrib
1032
1033 * Purpose:
1034 * Test if a specified attribute value is set for a SphMap.
1035
1036 * Type:
1037 * Private function.
1038
1039 * Synopsis:
1040 * #include "sphmap.h"
1041 * int TestAttrib( AstObject *this, const char *attrib, int *status, int *status )
1042
1043 * Class Membership:
1044 * SphMap member function (over-rides the astTestAttrib protected
1045 * method inherited from the Mapping class).
1046
1047 * Description:
1048 * This function returns a boolean result (0 or 1) to indicate whether
1049 * a value has been set for one of a SphMap's attributes.
1050
1051 * Parameters:
1052 * this
1053 * Pointer to the SphMap.
1054 * attrib
1055 * Pointer to a null-terminated string specifying the attribute
1056 * name. This should be in lower case with no surrounding white
1057 * space.
1058 * status
1059 * Pointer to the inherited status variable.
1060 * status
1061 * Pointer to the inherited status variable.
1062
1063 * Returned Value:
1064 * One if a value has been set, otherwise zero.
1065
1066 * Notes:
1067 * - A value of zero will be returned if this function is invoked
1068 * with the global status set, or if it should fail for any reason.
1069 */
1070
1071 /* Local Variables: */
1072 AstSphMap *this; /* Pointer to the SphMap structure */
1073 int result; /* Result value to return */
1074
1075 /* Initialise. */
1076 result = 0;
1077
1078 /* Check the global error status. */
1079 if ( !astOK ) return result;
1080
1081 /* Obtain a pointer to the SphMap structure. */
1082 this = (AstSphMap *) this_object;
1083
1084 /* UnitRadius */
1085 /* ---------- */
1086 if ( !strcmp( attrib, "unitradius" ) ) {
1087 result = astTestUnitRadius( this );
1088
1089 /* PolarLong */
1090 /* --------- */
1091 } else if ( !strcmp( attrib, "polarlong" ) ) {
1092 result = astTestPolarLong( this );
1093
1094 /* If the attribute is still not recognised, pass it on to the parent
1095 method for further interpretation. */
1096 } else {
1097 result = (*parent_testattrib)( this_object, attrib, status );
1098 }
1099
1100 /* Return the result, */
1101 return result;
1102 }
1103
Transform(AstMapping * this,AstPointSet * in,int forward,AstPointSet * out,int * status)1104 static AstPointSet *Transform( AstMapping *this, AstPointSet *in,
1105 int forward, AstPointSet *out, int *status ) {
1106 /*
1107 * Name:
1108 * Transform
1109
1110 * Purpose:
1111 * Apply a SphMap to transform a set of points.
1112
1113 * Type:
1114 * Private function.
1115
1116 * Synopsis:
1117 * #include "sphmap.h"
1118 * AstPointSet *Transform( AstMapping *this, AstPointSet *in,
1119 * int forward, AstPointSet *out, int *status, int *status )
1120
1121 * Class Membership:
1122 * SphMap member function (over-rides the astTransform protected
1123 * method inherited from the Mapping class).
1124
1125 * Description:
1126 * This function takes a SphMap and a set of points encapsulated in a
1127 * PointSet and transforms the points from Cartesian coordinates to
1128 * spherical coordinates.
1129
1130 * Parameters:
1131 * this
1132 * Pointer to the SphMap.
1133 * in
1134 * Pointer to the PointSet holding the input coordinate data.
1135 * forward
1136 * A non-zero value indicates that the forward coordinate transformation
1137 * should be applied, while a zero value requests the inverse
1138 * transformation.
1139 * out
1140 * Pointer to a PointSet which will hold the transformed (output)
1141 * coordinate values. A NULL value may also be given, in which case a
1142 * new PointSet will be created by this function.
1143 * status
1144 * Pointer to the inherited status variable.
1145 * status
1146 * Pointer to the inherited status variable.
1147
1148 * Returned Value:
1149 * Pointer to the output (possibly new) PointSet.
1150
1151 * Notes:
1152 * - A null pointer will be returned if this function is invoked with the
1153 * global error status set, or if it should fail for any reason.
1154 * - The number of coordinate values per point in the input PointSet must
1155 * match the number of coordinates for the SphMap being applied.
1156 * - If an output PointSet is supplied, it must have space for sufficient
1157 * number of points and coordinate values per point to accommodate the
1158 * result. Any excess space will be ignored.
1159 */
1160
1161 /* Local Variables: */
1162 AstPointSet *result; /* Pointer to output PointSet */
1163 AstSphMap *map; /* Pointer to SphMap to be applied */
1164 double **ptr_in; /* Pointer to input coordinate data */
1165 double **ptr_out; /* Pointer to output coordinate data */
1166 int npoint; /* Number of points */
1167 int point; /* Loop counter for points */
1168 double *p0; /* Pointer to x axis value */
1169 double *p1; /* Pointer to y axis value */
1170 double *p2; /* Pointer to z axis value */
1171 double *q0; /* Pointer to longitude value */
1172 double *q1; /* Pointer to latitude value */
1173 double mxerr; /* Largest value which is effectively zero */
1174 double polarlong; /* Longitude at either pole */
1175 double v[3]; /* Vector for a single point */
1176
1177 /* Check the global error status. */
1178 if ( !astOK ) return NULL;
1179
1180 /* Obtain a pointer to the SphMap. */
1181 map = (AstSphMap *) this;
1182
1183 /* Apply the parent mapping using the stored pointer to the Transform member
1184 function inherited from the parent Mapping class. This function validates
1185 all arguments and generates an output PointSet if necessary, but does not
1186 actually transform any coordinate values. */
1187 result = (*parent_transform)( this, in, forward, out, status );
1188
1189 /* We will now extend the parent astTransform method by performing the
1190 calculations needed to generate the output coordinate values. */
1191
1192 /* Determine the numbers of points and coordinates per point from the input
1193 PointSet and obtain pointers for accessing the input and output coordinate
1194 values. */
1195 npoint = astGetNpoint( in );
1196 ptr_in = astGetPoints( in );
1197 ptr_out = astGetPoints( result );
1198
1199 /* Determine whether to apply the forward or inverse mapping, according to the
1200 direction specified and whether the mapping has been inverted. */
1201 if ( astGetInvert( map ) ) forward = !forward;
1202
1203 /* Perform coordinate arithmetic. */
1204 /* ------------------------------ */
1205 if( astOK ){
1206
1207 /* First deal with forward mappings from Cartesian to Spherical. */
1208 if( forward ){
1209
1210 /* Get the longitude to return at either pole. */
1211 polarlong = astGetPolarLong( this );
1212
1213 /* Store pointers to the input Cartesian axes. */
1214 p0 = ptr_in[ 0 ];
1215 p1 = ptr_in[ 1 ];
1216 p2 = ptr_in[ 2 ];
1217
1218 /* Store pointers to the output Spherical axes. */
1219 q0 = ptr_out[ 0 ];
1220 q1 = ptr_out[ 1 ];
1221
1222 /* Apply the mapping to every point. */
1223 for( point = 0; point < npoint; point++ ){
1224 if( *p0 != AST__BAD && *p1 != AST__BAD && *p2 != AST__BAD ){
1225 v[0] = *p0;
1226 v[1] = *p1;
1227 v[2] = *p2;
1228
1229 /* At either pole, return the longitude equal to PolarLong attribute. */
1230 mxerr = fabs( 1000.0*v[ 2 ] )*DBL_EPSILON;
1231 if( fabs( v[ 0 ] ) < mxerr && fabs( v[ 1 ] ) < mxerr ) {
1232 if( v[ 2 ] < 0.0 ) {
1233 *(q0++) = polarlong;
1234 *(q1++) = -AST__DPIBY2;
1235 } else if( v[ 2 ] > 0.0 ) {
1236 *(q0++) = polarlong;
1237 *(q1++) = AST__DPIBY2;
1238 } else {
1239 *(q0++) = AST__BAD;
1240 *(q1++) = AST__BAD;
1241 }
1242
1243 /* Otherwise use a SLALIB function to do the conversion (SLALIB always
1244 returns zero at either pole which is why we make the above check). */
1245 } else {
1246 palDcc2s( v, q0++, q1++ );
1247 }
1248
1249 } else {
1250 *(q0++) = AST__BAD;
1251 *(q1++) = AST__BAD;
1252 }
1253 p0++;
1254 p1++;
1255 p2++;
1256 }
1257
1258 /* Now deal with inverse mappings from Spherical to Cartesian. */
1259 } else {
1260
1261 /* Store pointers to the input Spherical axes. */
1262 q0 = ptr_in[ 0 ];
1263 q1 = ptr_in[ 1 ];
1264
1265 /* Store pointers to the output Cartesian axes. */
1266 p0 = ptr_out[ 0 ];
1267 p1 = ptr_out[ 1 ];
1268 p2 = ptr_out[ 2 ];
1269
1270 /* Apply the mapping to every point. */
1271 for( point = 0; point < npoint; point++ ){
1272 if( *q0 != AST__BAD && *q1 != AST__BAD ){
1273 palDcs2c( *q0, *q1, v );
1274 *(p0++) = v[ 0 ];
1275 *(p1++) = v[ 1 ];
1276 *(p2++) = v[ 2 ];
1277 } else {
1278 *(p0++) = AST__BAD;
1279 *(p1++) = AST__BAD;
1280 *(p2++) = AST__BAD;
1281
1282 }
1283 q0++;
1284 q1++;
1285 }
1286
1287 }
1288
1289 }
1290
1291 /* Return a pointer to the output PointSet. */
1292 return result;
1293 }
1294
1295 /* Functions which access class attributes. */
1296 /* ---------------------------------------- */
1297 /* Implement member functions to access the attributes associated with
1298 this class using the macros defined for this purpose in the
1299 "object.h" file. For a description of each attribute, see the class
1300 interface (in the associated .h file). */
1301
1302 /* UnitRadius */
1303 /* ---------- */
1304 /*
1305 *att++
1306 * Name:
1307 * UnitRadius
1308
1309 * Purpose:
1310 * SphMap input vectors lie on a unit sphere?
1311
1312 * Type:
1313 * Public attribute.
1314
1315 * Synopsis:
1316 * Integer (boolean).
1317
1318 * Description:
1319 * This is a boolean attribute which indicates whether the
1320 * 3-dimensional vectors which are supplied as input to a SphMap
1321 * are known to always have unit length, so that they lie on a unit
1322 * sphere centred on the origin.
1323 *
1324 c If this condition is true (indicated by setting UnitRadius
1325 c non-zero), it implies that a CmpMap which is composed of a
1326 c SphMap applied in the forward direction followed by a similar
1327 c SphMap applied in the inverse direction may be simplified
1328 c (e.g. by astSimplify) to become a UnitMap. This is because the
1329 c input and output vectors will both have unit length and will
1330 c therefore have the same coordinate values.
1331 f If this condition is true (indicated by setting UnitRadius
1332 f non-zero), it implies that a CmpMap which is composed of a
1333 f SphMap applied in the forward direction followed by a similar
1334 f SphMap applied in the inverse direction may be simplified
1335 f (e.g. by AST_SIMPLIFY) to become a UnitMap. This is because the
1336 f input and output vectors will both have unit length and will
1337 f therefore have the same coordinate values.
1338 *
1339 * If UnitRadius is zero (the default), then although the output
1340 * vector produced by the CmpMap (above) will still have unit
1341 * length, the input vector may not have. This will, in general,
1342 * change the coordinate values, so it prevents the pair of SphMaps
1343 * being simplified.
1344
1345 * Notes:
1346 * - This attribute is intended mainly for use when SphMaps are
1347 * involved in a sequence of Mappings which project (e.g.) a
1348 * dataset on to the celestial sphere. By regarding the celestial
1349 * sphere as a unit sphere (and setting UnitRadius to be non-zero)
1350 * it becomes possible to cancel the SphMaps present, along with
1351 * associated sky projections, when two datasets are aligned using
1352 * celestial coordinates. This often considerably improves
1353 * performance.
1354 * - Such a situations often arises when interpreting FITS data and
1355 * is handled automatically by the FitsChan class.
1356 * - The value of the UnitRadius attribute is used only to control
1357 * the simplification of Mappings and has no effect on the value of
1358 * the coordinates transformed by a SphMap. The lengths of the
1359 * input 3-dimensional Cartesian vectors supplied are always
1360 * ignored, even if UnitRadius is non-zero.
1361
1362 * Applicability:
1363 * SphMap
1364 * All SphMaps have this attribute.
1365 *att--
1366 */
1367 astMAKE_CLEAR(SphMap,UnitRadius,unitradius,-1)
1368 astMAKE_GET(SphMap,UnitRadius,int,0,(this->unitradius == -1 ? 0 : this->unitradius))
1369 astMAKE_SET(SphMap,UnitRadius,int,unitradius,( value ? 1 : 0 ))
1370 astMAKE_TEST(SphMap,UnitRadius,( this->unitradius != -1 ))
1371
1372 /* PolarLong */
1373 /* --------- */
1374 /*
1375 *att++
1376 * Name:
1377 * PolarLong
1378
1379 * Purpose:
1380 * The longitude value to assign to either pole
1381
1382 * Type:
1383 * Public attribute.
1384
1385 * Synopsis:
1386 * Double precision.
1387
1388 * Description:
1389 * This attribute holds the longitude value, in radians, to be
1390 * returned when a Cartesian position corresponding to either the north
1391 * or south pole is transformed into spherical coordinates. The
1392 * default value is zero.
1393
1394 * Applicability:
1395 * SphMap
1396 * All SphMaps have this attribute.
1397 *att--
1398 */
astMAKE_CLEAR(SphMap,PolarLong,polarlong,AST__BAD)1399 astMAKE_CLEAR(SphMap,PolarLong,polarlong,AST__BAD)
1400 astMAKE_GET(SphMap,PolarLong,double,0.0,(this->polarlong == AST__BAD ? 0.0 : this->polarlong))
1401 astMAKE_SET(SphMap,PolarLong,double,polarlong,value)
1402 astMAKE_TEST(SphMap,PolarLong,( this->polarlong != AST__BAD ))
1403
1404 /* Copy constructor. */
1405 /* ----------------- */
1406 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
1407 /*
1408 * Name:
1409 * Copy
1410
1411 * Purpose:
1412 * Copy constructor for SphMap objects.
1413
1414 * Type:
1415 * Private function.
1416
1417 * Synopsis:
1418 * void Copy( const AstObject *objin, AstObject *objout, int *status, int *status, int *status )
1419
1420 * Description:
1421 * This function implements the copy constructor for SphMap objects.
1422
1423 * Parameters:
1424 * objin
1425 * Pointer to the SphMap to be copied.
1426 * objout
1427 * Pointer to the SphMap being constructed.
1428 * status
1429 * Pointer to the inherited status variable.
1430 * status
1431 * Pointer to the inherited status variable.
1432 * status
1433 * Pointer to the inherited status variable.
1434
1435 */
1436
1437 }
1438
1439 /* Destructor. */
1440 /* ----------- */
Delete(AstObject * obj,int * status)1441 static void Delete( AstObject *obj, int *status ) {
1442 /*
1443 * Name:
1444 * Delete
1445
1446 * Purpose:
1447 * Destructor for SphMap objects.
1448
1449 * Type:
1450 * Private function.
1451
1452 * Synopsis:
1453 * void Delete( AstObject *obj, int *status, int *status )
1454
1455 * Description:
1456 * This function implements the destructor for SphMap objects.
1457
1458 * Parameters:
1459 * obj
1460 * Pointer to the SphMap to be deleted.
1461 * status
1462 * Pointer to the inherited status variable.
1463 * status
1464 * Pointer to the inherited status variable.
1465
1466 * Notes:
1467 * - This destructor does nothing and exists only to maintain a
1468 * one-to-one correspondence between destructors and copy
1469 * constructors.
1470 */
1471
1472
1473 }
1474
1475 /* Dump function. */
1476 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)1477 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
1478 /*
1479 * Name:
1480 * Dump
1481
1482 * Purpose:
1483 * Dump function for SphMap objects.
1484
1485 * Type:
1486 * Private function.
1487
1488 * Synopsis:
1489 * void Dump( AstObject *this, AstChannel *channel, int *status, int *status, int *status, int *status )
1490
1491 * Description:
1492 * This function implements the Dump function which writes out data
1493 * for the SphMap class to an output Channel.
1494
1495 * Parameters:
1496 * this
1497 * Pointer to the SphMap whose data are being written.
1498 * channel
1499 * Pointer to the Channel to which the data are being written.
1500 * status
1501 * Pointer to the inherited status variable.
1502 * status
1503 * Pointer to the inherited status variable.
1504 * status
1505 * Pointer to the inherited status variable.
1506 * status
1507 * Pointer to the inherited status variable.
1508 */
1509
1510 /* Local Variables: */
1511 AstSphMap *this; /* Pointer to the SphMap structure */
1512 double dval; /* Double precision attribute value */
1513 int ival; /* Integer value */
1514 int set; /* Attribute value set? */
1515
1516 /* Check the global error status. */
1517 if ( !astOK ) return;
1518
1519 /* Obtain a pointer to the SphMap structure. */
1520 this = (AstSphMap *) this_object;
1521
1522 /* Write out values representing the instance variables for the
1523 SphMap class. Accompany these with appropriate comment strings,
1524 possibly depending on the values being written.*/
1525
1526 /* In the case of attributes, we first use the appropriate (private)
1527 Test... member function to see if they are set. If so, we then use
1528 the (private) Get... function to obtain the value to be written
1529 out.
1530
1531 For attributes which are not set, we use the astGet... method to
1532 obtain the value instead. This will supply a default value
1533 (possibly provided by a derived class which over-rides this method)
1534 which is more useful to a human reader as it corresponds to the
1535 actual default attribute value. Since "set" will be zero, these
1536 values are for information only and will not be read back. */
1537
1538 /* UnitRadius. */
1539 /* ------- */
1540 set = TestUnitRadius( this, status );
1541 ival = set ? GetUnitRadius( this, status ) : astGetUnitRadius( this );
1542 if( ival ) {
1543 astWriteInt( channel, "UntRd", set, 0, ival, "All input vectors have unit length" );
1544 } else {
1545 astWriteInt( channel, "UntRd", set, 0, ival, "Input vectors do not all have unit length" );
1546 }
1547
1548 /* PolarLong. */
1549 /* ---------- */
1550 set = TestPolarLong( this, status );
1551 dval = set ? GetPolarLong( this, status ) : astGetPolarLong( this );
1552 astWriteDouble( channel, "PlrLg", set, 1, dval, "Polar longitude (rad.s)" );
1553
1554 }
1555
1556 /* Standard class functions. */
1557 /* ========================= */
1558 /* Implement the astIsASphMap and astCheckSphMap functions using the macros
1559 defined for this purpose in the "object.h" header file. */
astMAKE_ISA(SphMap,Mapping)1560 astMAKE_ISA(SphMap,Mapping)
1561 astMAKE_CHECK(SphMap)
1562
1563 AstSphMap *astSphMap_( const char *options, int *status, ...) {
1564 /*
1565 *++
1566 * Name:
1567 c astSphMap
1568 f AST_SPHMAP
1569
1570 * Purpose:
1571 * Create a SphMap.
1572
1573 * Type:
1574 * Public function.
1575
1576 * Synopsis:
1577 c #include "sphmap.h"
1578 c AstSphMap *astSphMap( const char *options, ... )
1579 f RESULT = AST_SPHMAP( OPTIONS, STATUS )
1580
1581 * Class Membership:
1582 * SphMap constructor.
1583
1584 * Description:
1585 * This function creates a new SphMap and optionally initialises
1586 * its attributes.
1587 *
1588 * A SphMap is a Mapping which transforms points from a
1589 * 3-dimensional Cartesian coordinate system into a 2-dimensional
1590 * spherical coordinate system (longitude and latitude on a unit
1591 * sphere centred at the origin). It works by regarding the input
1592 * coordinates as position vectors and finding their intersection
1593 * with the sphere surface. The inverse transformation always
1594 * produces points which are a unit distance from the origin
1595 * (i.e. unit vectors).
1596
1597 * Parameters:
1598 c options
1599 f OPTIONS = CHARACTER * ( * ) (Given)
1600 c Pointer to a null-terminated string containing an optional
1601 c comma-separated list of attribute assignments to be used for
1602 c initialising the new SphMap. The syntax used is identical to
1603 c that for the astSet function and may include "printf" format
1604 c specifiers identified by "%" symbols in the normal way.
1605 f A character string containing an optional comma-separated
1606 f list of attribute assignments to be used for initialising the
1607 f new SphMap. The syntax used is identical to that for the
1608 f AST_SET routine.
1609 c ...
1610 c If the "options" string contains "%" format specifiers, then
1611 c an optional list of additional arguments may follow it in
1612 c order to supply values to be substituted for these
1613 c specifiers. The rules for supplying these are identical to
1614 c those for the astSet function (and for the C "printf"
1615 c function).
1616 f STATUS = INTEGER (Given and Returned)
1617 f The global status.
1618
1619 * Returned Value:
1620 c astSphMap()
1621 f AST_SPHMAP = INTEGER
1622 * A pointer to the new SphMap.
1623
1624 * Notes:
1625 * - The spherical coordinates are longitude (positive
1626 * anti-clockwise looking from the positive latitude pole) and
1627 * latitude. The Cartesian coordinates are right-handed, with the x
1628 * axis (axis 1) at zero longitude and latitude, and the z axis
1629 * (axis 3) at the positive latitude pole.
1630 * - At either pole, the longitude is set to the value of the
1631 * PolarLong attribute.
1632 * - If the Cartesian coordinates are all zero, then the longitude
1633 * and latitude are set to the value AST__BAD.
1634 * - A null Object pointer (AST__NULL) will be returned if this
1635 c function is invoked with the AST error status set, or if it
1636 f function is invoked with STATUS set to an error value, or if it
1637 * should fail for any reason.
1638
1639 * Status Handling:
1640 * The protected interface to this function includes an extra
1641 * parameter at the end of the parameter list descirbed above. This
1642 * parameter is a pointer to the integer inherited status
1643 * variable: "int *status".
1644
1645
1646 * Status Handling:
1647 * The protected interface to this function includes an extra
1648 * parameter at the end of the parameter list descirbed above. This
1649 * parameter is a pointer to the integer inherited status
1650 * variable: "int *status".
1651
1652
1653 * Status Handling:
1654 * The protected interface to this function includes an extra
1655 * parameter at the end of the parameter list descirbed above. This
1656 * parameter is a pointer to the integer inherited status
1657 * variable: "int *status".
1658
1659 *--
1660 */
1661
1662 /* Local Variables: */
1663 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
1664 AstSphMap *new; /* Pointer to new SphMap */
1665 va_list args; /* Variable argument list */
1666
1667 /* Get a pointer to the thread specific global data structure. */
1668 astGET_GLOBALS(NULL);
1669
1670 /* Check the global status. */
1671 if ( !astOK ) return NULL;
1672
1673 /* Initialise the SphMap, allocating memory and initialising the
1674 virtual function table as well if necessary. */
1675 new = astInitSphMap( NULL, sizeof( AstSphMap ), !class_init, &class_vtab,
1676 "SphMap" );
1677
1678 /* If successful, note that the virtual function table has been
1679 initialised. */
1680 if ( astOK ) {
1681 class_init = 1;
1682
1683 /* Obtain the variable argument list and pass it along with the options string
1684 to the astVSet method to initialise the new SphMap's attributes. */
1685 va_start( args, status );
1686 astVSet( new, options, NULL, args );
1687 va_end( args );
1688
1689 /* If an error occurred, clean up by deleting the new object. */
1690 if ( !astOK ) new = astDelete( new );
1691 }
1692
1693 /* Return a pointer to the new SphMap. */
1694 return new;
1695 }
1696
astSphMapId_(const char * options,...)1697 AstSphMap *astSphMapId_( const char *options, ...) {
1698 /*
1699 * Name:
1700 * astSphMapId_
1701
1702 * Purpose:
1703 * Create a SphMap.
1704
1705 * Type:
1706 * Private function.
1707
1708 * Synopsis:
1709 * #include "sphmap.h"
1710 * AstSphMap *astSphMapId_( const char *options, ... )
1711
1712 * Class Membership:
1713 * SphMap constructor.
1714
1715 * Description:
1716 * This function implements the external (public) interface to the
1717 * astSphMap constructor function. It returns an ID value (instead
1718 * of a true C pointer) to external users, and must be provided
1719 * because astSphMap_ has a variable argument list which cannot be
1720 * encapsulated in a macro (where this conversion would otherwise
1721 * occur).
1722 *
1723 * The variable argument list also prevents this function from
1724 * invoking astSphMap_ directly, so it must be a re-implementation
1725 * of it in all respects, except for the final conversion of the
1726 * result to an ID value.
1727
1728 * Parameters:
1729 * As for astSphMap_.
1730
1731 * Returned Value:
1732 * The ID value associated with the new SphMap.
1733 */
1734
1735 /* Local Variables: */
1736 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
1737 AstSphMap *new; /* Pointer to new SphMap */
1738 va_list args; /* Variable argument list */
1739 int *status; /* Pointer to inherited status value */
1740
1741 /* Get a pointer to the inherited status value. */
1742 status = astGetStatusPtr;
1743
1744 /* Get a pointer to the thread specific global data structure. */
1745 astGET_GLOBALS(NULL);
1746
1747 /* Check the global status. */
1748 if ( !astOK ) return NULL;
1749
1750 /* Initialise the SphMap, allocating memory and initialising the
1751 virtual function table as well if necessary. */
1752 new = astInitSphMap( NULL, sizeof( AstSphMap ), !class_init, &class_vtab,
1753 "SphMap" );
1754
1755 /* If successful, note that the virtual function table has been
1756 initialised. */
1757 if ( astOK ) {
1758 class_init = 1;
1759
1760 /* Obtain the variable argument list and pass it along with the options string
1761 to the astVSet method to initialise the new SphMap's attributes. */
1762 va_start( args, options );
1763 astVSet( new, options, NULL, args );
1764 va_end( args );
1765
1766 /* If an error occurred, clean up by deleting the new object. */
1767 if ( !astOK ) new = astDelete( new );
1768 }
1769
1770 /* Return an ID value for the new SphMap. */
1771 return astMakeId( new );
1772 }
1773
astInitSphMap_(void * mem,size_t size,int init,AstSphMapVtab * vtab,const char * name,int * status)1774 AstSphMap *astInitSphMap_( void *mem, size_t size, int init,
1775 AstSphMapVtab *vtab, const char *name, int *status ) {
1776 /*
1777 *+
1778 * Name:
1779 * astInitSphMap
1780
1781 * Purpose:
1782 * Initialise a SphMap.
1783
1784 * Type:
1785 * Protected function.
1786
1787 * Synopsis:
1788 * #include "sphmap.h"
1789 * AstSphMap *astInitSphMap( void *mem, size_t size, int init,
1790 * AstSphMapVtab *vtab, const char *name )
1791
1792 * Class Membership:
1793 * SphMap initialiser.
1794
1795 * Description:
1796 * This function is provided for use by class implementations to initialise
1797 * a new SphMap object. It allocates memory (if necessary) to accommodate
1798 * the SphMap plus any additional data associated with the derived class.
1799 * It then initialises a SphMap structure at the start of this memory. If
1800 * the "init" flag is set, it also initialises the contents of a virtual
1801 * function table for a SphMap at the start of the memory passed via the
1802 * "vtab" parameter.
1803
1804 * Parameters:
1805 * mem
1806 * A pointer to the memory in which the SphMap is to be initialised.
1807 * This must be of sufficient size to accommodate the SphMap data
1808 * (sizeof(SphMap)) plus any data used by the derived class. If a value
1809 * of NULL is given, this function will allocate the memory itself using
1810 * the "size" parameter to determine its size.
1811 * size
1812 * The amount of memory used by the SphMap (plus derived class data).
1813 * This will be used to allocate memory if a value of NULL is given for
1814 * the "mem" parameter. This value is also stored in the SphMap
1815 * structure, so a valid value must be supplied even if not required for
1816 * allocating memory.
1817 * init
1818 * A logical flag indicating if the SphMap's virtual function table is
1819 * to be initialised. If this value is non-zero, the virtual function
1820 * table will be initialised by this function.
1821 * vtab
1822 * Pointer to the start of the virtual function table to be associated
1823 * with the new SphMap.
1824 * name
1825 * Pointer to a constant null-terminated character string which contains
1826 * the name of the class to which the new object belongs (it is this
1827 * pointer value that will subsequently be returned by the astGetClass
1828 * method).
1829
1830 * Returned Value:
1831 * A pointer to the new SphMap.
1832
1833 * Notes:
1834 * - A null pointer will be returned if this function is invoked with the
1835 * global error status set, or if it should fail for any reason.
1836 *-
1837 */
1838
1839 /* Local Variables: */
1840 AstSphMap *new; /* Pointer to new SphMap */
1841
1842 /* Check the global status. */
1843 if ( !astOK ) return NULL;
1844
1845 /* If necessary, initialise the virtual function table. */
1846 if ( init ) astInitSphMapVtab( vtab, name );
1847
1848 /* Initialise. */
1849 new = NULL;
1850
1851 /* Initialise a Mapping structure (the parent class) as the first component
1852 within the SphMap structure, allocating memory if necessary. Specify that
1853 the Mapping should be defined in both the forward and inverse directions. */
1854 new = (AstSphMap *) astInitMapping( mem, size, 0,
1855 (AstMappingVtab *) vtab, name,
1856 3, 2, 1, 1 );
1857
1858 if ( astOK ) {
1859
1860 /* Initialise the SphMap data. */
1861 /* --------------------------- */
1862 /* Are all input vectors of unit length? Store a value of -1 to indicate that
1863 no value has yet been set. This will cause a default value of 0 (no, i.e.
1864 input vectors are not all of unit length) to be used. */
1865 new->unitradius = -1;
1866 new->polarlong = AST__BAD;
1867
1868 }
1869
1870 /* Return a pointer to the new SphMap. */
1871 return new;
1872 }
1873
astLoadSphMap_(void * mem,size_t size,AstSphMapVtab * vtab,const char * name,AstChannel * channel,int * status)1874 AstSphMap *astLoadSphMap_( void *mem, size_t size,
1875 AstSphMapVtab *vtab, const char *name,
1876 AstChannel *channel, int *status ) {
1877 /*
1878 *+
1879 * Name:
1880 * astLoadSphMap
1881
1882 * Purpose:
1883 * Load a SphMap.
1884
1885 * Type:
1886 * Protected function.
1887
1888 * Synopsis:
1889 * #include "sphmap.h"
1890 * AstSphMap *astLoadSphMap( void *mem, size_t size,
1891 * AstSphMapVtab *vtab, const char *name,
1892 * AstChannel *channel )
1893
1894 * Class Membership:
1895 * SphMap loader.
1896
1897 * Description:
1898 * This function is provided to load a new SphMap using data read
1899 * from a Channel. It first loads the data used by the parent class
1900 * (which allocates memory if necessary) and then initialises a
1901 * SphMap structure in this memory, using data read from the input
1902 * Channel.
1903 *
1904 * If the "init" flag is set, it also initialises the contents of a
1905 * virtual function table for a SphMap at the start of the memory
1906 * passed via the "vtab" parameter.
1907
1908
1909 * Parameters:
1910 * mem
1911 * A pointer to the memory into which the SphMap is to be
1912 * loaded. This must be of sufficient size to accommodate the
1913 * SphMap data (sizeof(SphMap)) plus any data used by derived
1914 * classes. If a value of NULL is given, this function will
1915 * allocate the memory itself using the "size" parameter to
1916 * determine its size.
1917 * size
1918 * The amount of memory used by the SphMap (plus derived class
1919 * data). This will be used to allocate memory if a value of
1920 * NULL is given for the "mem" parameter. This value is also
1921 * stored in the SphMap structure, so a valid value must be
1922 * supplied even if not required for allocating memory.
1923 *
1924 * If the "vtab" parameter is NULL, the "size" value is ignored
1925 * and sizeof(AstSphMap) is used instead.
1926 * vtab
1927 * Pointer to the start of the virtual function table to be
1928 * associated with the new SphMap. If this is NULL, a pointer
1929 * to the (static) virtual function table for the SphMap class
1930 * is used instead.
1931 * name
1932 * Pointer to a constant null-terminated character string which
1933 * contains the name of the class to which the new object
1934 * belongs (it is this pointer value that will subsequently be
1935 * returned by the astGetClass method).
1936 *
1937 * If the "vtab" parameter is NULL, the "name" value is ignored
1938 * and a pointer to the string "SphMap" is used instead.
1939
1940 * Returned Value:
1941 * A pointer to the new SphMap.
1942
1943 * Notes:
1944 * - A null pointer will be returned if this function is invoked
1945 * with the global error status set, or if it should fail for any
1946 * reason.
1947 *-
1948 */
1949
1950 #define KEY_LEN 50 /* Maximum length of a keyword */
1951
1952 /* Local Variables: */
1953 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
1954 AstSphMap *new; /* Pointer to the new SphMap */
1955
1956 /* Initialise. */
1957 new = NULL;
1958
1959 /* Check the global error status. */
1960 if( !astOK ) return new;
1961
1962 /* Get a pointer to the thread specific global data structure. */
1963 astGET_GLOBALS(channel);
1964
1965 /* If a NULL virtual function table has been supplied, then this is
1966 the first loader to be invoked for this SphMap. In this case the
1967 SphMap belongs to this class, so supply appropriate values to be
1968 passed to the parent class loader (and its parent, etc.). */
1969 if ( !vtab ) {
1970 size = sizeof( AstSphMap );
1971 vtab = &class_vtab;
1972 name = "SphMap";
1973
1974 /* If required, initialise the virtual function table for this class. */
1975 if ( !class_init ) {
1976 astInitSphMapVtab( vtab, name );
1977 class_init = 1;
1978 }
1979 }
1980
1981 /* Invoke the parent class loader to load data for all the ancestral
1982 classes of the current one, returning a pointer to the resulting
1983 partly-built SphMap. */
1984 new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name,
1985 channel );
1986
1987 if ( astOK ) {
1988
1989 /* Read input data. */
1990 /* ================ */
1991 /* Request the input Channel to read all the input data appropriate to
1992 this class into the internal "values list". */
1993 astReadClassData( channel, "SphMap" );
1994
1995 /* Now read each individual data item from this list and use it to
1996 initialise the appropriate instance variable(s) for this class. */
1997
1998 /* In the case of attributes, we first read the "raw" input value,
1999 supplying the "unset" value as the default. If a "set" value is
2000 obtained, we then use the appropriate (private) Set... member
2001 function to validate and set the value properly. */
2002
2003 /* UnitRadius. */
2004 /* ----------- */
2005 new->unitradius = astReadInt( channel, "untrd", -1 );
2006 if ( TestUnitRadius( new, status ) ) SetUnitRadius( new, new->unitradius, status );
2007
2008 /* PolarLong. */
2009 /* ---------- */
2010 new->polarlong = astReadDouble( channel, "plrlg", AST__BAD );
2011 if ( TestPolarLong( new, status ) ) SetPolarLong( new, new->polarlong, status );
2012
2013 }
2014
2015 /* If an error occurred, clean up by deleting the new SphMap. */
2016 if ( !astOK ) new = astDelete( new );
2017
2018 /* Return the new SphMap pointer. */
2019 return new;
2020 }
2021
2022 /* Virtual function interfaces. */
2023 /* ============================ */
2024 /* These provide the external interface to the virtual functions defined by
2025 this class. Each simply checks the global error status and then locates and
2026 executes the appropriate member function, using the function pointer stored
2027 in the object's virtual function table (this pointer is located using the
2028 astMEMBER macro defined in "object.h").
2029
2030 Note that the member function may not be the one defined here, as it may
2031 have been over-ridden by a derived class. However, it should still have the
2032 same interface. */
2033
2034
2035
2036
2037
2038