1 /*
2 *class++
3 *  Name:
4 *     Frame
5 
6 *  Purpose:
7 *     Coordinate system description.
8 
9 *  Constructor Function:
10 c     astFrame
11 f     AST_FRAME
12 
13 *  Description:
14 *     This class is used to represent coordinate systems. It does this
15 *     in rather the same way that a frame around a graph describes the
16 *     coordinate space in which data are plotted. Consequently, a
17 *     Frame has a Title (string) attribute, which describes the
18 *     coordinate space, and contains axes which in turn hold
19 *     information such as Label and Units strings which are used for
20 *     labelling (e.g.) graphical output. In general, however, the
21 *     number of axes is not restricted to two.
22 *
23 *     Functions are available for converting Frame coordinate values
24 *     into a form suitable for display, and also for calculating
25 *     distances and offsets between positions within the Frame.
26 *
27 *     Frames may also contain knowledge of how to transform to and
28 *     from related coordinate systems.
29 
30 *  Inheritance:
31 *     The Frame class inherits from the Mapping class.
32 
33 *  Attributes:
34 *     In addition to those attributes common to all Mappings, every
35 *     Frame also has the following attributes (if the Frame has only one
36 *     axis, the axis specifier can be omited from the following attribute
37 *     names):
38 *
39 *     - AlignSystem: Coordinate system used to align Frames
40 *     - Bottom(axis): Lowest axis value to display
41 *     - Digits/Digits(axis): Number of digits of precision
42 *     - Direction(axis): Display axis in conventional direction?
43 *     - Domain: Coordinate system domain
44 *     - Dut1: Difference between the UT1 and UTC timescale
45 *     - Epoch: Epoch of observation
46 *     - Format(axis): Format specification for axis values
47 *     - Label(axis): Axis label
48 *     - MatchEnd: Match trailing axes?
49 *     - MaxAxes: Maximum number of Frame axes to match
50 *     - MinAxes: Minimum number of Frame axes to match
51 *     - Naxes: Number of Frame axes
52 *     - NormUnit(axis): Normalised axis physical units
53 *     - ObsAlt: Geodetic altitude of observer
54 *     - ObsLat: Geodetic latitude of observer
55 *     - ObsLon: Geodetic longitude of observer
56 *     - Permute: Permute axis order?
57 *     - PreserveAxes: Preserve axes?
58 *     - Symbol(axis): Axis symbol
59 *     - System: Coordinate system used to describe the domain
60 *     - Title: Frame title
61 *     - Top(axis): Highest axis value to display
62 *     - Unit(axis): Axis physical units
63 
64 *  Functions:
65 c     In addition to those functions applicable to all Mappings, the
66 c     following functions may also be applied to all Frames:
67 f     In addition to those routines applicable to all Mappings, the
68 f     following routines may also be applied to all Frames:
69 *
70 c     - astAngle: Calculate the angle subtended by two points at a third point
71 c     - astAxAngle: Find the angle from an axis, to a line through two points
72 c     - astAxDistance: Calculate the distance between two axis values
73 c     - astAxOffset: Calculate an offset along an axis
74 c     - astConvert: Determine how to convert between two coordinate systems
75 c     - astDistance: Calculate the distance between two points in a Frame
76 c     - astFindFrame: Find a coordinate system with specified characteristics
77 c     - astFormat: Format a coordinate value for a Frame axis
78 c     - astGetActiveUnit: Determines how the Unit attribute will be used
79 c     - astIntersect: Find the intersection between two geodesic curves
80 c     - astMatchAxes: Find any corresponding axes in two Frames
81 c     - astNorm: Normalise a set of Frame coordinates
82 c     - astOffset: Calculate an offset along a geodesic curve
83 c     - astOffset2: Calculate an offset along a geodesic curve in a 2D Frame
84 c     - astPermAxes: Permute the order of a Frame's axes
85 c     - astPickAxes: Create a new Frame by picking axes from an existing one
86 c     - astResolve: Resolve a vector into two orthogonal components
87 c     - astSetActiveUnit: Specify how the Unit attribute should be used
88 c     - astUnformat: Read a formatted coordinate value for a Frame axis
89 f     - AST_ANGLE: Find the angle subtended by two points at a third point
90 f     - AST_AXANGLE: Find the angle from an axis, to a line through two points
91 f     - AST_AXDISTANCE: Calculate the distance between two axis values
92 f     - AST_AXOFFSET: Calculate an offset along an axis
93 f     - AST_CONVERT: Determine how to convert between two coordinate systems
94 f     - AST_DISTANCE: Calculate the distance between two points in a Frame
95 f     - AST_FINDFRAME: Find a coordinate system with specified characteristics
96 f     - AST_FORMAT: Format a coordinate value for a Frame axis
97 f     - AST_GETACTIVEUNIT: Determines how the Unit attribute will be used
98 f     - AST_INTERSECT: Find the intersection between two geodesic curves
99 f     - AST_MATCHAXES: Find any corresponding axes in two Frames
100 f     - AST_NORM: Normalise a set of Frame coordinates
101 f     - AST_OFFSET: Calculate an offset along a geodesic curve
102 f     - AST_OFFSET2: Calculate an offset along a geodesic curve in a 2D Frame
103 f     - AST_PERMAXES: Permute the order of a Frame's axes
104 f     - AST_PICKAXES: Create a new Frame by picking axes from an existing one
105 f     - AST_RESOLVE: Resolve a vector into two orthogonal components
106 f     - AST_SETACTIVEUNIT: Specify how the Unit attribute should be used
107 f     - AST_UNFORMAT: Read a formatted coordinate value for a Frame axis
108 
109 *  Notes:
110 *     - When used as a Mapping, a Frame implements a unit (null)
111 *     transformation in both the forward and inverse directions
112 *     (equivalent to a UnitMap). The Nin and Nout attribute values are
113 *     both equal to the number of Frame axes.
114 
115 *  Copyright:
116 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
117 *     Research Councils
118 
119 *  Licence:
120 *     This program is free software: you can redistribute it and/or
121 *     modify it under the terms of the GNU Lesser General Public
122 *     License as published by the Free Software Foundation, either
123 *     version 3 of the License, or (at your option) any later
124 *     version.
125 *
126 *     This program is distributed in the hope that it will be useful,
127 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
128 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
129 *     GNU Lesser General Public License for more details.
130 *
131 *     You should have received a copy of the GNU Lesser General
132 *     License along with this program.  If not, see
133 *     <http://www.gnu.org/licenses/>.
134 
135 *  Authors:
136 *     RFWS: R.F. Warren-Smith (Starlink)
137 *     DSB: B.S. Berry (Starlink)
138 
139 *  History:
140 *     1-MAR-1996 (RFWS):
141 *        Original version.
142 *     4-JUN-1996 (RFWS):
143 *        Added the CleanDomain function to fold all Domain strings to
144 *        upper case and remove white space.
145 *     12-JUL-1996 (RFWS):
146 *        Over-ride the astReportPoints method to provide
147 *        Frame-specific formatting.
148 *     11-SEP-1996 (RFWS):
149 *        Added astGap (written by DSB).
150 *     10-JUN-1997 (RFWS):
151 *        Re-implemented astConvert and astFindFrame.
152 *     1-SEP-1997 (RFWS):
153 *        Added missing return statement in astAbbrev_.
154 *     14-NOV-1997 (RFWS):
155 *        Fixed wrong amount of memory allocated in ValidateAxisSelection.
156 *     20-NOV-1997 (RFWS):
157 *        Updated astConvert prologue.
158 *     22-DEC-1997 (RFWS):
159 *        Updated astConvert prologue again.
160 *     15-FEB-1998 (RFWS):
161 *        Added astUnformat.
162 *     2-MAR-1999 (RFWS);
163 *        Fixed missing STATUS arguments in examples for AST_FINDFRAME
164 *        prologue.
165 *     18-JUL-1999 (RFWS):
166 *        Fixed memory leak in ConvertX.
167 *     21-JUN-2001 (DSB):
168 *        Added methods astAngle and astOffset2.
169 *     29-AUG-2001 (DSB):
170 *        Added methods astAxDistance and astAxOffset.
171 *     4-SEP-2001 (DSB):
172 *        Added method astResolve.
173 *     9-SEP-2001 (DSB):
174 *        Added method astBear.
175 *     21-SEP-2001 (DSB):
176 *        Replaced astBear with astAxAngle.
177 *     10-OCT-2002 (DSB):
178 *        Added Top and Bottom.
179 *     15-NOV-2002 (DSB):
180 *        Moved the System and Epoch attributes from the SkyFrame class to
181 *        this class. Added virtual method astValidateSystem, astSystemString,
182 *        astSystemCode. Added attribute AlignSystem.
183 *     17-DEC-2002 (DSB):
184 *        Added the GetActiveUnit, TestActiveUnit and SetActiveUnit functions.
185 *     8-JAN-2003 (DSB):
186 *        Changed private InitVtab method to protected astInitFrameVtab
187 *        method.
188 *     15-SEP-2003 (DSB):
189 *        Allow Frame attribute names to include an axis specifier within
190 *        GetAttrib, SetAttrib, TestAttrib and ClearAttrib (eg "Domain(1)"
191 *        is now accepted as equivalent to "Domain").
192 *     24-JAN-2004 (DSB):
193 *        o  Added astFields.
194 *        o  Added argument "fmt" to Abbrev.
195 *     24-MAR-2004 (DSB):
196 *        Add protected function astIsUnitFrame.
197 *     7-SEP-2004 (DSB):
198 *        Modified SetUnit to exclude any trailing spaces
199 *     8-SEP-2004 (DSB):
200 *        - Added astResolvePoints.
201 *        - Override astEqual.
202 *     29-NOV-2004 (DSB):
203 *        - Set/Get/Test/ClearAttrib: Allow axis specifier to be omitted from
204 *        axis attribute names if the Frame only has one axis.
205 *     2-FEB-2005 (DSB):
206 *        - Avoid using astStore to allocate more storage than is supplied
207 *        in the "data" pointer. This can cause access violations since
208 *        astStore will then read beyond the end of the "data" area.
209 *     17-FEB-2005 (DSB):
210 *        - Change use of ActiveUnit flag so that both target and template
211 *        Frames must have active units in order for the Mapping to take
212 *        account of differences in units. Previously, the test was based
213 *        on the template Frame alone.
214 *     23-MAR-2005 (DSB):
215 *        - GetActiveUnit: Always return zero if the Frame contains any
216 *        SkyAxes.
217 *     5-APR-2005 (DSB):
218 *        Correct error checking in Clear/Get/Set/TestAttrib.
219 *     12-MAY-2005 (DSB):
220 *        Added astNormBox method.
221 *     16-JUN-2005 (DSB):
222 *        Added documentation for the TimeFrame class.
223 *     12-AUG-2005 (DSB):
224 *        Added ObsLat and ObsLon attributes.
225 *     1-MAR-2006 (DSB):
226 *        Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM.
227 *     15-MAY-2006 (DSB):
228 *        Remove unused global variable parent_equal.
229 *     26-JUN-2006 (DSB):
230 *        Document the use of the Direction attribute by the Plot class.
231 *     30-JUN-2006 (DSB):
232 *        Allow astAbbrev to have a null "str1" value.
233 *     16-AUG-2006 (DSB):
234 *        Correct "Class Applicability" to "Applicability".
235 *     5-OCT-2006 (DSB):
236 *        Increase the number of digits used when formating a ObsLon or
237 *        ObsLat value in GetAttrib.
238 *     14-OCT-2006 (DSB):
239 *        - Add Dut1 attribute
240 *     26-JAN-2007 (DSB):
241 *        Fix bug in NewUnit that causes segvio when changing axis symbols
242 *        to accomodate changes in units.
243 *     17-MAY-2007 (DSB):
244 *        Added read-only attribute NormUnit.
245 *     21-MAY-2007 (DSB):
246 *        Use rather than ignore the value returned by astTestAxisDigits in
247 *        TestAttrib.
248 *     25-JUN-2007 (DSB):
249 *        Documentation typos.
250 *     26-NOV-2007 (DSB):
251 *        In Clear/Get/Set/TestAttrib, include any appropriate axis index in
252 *        the attribute name when attempting to get the attribute value from
253 *        the primary frame
254 *     17-NOV-2008 (DSB):
255 *        Correct parent class in invocation of astMAKE_ISA.
256 *     14-JAN-2009 (DSB):
257 *        Added astIntersect.
258 *     18-MAR-2009 (DSB):
259 *        Fixed bug in LineCrossing.
260 *     18-JUN-2000 (DSB):
261 *        Added ObsAlt attribute.
262 *     28-SEP-2009 (DSB):
263 *        Added astMatchAxes method.
264 *     22-MAR-2011 (DSB):
265 *        Add astFrameGrid method.
266 *     29-APR-2011 (DSB):
267 *        Prevent astFindFrame from matching a subclass template against a
268 *        superclass target.
269 *     11-APR-2012 (DSB):
270 *        Change astValidateAxis so that it can permute in either direction.
271 *     29-APR-2013 (DSB):
272 *        Added protected methods astSetFrameVariants and astGetFrameVariants.
273 *     1-MAY-2013 (DSB):
274 *        Override the astDoNotSimplify method to indicate that Frames should
275 *        always be simplified. This is mainly because the STC class uses the
276 *        Ident attribute with Frames, and preventing such frames from
277 *        simplifying (which is what the parent astDoNotSimplify method does)
278 *        causes the STC tester in the ast_tester directory to fail.
279 *class--
280 */
281 
282 /* Module Macros. */
283 /* ============== */
284 /* Set the name of the class we are implementing. This indicates to
285    the header files that define class interfaces that they should make
286    "protected" symbols available. */
287 #define astCLASS Frame
288 
289 /* Define numerical constants for use in this module. */
290 #define LABEL_BUFF_LEN 100       /* Max length of default axis Label string */
291 #define SYMBOL_BUFF_LEN 50       /* Max length of default axis Symbol string */
292 #define TITLE_BUFF_LEN 100       /* Max length of default title string */
293 #define GETATTRIB_BUFF_LEN 50    /* Max length of string returned by GetAttrib */
294 #define ASTFMTDECIMALYR_BUFF_LEN 50    /* Max length of string returned by GetAttrib */
295 #define ASTFORMATID_MAX_STRINGS 50     /* Number of string values buffer by astFormatID*/
296 
297 
298 /* Define the first and last acceptable System values. */
299 #define FIRST_SYSTEM AST__CART
300 #define LAST_SYSTEM AST__CART
301 
302 /* Define macros to implement methods for accessing axis attributes. */
303 /*
304 *  Name:
305 *     MAKE_CLEAR
306 
307 *  Purpose:
308 *     Implement a method to clear an attribute value for a Frame axis.
309 
310 *  Type:
311 *     Private macro.
312 
313 *  Synopsis:
314 *     #include "frame.h"
315 *     MAKE_CLEAR(attribute)
316 
317 *  Class Membership:
318 *     Defined by the Frame class.
319 
320 *  Description:
321 *     This macro expands to an implementation of a private member function of
322 *     the form:
323 *
324 *        static void Clear<Attribute>( AstFrame *this, int axis )
325 *
326 *     and an external interface function of the form:
327 *
328 *        void astClear<Attribute>_( AstFrame *this, int axis )
329 *
330 *     which implement a method for clearing an attribute value for a specified
331 *     axis of a Frame.
332 
333 *  Parameters:
334 *     attribute
335 *        The name of the attribute to be cleared, as it appears in the
336 *        function name (e.g. Label in "astClearLabel").
337 
338 *  Notes:
339 *     -  This macro assumes the existence of a method of the form:
340 *
341 *        void astClearAxis<Attribute>( AstAxis *this )
342 *
343 *     which clears the required attribute for an Axis object.
344 *     -  To avoid problems with some compilers, you should not leave any white
345 *     space around the macro arguments.
346 */
347 
348 /* Define the macro. */
349 #define MAKE_CLEAR(attribute) \
350 \
351 /* Private member function. */ \
352 /* ------------------------ */ \
353 static void Clear##attribute( AstFrame *this, int axis, int *status ) { \
354    AstAxis *ax;                  /* Pointer to Axis object */ \
355 \
356 /* Check the global error status. */ \
357    if ( !astOK ) return; \
358 \
359 /* Validate the axis index and obtain a pointer to the required Axis. */ \
360    (void) astValidateAxis( this, axis, 1, "astClear" #attribute ); \
361    ax = astGetAxis( this, axis ); \
362 \
363 /* Clear the Axis attribute. */ \
364    astClearAxis##attribute( ax ); \
365 \
366 /* Annul the Axis pointer. */ \
367    ax = astAnnul( ax ); \
368 } \
369 \
370 /* External interface. */ \
371 /* ------------------- */ \
372 void astClear##attribute##_( AstFrame *this, int axis, int *status ) { \
373 \
374 /* Check the global error status. */ \
375    if ( !astOK ) return; \
376 \
377 /* Invoke the required method via the virtual function table. */ \
378    (**astMEMBER(this,Frame,Clear##attribute))( this, axis, status ); \
379 }
380 
381 /*
382 *  Name:
383 *     MAKE_GET
384 
385 *  Purpose:
386 *     Implement a method to get an attribute value for a Frame axis.
387 
388 *  Type:
389 *     Private macro.
390 
391 *  Synopsis:
392 #     #include "frame.h"
393 *     MAKE_GET(attribute,type,bad_value,default,assign_default)
394 
395 *  Class Membership:
396 *     Defined by the Frame class.
397 
398 *  Description:
399 *     This macro expands to an implementation of a private member function of
400 *     the form:
401 *
402 *        static <Type> Get<Attribute>( AstFrame *this, int axis )
403 *
404 *     and an external interface function of the form:
405 *
406 *        Type astGet<Attribute>_( AstFrame *this, int axis )
407 *
408 *     which implement a method for getting an attribute value for a specified
409 *     axis of a Frame.
410 
411 *  Parameters:
412 *     attribute
413 *        The name of the attribute whose value is to be obtained, as
414 *        it appears in the function name (e.g. Label in
415 *        "astGetLabel").
416 *     type
417 *        The C type of the attribute.
418 *     bad_value
419 *        A constant value to return if the global error status is set, or if
420 *        the function fails.
421 *     default
422 *        A boolean (int) constant that indicates whether a new default value
423 *        should be returned by the method if the requested attribute has not
424 *        been set for the axis. If this value is zero, the axis default will
425 *        be used instead.
426 *     assign_default
427 *        An expression that evaluates to the new default value to be assigned.
428 *        This value is ignored if "default" is zero, but a valid (e.g.
429 *        constant) value should nevertheless be supplied.
430 
431 *  Notes:
432 *     -  This macro assumes the existence of a method of the form:
433 *
434 *           <Type> astGetAxis<Attribute>( AstAxis *this )
435 *
436 *     which gets the required attribute for an Axis object.
437 *     -  To avoid problems with some compilers, you should not leave any white
438 *     space around the macro arguments.
439 */
440 
441 /* Define the macro. */
442 #define MAKE_GET(attribute,type,bad_value,default,assign_default) \
443 \
444 /* Private member function. */ \
445 /* ------------------------ */ \
446 static type Get##attribute( AstFrame *this, int axis, int *status ) { \
447    AstAxis *ax;                  /* Pointer to Axis object */ \
448    int digits_set;               /* Axis Digits attribute set? */ \
449    int old_axis;                 /* Original (un-permuted) axis index */ \
450    type result;                  /* Result to be returned */ \
451 \
452 /* Initialise. */ \
453    result = (bad_value); \
454 \
455 /* Check the global error status. */ \
456    if ( !astOK ) return result; \
457 \
458 /* Validate and permute the axis index and obtain a pointer to the required \
459    Axis. */ \
460    old_axis = axis; \
461    axis = astValidateAxis( this, axis, 1, "astGet" #attribute ); \
462    ax = astGetAxis( this, old_axis ); \
463 \
464 /* Since the Axis is "managed" by the enclosing Frame, we next test if any \
465    Axis attributes which may affect the result are undefined (i.e. have not \
466    been explicitly set). If so, we over-ride them, giving them temporary \
467    values dictated by the Frame. Only the Digits attribute is relevant \
468    here. */ \
469    digits_set = astTestAxisDigits( ax ); \
470    if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) ); \
471 \
472 /* If the default value is to be over-ridden, test if the Axis attribute has \
473    been set. Then, if required, obtain the attribute value from the Axis. */ \
474    if ( !(default) || astTestAxis##attribute( ax ) ) { \
475       result = astGetAxis##attribute( ax ); \
476 \
477 /* If required, assign the new default value. */ \
478    } else { \
479       result = (assign_default); \
480    } \
481 \
482 /* Clear Axis attributes which were temporarily over-ridden above and annul \
483    the Axis pointer. */ \
484    if ( !digits_set ) astClearAxisDigits( ax ); \
485    ax = astAnnul( ax ); \
486 \
487 /* If an error occurred, clear the result value. */ \
488    if ( !astOK ) result = (bad_value); \
489 \
490 /* Return the result. */ \
491    return result; \
492 } \
493 \
494 /* External interface. */ \
495 /* ------------------- */ \
496 type astGet##attribute##_( AstFrame *this, int axis, int *status ) { \
497 \
498 /* Check the global error status. */ \
499    if ( !astOK ) return (bad_value); \
500 \
501 /* Invoke the required method via the virtual function table. */ \
502    return (**astMEMBER(this,Frame,Get##attribute))( this, axis, status ); \
503 }
504 
505 /*
506 *  Name:
507 *     MAKE_SET
508 
509 *  Purpose:
510 *     Implement a method to set an attribute value for a Frame axis.
511 
512 *  Type:
513 *     Private macro.
514 
515 *  Synopsis:
516 *     #include "frame.h"
517 *     MAKE_SET(attribute,type)
518 
519 *  Class Membership:
520 *     Defined by the Frame class.
521 
522 *  Description:
523 *     This macro expands to an implementation of a private member function of
524 *     the form:
525 *
526 *        static void Set<Attribute>( AstFrame *this, int axis, <Type> value )
527 *
528 *     and an external interface function of the form:
529 *
530 *        void astSet<Attribute>_( AstFrame *this, int axis, <Type> value )
531 *
532 *     which implement a method for setting an attribute value for a specified
533 *     axis of a Frame.
534 
535 *  Parameters:
536 *      attribute
537 *         The name of the attribute to be set, as it appears in the
538 *         function name (e.g. Label in "astSetLabel").
539 *      type
540 *         The C type of the attribute.
541 
542 *  Notes:
543 *     -  This macro assumes the existence of a method of the form:
544 *
545 *           void astSetAxis<Attribute>( AstAxis *this, <Type> value )
546 *
547 *     which sets the required attribute for an Axis object.
548 *     -  To avoid problems with some compilers, you should not leave any white
549 *     space around the macro arguments.
550 */
551 
552 /* Define the macro. */
553 #define MAKE_SET(attribute,type) \
554 \
555 /* Private member function. */ \
556 /* ------------------------ */ \
557 static void Set##attribute( AstFrame *this, int axis, type value, int *status ) { \
558    AstAxis *ax;                  /* Pointer to Axis object */ \
559 \
560 /* Check the global error status. */ \
561    if ( !astOK ) return; \
562 \
563 /* Validate the axis index and obtain a pointer to the required Axis. */ \
564    (void) astValidateAxis( this, axis, 1, "astSet" #attribute ); \
565    ax = astGetAxis( this, axis ); \
566 \
567 /* Set the Axis attribute value. */ \
568    astSetAxis##attribute( ax, value ); \
569 \
570 /* Annul the Axis pointer. */ \
571    ax = astAnnul( ax ); \
572 } \
573 \
574 /* External interface. */ \
575 /* ------------------- */ \
576 void astSet##attribute##_( AstFrame *this, int axis, type value, int *status ) { \
577 \
578 /* Check the global error status. */ \
579    if ( !astOK ) return; \
580 \
581 /* Invoke the required method via the virtual function table. */ \
582    (**astMEMBER(this,Frame,Set##attribute))( this, axis, value, status ); \
583 }
584 
585 /*
586 *  Name:
587 *     MAKE_TEST
588 
589 *  Purpose:
590 *     Implement a method to test if an attribute has been set for a Frame axis.
591 
592 *  Type:
593 *     Private macro.
594 
595 *  Synopsis:
596 *     #include "frame.h"
597 *     MAKE_TEST(attribute)
598 
599 *  Class Membership:
600 *     Defined by the Frame class.
601 
602 *  Description:
603 *     This macro expands to an implementation of a private member function of
604 *     the form:
605 *
606 *        static int Test<Attribute>( AstFrame *this, int axis )
607 *
608 *     and an external interface function of the form:
609 *
610 *        int astTest<Attribute>_( AstFrame *this, int axis )
611 *
612 *     which implement a method for testing if an attribute has been set for a
613 *     specified axis of a Frame.
614 
615 *  Parameters:
616 *      attribute
617 *         The name of the attribute to be tested, as it appears in the
618 *         function name (e.g. Label in "astTestLabel").
619 
620 *  Notes:
621 *     -  This macro assumes the existence of a method of the form:
622 *
623 *           void astTestAxis<Attribute>( AstAxis *this )
624 *
625 *     which tests the required attribute for an Axis object.
626 *     -  To avoid problems with some compilers, you should not leave any white
627 *     space around the macro arguments.
628 */
629 
630 /* Define the macro. */
631 #define MAKE_TEST(attribute) \
632 \
633 /* Private member function. */ \
634 /* ------------------------ */ \
635 static int Test##attribute( AstFrame *this, int axis, int *status ) { \
636    AstAxis *ax;                  /* Pointer to Axis object */ \
637    int result;                   /* Value to be returned */ \
638 \
639 /* Check the global error status. */ \
640    if ( !astOK ) return 0; \
641 \
642 /* Validate the axis index and obtain a pointer to the required Axis. */ \
643    (void) astValidateAxis( this, axis, 1, "astTest" #attribute ); \
644    ax = astGetAxis( this, axis ); \
645 \
646 /* Test if the attribute has been set. */ \
647    result = astTestAxis##attribute( ax ); \
648 \
649 /* Annul the Axis pointer. */ \
650    ax = astAnnul( ax ); \
651 \
652 /* If an error occurred, clear the result value. */ \
653    if ( !astOK ) result = 0; \
654 \
655 /* Return the result. */ \
656    return result; \
657 } \
658 \
659 /* External interface. */ \
660 /* ------------------- */ \
661 int astTest##attribute##_( AstFrame *this, int axis, int *status ) { \
662 \
663 /* Check the global error status. */ \
664    if ( !astOK ) return 0; \
665 \
666 /* Invoke the required method via the virtual function table. */ \
667    return (**astMEMBER(this,Frame,Test##attribute))( this, axis, status ); \
668 }
669 
670 /* Header files. */
671 /* ============= */
672 /* Interface definitions. */
673 /* ---------------------- */
674 
675 #include "globals.h"             /* Thread-safe global data access */
676 #include "error.h"               /* Error reporting facilities */
677 #include "memory.h"              /* Memory allocation facilities */
678 #include "object.h"              /* Base Object class */
679 #include "mapping.h"             /* Coordinate mappings (parent class) */
680 #include "pointset.h"            /* Sets of points */
681 #include "unitmap.h"             /* Unit Mapping */
682 #include "permmap.h"             /* Coordinate permutation Mapping */
683 #include "cmpmap.h"              /* Compound Mappings */
684 #include "axis.h"                /* Coordinate Axis */
685 #include "skyaxis.h"             /* Sky coordinate axes */
686 #include "skyframe.h"            /* Celestial coordinate frames */
687 #include "channel.h"             /* I/O channels */
688 #include "frame.h"               /* Interface definition for this class */
689 #include "frameset.h"            /* Collections of Frames */
690 #include "cmpframe.h"            /* Compound Frames */
691 #include "pal.h"                 /* SLALIB library interface */
692 #include "unit.h"                /* Units identification and mapping */
693 #include "globals.h"             /* Thread-safe global data access */
694 
695 /* Error code definitions. */
696 /* ----------------------- */
697 #include "ast_err.h"             /* AST error codes */
698 
699 /* C header files. */
700 /* --------------- */
701 #include <ctype.h>
702 #include <limits.h>
703 #include <math.h>
704 #include <stddef.h>
705 #include <stdio.h>
706 #include <string.h>
707 
708 /* Module Variables. */
709 /* ================= */
710 
711 /* Address of this static variable is used as a unique identifier for
712    member of this class. */
713 static int class_check;
714 
715 /* Pointers to parent class methods which are extended by this class. */
716 static const char *(* parent_getattrib)( AstObject *, const char *, int * );
717 static int (* parent_testattrib)( AstObject *, const char *, int * );
718 static void (* parent_clearattrib)( AstObject *, const char *, int * );
719 static void (* parent_setattrib)( AstObject *, const char *, int * );
720 static void (* parent_cleanattribs)( AstObject *, int * );
721 static int (* parent_getobjsize)( AstObject *, int * );
722 
723 #if defined(THREAD_SAFE)
724 static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
725 #endif
726 
727 /* Define a variable to hold a SkyFrame which will be used for formatting
728    and unformatting ObsLat and ObsLon values. */
729 static AstSkyFrame *skyframe;
730 
731 /* Define macros for accessing each item of thread specific global data. */
732 #ifdef THREAD_SAFE
733 
734 /* Define how to initialise thread-specific globals. */
735 #define GLOBAL_inits \
736    globals->Class_Init = 0; \
737    globals->GetAttrib_Buff[ 0 ] = 0; \
738    globals->AstFormatID_Init = 0; \
739    globals->AstFormatID_Istr = 0; \
740    globals->Label_Buff[ 0 ] = 0; \
741    globals->Symbol_Buff[ 0 ] = 0; \
742    globals->Title_Buff[ 0 ] = 0; \
743    globals->AstFmtDecimalYr_Buff[ 0 ] = 0;
744 
745 /* Create the function that initialises global data for this module. */
746 astMAKE_INITGLOBALS(Frame)
747 
748 #define class_init astGLOBAL(Frame,Class_Init)
749 #define class_vtab astGLOBAL(Frame,Class_Vtab)
750 #define getattrib_buff astGLOBAL(Frame,GetAttrib_Buff)
751 #define astformatid_strings astGLOBAL(Frame,AstFormatID_Strings)
752 #define astformatid_istr astGLOBAL(Frame,AstFormatID_Istr)
753 #define astformatid_init astGLOBAL(Frame,AstFormatID_Init)
754 #define label_buff astGLOBAL(Frame,Label_Buff)
755 #define symbol_buff astGLOBAL(Frame,Symbol_Buff)
756 #define title_buff astGLOBAL(Frame,Title_Buff)
757 #define astfmtdecimalyr_buff astGLOBAL(Frame,AstFmtDecimalYr_Buff)
758 
759 
760 
761 /* If thread safety is not needed, declare and initialise globals at static
762    variables. */
763 #else
764 
765 /* Buffer returned by GetAttrib. */
766 static char getattrib_buff[ GETATTRIB_BUFF_LEN + 1 ];
767 
768 /* Strings returned by astFormatID */
769 static char *astformatid_strings[ ASTFORMATID_MAX_STRINGS ];
770 
771 /* Offset of next string in "AstFormatID_Strings" */
772 static int astformatid_istr;
773 
774 /* "AstFormatID_Strings" array initialised? */
775 static int astformatid_init;
776 
777 /* Default Label string buffer */
778 static char label_buff[ LABEL_BUFF_LEN + 1 ];
779 
780 /* Default Symbol buffer */
781 static char symbol_buff[ SYMBOL_BUFF_LEN + 1 ];
782 
783 /* Default Title string buffer */
784 static char title_buff[ TITLE_BUFF_LEN + 1 ];
785 
786 /* Buffer for result string */
787 static char astfmtdecimalyr_buff[ ASTFMTDECIMALYR_BUFF_LEN + 1 ];
788 
789 
790 /* Define the class virtual function table and its initialisation flag
791    as static variables. */
792 static AstFrameVtab class_vtab;   /* Virtual function table */
793 static int class_init = 0;       /* Virtual function table initialised? */
794 
795 #endif
796 
797 
798 /* Prototypes for Private Member Functions. */
799 /* ======================================== */
800 static AstAxis *GetAxis( AstFrame *, int, int * );
801 static AstFrame *PickAxes( AstFrame *, int, const int[], AstMapping **, int * );
802 static AstFrameSet *Convert( AstFrame *, AstFrame *, const char *, int * );
803 static AstFrameSet *ConvertX( AstFrame *, AstFrame *, const char *, int * );
804 static AstFrameSet *FindFrame( AstFrame *, AstFrame *, const char *, int * );
805 static void MatchAxes( AstFrame *, AstFrame *, int *, int * );
806 static void MatchAxesX( AstFrame *, AstFrame *, int *, int * );
807 static AstLineDef *LineDef( AstFrame *, const double[2], const double[2], int * );
808 static AstPointSet *FrameGrid( AstFrame *, int, const double *, const double *, int * );
809 static AstPointSet *ResolvePoints( AstFrame *, const double [], const double [], AstPointSet *, AstPointSet *, int * );
810 static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
811 static char *CleanDomain( char *, int * );
812 static const char *Abbrev( AstFrame *, int, const char *, const char *, const char *, int * );
813 static const char *Format( AstFrame *, int, double, int * );
814 static const char *GetAttrib( AstObject *, const char *, int * );
815 static const char *GetDefaultLabel( int, int * );
816 static const char *GetDefaultSymbol( AstFrame *, int, int * );
817 static const char *GetDefaultTitle( AstFrame *, int * );
818 static const char *GetDomain( AstFrame *, int * );
819 static const char *GetFormat( AstFrame *, int, int * );
820 static const char *GetLabel( AstFrame *, int, int * );
821 static const char *GetNormUnit( AstFrame *, int, int * );
822 static const char *GetSymbol( AstFrame *, int, int * );
823 static const char *GetTitle( AstFrame *, int * );
824 static const char *GetUnit( AstFrame *, int, int * );
825 static const int *GetPerm( AstFrame *, int * );
826 static double Angle( AstFrame *, const double[], const double[], const double[], int * );
827 static double AxAngle( AstFrame *, const double[], const double[], int, int * );
828 static double AxDistance( AstFrame *, int, double, double, int * );
829 static double AxOffset( AstFrame *, int, double, double, int * );
830 static double Distance( AstFrame *, const double[], const double[], int * );
831 static double Gap( AstFrame *, int, double, int *, int * );
832 static double Offset2( AstFrame *, const double[2], double, double, double[2], int * );
833 static int AxIn( AstFrame *, int, double, double, double, int, int * );
834 static int ConsistentMaxAxes( AstFrame *, int, int * );
835 static int ConsistentMinAxes( AstFrame *, int, int * );
836 static int DefaultMaxAxes( AstFrame *, int * );
837 static int DefaultMinAxes( AstFrame *, int * );
838 static int DoNotSimplify( AstMapping *, int * );
839 static int Equal( AstObject *, AstObject *, int * );
840 static int Fields( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * );
841 static int GetDigits( AstFrame *, int * );
842 static int GetDirection( AstFrame *, int, int * );
843 static int GetIsLinear( AstMapping *, int * );
844 static int GetIsSimple( AstMapping *, int * );
845 static int LineContains( AstFrame *, AstLineDef *, int, double *, int * );
846 static int LineCrossing( AstFrame *, AstLineDef *, AstLineDef *, double **, int * );
847 static int GetObjSize( AstObject *, int * );
848 static void CleanAttribs( AstObject *, int * );
849 static void LineOffset( AstFrame *, AstLineDef *, double, double, double[2], int * );
850 
851 static double GetTop( AstFrame *, int, int * );
852 static int TestTop( AstFrame *, int, int * );
853 static void ClearTop( AstFrame *, int, int * );
854 static void SetTop( AstFrame *, int, double, int * );
855 
856 static double GetBottom( AstFrame *, int, int * );
857 static int TestBottom( AstFrame *, int, int * );
858 static void ClearBottom( AstFrame *, int, int * );
859 static void SetBottom( AstFrame *, int, double, int * );
860 
861 static AstSystemType GetSystem( AstFrame *, int * );
862 static int TestSystem( AstFrame *, int * );
863 static void ClearSystem( AstFrame *, int * );
864 static void SetSystem( AstFrame *, AstSystemType, int * );
865 
866 static AstSystemType GetAlignSystem( AstFrame *, int * );
867 static int TestAlignSystem( AstFrame *, int * );
868 static void ClearAlignSystem( AstFrame *, int * );
869 static void SetAlignSystem( AstFrame *, AstSystemType, int * );
870 
871 static double GetEpoch( AstFrame *, int * );
872 static int TestEpoch( AstFrame *, int * );
873 static void ClearEpoch( AstFrame *, int * );
874 static void SetEpoch( AstFrame *, double, int * );
875 
876 static double GetObsLat( AstFrame *, int * );
877 static int TestObsLat( AstFrame *, int * );
878 static void ClearObsLat( AstFrame *, int * );
879 static void SetObsLat( AstFrame *, double, int * );
880 
881 static double GetObsLon( AstFrame *, int * );
882 static int TestObsLon( AstFrame *, int * );
883 static void ClearObsLon( AstFrame *, int * );
884 static void SetObsLon( AstFrame *, double, int * );
885 
886 static double GetObsAlt( AstFrame *, int * );
887 static int TestObsAlt( AstFrame *, int * );
888 static void ClearObsAlt( AstFrame *, int * );
889 static void SetObsAlt( AstFrame *, double, int * );
890 
891 static double GetDut1( AstFrame *, int * );
892 static int TestDut1( AstFrame *, int * );
893 static void ClearDut1( AstFrame *, int * );
894 static void SetDut1( AstFrame *, double, int * );
895 
896 static int GetActiveUnit( AstFrame *, int * );
897 static int TestActiveUnit( AstFrame *, int * );
898 static void SetActiveUnit( AstFrame *, int, int * );
899 
900 static AstFrameSet *GetFrameVariants( AstFrame *, int * );
901 static void SetFrameVariants( AstFrame *, AstFrameSet *, int * );
902 
903 static int GetFrameFlags( AstFrame *, int * );
904 static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * );
905 static int GetMatchEnd( AstFrame *, int * );
906 static int GetMaxAxes( AstFrame *, int * );
907 static int GetMinAxes( AstFrame *, int * );
908 static int GetNaxes( AstFrame *, int * );
909 static int GetNin( AstMapping *, int * );
910 static int GetNout( AstMapping *, int * );
911 static int GetPermute( AstFrame *, int * );
912 static int GetPreserveAxes( AstFrame *, int * );
913 static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
914 static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
915 static int TestAttrib( AstObject *, const char *, int * );
916 static int TestDigits( AstFrame *, int * );
917 static int TestDirection( AstFrame *, int, int * );
918 static int TestDomain( AstFrame *, int * );
919 static int TestFormat( AstFrame *, int, int * );
920 static int TestLabel( AstFrame *, int, int * );
921 static int TestMatchEnd( AstFrame *, int * );
922 static int TestMaxAxes( AstFrame *, int * );
923 static int TestMinAxes( AstFrame *, int * );
924 static int TestPermute( AstFrame *, int * );
925 static int TestPreserveAxes( AstFrame *, int * );
926 static int TestSymbol( AstFrame *, int, int * );
927 static int TestTitle( AstFrame *, int * );
928 static int TestUnit( AstFrame *, int, int * );
929 static int IsUnitFrame( AstFrame *, int * );
930 static int Unformat( AstFrame *, int, const char *, double *, int * );
931 static int ValidateAxis( AstFrame *, int, int, const char *, int * );
932 static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * );
933 static AstSystemType SystemCode( AstFrame *, const char *, int * );
934 static const char *SystemString( AstFrame *, AstSystemType, int * );
935 static void AddUnderscores( char *, int * );
936 static void CheckPerm( AstFrame *, const int *, const char *, int * );
937 static void ClearAttrib( AstObject *, const char *, int * );
938 static void ClearDigits( AstFrame *, int * );
939 static void ClearDirection( AstFrame *, int, int * );
940 static void ClearDomain( AstFrame *, int * );
941 static void ClearFormat( AstFrame *, int, int * );
942 static void ClearLabel( AstFrame *, int, int * );
943 static void ClearMatchEnd( AstFrame *, int * );
944 static void ClearMaxAxes( AstFrame *, int * );
945 static void ClearMinAxes( AstFrame *, int * );
946 static void ClearPermute( AstFrame *, int * );
947 static void ClearPreserveAxes( AstFrame *, int * );
948 static void ClearSymbol( AstFrame *, int, int * );
949 static void ClearTitle( AstFrame *, int * );
950 static void ClearUnit( AstFrame *, int, int * );
951 static void Copy( const AstObject *, AstObject *, int * );
952 static void Delete( AstObject *, int * );
953 static void Dump( AstObject *, AstChannel *, int * );
954 static void Intersect( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * );
955 static void Norm( AstFrame *, double[], int * );
956 static void NormBox( AstFrame *, double[], double[], AstMapping *, int * );
957 static void Offset( AstFrame *, const double[], const double[], double, double[], int * );
958 static void Overlay( AstFrame *, const int *, AstFrame *, int * );
959 static void PermAxes( AstFrame *, const int[], int * );
960 static void PrimaryFrame( AstFrame *, int, AstFrame **, int *, int * );
961 static void ReportPoints( AstMapping *, int, AstPointSet *, AstPointSet *, int * );
962 static void Resolve( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * );
963 static void SetAttrib( AstObject *, const char *, int * );
964 static void SetAxis( AstFrame *, int, AstAxis *, int * );
965 static void SetDigits( AstFrame *, int, int * );
966 static void SetDirection( AstFrame *, int, int, int * );
967 static void SetDomain( AstFrame *, const char *, int * );
968 static void SetFormat( AstFrame *, int, const char *, int * );
969 static void SetFrameFlags( AstFrame *, int, int * );
970 static void SetLabel( AstFrame *, int, const char *, int * );
971 static void SetMatchEnd( AstFrame *, int, int * );
972 static void SetMaxAxes( AstFrame *, int, int * );
973 static void SetMinAxes( AstFrame *, int, int * );
974 static void SetPermute( AstFrame *, int, int * );
975 static void SetPreserveAxes( AstFrame *, int, int * );
976 static void SetSymbol( AstFrame *, int, const char *, int * );
977 static void SetTitle( AstFrame *, const char *, int * );
978 static void SetUnit( AstFrame *, int, const char *, int * );
979 static void NewUnit( AstAxis *, const char *, const char *, const char *, const char *, int * );
980 static void ValidateAxisSelection( AstFrame *, int, const int *, const char *, int * );
981 
982 #if defined(THREAD_SAFE)
983 static int ManageLock( AstObject *, int, int, AstObject **, int * );
984 #endif
985 
986 /* Member functions. */
987 /* ================= */
Abbrev(AstFrame * this,int axis,const char * fmt,const char * str1,const char * str2,int * status)988 static const char *Abbrev( AstFrame *this, int axis,  const char *fmt,
989                            const char *str1, const char *str2, int *status ) {
990 /*
991 *+
992 *  Name:
993 *     astAbbrev
994 
995 *  Purpose:
996 *     Abbreviate a formatted Frame axis value by skipping leading fields.
997 
998 *  Type:
999 *     Protected virtual function.
1000 
1001 *  Synopsis:
1002 *     #include "frame.h"
1003 *     const char *astAbbrev( AstFrame *this, int axis, const char *fmt,
1004 *                            const char *str1, const char *str2 )
1005 
1006 *  Class Membership:
1007 *     Frame method.
1008 
1009 *  Description:
1010 *     This function compares two Frame axis values that have been
1011 *     formatted (using astFormat) and determines if they have any
1012 *     redundant leading fields (i.e. leading fields in common which
1013 *     can be suppressed when tabulating the values or plotting them on
1014 *     the axis of a graph).
1015 
1016 *  Parameters:
1017 *     this
1018 *        Pointer to the Frame.
1019 *     axis
1020 *        The number of the Frame axis for which the values have been
1021 *        formatted (axis numbering starts at zero for the first axis).
1022 *     fmt
1023 *        Pointer to a constant null-terminated string containing the
1024 *        format specification used to format the two values.
1025 *     str1
1026 *        Pointer to a constant null-terminated string containing the
1027 *        first formatted value. If this is null, the returned pointer
1028 *        points to the start of the final field in str2.
1029 *     str2
1030 *        Pointer to a constant null-terminated string containing the
1031 *        second formatted value.
1032 
1033 *  Returned Value:
1034 *     A pointer into the "str2" string which locates the first
1035 *     character in the first field that differs between the two
1036 *     formatted values.
1037 *
1038 *     If the two values have no leading fields in common, the returned
1039 *     value will point at the start of string "str2". If the two
1040 *     values are equal, it will point at the terminating null at the
1041 *     end of this string.
1042 
1043 *  Notes:
1044 *     - This function assumes that the format specification used was
1045 *     the same when both values were formatted and that they both
1046 *     apply to the same Frame axis.
1047 *     - A pointer to the start of "str2" will be returned if this
1048 *     function is invoked with the global error status set, or if it
1049 *     should fail for any reason.
1050 *-
1051 */
1052 
1053 /* Local Variables: */
1054    AstAxis *ax;                  /* Pointer to Axis object */
1055    const char *result;           /* Result pointer to return */
1056 
1057 /* Initialise. */
1058    result = str2;
1059 
1060 /* Check the global error status. */
1061    if ( !astOK ) return result;
1062 
1063 /* Validate the axis index and obtain a pointer to the required
1064    Axis. */
1065    (void) astValidateAxis( this, axis, 1, "astAbbrev" );
1066    ax = astGetAxis( this, axis );
1067 
1068 /* Invoke the Axis astAxisAbbrev method to perform the processing. */
1069    result = astAxisAbbrev( ax, fmt, str1, str2 );
1070 
1071 /* Annul the Axis pointer. */
1072    ax = astAnnul( ax );
1073 
1074 /* If an error occurred, clear the returned value. */
1075    if ( !astOK ) result = str2;
1076 
1077 /* Return the result. */
1078    return result;
1079 }
1080 
AddUnderscores(char * string,int * status)1081 static void AddUnderscores( char *string, int *status ) {
1082 /*
1083 *  Name:
1084 *     AddUnderscores
1085 
1086 *  Purpose:
1087 *     Add underscores to a string in place of white space.
1088 
1089 *  Type:
1090 *     Private function.
1091 
1092 *  Synopsis:
1093 *     #include "frame.h"
1094 *     void AddUnderscores( char *string, int *status )
1095 
1096 *  Class Membership:
1097 *     Frame member function.
1098 
1099 *  Description:
1100 *     This function changes all white space characters in a string into
1101 *     the underscore character '_'.
1102 
1103 *  Parameters:
1104 *     this
1105 *        Pointer to the Frame.
1106 *     string
1107 *        Pointer to the null terminated string to be processed.
1108 *     status
1109 *        Pointer to the inherited status variable.
1110 */
1111 
1112 /* Local Variables. */
1113    int i;                        /* Loop counter for characters */
1114 
1115 /* Inspect each character in the string. */
1116    for ( i = 0; string[ i ]; i++ ) {
1117 
1118 /* If it is a white space character, replace it with an underscore. */
1119       if ( isspace( string[ i ] ) ) string[ i ] = '_';
1120    }
1121 }
1122 
Angle(AstFrame * this,const double a[],const double b[],const double c[],int * status)1123 static double Angle( AstFrame *this, const double a[],
1124                      const double b[], const double c[], int *status ) {
1125 /*
1126 *++
1127 *  Name:
1128 c     astAngle
1129 f     AST_ANGLE
1130 
1131 *  Purpose:
1132 *     Calculate the angle subtended by two points at a third point.
1133 
1134 *  Type:
1135 *     Public virtual function.
1136 
1137 *  Synopsis:
1138 c     #include "frame.h"
1139 c     double astAngle( AstFrame *this, const double a[], const double b[],
1140 c                      const double c[] )
1141 f     RESULT = AST_ANGLE( THIS, A, B, C, STATUS )
1142 
1143 *  Class Membership:
1144 *     Frame method.
1145 
1146 *  Description:
1147 c     This function
1148 f     This routine
1149 *     finds the angle at point B between the line joining points A and B,
1150 *     and the line joining points C and B. These lines will in fact be
1151 *     geodesic curves appropriate to the Frame in use. For instance, in
1152 *     SkyFrame, they will be great circles.
1153 
1154 *  Parameters:
1155 c     this
1156 f     THIS = INTEGER (Given)
1157 *        Pointer to the Frame.
1158 c     a
1159 f     A( * ) = DOUBLE PRECISION (Given)
1160 c        An array of double, with one element for each Frame axis
1161 f        An array with one element for each Frame axis
1162 *        (Naxes attribute) containing the coordinates of the first point.
1163 c     b
1164 f     B( * ) = DOUBLE PRECISION (Given)
1165 c        An array of double, with one element for each Frame axis
1166 f        An array with one element for each Frame axis
1167 *        (Naxes attribute) containing the coordinates of the second point.
1168 c     c
1169 f     C( * ) = DOUBLE PRECISION (Given)
1170 c        An array of double, with one element for each Frame axis
1171 f        An array with one element for each Frame axis
1172 *        (Naxes attribute) containing the coordinates of the third point.
1173 f     STATUS = INTEGER (Given and Returned)
1174 f        The global status.
1175 
1176 *  Returned Value:
1177 c     astAngle
1178 f     AST_ANGLE = DOUBLE PRECISION
1179 *        The angle in radians, from the line AB to the line CB. If the
1180 *        Frame is 2-dimensional, it will be in the range $\pm \pi$,
1181 *        and positive rotation is in the same sense as rotation from
1182 *        the positive direction of axis 2 to the positive direction of
1183 *        axis 1. If the Frame has more than 2 axes, a positive value will
1184 *        always be returned in the range zero to $\pi$.
1185 
1186 *  Notes:
1187 *     - A value of AST__BAD will also be returned if points A and B are
1188 *     co-incident, or if points B and C are co-incident.
1189 *     - A value of AST__BAD will also be returned if this function is
1190 c     invoked with the AST error status set, or if it should fail for
1191 f     invoked with STATUS set to an error value, or if it should fail for
1192 *     any reason.
1193 *--
1194 */
1195 
1196 /* Local Variables: */
1197    double *ab;                   /* Pointer to vector AB */
1198    double *cb;                   /* Pointer to vector CB */
1199    double cos;                   /* cosine of required angle */
1200    double anga;                  /* Angle from +ve Y to the line BA */
1201    double angc;                  /* Angle from +ve Y to the line BC */
1202    double result;                /* Result value to return */
1203    double sla;                   /* Squared length of vector AB */
1204    double slc;                   /* Squared length of vector CB */
1205    double sp;                    /* Scalar product of AB and CB */
1206    int axis;                     /* Axis index */
1207    int naxes;                    /* Number of Frame axes */
1208    int ok;                       /* Supplied points OK? */
1209 
1210 /* Initialise. */
1211    result = AST__BAD;
1212 
1213 /* Check the global error status. */
1214    if ( !astOK ) return result;
1215 
1216 /* Assume everything is ok */
1217    ok = 1;
1218 
1219 /* Obtain the number of Frame axes. */
1220    naxes = astGetNaxes( this );
1221 
1222 /* Obtain workspace. */
1223    ab = (double *) astMalloc( sizeof(double)*naxes );
1224    cb = (double *) astMalloc( sizeof(double)*naxes );
1225 
1226 /* Check all positions are good, and form the vectors from b to a, and
1227    from b to c. Also find the squared length of each vector. */
1228    if( astOK ) {
1229       sla = 0.0;
1230       slc = 0.0;
1231       for( axis = 0; axis < naxes; axis++ ) {
1232          if( a[ axis ] == AST__BAD || b[ axis ] == AST__BAD ||
1233              c[ axis ] == AST__BAD ) {
1234             ok = 0;
1235             break;
1236          } else {
1237             ab[ axis ] = a[ axis ] - b[ axis ];
1238             cb[ axis ] = c[ axis ] - b[ axis ];
1239             sla += ( ab[ axis ] )*( ab[ axis ] );
1240             slc += ( cb[ axis ] )*( cb[ axis ] );
1241          }
1242       }
1243 
1244 /* Check that neither of the vectors have zero length. */
1245       if( sla == 0 || slc == 0 ) ok = 0;
1246 
1247 /* Only proceed if these checks were passed. */
1248       if ( ok ) {
1249 
1250 /* Deal first with 2-dimensional Frames. */
1251          if( naxes == 2 ) {
1252 
1253 /* Find the angle from +ve Y to the line BA. */
1254             anga = atan2( ab[ 0 ], ab[ 1 ] );
1255 
1256 /* Find the angle from +ve Y to the line BC. */
1257             angc = atan2( cb[ 0 ], cb[ 1 ] );
1258 
1259 /* Find the difference, folded into the range +/- PI. */
1260             result = palDrange( angc - anga );
1261 
1262 /* Now deal with Frames with more than 2 axes. */
1263          } else {
1264 
1265 /* Form the scalar product of the two vectors. */
1266             sp = 0.0;
1267             for( axis = 0; axis < naxes; axis++ ) {
1268                sp += ab[ axis ]*cb[ axis ];
1269             }
1270 
1271 /* Derive the required angle from the normalized scalar product. */
1272             cos = sp/sqrt( sla*slc );
1273             if( cos > 1.0 ) {
1274                cos = 1.0;
1275             } else if( cos < -1.0 ) {
1276                cos = -1.0;
1277             }
1278             result =acos( cos );
1279          }
1280       }
1281    }
1282 
1283 /* Free the work space. */
1284    ab = (double *) astFree( (void *) ab );
1285    cb = (double *) astFree( (void *) cb );
1286 
1287 /* Return the result. */
1288    return result;
1289 }
1290 
AxAngle(AstFrame * this,const double a[],const double b[],int axis,int * status)1291 static double AxAngle( AstFrame *this, const double a[], const double b[], int axis, int *status ) {
1292 /*
1293 *++
1294 *  Name:
1295 c     astAxAngle
1296 f     AST_AXANGLE
1297 
1298 *  Purpose:
1299 *     Returns the angle from an axis, to a line through two points.
1300 
1301 *  Type:
1302 *     Public virtual function.
1303 
1304 *  Synopsis:
1305 c     #include "frame.h"
1306 c     double astAxAngle( AstFrame *this, const double a[], const double b[], int axis )
1307 f     RESULT = AST_AXANGLE( THIS, A, B, AXIS, STATUS )
1308 
1309 *  Class Membership:
1310 *     Frame method.
1311 
1312 *  Description:
1313 c     This function
1314 f     This routine
1315 *     finds the angle, as seen from point A, between the positive
1316 *     direction of a specified axis, and the geodesic curve joining point
1317 *     A to point B.
1318 
1319 *  Parameters:
1320 c     this
1321 f     THIS = INTEGER (Given)
1322 *        Pointer to the Frame.
1323 c     a
1324 f     A( * ) = DOUBLE PRECISION (Given)
1325 c        An array of double, with one element for each Frame axis
1326 f        An array with one element for each Frame axis
1327 *        (Naxes attribute) containing the coordinates of the first point.
1328 c     b
1329 f     B( * ) = DOUBLE PRECISION (Given)
1330 c        An array of double, with one element for each Frame axis
1331 f        An array with one element for each Frame axis
1332 *        (Naxes attribute) containing the coordinates of the second point.
1333 c     axis
1334 f     AXIS = INTEGER (Given)
1335 *        The number of the Frame axis from which the angle is to be
1336 *        measured (axis numbering starts at 1 for the first axis).
1337 f     STATUS = INTEGER (Given and Returned)
1338 f        The global status.
1339 
1340 *  Returned Value:
1341 c     astAxAngle
1342 f     AST_AXANGLE = DOUBLE PRECISION
1343 *        The angle in radians, from the positive direction of the
1344 *        specified axis, to the line AB. If the Frame is 2-dimensional,
1345 *        it will be in the range [-PI/2,+PI/2], and positive rotation is in
1346 *        the same sense as rotation from the positive direction of axis 2
1347 *        to the positive direction of axis 1. If the Frame has more than 2
1348 *        axes, a positive value will always be returned in the range zero
1349 *        to PI.
1350 
1351 *  Notes:
1352 c     - The geodesic curve used by this function is the path of
1353 f     - The geodesic curve used by this routine is the path of
1354 *     shortest distance between two points, as defined by the
1355 c     astDistance function.
1356 f     AST_DISTANCE function.
1357 *     - This function will return "bad" coordinate values (AST__BAD)
1358 *     if any of the input coordinates has this value, or if the require
1359 *     position angle is undefined.
1360 *--
1361 */
1362 
1363 /* Local Variables: */
1364    double *aa;                   /* Pointer to third point */
1365    double ab;                    /* Absolute value of component */
1366    double mxab;                  /* Largest absolute value of component */
1367    double result;                /* The returned value */
1368    int iaxis;                    /* Axis index */
1369    int naxes;                    /* Number of Frame axes */
1370    int ok;                       /* Are values ok to use? */
1371 
1372 /* Initialise. */
1373    result = AST__BAD;
1374 
1375 /* Check the global error status. */
1376    if ( !astOK ) return result;
1377 
1378 /* Validate the axis index. */
1379    (void) astValidateAxis( this, axis - 1, 1, "astAxAngle" );
1380 
1381 /* Obtain the number of Frame axes. */
1382    naxes = astGetNaxes( this );
1383 
1384 /* Obtain workspace. */
1385    aa = (double *) astMalloc( sizeof(double)*naxes );
1386 
1387 /* Create a position which is offset slightly from point A in the
1388    positive direction of the specified axis. Also get the largest absolute
1389    value of any component of the vector AB. */
1390    if( astOK ) {
1391       ok = 1;
1392       mxab = 0.0;
1393 
1394       for( iaxis = 0; iaxis < naxes; iaxis++ ) {
1395          if( a[ iaxis ] != AST__BAD && b[ iaxis ] != AST__BAD ) {
1396             aa[ iaxis ] = a[ iaxis ];
1397             ab = fabs( a[ iaxis ] - b[ iaxis ] );
1398             if( ab > mxab ) mxab = ab;
1399          } else {
1400             ok = 0;
1401             break;
1402          }
1403       }
1404 
1405       if( ok ) {
1406 
1407          if( a[ axis - 1 ] != 0.0 ) {
1408             aa[ axis - 1 ] += 10000.0*DBL_EPSILON*fabs( a[ axis - 1 ] );
1409 
1410          } else if( b[ axis - 1 ] != 0.0 ) {
1411             aa[ axis - 1 ] = 10000.0*DBL_EPSILON*fabs( b[ iaxis - 1 ] );
1412 
1413          } else if( mxab != 0.0 ) {
1414             aa[ axis - 1 ] = 10000.0*DBL_EPSILON*mxab;
1415 
1416          } else {
1417             aa[ axis - 1 ] = 1.0;
1418          }
1419 
1420 /* Use astAngle to get the required angle. */
1421          result = astAngle( this, aa, a, b );
1422       }
1423    }
1424 
1425 /* Free the workspace. */
1426    aa = (double *) astFree( (void *) aa );
1427 
1428 /* Return the result. */
1429    return result;
1430 
1431 }
1432 
AxDistance(AstFrame * this,int axis,double v1,double v2,int * status)1433 static double AxDistance( AstFrame *this, int axis, double v1, double v2, int *status ) {
1434 /*
1435 *++
1436 *  Name:
1437 c     astAxDistance
1438 f     AST_AXDISTANCE
1439 
1440 *  Purpose:
1441 *     Find the distance between two axis values.
1442 
1443 *  Type:
1444 *     Public virtual function.
1445 
1446 *  Synopsis:
1447 c     #include "frame.h"
1448 c     double astAxDistance( AstFrame *this, int axis, double v1, double v2 )
1449 f     RESULT = AST_AXDISTANCE( THIS, AXIS, V1, V2, STATUS )
1450 
1451 *  Class Membership:
1452 *     Frame method.
1453 
1454 *  Description:
1455 c     This function returns a signed value representing the axis increment
1456 f     This routine returns a signed value representing the axis increment
1457 *     from axis value v1 to axis value v2.
1458 *
1459 *     For a simple Frame, this is a trivial operation returning the
1460 *     difference between the two axis values. But for other derived classes
1461 *     of Frame (such as a SkyFrame) this is not the case.
1462 
1463 *  Parameters:
1464 c     this
1465 f     THIS = INTEGER (Given)
1466 *        Pointer to the Frame.
1467 c     axis
1468 f     AXIS = INTEGER (Given)
1469 *        The index of the axis to which the supplied values refer. The
1470 *        first axis has index 1.
1471 c     v1
1472 f     V1 = DOUBLE PRECISION (Given)
1473 *        The first axis value.
1474 c     v2
1475 f     V2 = DOUBLE PRECISION (Given)
1476 *        The second axis value.
1477 f     STATUS = INTEGER (Given and Returned)
1478 f        The global status.
1479 
1480 *  Returned Value:
1481 c     astAxDistance
1482 f     AST_AXDISTANCE = DOUBLE PRECISION
1483 *        The distance from the first to the second axis value.
1484 
1485 *  Notes:
1486 *     - This function will return a "bad" result value (AST__BAD) if
1487 *     any of the input values has this value.
1488 *     - A "bad" value will also be returned if this function is
1489 c     invoked with the AST error status set, or if it should fail for
1490 f     invoked with STATUS set to an error value, or if it should fail for
1491 *     any reason.
1492 *--
1493 
1494 *  Implementation Deficiencies;
1495 *     - The protected interface for this function uses 1-based axis
1496 *     numbering (like the public interface), rather than the more usual
1497 *     zero-based system used by all other protected interfaces. There is
1498 *     no real reason for this, and it should be changed at some time.
1499 
1500 */
1501 
1502 /* Local Variables: */
1503    AstAxis *ax;                  /* Pointer to Axis object */
1504    double result;                /* The returned answer */
1505 
1506 /* Initialise. */
1507    result = AST__BAD;
1508 
1509 /* Check the global error status. */
1510    if ( !astOK ) return result;
1511 
1512 /* Validate the axis index and obtain a pointer to the required Axis. */
1513    (void) astValidateAxis( this, axis - 1, 1, "astAxDistance" );
1514    ax = astGetAxis( this, axis - 1 );
1515 
1516 /* Use the AxisDistance method associated with the Axis. */
1517    if( astOK ) result = astAxisDistance( ax, v1, v2 );
1518 
1519 /* Annul the Axis pointer. */
1520    ax = astAnnul( ax );
1521 
1522 /* Return the result. */
1523    return result;
1524 
1525 }
1526 
AxIn(AstFrame * this,int axis,double lo,double hi,double val,int closed,int * status)1527 static int AxIn( AstFrame *this, int axis, double lo, double hi, double val,
1528                  int closed, int *status ){
1529 /*
1530 *+
1531 *  Name:
1532 *     astAxIn
1533 
1534 *  Purpose:
1535 *     Test if an axis value lies within a given interval.
1536 
1537 *  Type:
1538 *     Protected virtual function.
1539 
1540 *  Synopsis:
1541 *     #include "frame.h"
1542 *     int astAxIn( AstFrame *this, int axis, double lo, double hi, double val,
1543 *                  int closed )
1544 
1545 *  Class Membership:
1546 *     Frame member function.
1547 
1548 *  Description:
1549 *     This function returns non-zero if a given axis values lies within a
1550 *     given axis interval.
1551 
1552 *  Parameters:
1553 *     this
1554 *        Pointer to the Frame.
1555 *     axis
1556 *        The index of the axis. The first axis has index 0.
1557 *     lo
1558 *        The lower axis limit of the interval.
1559 *     hi
1560 *        The upper axis limit of the interval.
1561 *     val
1562 *        The axis value to be tested.
1563 *     closed
1564 *        If non-zero, then the lo and hi axis values are themselves
1565 *        considered to be within the interval. Otherwise they are outside.
1566 
1567 *  Returned Value:
1568 *     Non-zero if the test value is inside the interval.
1569 
1570 *  Applicability:
1571 *     Frame
1572 *        Uses simple Euclidean test
1573 *     SkyFrame
1574 *        All angles which are numerically between "lo" and "hi" are within
1575 *        the interval. Angle outside this range are also within the interval
1576 *        if they can be brought into the range by addition or subtraction
1577 *        of a multiple of 2.PI.
1578 *-
1579 */
1580 
1581 /* Local Variables: */
1582    AstAxis *ax;                  /* Pointer to Axis object */
1583    int result;                   /* Returned value */
1584 
1585 /* For speed, omit the astOK check and axis validation (since this is
1586    protected code, AST should get it right). Obtain a pointer to the
1587    required Axis. */
1588    ax = astGetAxis( this, axis );
1589 
1590 /* Use the AxisIn method associated with the Axis. */
1591    result = ax ? astAxisIn( ax, lo, hi, val, closed ) : 0;
1592 
1593 /* Annul the Axis pointer. */
1594    ax = astAnnul( ax );
1595 
1596 /* Return the result. */
1597    return result;
1598 }
1599 
AxOffset(AstFrame * this,int axis,double v1,double dist,int * status)1600 static double AxOffset( AstFrame *this, int axis, double v1, double dist, int *status ) {
1601 /*
1602 *++
1603 *  Name:
1604 c     astAxOffset
1605 f     AST_AXOFFSET
1606 
1607 *  Purpose:
1608 *     Add an increment onto a supplied axis value.
1609 
1610 *  Type:
1611 *     Public virtual function.
1612 
1613 *  Synopsis:
1614 c     #include "frame.h"
1615 c     double astAxOffset( AstFrame *this, int axis, double v1, double dist )
1616 f     RESULT = AST_AXOFFSET( THIS, AXIS, V1, DIST, STATUS )
1617 
1618 *  Class Membership:
1619 *     Frame method.
1620 
1621 *  Description:
1622 c     This function returns an axis value formed by adding a signed axis
1623 f     This routine returns an axis value formed by adding a signed axis
1624 *     increment onto a supplied axis value.
1625 *
1626 *     For a simple Frame, this is a trivial operation returning the
1627 *     sum of the two supplied values. But for other derived classes
1628 *     of Frame (such as a SkyFrame) this is not the case.
1629 
1630 *  Parameters:
1631 c     this
1632 f     THIS = INTEGER (Given)
1633 *        Pointer to the Frame.
1634 c     axis
1635 f     AXIS = INTEGER (Given)
1636 *        The index of the axis to which the supplied values refer. The
1637 *        first axis has index 1.
1638 c     v1
1639 f     V1 = DOUBLE PRECISION (Given)
1640 *        The original axis value.
1641 c     dist
1642 f     DIST = DOUBLE PRECISION (Given)
1643 *        The axis increment to add to the original axis value.
1644 f     STATUS = INTEGER (Given and Returned)
1645 f        The global status.
1646 
1647 *  Returned Value:
1648 c     astAxOffset
1649 f     AST_AXOFFSET = DOUBLE PRECISION
1650 *        The incremented axis value.
1651 
1652 *  Notes:
1653 *     - This function will return a "bad" result value (AST__BAD) if
1654 *     any of the input values has this value.
1655 *     - A "bad" value will also be returned if this function is
1656 c     invoked with the AST error status set, or if it should fail for
1657 f     invoked with STATUS set to an error value, or if it should fail for
1658 *     any reason.
1659 *--
1660 */
1661 
1662 /* Local Variables: */
1663    AstAxis *ax;                  /* Pointer to Axis object */
1664    double result;                /* The returned answer */
1665 
1666 /* Initialise. */
1667    result = AST__BAD;
1668 
1669 /* Check the global error status. */
1670    if ( !astOK ) return result;
1671 
1672 /* Validate the axis index and obtain a pointer to the required Axis. */
1673    (void) astValidateAxis( this, axis - 1, 1, "astAxOffset" );
1674    ax = astGetAxis( this, axis - 1 );
1675 
1676 /* Use the AxisOffset method associated with the Axis. */
1677    if( astOK ) result = astAxisOffset( ax, v1, dist );
1678 
1679 /* Annul the Axis pointer. */
1680    ax = astAnnul( ax );
1681 
1682 /* Return the result. */
1683    return result;
1684 
1685 }
1686 
CheckPerm(AstFrame * this,const int * perm,const char * method,int * status)1687 static void CheckPerm( AstFrame *this, const int *perm, const char *method, int *status ) {
1688 /*
1689 *+
1690 *  Name:
1691 *     astCheckPerm
1692 
1693 *  Purpose:
1694 *     Check that an array contains a valid permutation.
1695 
1696 *  Type:
1697 *     Protected virtual function.
1698 
1699 *  Synopsis:
1700 *     #include "frame.h"
1701 *     void astCheckPerm( AstFrame *this, const int *perm, const char *method )
1702 
1703 *  Class Membership:
1704 *     Frame method.
1705 
1706 *  Description:
1707 *     This function checks the validity of a permutation array that
1708 *     will be used to permute the order of a Frame's axes. If the
1709 *     permutation specified by the array is not valid, an error is
1710 *     reported and the global error status is set. Otherwise, the
1711 *     function returns without further action.
1712 
1713 *  Parameters:
1714 *     this
1715 *        Pointer to the Frame.
1716 *     perm
1717 *        Pointer to an array of integers with the same number of
1718 *        elements as there are axes in the Frame. For each axis, the
1719 *        corresponding integer gives the (zero based) axis index to be
1720 *        used to identify the information for that axis (using the
1721 *        un-permuted axis numbering). To be valid, the integers in
1722 *        this array should therefore all lie in the range zero to
1723 *        (naxes-1) inclusive, where "naxes" is the number of Frame
1724 *        axes, and each value should occur exactly once.
1725 *     method
1726 *        Pointer to a constant null-terminated character string
1727 *        containing the name of the method that invoked this function
1728 *        to validate a permutation array. This method name is used
1729 *        solely for constructing error messages.
1730 
1731 *  Notes:
1732 *     - Error messages issued by this function refer to the external
1733 *     (public) numbering system used for axes (which is one-based),
1734 *     whereas zero-based axis indices are used internally.
1735 *-
1736 */
1737 
1738 /* Local Variables: */
1739    int *there;                   /* Pointer to temporary array */
1740    int axis;                     /* Loop counter for axes */
1741    int naxes;                    /* Number of Frame axes */
1742    int valid;                    /* Permutation array is valid? */
1743 
1744 /* Check the global error status. */
1745    if ( !astOK ) return;
1746 
1747 /* Initialise. */
1748    valid = 1;
1749 
1750 /* Obtain the number of Frame axes and allocate a temporary array of integers
1751    with the same number of elements. */
1752    naxes = astGetNaxes( this );
1753    there = astMalloc( sizeof( int ) * (size_t) naxes );
1754    if ( astOK ) {
1755 
1756 /* Initialise the temporary array to zero. */
1757       for ( axis = 0; axis < naxes; axis++ ) there[ axis ] = 0;
1758 
1759 /* Scan the permutation array, checking that each permuted axis index it
1760    contains is within the correct range. Note an error and quit checking
1761    if an invalid value is found. */
1762       for ( axis = 0; axis < naxes; axis++ ) {
1763          if ( ( perm[ axis ] < 0 ) || ( perm[ axis ] >= naxes ) ) {
1764             valid = 0;
1765             break;
1766 
1767 /* Use the temporary array to count how many times each valid axis index
1768    occurs. */
1769 	 } else {
1770             there[ perm[ axis ] ]++;
1771 	 }
1772       }
1773 
1774 /* If all the axis indices were within range, check to ensure that each value
1775    occurred only once. */
1776       if ( valid ) {
1777          for ( axis = 0; axis < naxes; axis++ ) {
1778 
1779 /* Note an error and quit checking if any value did not occur exactly once. */
1780             if ( there[ axis ] != 1 ) {
1781                valid = 0;
1782                break;
1783 	    }
1784 	 }
1785       }
1786    }
1787 
1788 /* Free the temporary array. */
1789    there = astFree( there );
1790 
1791 /* If an invalid permutation was detected and no other error has
1792    occurred, then report an error (note we convert to one-based axis
1793    numbering in the error message). */
1794    if ( !valid && astOK ) {
1795       astError( AST__PRMIN, "%s(%s): Invalid axis permutation array.", status,
1796                 method, astGetClass( this ) );
1797       astError( AST__PRMIN, "Each axis index should lie in the range 1 to %d "
1798                 "and should occur only once.", status, naxes );
1799    }
1800 }
1801 
CleanAttribs(AstObject * this_object,int * status)1802 static void CleanAttribs( AstObject *this_object, int *status ) {
1803 /*
1804 *  Name:
1805 *     CleanAttribs
1806 
1807 *  Purpose:
1808 *     Clear any invalid set attribute values.
1809 
1810 *  Type:
1811 *     Private function.
1812 
1813 *  Synopsis:
1814 *     #include "frame.h"
1815 *     void CleanAttribs( AstObject *this_object, int *status )
1816 
1817 *  Class Membership:
1818 *     Frame member function (over-rides the protected astCleanAttribs
1819 *     method inherited from the Object class).
1820 
1821 *  Description:
1822 *     This function clears any attributes that are currently set to
1823 *     invalid values in thr supplied object.
1824 
1825 *  Parameters:
1826 *     this
1827 *        Pointer to the Object to be cleaned.
1828 
1829 */
1830 
1831 /* Local Variables; */
1832    AstAxis *ax;
1833    AstFrame *this;
1834    int i;
1835    int nax;
1836    int reporting;
1837 
1838 /* Check inherited status */
1839    if( !astOK ) return;
1840 
1841 /* Get a pointer to the Frame structure. */
1842    this = (AstFrame *) this_object;
1843 
1844 /* Defer error reporting, as required by the astCLEAN_ATTRIB macro. */
1845    reporting = astReporting( 0 );
1846 
1847 /* Clean attributes in any Objects contained within "this". */
1848    nax = astGetNaxes( this );
1849    for( i = 0; i < nax; i++ ) {
1850       ax = astGetAxis( this, i );
1851       astCleanAttribs( ax );
1852       ax = astAnnul( ax );
1853    }
1854 
1855 /* Clean attributes of this class. */
1856    astCLEAN_ATTRIB(System)
1857    astCLEAN_ATTRIB(AlignSystem)
1858 
1859 /* Re-establish error reporting. */
1860    astReporting( reporting );
1861 
1862 /* Invoke the method inherited form the parent to clean attributes
1863    defined by the parent class. */
1864    (*parent_cleanattribs)( this_object, status );
1865 }
1866 
CleanDomain(char * domain,int * status)1867 static char *CleanDomain( char *domain, int *status ) {
1868 /*
1869 *  Name:
1870 *     CleanDomain
1871 
1872 *  Purpose:
1873 *     Clean a Domain string and convert to upper case.
1874 
1875 *  Type:
1876 *     Private function.
1877 
1878 *  Synopsis:
1879 *     #include "frame.h"
1880 *     char *CleanDomain( char *domain, int *status )
1881 
1882 *  Class Membership:
1883 *     Frame member function.
1884 
1885 *  Description:
1886 *     This function removes all white space from a string and converts
1887 *     other characters to upper case. It is intended for cleaning up
1888 *     values supplied for the Domain attribute of a Frame.
1889 
1890 *  Parameters:
1891 *     domain
1892 *        Pointer to the null terminated Domain string to be modified.
1893 *     status
1894 *        Pointer to the inherited status variable.
1895 
1896 *  Returned Value:
1897 *     The pointer value "domain" is always returned (even under error
1898 *     conditions).
1899 */
1900 
1901 /* Local Variables: */
1902    int i;                        /* Loop counter for characters */
1903    int j;                        /* Good character count */
1904 
1905 /* Check the global error status. */
1906    if ( !astOK ) return domain;
1907 
1908 /* Eliminate white space characters and convert the rest to upper
1909    case. */
1910    for ( i = j = 0; domain[ i ]; i++ ) {
1911       if ( !isspace( domain[ i ] ) ) domain[ j++ ] = toupper( domain[ i ] );
1912    }
1913    domain[ j ] = '\0';
1914 
1915 /* Return the string pointer. */
1916    return domain;
1917 }
1918 
ClearAttrib(AstObject * this_object,const char * attrib,int * status)1919 static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
1920 /*
1921 *  Name:
1922 *     ClearAttrib
1923 
1924 *  Purpose:
1925 *     Clear an attribute value for a Frame.
1926 
1927 *  Type:
1928 *     Private function.
1929 
1930 *  Synopsis:
1931 *     #include "frame.h"
1932 *     void ClearAttrib( AstObject *this, const char *attrib, int *status )
1933 
1934 *  Class Membership:
1935 *     Frame member function (over-rides the astClearAttrib protected
1936 *     method inherited from the Mapping class).
1937 
1938 *  Description:
1939 *     This function clears the value of a specified attribute for a
1940 *     Frame, so that the default value will subsequently be used.
1941 
1942 *  Parameters:
1943 *     this
1944 *        Pointer to the Frame.
1945 *     attrib
1946 *        Pointer to a null terminated string specifying the attribute
1947 *        name.  This should be in lower case with no surrounding white
1948 *        space.
1949 *     status
1950 *        Pointer to the inherited status variable.
1951 
1952 *  Notes:
1953 *     - This function uses one-based axis numbering so that it is
1954 *     suitable for external (public) use.
1955 */
1956 
1957 /* Local Variables: */
1958    AstAxis *ax;                  /* Pointer to Axis */
1959    AstFrame *pfrm;               /* Pointer to primary Frame containing axis */
1960    AstFrame *this;               /* Pointer to the Frame structure */
1961    char pfrm_attrib[ 100 ];      /* Primary Frame attribute */
1962    char *axis_attrib;            /* Pointer to axis attribute name */
1963    const char *old_attrib;       /* Pointer to supplied attribute name string */
1964    int axis;                     /* Frame axis number */
1965    int axis_nc;                  /* No. characters in axis attribute name */
1966    int free_axis_attrib;         /* Should axis_attrib be freed? */
1967    int has_axis;                 /* Does attrib name include axis specifier? */
1968    int len;                      /* Length of attrib string */
1969    int nc;                       /* No. characters read by astSscanf */
1970    int oldrep;                   /* Original error reporting state */
1971    int paxis;                    /* Axis index within primary frame */
1972    int used;                     /* Could the setting string be used? */
1973 
1974 /* Check the global error status. */
1975    if ( !astOK ) return;
1976 
1977 /* Obtain a pointer to the Frame structure. */
1978    this = (AstFrame *) this_object;
1979 
1980 /* Set a flag indicating if the attribute name includes an axis
1981    specifier. */
1982    has_axis = ( strchr( attrib, '(' ) != NULL );
1983 
1984 /* A flag indicating that we do not need to free the axis_attrib memory. */
1985    free_axis_attrib = 0;
1986 
1987 /* Initialise things to avoid compiler warnings. */
1988    axis_attrib = NULL;
1989    old_attrib = NULL;
1990 
1991 /* Jump back to here if we are trying the same attribute but with an explicit
1992    axis "(1)" added to the end of the name. */
1993 L1:
1994 
1995 /* Obtain the length of the "attrib" string. */
1996    len = strlen( attrib );
1997 
1998 /* Check the attribute name and clear the appropriate attribute. */
1999 
2000 /* Digits. */
2001 /* ------- */
2002    if ( !strcmp( attrib, "digits" ) ) {
2003       astClearDigits( this );
2004 
2005 /* Digits(axis). */
2006 /* ------------- */
2007    } else if ( nc = 0,
2008                ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) )
2009                && ( nc >= len ) ) {
2010 
2011 /* There is no function to clear the Digits attribute for an axis
2012    directly, so obtain a pointer to the Axis and use this to clear the
2013    attribute. */
2014       (void) astValidateAxis( this, axis - 1, 1, "astClearDigits(axis)" );
2015       ax = astGetAxis( this, axis - 1 );
2016       astClearAxisDigits( ax );
2017       ax = astAnnul( ax );
2018 
2019 /* Direction(axis). */
2020 /* ---------------- */
2021    } else if ( nc = 0,
2022                ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) )
2023                && ( nc >= len ) ) {
2024       astClearDirection( this, axis - 1 );
2025 
2026 /* Epoch. */
2027 /* ------ */
2028    } else if ( !strcmp( attrib, "epoch" ) ) {
2029       astClearEpoch( this );
2030 
2031 /* Top(axis). */
2032 /* ---------- */
2033    } else if ( nc = 0,
2034                ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) )
2035                && ( nc >= len ) ) {
2036       astClearTop( this, axis - 1 );
2037 
2038 /* Bottom(axis). */
2039 /* ------------- */
2040    } else if ( nc = 0,
2041                ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) )
2042                && ( nc >= len ) ) {
2043       astClearBottom( this, axis - 1 );
2044 
2045 /* Domain. */
2046 /* ------- */
2047    } else if ( !strcmp( attrib, "domain" ) ) {
2048       astClearDomain( this );
2049 
2050 /* Format(axis). */
2051 /* ------------- */
2052    } else if ( nc = 0,
2053                ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) )
2054                && ( nc >= len ) ) {
2055       astClearFormat( this, axis - 1 );
2056 
2057 /* Label(axis). */
2058 /* ------------ */
2059    } else if ( nc = 0,
2060                ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) )
2061                && ( nc >= len ) ) {
2062       astClearLabel( this, axis - 1 );
2063 
2064 /* MatchEnd. */
2065 /* --------- */
2066    } else if ( !strcmp( attrib, "matchend" ) ) {
2067       astClearMatchEnd( this );
2068 
2069 /* MaxAxes. */
2070 /* -------- */
2071    } else if ( !strcmp( attrib, "maxaxes" ) ) {
2072       astClearMaxAxes( this );
2073 
2074 /* MinAxes. */
2075 /* -------- */
2076    } else if ( !strcmp( attrib, "minaxes" ) ) {
2077       astClearMinAxes( this );
2078 
2079 /* Permute. */
2080 /* -------- */
2081    } else if ( !strcmp( attrib, "permute" ) ) {
2082       astClearPermute( this );
2083 
2084 /* PreserveAxes. */
2085 /* ------------- */
2086    } else if ( !strcmp( attrib, "preserveaxes" ) ) {
2087       astClearPreserveAxes( this );
2088 
2089 /* Symbol(axis). */
2090 /* ------------- */
2091    } else if ( nc = 0,
2092                ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) )
2093                && ( nc >= len ) ) {
2094       astClearSymbol( this, axis - 1 );
2095 
2096 /* System. */
2097 /* ------- */
2098    } else if ( !strcmp( attrib, "system" ) ) {
2099       astClearSystem( this );
2100 
2101 /* AlignSystem. */
2102 /* ------------ */
2103    } else if ( !strcmp( attrib, "alignsystem" ) ) {
2104       astClearAlignSystem( this );
2105 
2106 /* Title. */
2107 /* ------ */
2108    } else if ( !strcmp( attrib, "title" ) ) {
2109       astClearTitle( this );
2110 
2111 /* Unit(axis). */
2112 /* ----------- */
2113    } else if ( nc = 0,
2114                ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) )
2115                && ( nc >= len ) ) {
2116       astClearUnit( this, axis - 1 );
2117 
2118 /* ObsLat. */
2119 /* ------- */
2120    } else if ( !strcmp( attrib, "obslat" ) ) {
2121       astClearObsLat( this );
2122 
2123 /* ObsLon. */
2124 /* ------- */
2125    } else if ( !strcmp( attrib, "obslon" ) ) {
2126       astClearObsLon( this );
2127 
2128 /* ObsAlt. */
2129 /* ------- */
2130    } else if ( !strcmp( attrib, "obsalt" ) ) {
2131       astClearObsAlt( this );
2132 
2133 /* Dut1 */
2134 /* --- */
2135    } else if ( !strcmp( attrib, "dut1" ) ) {
2136       astClearDut1( this );
2137 
2138 /* Read-only attributes. */
2139 /* --------------------- */
2140 /* Test if the attribute name matches any of the read-only attributes
2141    of this class. If it does, then report an error. */
2142    } else if ( !strcmp( attrib, "naxes" ) ||
2143                !strncmp( attrib, "normunit", 8 ) ) {
2144       astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" "
2145                 "value for a %s.", status, attrib, astGetClass( this ) );
2146       astError( AST__NOWRT, "This is a read-only attribute." , status);
2147 
2148 /* Other axis attributes. */
2149 /* ---------------------- */
2150 /* If the attribute was not identified above, but appears to refer to
2151    a Frame axis, then it may refer to an Axis object of a derived type
2152    (which has additional attributes not recognised here). */
2153    } else if( !free_axis_attrib && ( nc = 0,
2154                  ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n",
2155                                       &axis_nc, &axis, &nc ) )
2156                && ( nc >= len ) ) ) {
2157 
2158 /* Validate the axis index and extract the attribute name. */
2159       (void) astValidateAxis( this, axis - 1, 1, "astClear" );
2160       axis_attrib = astString( attrib, axis_nc );
2161 
2162 /* Obtain a pointer to the Axis object. */
2163       ax = astGetAxis( this, axis - 1 );
2164       if( astOK ) {
2165 
2166 /* Assume that we will be able to use the attribute name. */
2167          used = 1;
2168 
2169 /* Temporarily switch off error reporting so that if the following attempt
2170    to access the axis attribute fails, we can try to interpret the
2171    attribute name as an attribute of the primary Frame containing the
2172    specified axis. Any errors reported in this context will simply be
2173    ignored, in particularly they are not deferred for later delivery. */
2174          oldrep = astReporting( 0 );
2175 
2176 /* Use the Axis astClearAttrib method to clear the attribute value. */
2177          astClearAttrib( ax, axis_attrib );
2178 
2179 /* If the above call failed with a status of AST__BADAT, indicating that
2180    the attribute name was not recognised, clear the status so that we can
2181    try to interpret the attribute name as an attribute of the primary Frame
2182    containing the specified axis. */
2183          if( astStatus == AST__BADAT ) {
2184             astClearStatus;
2185 
2186 /* Find the primary Frame containing the specified axis. */
2187             astPrimaryFrame( this, axis - 1, &pfrm, &paxis );
2188 
2189 /* Only attempt to use the primary Frame if it is not the same as "this"
2190    - otherwise we could end up in an infinite loop. */
2191             if( pfrm != this ) {
2192 
2193 /* astPrimaryFrame returns the original - unpermuted - axis index within
2194    the primary Frame. So we need to take into account any axis permutation
2195    which has been applied to the primary Frame when forming the attribute name
2196    to use below. Find the permuted (external) axis index which corresponds to
2197    the internal (unpermuted) axis index "paxis". */
2198                paxis = astValidateAxis( pfrm, paxis, 0, "astClear" );
2199 
2200 /* Modify the attribute name to refer to the axis numbering of the
2201    primary frame. */
2202                sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 );
2203 
2204 /* Attempt to clear the attribute as an attribute of the primary Frame. */
2205                astClearAttrib( pfrm, pfrm_attrib );
2206 
2207 /* If this failed, clear the status and indicate that we have not managed to
2208    use the attribute name. */
2209                if( !astOK ) {
2210                   astClearStatus;
2211                   used = 0;
2212                }
2213 
2214             } else {
2215                used = 0;
2216             }
2217 
2218 /* If not found attempt to clear the attribute value in the Axis, omitting
2219    the axis index. */
2220             if( ! used ) {
2221                astClearAttrib( pfrm, axis_attrib );
2222                if( !astOK ) {
2223                   astClearStatus;
2224                } else {
2225                   used = 1;
2226                }
2227             }
2228 
2229 /* Annul the primary Frame pointer. */
2230             pfrm = astAnnul( pfrm );
2231          }
2232 
2233 /* Re-instate the original error reporting state. */
2234          astReporting( oldrep );
2235 
2236 /* If we could not use the attribute name, attempt to clear the axis
2237    attribute again, this time retaining the error report. This is done
2238    to ensure the user gets an appropriate error message. */
2239          if( !used ) astClearAttrib( ax, axis_attrib );
2240       }
2241 
2242 /* Annul the Axis pointer and free the memory holding the attribute
2243    name. */
2244       ax = astAnnul( ax );
2245       axis_attrib = astFree( axis_attrib );
2246 
2247 /* Not recognised. */
2248 /* --------------- */
2249 /* If the attribute is still not recognised, and the Frame has only 1 axis,
2250    and the attribute name does not already include an axis specifier, try
2251    again after appending "(1)" to the end of the attribute name. */
2252    } else if( !has_axis && astGetNaxes( this ) == 1 ) {
2253 
2254 /* Take a copy of the supplied name, allowing 3 extra characters for the
2255    axis specifier "(1)". */
2256       axis_attrib = astMalloc( len + 4 );
2257       if( axis_attrib ) memcpy( axis_attrib, attrib, len );
2258 
2259 /* Indicate we should free the axis_attrib memory. */
2260       free_axis_attrib = 1;
2261 
2262 /* Add in the axis specifier. */
2263       strcpy( axis_attrib + len, "(1)" );
2264 
2265 /* Use the new attribute name instead of the supplied name. */
2266       old_attrib = attrib;
2267       attrib = axis_attrib;
2268 
2269 /* Indicate the attribute name now has an axis specifier. */
2270       has_axis = 1;
2271 
2272 /* Jump back to try interpreting the new attribute name. */
2273       goto L1;
2274 
2275 /* Not recognised. */
2276 /* --------------- */
2277 /* If the attribute name is still not recognised, pass it on to the parent
2278    method for further interpretation. First re-instate the original attrib
2279    name string if it was changed above. */
2280    } else {
2281       if( free_axis_attrib ) {
2282          attrib = old_attrib;
2283          axis_attrib = astFree( axis_attrib );
2284       }
2285       (*parent_clearattrib)( this_object, attrib, status );
2286    }
2287 }
2288 
ClearUnit(AstFrame * this,int axis,int * status)2289 static void ClearUnit( AstFrame *this, int axis, int *status ) {
2290 /*
2291 *  Name:
2292 *     ClearUnit
2293 
2294 *  Purpose:
2295 *     Clear the Unit attribute of a Frame.
2296 
2297 *  Type:
2298 *     Protected virtual function.
2299 
2300 *  Synopsis:
2301 *     #include "frame.h"
2302 *     void ClearUnit( AstFrame *this, int axis, int *status )
2303 
2304 *  Class Membership:
2305 *     Frame method.
2306 
2307 *  Description:
2308 *     This function clears the Unit value for an axis of a Frame.
2309 
2310 *  Parameters:
2311 *     this
2312 *        Pointer to the Frame.
2313 *     axis
2314 *        The number of the axis (zero-based) for which the Unit value is to
2315 *        be cleared.
2316 *     unit
2317 *        The new value to be set.
2318 *     status
2319 *        Pointer to the inherited status variable.
2320 
2321 *  Returned Value:
2322 *     void.
2323 */
2324 
2325 /* Local Variables: */
2326    AstAxis *ax;                  /* Pointer to Axis object */
2327    const char *units;            /* Pointer to units string */
2328    char *old_units;              /* Pointer to copy of original units */
2329 
2330 /* Check the global error status. */
2331    if ( !astOK ) return;
2332 
2333 /* Validate the axis index. */
2334    (void) astValidateAxis( this, axis, 1, "astSetUnit" );
2335 
2336 /* Do nothing more if the attribute is already cleared. */
2337    if( astTestUnit( this, axis ) ) {
2338 
2339 /* Obtain a pointer to the required Axis. */
2340       ax = astGetAxis( this, axis );
2341 
2342 /* Save a copy of the old units. */
2343       units = astGetAxisUnit( ax );
2344       old_units = astStore( NULL, units, strlen( units ) + 1 );
2345 
2346 /* Clear the Axis Unit attribute value, and then get a pointer to the
2347    new default Units string. */
2348       astClearAxisUnit( ax );
2349       units = astGetUnit( this, axis );
2350 
2351 /* The new unit may require the Label and/or Symbol to be changed, but
2352    only if the Frames ActiveUnit flag is set. */
2353       if( astGetActiveUnit( this ) ) NewUnit( ax, old_units, units,
2354                                               "astSetUnit", astGetClass( this ), status );
2355 
2356 /* Free resources. */
2357       old_units = astFree( old_units );
2358 
2359 /* Annul the Axis pointer. */
2360       ax = astAnnul( ax );
2361    }
2362 }
2363 
ConsistentMaxAxes(AstFrame * this,int value,int * status)2364 static int ConsistentMaxAxes( AstFrame *this, int value, int *status ) {
2365 /*
2366 *  Name:
2367 *     ConsistentMaxAxes
2368 
2369 *  Purpose:
2370 *     Ensure a consistent value when setting the MaxAxes attribute.
2371 
2372 *  Type:
2373 *     Private function.
2374 
2375 *  Synopsis:
2376 *     #include "frame.h"
2377 *     int ConsistentMaxAxes( AstFrame *this, int value, int *status )
2378 
2379 *  Class Membership:
2380 *     Frame member function.
2381 
2382 *  Description:
2383 *     This function accepts a value which is to be set for a Frame's MaxAxes
2384 *     attribute and returns an appropriately adjusted value to be assigned
2385 *     to the Frame structure's max_axes component. If necessary, the Frame's
2386 *     MinAxes attribute is adjusted to remain consistent with the new MaxAxes
2387 *     value (but note that the MaxAxes value itself is not assigned by this
2388 *     function).
2389 
2390 *  Parameters:
2391 *     this
2392 *        Pointer to the Frame.
2393 *     value
2394 *        The new value being set for the MaxAxes attribute.
2395 *     status
2396 *        Pointer to the inherited status variable.
2397 
2398 *  Returned Value:
2399 *     The value to be assigned to the max_axes component.
2400 
2401 *  Notes:
2402 *     - A value of -INT_MAX will be returned if this function is
2403 *     invoked with the global error status set, or if it should fail
2404 *     for any reason.
2405 */
2406 
2407 /* Local Variables: */
2408    int result;                   /* Result to be returned */
2409 
2410 /* Check the global error status. */
2411    if ( !astOK ) return -INT_MAX;
2412 
2413 /* Ensure that the result value isn't negative. */
2414    result = ( value >= 0 ) ? value : 0;
2415 
2416 /* Check if the MinAxes attribute is set. If not, its default value will be
2417    consistent with the MaxAxes value (the DefaultMinAxes function ensures
2418    this). Otherwise, obtain its value to check for consistency. */
2419    if ( astTestMinAxes( this ) ) {
2420 
2421 /* If necessary, set a new MinAxes value to prevent it exceeding the MaxAxes
2422    value about to be returned. */
2423       if ( astGetMinAxes( this ) > result ) astSetMinAxes( this, result );
2424    }
2425 
2426 /* If an error occurred, clear the result value. */
2427    if ( !astOK ) result = -INT_MAX;
2428 
2429 /* Return the result. */
2430    return result;
2431 }
2432 
ConsistentMinAxes(AstFrame * this,int value,int * status)2433 static int ConsistentMinAxes( AstFrame *this, int value, int *status ) {
2434 /*
2435 *  Name:
2436 *     ConsistentMinAxes
2437 
2438 *  Purpose:
2439 *     Ensure a consistent value when setting the MinAxes attribute.
2440 
2441 *  Type:
2442 *     Private function.
2443 
2444 *  Synopsis:
2445 *     #include "frame.h"
2446 *     int ConsistentMinAxes( AstFrame *this, int value, int *status )
2447 
2448 *  Class Membership:
2449 *     Frame member function.
2450 
2451 *  Description:
2452 *     This function accepts a value which is to be set for a Frame's MinAxes
2453 *     attribute and returns an appropriately adjusted value to be assigned
2454 *     to the Frame structure's min_axes component. If necessary, the Frame's
2455 *     MaxAxes attribute is adjusted to remain consistent with the new MinAxes
2456 *     value (but note that the MinAxes value itself is not assigned by this
2457 *     function).
2458 
2459 *  Parameters:
2460 *     this
2461 *        Pointer to the Frame.
2462 *     value
2463 *        The new value being set for the MinAxes attribute.
2464 *     status
2465 *        Pointer to the inherited status variable.
2466 
2467 *  Returned Value:
2468 *     The value to be assigned to the min_axes component.
2469 
2470 *  Notes:
2471 *     - A value of -INT_MAX will be returned if this function is
2472 *     invoked with the global error status set, or if it should fail
2473 *     for any reason.
2474 */
2475 
2476 /* Local Variables: */
2477    int result;                   /* Result to be returned */
2478 
2479 /* Check the global error status. */
2480    if ( !astOK ) return -INT_MAX;
2481 
2482 /* Ensure that the result value isn't negative. */
2483    result = ( value >= 0 ) ? value : 0;
2484 
2485 /* Check if the MaxAxes attribute is set. If not, its default value will be
2486    consistent with the MinAxes value (the DefaultMaxAxes function ensures
2487    this). Otherwise, obtain its value to check for consistency. */
2488    if ( astTestMaxAxes( this ) ) {
2489 
2490 /* If necessary, set a new MaxAxes value to prevent it being less than the
2491    MinAxes value about to be returned. */
2492       if ( astGetMaxAxes( this ) < result ) astSetMaxAxes( this, result );
2493    }
2494 
2495 /* If an error occurred, clear the result value. */
2496    if ( !astOK ) result = -INT_MAX;
2497 
2498 /* Return the result. */
2499    return result;
2500 }
2501 
Convert(AstFrame * from,AstFrame * to,const char * domainlist,int * status)2502 static AstFrameSet *Convert( AstFrame *from, AstFrame *to,
2503                              const char *domainlist, int *status ) {
2504 /*
2505 *++
2506 *  Name:
2507 c     astConvert
2508 f     AST_CONVERT
2509 
2510 *  Purpose:
2511 *     Determine how to convert between two coordinate systems.
2512 
2513 *  Type:
2514 *     Public virtual function.
2515 
2516 *  Synopsis:
2517 c     #include "frame.h"
2518 c     AstFrameSet *astConvert( AstFrame *from, AstFrame *to,
2519 c                              const char *domainlist )
2520 f     RESULT = AST_CONVERT( FROM, TO, DOMAINLIST, STATUS )
2521 
2522 *  Class Membership:
2523 *     Frame method.
2524 
2525 *  Description:
2526 *     This function compares two Frames and determines whether it is
2527 *     possible to convert between the coordinate systems which they
2528 *     represent. If conversion is possible, it returns a FrameSet
2529 *     which describes the conversion and which may be used (as a
2530 *     Mapping) to transform coordinate values in either direction.
2531 *
2532 *     The same function may also be used to determine how to convert
2533 *     between two FrameSets (or between a Frame and a FrameSet, or
2534 *     vice versa). This mode is intended for use when (for example)
2535 *     two images have been calibrated by attaching a FrameSet to each.
2536 c     astConvert might then be used to search for a
2537 f     AST_CONVERT might then be used to search for a
2538 *     celestial coordinate system that both images have in common, and
2539 *     the result could then be used to convert between the pixel
2540 *     coordinates of both images -- having effectively used their
2541 *     celestial coordinate systems to align them.
2542 *
2543 *     When using FrameSets, there may be more than one possible
2544 *     intermediate coordinate system in which to perform the
2545 *     conversion (for instance, two FrameSets might both have
2546 *     celestial coordinates, detector coordinates, pixel coordinates,
2547 *     etc.). A comma-separated list of coordinate system domains may
2548 *     therefore be given which defines a priority order to use when
2549 *     selecting the intermediate coordinate system.  The path used for
2550 *     conversion must go via an intermediate coordinate system whose
2551 *     Domain attribute matches one of the domains given. If conversion
2552 *     cannot be achieved using the first domain, the next one is
2553 *     considered, and so on, until success is achieved.
2554 
2555 *  Parameters:
2556 c     from
2557 f     FROM = INTEGER (Given)
2558 *        Pointer to a Frame which represents the "source" coordinate
2559 *        system.  This is the coordinate system in which you already
2560 *        have coordinates available.
2561 *
2562 *        If a FrameSet is given, its current Frame (as determined by
2563 *        its Current attribute) is taken to describe the source
2564 *        coordinate system. Note that the Base attribute of this
2565 *        FrameSet may be modified by this function to indicate which
2566 *        intermediate coordinate system was used (see under
2567 *        "FrameSets" in the "Applicability" section for details).
2568 c     to
2569 f     TO = INTEGER (Given)
2570 *        Pointer to a Frame which represents the "destination"
2571 *        coordinate system. This is the coordinate system into which
2572 *        you wish to convert your coordinates.
2573 *
2574 *        If a FrameSet is given, its current Frame (as determined by
2575 *        its Current attribute) is taken to describe the destination
2576 *        coordinate system. Note that the Base attribute of this
2577 *        FrameSet may be modified by this function to indicate which
2578 *        intermediate coordinate system was used (see under
2579 *        "FrameSets" in the "Applicability" section for details).
2580 c     domainlist
2581 f     DOMAINLIST = CHARACTER * ( * ) (Given)
2582 c        Pointer to a null-terminated character string containing a
2583 f        A character string containing a
2584 *        comma-separated list of Frame domains. This may be used to
2585 *        define a priority order for the different intermediate
2586 *        coordinate systems that might be used to perform the
2587 *        conversion.
2588 *
2589 *        The function will first try to obtain a conversion by making
2590 *        use only of an intermediate coordinate system whose Domain
2591 *        attribute matches the first domain in this list. If this
2592 *        fails, the second domain in the list will be used, and so on,
2593 *        until conversion is achieved. A blank domain (e.g. two
2594 *        consecutive commas) indicates that all coordinate systems
2595 *        should be considered, regardless of their domains.
2596 *
2597 *        This list is case-insensitive and all white space is ignored.
2598 *        If you do not wish to restrict the domain in this way,
2599 c        you should supply an empty string. This is normally
2600 f        you should supply a blank string. This is normally
2601 *        appropriate if either of the source or destination coordinate
2602 *        systems are described by Frames (rather than FrameSets),
2603 *        since there is then usually only one possible choice of
2604 *        intermediate coordinate system.
2605 f     STATUS = INTEGER (Given and Returned)
2606 f        The global status.
2607 
2608 *  Returned Value:
2609 c     astConvert()
2610 f     AST_CONVERT = INTEGER
2611 *        If the requested coordinate conversion is possible, the
2612 *        function returns a pointer to a FrameSet which describes the
2613 *        conversion. Otherwise, a null Object pointer (AST__NULL) is
2614 *        returned without error.
2615 *
2616 *        If a FrameSet is returned, it will contain two Frames. Frame
2617 *        number 1 (its base Frame) will describe the source coordinate
2618 c        system, corresponding to the "from" parameter. Frame number 2
2619 f        system, corresponding to the FROM argument. Frame number 2
2620 *        (its current Frame) will describe the destination coordinate
2621 c        system, corresponding to the "to" parameter. The Mapping
2622 f        system, corresponding to the TO argument. The Mapping
2623 *        which inter-relates these two Frames will perform the
2624 *        required conversion between their respective coordinate
2625 *        systems.
2626 *
2627 *        Note that a FrameSet may be used both as a Mapping and as a
2628 *        Frame.  If the result is used as a Mapping (e.g. with
2629 c        astTran2), then it provides a means of converting coordinates
2630 f        AST_TRAN2), then it provides a means of converting coordinates
2631 *        from the source to the destination coordinate system (or
2632 *        vice versa if its inverse transformation is selected). If it
2633 *        is used as a Frame, its attributes will describe the
2634 *        destination coordinate system.
2635 
2636 *  Applicability:
2637 *     DSBSpecFrame
2638 *        If the AlignSideBand attribute is non-zero, alignment occurs in the
2639 *        upper sideband expressed within the spectral system and standard of
2640 *        rest given by attributes AlignSystem and AlignStdOfRest. If
2641 *        AlignSideBand is zero, the two DSBSpecFrames are aligned as if
2642 *        they were simple SpecFrames (i.e. the SideBand is ignored).
2643 *     Frame
2644 *        This function applies to all Frames. Alignment occurs within the
2645 *        coordinate system given by attribute AlignSystem.
2646 *     FrameSet
2647 c        If either of the "from" or "to" parameters is a pointer to a
2648 f        If either of the FROM or TO arguments is a pointer to a
2649 c        FrameSet, then astConvert will attempt to convert from the
2650 f        FrameSet, then AST_CONVERT will attempt to convert from the
2651 c        coordinate system described by the current Frame of the "from"
2652 f        coordinate system described by the current Frame of the FROM
2653 c        FrameSet to that described by the current Frame of the "to"
2654 f        FrameSet to that described by the current Frame of the TO
2655 *        FrameSet.
2656 *
2657 *        To achieve this, it will consider all of the Frames within
2658 *        each FrameSet as a possible way of reaching an intermediate
2659 *        coordinate system that can be used for the conversion. There
2660 *        is then the possibility that more than one conversion path
2661 *        may exist and, unless the choice is sufficiently restricted
2662 c        by the "domainlist" string, the sequence in which the Frames
2663 f        by the DOMAINLIST string, the sequence in which the Frames
2664 *        are considered can be important. In this case, the search
2665 *        for a conversion path proceeds as follows:
2666 c        - Each field in the "domainlist" string is considered in turn.
2667 f        - Each field in the DOMAINLIST string is considered in turn.
2668 *        - The Frames within each FrameSet are considered in a
2669 *        specific order: (1) the base Frame is always considered
2670 *        first, (2) after this come all the other Frames in
2671 *        Frame-index order (but omitting the base and current Frames),
2672 *        (3) the current Frame is always considered last.  However, if
2673 *        either FrameSet's Invert attribute is set to a non-zero value
2674 *        (so that the FrameSet is inverted), then its Frames are
2675 *        considered in reverse order. (Note that this still means that
2676 *        the base Frame is considered first and the current Frame
2677 *        last, because the Invert value will also cause these Frames
2678 *        to swap places.)
2679 *        - All source Frames are first considered (in the appropriate
2680 *        order) for conversion to the first destination Frame. If no
2681 *        suitable intermediate coordinate system emerges, they are
2682 *        then considered again for conversion to the second
2683 *        destination Frame (in the appropriate order), and so on.
2684 *        - Generally, the first suitable intermediate coordinate
2685 *        system found is used. However, the overall Mapping between
2686 *        the source and destination coordinate systems is also
2687 *        examined.  Preference is given to cases where both the
2688 *        forward and inverse transformations are defined (as indicated
2689 *        by the TranForward and TranInverse attributes). If only one
2690 *        transformation is defined, the forward one is preferred.
2691 *        - If the domain of the intermediate coordinate system matches
2692 c        the current "domainlist" field, the conversion path is
2693 f        the current DOMAINLIST field, the conversion path is
2694 c        accepted. Otherwise, the next "domainlist" field is considered
2695 f        accepted. Otherwise, the next DOMAINLIST field is considered
2696 *        and the process repeated.
2697 *
2698 *        If conversion is possible, the Base attributes of the two
2699 *        FrameSets will be modified on exit to identify the Frames
2700 *        used to access the intermediate coordinate system which was
2701 *        finally accepted.
2702 *
2703 *        Note that it is possible to force a particular Frame within a
2704 *        FrameSet to be used as the basis for the intermediate
2705 *        coordinate system, if it is suitable, by (a) focussing
2706 *        attention on
2707 c        it by specifying its domain in the "domainlist" string, or (b)
2708 f        it by specifying its domain in the DOMAINLIST string, or (b)
2709 *        making it the base Frame, since this is always considered
2710 *        first.
2711 *     SpecFrame
2712 *        Alignment occurs within the spectral system and standard of rest
2713 *        given by attributes AlignSystem and AlignStdOfRest.
2714 *     TimeFrame
2715 *        Alignment occurs within the time system and time scale given by
2716 *        attributes AlignSystem and AlignTimeScale.
2717 
2718 *  Examples:
2719 c     cvt = astConvert( a, b, "" );
2720 f     CVT = AST_CONVERT( A, B, ' ', STATUS )
2721 *        Attempts to convert between the coordinate systems represented
2722 c        by "a" and "b" (assumed to be Frames). If successful, a FrameSet
2723 f        by A and B (assumed to be Frames). If successful, a FrameSet
2724 c        is returned via the "cvt" pointer which may be used to apply the
2725 f        is returned via the CVT pointer which may be used to apply the
2726 c        conversion to sets of coordinates (e.g. using astTran2).
2727 f        conversion to sets of coordinates (e.g. using AST_TRAN2).
2728 c     cvt = astConvert( astSkyFrame(""), astSkyFrame("Equinox=2005"), "" );
2729 f     CVT = AST_CONVERT( AST_SKYFRAME( ' ', STATUS ), AST_SKYFRAME( 'Equinox=2005', STATUS ), ' ', STATUS )
2730 *        Creates a FrameSet which describes precession in the default
2731 *        FK5 celestial coordinate system between equinoxes J2000 (also
2732 c        the default) and J2005. The returned "cvt" pointer may then
2733 f        the default) and J2005. The returned CVT pointer may then
2734 c        be passed to astTran2 to apply this precession correction to
2735 f        be passed to AST_TRAN2 to apply this precession correction to
2736 *        any number of coordinate values given in radians.
2737 *
2738 *        Note that the returned FrameSet also contains information
2739 *        about how to format coordinate values. This means that
2740 *        setting its Report attribute to 1 is a simple way to obtain
2741 *        printed output (formatted in sexagesimal notation) to show
2742 *        the coordinate values before and after conversion.
2743 c     cvt = astConvert( a, b, "sky,detector," );
2744 f     CVT = AST_CONVERT( A, B, 'SKY,DETECTOR,', STATUS )
2745 *        Attempts to convert between the coordinate systems
2746 c        represented by the current Frames of "a" and "b"
2747 f        represented by the current Frames of A and B
2748 *        (now assumed to be FrameSets), via the intermediate "SKY"
2749 *        coordinate system.  This, by default, is the Domain
2750 *        associated with a celestial coordinate system represented by
2751 *        a SkyFrame.
2752 *
2753 *        If this fails (for example, because either FrameSet lacks
2754 *        celestial coordinate information), then the user-defined
2755 *        "DETECTOR" coordinate system is used instead. If this also
2756 *        fails, then all other possible ways of achieving conversion
2757 *        are considered before giving up.
2758 *
2759 c        The returned pointer "cvt" indicates whether conversion was
2760 f        The returned pointer CVT indicates whether conversion was
2761 *        possible and will have the value AST__NULL if it was not. If
2762 c        conversion was possible, "cvt" will point at a new FrameSet
2763 f        conversion was possible, CVT will point at a new FrameSet
2764 *        describing the conversion.
2765 *
2766 *        The Base attributes of the two FrameSets
2767 c        will be set by astConvert to indicate which of their Frames was
2768 f        will be set by AST_CONVERT to indicate which of their Frames was
2769 *        used for the intermediate coordinate system. This means that
2770 *        you can subsequently determine which coordinate system was
2771 *        used by enquiring the Domain attribute of either base Frame.
2772 
2773 *  Notes:
2774 *     -  The Mapping represented by the returned FrameSet results in
2775 *     alignment taking place in the coordinate system specified by the
2776 c     AlignSystem attribute of the "to" Frame. See the description of the
2777 f     AlignSystem attribute of the TO Frame. See the description of the
2778 *     AlignSystem attribute for further details.
2779 *     - When aligning (say) two images, which have been calibrated by
2780 *     attaching FrameSets to them, it is usually necessary to convert
2781 *     between the base Frames (representing "native" pixel
2782 *     coordinates) of both FrameSets. This may be achieved by
2783 *     inverting the FrameSets (e.g. using astInvert) so as to
2784 *     interchange their base and current Frames before using
2785 *     astConvert.
2786 *     - A null Object pointer (AST__NULL) will be returned if this
2787 c     function is invoked with the AST error status set, or if it
2788 f     function is invoked with STATUS set to an error value, or if it
2789 *     should fail for any reason.
2790 *--
2791 
2792 * Implementation Notes:
2793 *    This function is simply a wrap-up for the protected astConvertX
2794 *    method which performs the required processing but swaps the order
2795 *    of the first two arguments. This is a trick to allow the
2796 *    astConvert method to be over-ridden by derived classes on the
2797 *    basis of the class of either of the first two arguments.
2798 */
2799 
2800 /* Check the global error status. */
2801    if ( !astOK ) return NULL;
2802 
2803 /* Invoke the "astConvertX" method with the first two arguments
2804    swapped. */
2805    return astConvertX( to, from, domainlist );
2806 }
2807 
ConvertX(AstFrame * to,AstFrame * from,const char * domainlist,int * status)2808 static AstFrameSet *ConvertX( AstFrame *to, AstFrame *from,
2809                               const char *domainlist, int *status ) {
2810 /*
2811 *+
2812 *  Name:
2813 *     astConvertX
2814 
2815 *  Purpose:
2816 *     Determine how to convert between two coordinate systems.
2817 
2818 *  Type:
2819 *     Protected virtual function.
2820 
2821 *  Synopsis:
2822 *     #include "frame.h"
2823 *     AstFrameSet *astConvertX( AstFrame *to, AstFrame *from,
2824 *                               const char *domainlist )
2825 
2826 *  Class Membership:
2827 *     Frame method.
2828 
2829 *  Description:
2830 *     This function performs the processing for the public astConvert
2831 *     method and has exactly the same interface except that the order
2832 *     of the first two arguments is swapped. This is a trick to allow
2833 *     the astConvert method to be over-ridden by derived classes on
2834 *     the basis of the class of either of its first two arguments.
2835 *
2836 *     See the astConvert method for details of the interface.
2837 *-
2838 
2839 *  Implementation Deficiencies:
2840 *     - This function's job is basically to negotiate with two Frames
2841 *     to try and find a mutually agreeable coordinate system for
2842 *     conversion.  Ideally, it should be able to juggle the number of
2843 *     axes, etc. to do this.  At present, however, the implementation
2844 *     is much simpler. This is adequate for the Frame classes which
2845 *     exist at the time of writing, but the implementation may need
2846 *     beefing up in future.
2847 *     - One likely problem is with attributes which default in both
2848 *     the source and destination Frames. This means they also default
2849 *     in the common coordinate system. If these default values were to
2850 *     differ when matching different target Frames, however, we would
2851 *     be in trouble, because the common coordinate system would not
2852 *     then be remaining constant. The longer-term solution to this is
2853 *     probably to provide some mechanism to "fix" all attribute values
2854 *     for a Frame, by taking any attributes that are un-set and
2855 *     explicitly setting a firm value (equal to the default) so they
2856 *     cannot then change.
2857 */
2858 
2859 /* Local Variables: */
2860    AstFrameSet *result;          /* Pointer to Mapping to be returned */
2861    AstFrame *ftmp;                /* Pointer to returned Frame */
2862    AstMapping **map1_address;    /* Location of first Mapping pointer */
2863    AstMapping **map2_address;    /* Location of second Mapping pointer */
2864    AstMapping *common0;          /* Initial common coordinate system */
2865    AstMapping *common1;          /* Improved common coordinate system */
2866    AstMapping *common2;          /* Final common coordinate system */
2867    AstMapping *frame1;           /* Pointer to Frame for first match */
2868    AstMapping *frame2;           /* Pointer to Frame for second match */
2869    AstMapping *from_map;         /* Pointer to "from" Mapping */
2870    AstMapping *map;              /* Pointer to conversion Mapping */
2871    AstMapping *result_map;       /* Pointer to result Mapping */
2872    AstMapping *tmp;              /* Temporary Mapping pointer */
2873    AstMapping *to_map;           /* Pointer to "to" Mapping */
2874    char *domain;                 /* Pointer to result domain */
2875    char *domain_end;             /* Pointer to null at end of domain */
2876    char *domainlist_copy;        /* Pointer to copy of domainlist */
2877    int *axes1;                   /* Pointer to axis assignments */
2878    int *axes2;                   /* Pointer to axis assignments */
2879    int best_score;               /* Score assigned to best match */
2880    int icom;                     /* Common coordinate system loop counter */
2881    int match1;                   /* First match succeeded? */
2882    int match2;                   /* Second match succeeded? */
2883    int match;                    /* Overall match found? */
2884    int perfect;                  /* Perfect match found? */
2885    int score;                    /* Score assigned to match */
2886 
2887 /* Initialise. */
2888    result = NULL;
2889 
2890 /* Check the global error status. */
2891    if ( !astOK ) return result;
2892 
2893 /* Further initialisation. */
2894    result_map = NULL;
2895 
2896 /* Make a temporary copy of the domains list. */
2897    domainlist_copy = astStore( NULL, domainlist,
2898                                strlen( domainlist ) + (size_t) 1 );
2899    if ( astOK ) {
2900 
2901 /* Loop to inspect each comma-separated field in the domains list
2902    until an error occurs, all the domains are used up, or a match is
2903    found. */
2904       domain = domainlist_copy;
2905       match = 0;
2906       while ( astOK && domain && !match ) {
2907 
2908 /* Change the comma at the end of each field to a null to terminate
2909    the domain. Then convert the domain to upper case and eliminate
2910    white space. */
2911          if ( ( domain_end = strchr( domain, ',' ) ) ) *domain_end = '\0';
2912          CleanDomain( domain, status );
2913 
2914 /* For any given domain, we will ignore imperfect matches in favour of
2915    better ones by assigning a score to each match. Initialise the best
2916    score value for the current domain. */
2917          best_score = -1;
2918 
2919 /* Loop to consider both the "to" and "from" Frames in turn as the
2920    basis of a possible common coordinate system. Quit looping early if
2921    an error occurs or a perfect match is found. */
2922          perfect = 0;
2923          for ( icom = 0; astOK && !perfect && ( icom <= 1 ); icom++ ) {
2924 
2925 /* Make a copy of the Frame representing the initial guess at a common
2926    coordinate system. We will use this to probe the other
2927    Frame. Ensure that axes are not preserved (so that we convert to
2928    the common axis number/order). */
2929             common0 = astCopy( icom ? from : to );
2930             astSetPreserveAxes( common0, 0 );
2931 
2932 /* Also, if the current domain is not blank, set the Domain attribute (so
2933    we will only find coordinate systems which match the current
2934    "domainlist" field). */
2935             if ( *domain ) astSetDomain( common0, domain );
2936 
2937 /* Obtain a pointer to the other Frame. */
2938             frame1 = astClone( icom ? to : from );
2939 
2940 /* Set the address at which to store the resulting Mapping pointer. */
2941             map1_address = icom ? &to_map : &from_map;
2942 
2943 /* See if conversion from "frame1" to the common coordinate system is
2944    possible.  If successful, this results in a new approximation
2945    ("common1") to the possible common coordinate system. */
2946             match1 = astMatch( common0, frame1, 1, &axes1, &axes2,
2947                                map1_address, &ftmp );
2948             common1 = (AstMapping *) ftmp;
2949 
2950 /* If successful, free memory allocated for the axis association
2951    arrays, which are not needed. */
2952             if ( astOK && match1 ) {
2953                axes1 = astFree( axes1 );
2954                axes2 = astFree( axes2 );
2955 
2956 /* Using the improved approximation to the common coordinate system,
2957    now test if conversion from the alternative Frame "frame2" is
2958    possible. */
2959                frame2 = astClone( icom ? from : to );
2960                map2_address = icom ? &from_map : &to_map;
2961                astSetPreserveAxes( common1, 0 );
2962                match2 = astMatch( common1, frame2, 1, &axes1, &axes2,
2963                                   map2_address, &ftmp );
2964                common2 = (AstMapping *) ftmp;
2965 
2966 /* If successful, free memory allocated for the axis association
2967    arrays, which are not needed. */
2968                if ( astOK && match2 ) {
2969                   axes1 = astFree( axes1 );
2970                   axes2 = astFree( axes2 );
2971 
2972 /* Invert the "to" Mapping and concatenate the two Mappings to
2973    describe the conversion between the "from" and "to" Frames. Then
2974    simplify the result. */
2975                   astInvert( to_map );
2976                   tmp = (AstMapping *) astCmpMap( from_map, to_map, 1, "", status );
2977                   map = astSimplify( tmp );
2978                   tmp = astAnnul( tmp );
2979 
2980 /* Assign a score that favours Mappings with both transformations
2981    available over those with only one, and Mappings with only a
2982    forward transformation over those with only an inverse
2983    transformation. */
2984                   score = ( astGetTranForward( map ) ? 2 : 0 ) +
2985                           ( astGetTranInverse( map ) ? 1 : 0 );
2986 
2987 /* If the new score is better than the previous one (or is the first
2988    one), note that we have a possible match. */
2989                   if ( astOK && ( score > best_score ) ) {
2990                      match = 1;
2991 
2992 /* Update the best score and note if it indicates a perfect match (in
2993    which case we can stop searching at this point). */
2994                      best_score = score;
2995                      perfect = ( best_score >= 3 );
2996 
2997 /* Annul any previous result Mapping pointer and replace it with this
2998    better one. */
2999                      if ( result_map ) result_map = astAnnul( result_map );
3000                      result_map = astClone( map );
3001                   }
3002 
3003 /* Annul pointers to all the intermediate Objects. */
3004                   map = astAnnul( map );
3005                   common2 = astAnnul( common2 );
3006                   *map2_address = astAnnul( *map2_address );
3007                }
3008                frame2 = astAnnul( frame2 );
3009                common1 = astAnnul( common1 );
3010                *map1_address = astAnnul( *map1_address );
3011             }
3012             frame1 = astAnnul( frame1 );
3013             common0 = astAnnul( common0 );
3014          }
3015 
3016 /* Go on to consider the next field in the domains list. */
3017          domain = domain_end ? domain_end + 1 : NULL;
3018       }
3019    }
3020 
3021 /* Free the domain list copy. */
3022    domainlist_copy = astFree( domainlist_copy );
3023 
3024 /* If returning a result, build the result FrameSet. Then annul the
3025    result Mapping pointer. */
3026    if ( result_map ) {
3027       result = astFrameSet( from, "", status );
3028       astAddFrame( result, AST__BASE, result_map, to );
3029       result_map = astAnnul( result_map );
3030    }
3031 
3032 /* If an error occurred, annul the result FrameSet pointer. */
3033    if ( !astOK ) result = astAnnul( result );
3034 
3035 /* Return the result. */
3036    return result;
3037 }
3038 
DefaultMaxAxes(AstFrame * this,int * status)3039 static int DefaultMaxAxes( AstFrame *this, int *status ) {
3040 /*
3041 *  Name:
3042 *     DefaultMaxAxes
3043 
3044 *  Purpose:
3045 *     Obtain the MaxAxes attribute from a Frame structure, with defaulting.
3046 
3047 *  Type:
3048 *     Private function.
3049 
3050 *  Synopsis:
3051 *     #include "frame.h"
3052 *     int DefaultMaxAxes( AstFrame *this, int *status )
3053 
3054 *  Class Membership:
3055 *     Frame member function.
3056 
3057 *  Description:
3058 *     This function inspects the max_axes component of a Frame structure and
3059 *     derives a value for the MaxAxes attribute. If the component's value
3060 *     indicates that the attribute has not been set, a suitable default is
3061 *     returned which is consistent with the state of the Frames's MinAxes
3062 *     attribute.
3063 
3064 *  Parameters:
3065 *     this
3066 *        Pointer to the Frame.
3067 *     status
3068 *        Pointer to the inherited status variable.
3069 
3070 *  Returned Value:
3071 *     The value to be used for the MaxAxes attribute.
3072 */
3073 
3074 /* Local Variables. */
3075    int result;                   /* Result to be returned */
3076    int min_axes;                 /* Value of MinAxes attribute */
3077 
3078 /* Check the global error status. */
3079    if ( !astOK ) return 0;
3080 
3081 /* If the Frame's max_axes component is set, return its value. */
3082    if ( this->max_axes != -INT_MAX ) {
3083       result = this->max_axes;
3084 
3085 /* Otherwise, the preferred default value is the number of Frame axes. */
3086    } else {
3087       result = astGetNaxes( this );
3088 
3089 /* Before returning this value, check if the MinAxes attribute is set. If it
3090    is, obtain its value. */
3091       if ( astTestMinAxes( this ) ) {
3092          min_axes = astGetMinAxes( this );
3093 
3094 /* If necessary, increase the MaxAxes default value so that it is not less than
3095    MinAxes. */
3096          if ( result < min_axes ) result = min_axes;
3097       }
3098    }
3099 
3100 /* If an error occurred, clear the result value. */
3101    if ( !astOK ) result = 0;
3102 
3103 /* Return the result. */
3104    return result;
3105 }
3106 
DefaultMinAxes(AstFrame * this,int * status)3107 static int DefaultMinAxes( AstFrame *this, int *status ) {
3108 /*
3109 *  Name:
3110 *     DefaultMinAxes
3111 
3112 *  Purpose:
3113 *     Obtain the MinAxes attribute from a Frame structure, with defaulting.
3114 
3115 *  Type:
3116 *     Private function.
3117 
3118 *  Synopsis:
3119 *     #include "frame.h"
3120 *     int DefaultMinAxes( AstFrame *this, int *status )
3121 
3122 *  Class Membership:
3123 *     Frame member function.
3124 
3125 *  Description:
3126 *     This function inspects the min_axes component of a Frame structure and
3127 *     derives a value for the MinAxes attribute. If the component's value
3128 *     indicates that the attribute has not been set, a suitable default is
3129 *     returned which is consistent with the state of the Frames's MaxAxes
3130 *     attribute.
3131 
3132 *  Parameters:
3133 *     this
3134 *        Pointer to the Frame.
3135 *     status
3136 *        Pointer to the inherited status variable.
3137 
3138 *  Returned Value:
3139 *     The value to be used for the MinAxes attribute.
3140 */
3141 
3142 /* Local Variables: */
3143    int result;                   /* Result to be returned */
3144    int max_axes;                 /* Value of MaxAxes attribute */
3145 
3146 /* Check the global error status. */
3147    if ( !astOK ) return 0;
3148 
3149 /* If the Frame's min_axes component is set, return its value. */
3150    if ( this->min_axes != -INT_MAX ) {
3151       result = this->min_axes;
3152 
3153 /* Otherwise, the preferred default value is the number of Frame axes. */
3154    } else {
3155       result = astGetNaxes( this );
3156 
3157 /* Before returning this value, check if the MaxAxes attribute is set. If it
3158    is, obtain its value. */
3159       if ( astTestMaxAxes( this ) ) {
3160          max_axes = astGetMaxAxes( this );
3161 
3162 /* If necessary, reduce the MinAxes default value so that it does not exceed
3163    MaxAxes. */
3164          if ( result > max_axes ) result = max_axes;
3165       }
3166    }
3167 
3168 /* If an error occurred, clear the result value. */
3169    if ( !astOK ) result = 0;
3170 
3171 /* Return the result. */
3172    return result;
3173 }
3174 
Distance(AstFrame * this,const double point1[],const double point2[],int * status)3175 static double Distance( AstFrame *this,
3176                         const double point1[], const double point2[], int *status ) {
3177 /*
3178 *++
3179 *  Name:
3180 c     astDistance
3181 f     AST_DISTANCE
3182 
3183 *  Purpose:
3184 *     Calculate the distance between two points in a Frame.
3185 
3186 *  Type:
3187 *     Public virtual function.
3188 
3189 *  Synopsis:
3190 c     #include "frame.h"
3191 c     double astDistance( AstFrame *this,
3192 c                         const double point1[], const double point2[] )
3193 f     RESULT = AST_DISTANCE( THIS, POINT1, POINT2, STATUS )
3194 
3195 *  Class Membership:
3196 *     Frame method.
3197 
3198 *  Description:
3199 *     This function finds the distance between two points whose Frame
3200 *     coordinates are given. The distance calculated is that along
3201 *     the geodesic curve that joins the two points.
3202 *
3203 *     For example, in a basic Frame, the distance calculated will be
3204 *     the Cartesian distance along the straight line joining the two
3205 *     points. For a more specialised Frame describing a sky coordinate
3206 *     system, however, it would be the distance along the great circle
3207 *     passing through two sky positions.
3208 
3209 *  Parameters:
3210 c     this
3211 f     THIS = INTEGER (Given)
3212 *        Pointer to the Frame.
3213 c     point1
3214 f     POINT1( * ) = DOUBLE PRECISION (Given)
3215 c        An array of double, with one element for each Frame axis
3216 f        An array with one element for each Frame axis
3217 *        (Naxes attribute) containing the coordinates of the first point.
3218 c     point2
3219 f     POINT2( * ) = DOUBLE PRECISION (Given)
3220 c        An array of double, with one element for each Frame axis
3221 f        An array with one element for each Frame axis
3222 *        containing the coordinates of the second point.
3223 f     STATUS = INTEGER (Given and Returned)
3224 f        The global status.
3225 
3226 *  Returned Value:
3227 c     astDistance
3228 f     AST_DISTANCE = DOUBLE PRECISION
3229 *        The distance between the two points.
3230 
3231 *  Notes:
3232 *     - This function will return a "bad" result value (AST__BAD) if
3233 *     any of the input coordinates has this value.
3234 *     - A "bad" value will also be returned if this function is
3235 c     invoked with the AST error status set, or if it should fail for
3236 f     invoked with STATUS set to an error value, or if it should fail for
3237 *     any reason.
3238 *--
3239 */
3240 
3241 /* Local Variables: */
3242    double delta;                 /* Separation along an axis */
3243    double result;                /* Result value to return */
3244    int axis;                     /* Loop counter for axes */
3245    int naxes;                    /* Number of Frame axes */
3246 
3247 /* Initialise. */
3248    result = AST__BAD;
3249 
3250 /* Check the global error status. */
3251    if ( !astOK ) return result;
3252 
3253 /* Obtain the number of Frame axes. */
3254    naxes = astGetNaxes( this );
3255    if ( astOK ) {
3256 
3257 /* Loop to determine the Cartesian distance between the points. */
3258       result = 0.0;
3259       for ( axis = 0; axis < naxes; axis++ ) {
3260 
3261 /* If any of the coordinates supplied is bad, set the distance to be
3262    bad and quit looping. */
3263          if ( ( point1[ axis ] == AST__BAD ) ||
3264               ( point2[ axis ] == AST__BAD ) ) {
3265             result = AST__BAD;
3266             break;
3267 
3268 /* Otherwise, accumulate the sum of squared separations along each
3269    axis. */
3270          } else {
3271             delta = point1[ axis ] - point2[ axis ];
3272             result += ( delta * delta );
3273          }
3274       }
3275 
3276 /* Take the square root to find the distance (if valid). */
3277       if ( result != AST__BAD ) result = sqrt( result );
3278    }
3279 
3280 /* Return the result. */
3281    return result;
3282 }
3283 
DoNotSimplify(AstMapping * this,int * status)3284 static int DoNotSimplify( AstMapping *this, int *status ) {
3285 /*
3286 *  Name:
3287 *     DoNotSimplify
3288 
3289 *  Purpose:
3290 *     Check if a Mapping is appropriate for simplification.
3291 
3292 *  Type:
3293 *     Private function.
3294 
3295 *  Synopsis:
3296 *     #include "object.h"
3297 *     int DoNotSImplify( AstMapping *this );
3298 
3299 *  Class Membership:
3300 *     CmpMap member function (over-rides the astDoNotSimplify protected
3301 *     method inherited from the parent class).
3302 
3303 *  Description:
3304 *     This function returns a flag indivating if the supplied Mapping is
3305 *     appropriate for simplification.
3306 
3307 *  Parameters:
3308 *     this
3309 *        Pointer to the Mapping.
3310 *     status
3311 *        Pointer to the inherited status variable.
3312 
3313 *  Returned Value:
3314 *     Non-zero if the supplied Mapping is not appropriate for
3315 *     simplification, and zero otherwise.
3316 
3317 *  Notes:
3318 *     - A value of 0 will be returned if this function is invoked
3319 *     with the global error status set, or if it should fail for any
3320 *     reason.
3321 
3322 */
3323 
3324 /* Unlike basic Mappings, Frames that have a set value for the Ident
3325    can be simplified. So always return zero. */
3326    return 0;
3327 }
3328 
Equal(AstObject * this_object,AstObject * that_object,int * status)3329 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
3330 /*
3331 *  Name:
3332 *     Equal
3333 
3334 *  Purpose:
3335 *     Test if two Frames are equivalent.
3336 
3337 *  Type:
3338 *     Private function.
3339 
3340 *  Synopsis:
3341 *     #include "frame.h"
3342 *     int Equal( AstObject *this, AstObject *that, int *status )
3343 
3344 *  Class Membership:
3345 *     Frame member function (over-rides the astEqual protected
3346 *     method inherited from the Mapping class).
3347 
3348 *  Description:
3349 *     This function returns a boolean result (0 or 1) to indicate whether
3350 *     two Frames are equivalent.
3351 
3352 *  Parameters:
3353 *     this
3354 *        Pointer to the first Frame.
3355 *     that
3356 *        Pointer to the second Frame.
3357 *     status
3358 *        Pointer to the inherited status variable.
3359 
3360 *  Returned Value:
3361 *     One if the Frames are equivalent, zero otherwise.
3362 
3363 *  Notes:
3364 *     - The two Frames are considered equivalent if the Mapping between
3365 *     them is a UnitMap.
3366 *     - A value of zero will be returned if this function is invoked
3367 *     with the global status set, or if it should fail for any reason.
3368 */
3369 
3370 /* Local Variables: */
3371    AstFrame *that;            /* Pointer to the second Frame structure */
3372    AstFrame *this;            /* Pointer to the first Frame structure */
3373    AstFrameSet *fs;           /* FrameSet connecting the two Frames */
3374    AstMapping *map1;          /* Mapping connecting the two Frames */
3375    AstMapping *map2;          /* Simplified mapping connecting two Frames */
3376    int result;                /* Result value to return */
3377 
3378 /* Initialise. */
3379    result = 0;
3380 
3381 /* Check the global error status. */
3382    if ( !astOK ) return result;
3383 
3384 /* Checks that the second object is of the same class as the first . */
3385    if( !strcmp( astGetClass( this_object ), astGetClass( that_object ) ) ){
3386 
3387 /* Obtain pointers to the two Frame structures. */
3388       this = (AstFrame *) this_object;
3389       that = (AstFrame *) that_object;
3390 
3391 /* Get the Mapping between them, and see if it is a UnitMap. */
3392       fs = astConvert( that, this, "" );
3393       if( fs ) {
3394          map1 = astGetMapping( fs, AST__BASE, AST__CURRENT );
3395          map2 = astSimplify( map1 );
3396          result = astIsAUnitMap( map2 );
3397          map1 = astAnnul( map1 );
3398          map2 = astAnnul( map2 );
3399          fs = astAnnul( fs );
3400       }
3401    }
3402 
3403 /* If an error occurred, clear the result value. */
3404    if ( !astOK ) result = 0;
3405 
3406 /* Return the result, */
3407    return result;
3408 }
3409 
Fields(AstFrame * this,int axis,const char * fmt,const char * str,int maxfld,char ** fields,int * nc,double * val,int * status)3410 static int Fields( AstFrame *this, int axis, const char *fmt,
3411                    const char *str, int maxfld, char **fields,
3412                    int *nc, double *val, int *status ) {
3413 /*
3414 *+
3415 *  Name:
3416 *     astFields
3417 
3418 *  Purpose:
3419 *     Identify numerical fields within a formatted Axis value.
3420 
3421 *  Type:
3422 *     Protected virtual function.
3423 
3424 *  Synopsis:
3425 *     #include "frame.h"
3426 *     int astFields( AstFrame *this, int axis, const char *fmt,
3427 *                    const char *str, int maxfld, char **fields,
3428 *                    int *nc, double *val )
3429 
3430 *  Class Membership:
3431 *     Frame method.
3432 
3433 *  Description:
3434 *     This function identifies the numerical fields within a Frame axis
3435 *     value that has been formatted using astAxisFormat. It assumes that
3436 *     the value was formatted using the supplied format string. It also
3437 *     returns the equivalent floating point value.
3438 
3439 *  Parameters:
3440 *     this
3441 *        Pointer to the Frame.
3442 *     axis
3443 *        The number of the Frame axis for which the values have been
3444 *        formatted (axis numbering starts at zero for the first axis).
3445 *     fmt
3446 *        Pointer to a constant null-terminated string containing the
3447 *        format used when creating "str".
3448 *     str
3449 *        Pointer to a constant null-terminated string containing the
3450 *        formatted value.
3451 *     maxfld
3452 *        The maximum number of fields to identify within "str".
3453 *     fields
3454 *        A pointer to an array of at least "maxfld" character pointers.
3455 *        Each element is returned holding a pointer to the start of the
3456 *        corresponding field  in "str" (in the order in which they occur
3457 *        within "str"), or NULL if no corresponding field can be found.
3458 *     nc
3459 *        A pointer to an array of at least "maxfld" integers. Each
3460 *        element is returned holding the number of characters in the
3461 *        corresponding field, or zero if no corresponding field can be
3462 *        found.
3463 *     val
3464 *        Pointer to a location at which to store the value
3465 *        equivalent to the returned field values. If this is NULL,
3466 *        it is ignored.
3467 
3468 *  Returned Value:
3469 *     The number of fields succesfully identified and returned.
3470 
3471 *  Notes:
3472 *     - Leading and trailing spaces are ignored.
3473 *     - If the formatted value is not consistent with the supplied format
3474 *     string, then a value of zero will be returned, "fields" will be
3475 *     returned holding NULLs, "nc" will be returned holding zeros, and
3476 *     "val" is returned holding VAL__BAD.
3477 *     - Fields are counted from the start of the formatted string. If the
3478 *     string contains more than "maxfld" fields, then trailing fields are
3479 *     ignored.
3480 *     - If this function is invoked with the global error status set, or
3481 *     if it should fail for any reason, then a value of zero will be returned
3482 *     as the function value, and "fields", "nc" and "val"  will be returned
3483 *     holding their supplied values
3484 *-
3485 */
3486 
3487 /* Local Variables: */
3488    AstAxis *ax;                  /* Pointer to Axis object */
3489    int result;                   /* Result field count to return */
3490 
3491 /* Initialise. */
3492    result = 0;
3493 
3494 /* Check the global error status. */
3495    if ( !astOK ) return result;
3496 
3497 /* Validate the axis index and obtain a pointer to the required
3498    Axis. */
3499    (void) astValidateAxis( this, axis, 1, "astFields" );
3500    ax = astGetAxis( this, axis );
3501 
3502 /* Invoke the Axis astAxisFields method to perform the processing. */
3503    result = astAxisFields( ax, fmt, str, maxfld, fields, nc, val );
3504 
3505 /* Annul the Axis pointer. */
3506    ax = astAnnul( ax );
3507 
3508 /* If an error occurred, clear the returned value. */
3509    if ( !astOK ) result = 0;
3510 
3511 /* Return the result. */
3512    return result;
3513 }
3514 
FindFrame(AstFrame * target,AstFrame * template,const char * domainlist,int * status)3515 static AstFrameSet *FindFrame( AstFrame *target, AstFrame *template,
3516                                const char *domainlist, int *status ) {
3517 /*
3518 *++
3519 *  Name:
3520 c     astFindFrame
3521 f     AST_FINDFRAME
3522 
3523 *  Purpose:
3524 *     Find a coordinate system with specified characteristics.
3525 
3526 *  Type:
3527 *     Public virtual function.
3528 
3529 *  Synopsis:
3530 c     #include "frame.h"
3531 c     AstFrameSet *astFindFrame( AstFrame *target, AstFrame *template,
3532 c                                const char *domainlist )
3533 f     RESULT = AST_FINDFRAME( TARGET, TEMPLATE, DOMAINLIST, STATUS )
3534 
3535 *  Class Membership:
3536 *     Frame method.
3537 
3538 *  Description:
3539 *     This function uses a "template" Frame to search another Frame
3540 *     (or FrameSet) to identify a coordinate system which has a
3541 *     specified set of characteristics. If a suitable coordinate
3542 *     system can be found, the function returns a pointer to a
3543 *     FrameSet which describes the required coordinate system and how
3544 *     to convert coordinates to and from it.
3545 *
3546 *     This function is provided to help answer general questions about
3547 *     coordinate systems, such as typically arise when coordinate
3548 *     information is imported into a program as part of an initially
3549 *     unknown dataset. For example:
3550 *     - Is there a wavelength scale?
3551 *     - Is there a 2-dimensional coordinate system?
3552 *     - Is there a celestial coordinate system?
3553 *     - Can I plot the data in ecliptic coordinates?
3554 *
3555 *     You can also use this function as a means of reconciling a
3556 *     user's preference for a particular coordinate system (for
3557 *     example, what type of axes to draw) with what is actually
3558 *     possible given the coordinate information available.
3559 *
3560 *     To perform a search, you supply a "target" Frame (or FrameSet)
3561 *     which represents the set of coordinate systems to be searched.
3562 *     If a basic Frame is given as the target, this set of coordinate
3563 *     systems consists of the one described by this Frame, plus all
3564 *     other "virtual" coordinate systems which can potentially be
3565 *     reached from it by applying built-in conversions (for example,
3566 *     any of the celestial coordinate conversions known to the AST
3567 *     library would constitute a "built-in" conversion). If a FrameSet
3568 *     is given as the target, the set of coordinate systems to be
3569 *     searched consists of the union of those represented by all the
3570 *     individual Frames within it.
3571 *
3572 *     To select from this large set of possible coordinate systems,
3573 *     you supply a "template" Frame which is an instance of the type
3574 *     of Frame you are looking for. Effectively, you then ask the
3575 *     function to "find a coordinate system that looks like this".
3576 *
3577 *     You can make your request more or less specific by setting
3578 *     attribute values for the template Frame. If a particular
3579 *     attribute is set in the template, then the function will only
3580 *     find coordinate systems which have exactly the same value for
3581 *     that attribute.  If you leave a template attribute un-set,
3582 *     however, then the function has discretion about the value the
3583 *     attribute should have in any coordinate system it finds. The
3584 *     attribute will then take its value from one of the actual
3585 *     (rather than virtual) coordinate systems in the target. If the
3586 *     target is a FrameSet, its Current attribute will be modified to
3587 *     indicate which of its Frames was used for this purpose.
3588 *
3589 *     The result of this process is a coordinate system represented by
3590 *     a hybrid Frame which acquires some attributes from the template
3591 *     (but only if they were set) and the remainder from the
3592 *     target. This represents the "best compromise" between what you
3593 *     asked for and what was available. A Mapping is then generated
3594 *     which converts from the target coordinate system to this hybrid
3595 *     one, and the returned FrameSet encapsulates all of this
3596 *     information.
3597 
3598 *  Parameters:
3599 c     target
3600 f     TARGET = INTEGER (Given)
3601 *        Pointer to the target Frame (or FrameSet).
3602 *
3603 *        Note that if a FrameSet is supplied (and a suitable
3604 *        coordinate system is found), then its Current attribute will
3605 *        be modified to indicate which Frame was used to obtain
3606 *        attribute values which were not specified by the template.
3607 *        This Frame will, in some sense, represent the "closest"
3608 *        non-virtual coordinate system to the one you requested.
3609 c     template
3610 f     TEMPLATE = INTEGER (Given)
3611 *        Pointer to the template Frame, which should be an instance of
3612 *        the type of Frame you wish to find. If you wanted to find a
3613 *        Frame describing a celestial coordinate system, for example,
3614 *        then you might use a SkyFrame here. See the "Examples"
3615 *        section for more ideas.
3616 c     domainlist
3617 f     DOMAINLIST = CHARACTER * ( * ) (Given)
3618 c        Pointer to a null-terminated character string containing a
3619 f        A character string containing a
3620 *        comma-separated list of Frame domains. This may be used to
3621 *        establish a priority order for the different types of
3622 *        coordinate system that might be found.
3623 *
3624 *        The function will first try to find a suitable coordinate
3625 *        system whose Domain attribute equals the first domain in this
3626 *        list. If this fails, the second domain in the list will be
3627 *        used, and so on, until a result is obtained. A blank domain
3628 *        (e.g. two consecutive commas) indicates that any coordinate
3629 *        system is acceptable (subject to the template) regardless of
3630 *        its domain.
3631 *
3632 *        This list is case-insensitive and all white space is ignored.
3633 *        If you do not wish to restrict the domain in this way,
3634 c        you should supply an empty string.
3635 f        you should supply a blank string.
3636 f     STATUS = INTEGER (Given and Returned)
3637 f        The global status.
3638 
3639 *  Returned Value:
3640 c     astFindFrame()
3641 f     AST_FINDFRAME = INTEGER
3642 *        If the search is successful, the function returns a pointer
3643 *        to a FrameSet which contains the Frame found and a
3644 *        description of how to convert to (and from) the coordinate
3645 *        system it represents. Otherwise, a null Object pointer
3646 *        (AST__NULL) is returned without error.
3647 *
3648 *        If a FrameSet is returned, it will contain two Frames. Frame
3649 *        number 1 (its base Frame) represents the target coordinate
3650 *        system and will be the same as the (base Frame of the)
3651 *        target. Frame number 2 (its current Frame) will be a Frame
3652 *        representing the coordinate system which the function
3653 *        found. The Mapping which inter-relates these two Frames will
3654 *        describe how to convert between their respective coordinate
3655 *        systems.
3656 *
3657 *        Note that a FrameSet may be used both as a Mapping and as a
3658 *        Frame. If the result is used as a Mapping (e.g. with
3659 *        astTran2), then it provides a means of converting coordinates
3660 *        from the target coordinate system into the new coordinate
3661 *        system that was found (and vice versa if its inverse
3662 *        transformation is selected). If it is used as a Frame, its
3663 *        attributes will describe the new coordinate system.
3664 
3665 *  Applicability:
3666 *     Frame
3667 *        This function applies to all Frames.
3668 *     FrameSet
3669 *        If the target is a FrameSet, the possibility exists that
3670 *        several of the Frames within it might be matched by the
3671 *        template.  Unless the choice is sufficiently restricted by
3672 c        the "domainlist" string, the sequence in which Frames are
3673 f        the DOMAINLIST string, the sequence in which Frames are
3674 *        searched can then become important. In this case, the search
3675 *        proceeds as follows:
3676 c        - Each field in the "domainlist" string is considered in turn.
3677 f        - Each field in the DOMAINLIST string is considered in turn.
3678 *        - An attempt is made to match the template to each of the
3679 *        target's Frames in the order: (1) the current Frame, (2) the
3680 *        base Frame, (3) each remaining Frame in the order of being
3681 *        added to the target FrameSet.
3682 *        - Generally, the first match found is used. However, the
3683 *        Mapping between the target coordinate system and the
3684 *        resulting Frame is also examined. Preference is given to
3685 *        cases where both the forward and inverse transformations are
3686 *        defined (as indicated by the TranForward and TranInverse
3687 *        attributes). If only one transformation is defined, the
3688 *        forward one is preferred.
3689 *        - If a match is found and the domain of the resulting Frame also
3690 c        matches the current "domainlist" field, it is
3691 f        matches the current DOMAINLIST field, it is
3692 c        accepted. Otherwise, the next "domainlist" field is considered
3693 f        accepted. Otherwise, the next DOMAINLIST field is considered
3694 *        and the process repeated.
3695 *
3696 *        If a suitable coordinate system is found, the Current
3697 *        attribute of the target FrameSet will be modified on exit to
3698 *        identify the Frame whose match with the target was eventually
3699 *        accepted.
3700 
3701 *  Examples:
3702 c     result = astFindFrame( target, astFrame( 3, "" ), "" );
3703 f     RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 3, ' ', STATUS ), ' ', STATUS )
3704 *        Searches for a 3-dimensional coordinate system in the target
3705 *        Frame (or FrameSet). No attributes have been set in the
3706 c        template Frame (created by astFrame), so no restriction has
3707 f        template Frame (created by AST_FRAME), so no restriction has
3708 *        been placed on the required coordinate system, other than
3709 *        that it should have 3 dimensions. The first suitable Frame
3710 c        found will be returned as part of the "result" FrameSet.
3711 f        found will be returned as part of the RESULT FrameSet.
3712 c     result = astFindFrame( target, astSkyFrame( "" ), "" );
3713 f     RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( ' ', STATUS ), ' ', STATUS )
3714 *        Searches for a celestial coordinate system in the target
3715 *        Frame (or FrameSet). The type of celestial coordinate system
3716 c        is unspecified, so astFindFrame will return the first one
3717 f        is unspecified, so AST_FINDFRAME will return the first one
3718 c        found as part of the "result" FrameSet. If the target is
3719 f        found as part of the RESULT FrameSet. If the target is
3720 *        a FrameSet, then its Current attribute will be updated to
3721 *        identify the Frame that was used.
3722 *
3723 *        If no celestial coordinate system can be found, a value of
3724 *        AST__NULL will be returned without error.
3725 c     result = astFindFrame( target, astSkyFrame( "MaxAxes=100" ), "" );
3726 f     RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'MaxAxes=100', STATUS ), ' ', STATUS )
3727 *        This is like the last example, except that in the event of the
3728 *        target being a CmpFrame, the component Frames encapsulated by the
3729 *        CmpFrame will be searched for a SkyFrame. If found, the returned
3730 *        Mapping will included a PermMap which selects the required axes
3731 *        from the target CmpFrame.
3732 *
3733 *        This is acomplished by setting the MaxAxes attribute of the
3734 *        template SkyFrame to a large number (larger than or equal to the
3735 *        number of axes in the target CmpFrame). This allows the SkyFrame
3736 *        to be used as a match for Frames containing from 2 to 100 axes.
3737 c     result = astFindFrame( target, astSkyFrame( "System=FK5" ), "" );
3738 f     RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'System=FK5', STATUS ), ' ', STATUS )
3739 *        Searches for an equatorial (FK5) coordinate system in the
3740 *        target. The Equinox value for the coordinate system has not
3741 *        been specified, so will be obtained from the target. If the
3742 *        target is a FrameSet, its Current attribute will be updated
3743 *        to indicate which SkyFrame was used to obtain this value.
3744 c     result = astFindFrame( target, astFrame( 2, "" ), "sky,pixel," );
3745 f     RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 2, ' ', STATUS ), 'SKY,PIXEL,', STATUS )
3746 *        Searches for a 2-dimensional coordinate system in the
3747 *        target. Initially, a search is made for a suitable coordinate
3748 *        system whose Domain attribute has the value "SKY". If this
3749 *        search fails, a search is then made for one with the domain
3750 *        "PIXEL". If this also fails, then any 2-dimensional
3751 c        coordinate system is returned as part of the "result"
3752 f        coordinate system is returned as part of the RESULT
3753 *        FrameSet.
3754 *
3755 *        Only if no 2-dimensional coordinate systems can be reached by
3756 *        applying built-in conversions to any of the Frames in the
3757 *        target will a value of AST__NULL be returned.
3758 c     result = astFindFrame( target, astFrame( 1, "Domain=WAVELENGTH" ), "" );
3759 f     RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, 'Domain=WAVELENGTH', STATUS ), ' ', STATUS )
3760 *        Searches for any 1-dimensional coordinate system in the
3761 *        target which has the domain "WAVELENGTH".
3762 c     result = astFindFrame( target, astFrame( 1, "" ), "wavelength" );
3763 f     RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, ' ', STATUS ), 'WAVELENGTH', STATUS )
3764 *        This example has exactly the same effect as that above. It
3765 *        illustrates the equivalence of the template's Domain attribute
3766 c        and the fields in the "domainlist" string.
3767 f        and the fields in the DOMAINLIST string.
3768 c     result = astFindFrame( target, astFrame( 1, "MaxAxes=3" ), "" );
3769 f     RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, 'MaxAxes=3', STATUS ), ' ', STATUS )
3770 *        This is a more advanced example which will search for any
3771 *        coordinate system in the target having 1, 2 or 3
3772 c        dimensions. The Frame returned (as part of the "result"
3773 f        dimensions. The Frame returned (as part of the RESULT
3774 *        FrameSet) will always be 1-dimensional, but will be related
3775 *        to the coordinate system that was found by a suitable Mapping
3776 *        (e.g. a PermMap) which simply extracts the first axis.
3777 *
3778 *        If we had wanted a Frame representing the actual (1, 2 or
3779 *        3-dimensional) coordinate system found, we could set the
3780 *        PreserveAxes attribute to a non-zero value in the template.
3781 c     result = astFindFrame( target, astSkyFrame( "Permute=0" ), "" );
3782 f     RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'Permute=0', STATUS ), ' ', STATUS )
3783 *        Searches for any celestial coordinate system in the target,
3784 *        but only finds one if its axes are in the conventional
3785 *        (longitude,latitude) order and have not been permuted
3786 c        (e.g. with astPermAxes).
3787 f        (e.g. with AST_PERMAXES).
3788 
3789 *  Notes:
3790 *     -  The Mapping represented by the returned FrameSet results in
3791 *     alignment taking place in the coordinate system specified by the
3792 c     AlignSystem attribute of the "template" Frame. See the description
3793 f     AlignSystem attribute of the TEMPLATE Frame. See the description
3794 *     of the AlignSystem attribute for further details.
3795 *     - Beware of setting the Domain attribute of the template and then
3796 c     using a "domainlist" string which does not include the template's domain
3797 f     using a DOMAINLIST string which does not include the template's domain
3798 *     (or a blank field). If you do so, no coordinate system will be
3799 *     found.
3800 *     - A null Object pointer (AST__NULL) will be returned if this
3801 c     function is invoked with the AST error status set, or if it
3802 f     function is invoked with STATUS set to an error value, or if it
3803 *     should fail for any reason.
3804 
3805 *  More on Using Templates:
3806 *     A Frame (describing a coordinate system) will be found by this
3807 *     function if (a) it is "matched" by the template you supply, and
3808 c     (b) the value of its Domain attribute appears in the "domainlist"
3809 f     (b) the value of its Domain attribute appears in the DOMAINLIST
3810 *     string (except that a blank field in this string permits any
3811 *     domain). A successful match by the template depends on a number
3812 *     of criteria, as outlined below:
3813 *     - In general, a template will only match another Frame which
3814 *     belongs to the same class as the template, or to a derived (more
3815 *     specialised) class. For example, a SkyFrame template will match
3816 *     any other SkyFrame, but will not match a basic
3817 *     Frame. Conversely, a basic Frame template will match any class
3818 *     of Frame.
3819 *     - The exception to this is that a Frame of any class can be used to
3820 *     match a CmpFrame, if that CmpFrame contains a Frame of the same
3821 *     class as the template. Note however, the MaxAxes and MinAxes
3822 *     attributes of the template must be set to suitable values to allow
3823 *     it to match the CmpFrame. That is, the MinAxes attribute must be
3824 *     less than or equal to the number of axes in the target, and the MaxAxes
3825 *     attribute must be greater than or equal to the number of axes in
3826 *     the target.
3827 *     - If using a CmpFrame as a template frame, the MinAxes and MaxAxes
3828 *     for the template are determined by the MinAxes and MaxAxes values of
3829 *     the component Frames within the template. So if you want a template
3830 *     CmpFrame to be able to match Frames with different numbers of axes,
3831 *     then you must set the MaxAxes and/or MinAxes attributes in the component
3832 *     template Frames, before combining them together into the template
3833 *     CmpFrame.
3834 *     - If a template has a value set for any of its main attributes, then
3835 *     it will only match Frames which have an identical value for that
3836 *     attribute (or which can be transformed, using a built-in
3837 *     conversion, so that they have the required value for that
3838 *     attribute). If any attribute in the template is un-set, however,
3839 *     then Frames are matched regardless of the value they may have
3840 *     for that attribute. You may therefore make a template more or
3841 *     less specific by choosing the attributes for which you set
3842 *     values. This requirement does not apply to 'descriptive' attributes
3843 *     such as titles, labels, symbols, etc.
3844 *     - An important application of this principle involves the Domain
3845 *     attribute. Setting the Domain attribute of the template has the
3846 *     effect of restricting the search to a particular type of Frame
3847 *     (with the domain you specify).  Conversely, if the Domain
3848 *     attribute is not set in the template, then the domain of the
3849 *     Frame found is not relevant, so all Frames are searched.  Note
3850 *     that the
3851 c     "domainlist" string provides an alternative way of restricting the
3852 f     DOMAINLIST string provides an alternative way of restricting the
3853 *     search in the same manner, but is a more convenient interface if
3854 *     you wish to search automatically for another domain if the first
3855 *     search fails.
3856 *     - Normally, a template will only match a Frame which has the
3857 *     same number of axes as itself. However, for some classes of
3858 *     template, this default behaviour may be changed by means of the
3859 *     MinAxes, MaxAxes and MatchEnd attributes. In addition, the
3860 *     behaviour of a template may be influenced by its Permute and
3861 *     PreserveAxes attributes, which control whether it matches Frames
3862 *     whose axes have been permuted, and whether this permutation is
3863 *     retained in the Frame which is returned (as opposed to returning
3864 *     the axes in the order specified in the template, which is the
3865 *     default behaviour). You should consult the descriptions of these
3866 *     attributes for details of this more advanced use of templates.
3867 *--
3868 */
3869 
3870 /* Local Variables: */
3871    AstFrame *frame;              /* Pointer to result Frame */
3872    AstFrameSet *result;          /* Pointer to result FrameSet */
3873    AstMapping *map;              /* Pointer to result Mapping */
3874    AstMapping *tmp;              /* Temporary Mapping pointer */
3875    char *domain_copy;            /* Pointer to copy of result domain */
3876    char *domainlist_copy;        /* Pointer to copy of domains list */
3877    const char *domain;           /* Pointer to result Domain value */
3878    int *target_axes;             /* Pointer to target axis assignments */
3879    int *template_axes;           /* Pointer to template axis assignments */
3880    int i;                        /* Loop counter for characters */
3881    int j;                        /* Character index */
3882    int match;                    /* Template matched target? */
3883 
3884 /* Initialise. */
3885    result = NULL;
3886 
3887 /* Check the global error status. */
3888    if ( !astOK ) return result;
3889 
3890 /* Allocate space to store a copy of the domains list, with added
3891    commas. */
3892    domainlist_copy = astMalloc( strlen( domainlist ) + (size_t) 3 );
3893    if ( astOK ) {
3894 
3895 /* Make a copy of the domains list, with an extra comma added at each
3896    end. Also remove all white space and convert to upper case. */
3897       domainlist_copy[ 0 ] = ',';
3898       for ( i = 0, j = 1; domainlist[ i ]; i++ ) {
3899          if ( !isspace( domainlist[ i ] ) ) {
3900             domainlist_copy[ j++ ] = toupper( domainlist[ i ] );
3901          }
3902       }
3903       domainlist_copy[ j++ ] = ',';
3904       domainlist_copy[ j ] = '\0';
3905 
3906 /* Invoke the protected astMatch method associated with the template
3907    Frame. This matches the template to the target and returns
3908    information about how to convert between the target and the Frame
3909    it found (if any). */
3910       match = astMatch( template, target, 0,
3911                         &template_axes, &target_axes, &map, &frame );
3912 
3913 /* If successful, obtain a pointer to the Domain string of the result
3914    Frame. Allocate space for a copy of this string, with added
3915    commas. */
3916       if ( match && astOK ) {
3917          domain = astGetDomain( frame );
3918          if ( astOK ) {
3919             domain_copy = astMalloc( strlen( domain ) + (size_t) 3 );
3920             if ( astOK ) {
3921 
3922 /* Make a copy of the domain, adding an extra comma at each end. */
3923                domain_copy[ 0 ] = ',';
3924                for ( i = 0, j = 1; domain[ i ]; i++ ) {
3925                   domain_copy[ j++ ] = domain[ i ];
3926                }
3927                domain_copy[ j++ ] = ',';
3928                domain_copy[ j ] = '\0';
3929 
3930 /* Test if the domain appears in the domains list (with added
3931    commas). If not, test if a blank domain (which permits the result
3932    Frame to have any Domain) appears instead. */
3933                if ( strstr( domainlist_copy, domain_copy ) ||
3934                     strstr( domainlist_copy, ",," ) ) {
3935 
3936 /* If the result Frame is acceptable, simplify the result Mapping. */
3937                   tmp = astSimplify( map );
3938                   map = astAnnul( map );
3939                   map = tmp;
3940 
3941 /* Build the result FrameSet. */
3942                   result = astFrameSet( target, "", status );
3943                   astAddFrame( result, AST__BASE, map, frame );
3944                }
3945             }
3946 
3947 /* Free the copy of the result domain. */
3948             domain_copy = astFree( domain_copy );
3949          }
3950 
3951 /* Free space and annul pointers allocated by astMatch. */
3952          template_axes = astFree( template_axes );
3953          target_axes = astFree( target_axes );
3954          map = astAnnul( map );
3955          frame = astAnnul( frame );
3956       }
3957    }
3958 
3959 /* Free the copy of the domains list. */
3960    domainlist_copy = astFree( domainlist_copy );
3961 
3962 /* If an error occurred, annul any result pointer. */
3963    if ( !astOK && result ) result = astAnnul( result );
3964 
3965 /* Return the result. */
3966    return result;
3967 }
3968 
astFmtDecimalYr_(double year,int digits,int * status)3969 const char *astFmtDecimalYr_( double year, int digits, int *status ) {
3970 /*
3971 *+
3972 *  Name:
3973 *     astFmtDecimalYr
3974 
3975 *  Purpose:
3976 *     Format an epoch expressed in years as a decimal string.
3977 
3978 *  Type:
3979 *     Protected function.
3980 
3981 *  Synopsis:
3982 *     #include "frame.h"
3983 *     const char *astFmtDecimalYr( double year, int digits )
3984 
3985 *  Class Membership:
3986 *     Frame member function.
3987 
3988 *  Description:
3989 *     This function formats an epoch expressed in years as a decimal string
3990 *     and returns a pointer to the result. It is intended for formatting
3991 *     Frame Epoch values, etc, for display.
3992 
3993 *  Parameters:
3994 *     year
3995 *        The epoch to be formatted.
3996 *     digits
3997 *        The number of digits of precision required.
3998 
3999 *  Returned Value:
4000 *     Pointer to a null terminated string containing the formatted value.
4001 
4002 *  Notes:
4003 *     - The result string is stored in static memory and may be
4004 *     over-written by a subsequent invocation of this function.
4005 *     - A NULL pointer is returned if this function is invoked with
4006 *     the global error status set or if it should fail for any reason.
4007 *-
4008 */
4009 
4010 /* Local Variables: */
4011    astDECLARE_GLOBALS            /* Declare the thread specific global data */
4012    int nc;                       /* Number of characters in buffer */
4013 
4014 /* Check the global error status. */
4015    if ( !astOK ) return NULL;
4016 
4017 /* Get a pointer to the structure holding thread-specific global data. */
4018    astGET_GLOBALS(NULL);
4019 
4020 /* Limit the precision to what is meaningful. */
4021    digits = ( digits > DBL_DIG ) ? DBL_DIG : digits;
4022 
4023 /* Format the year value. Use "g" format to avoid buffer overflow and
4024    to get useful diagnostic output if a silly value is given. */
4025    nc = sprintf( astfmtdecimalyr_buff, "%#.*g", digits, year );
4026 
4027 /* Loop to remove redundant zeros from the end of the result. */
4028    while ( astfmtdecimalyr_buff[ --nc ] == '0' ) astfmtdecimalyr_buff[ nc ] = '\0';
4029 
4030 /* If the last character is now a decimal point, put back one zero. */
4031    if ( astfmtdecimalyr_buff[ nc ] == '.' ) {
4032       astfmtdecimalyr_buff[ ++nc ] = '0';
4033       astfmtdecimalyr_buff[ ++nc ] = '\0';
4034    }
4035 
4036 /* Return the result. */
4037    return astfmtdecimalyr_buff;
4038 }
4039 
Format(AstFrame * this,int axis,double value,int * status)4040 static const char *Format( AstFrame *this, int axis, double value, int *status ) {
4041 /*
4042 *+
4043 *  Name:
4044 *     astFormat
4045 
4046 *  Purpose:
4047 *     Format a coordinate value for a Frame axis.
4048 
4049 *  Type:
4050 *     Protected virtual function.
4051 
4052 *  Synopsis:
4053 *     #include "frame.h"
4054 *     const char *astFormat( AstFrame *this, int axis, double value )
4055 
4056 *  Class Membership:
4057 *     Frame method.
4058 
4059 *  Description:
4060 *     This function returns a pointer to a string containing the
4061 *     formatted (character) version of a coordinate value for a Frame
4062 *     axis. The formatting applied is determined by the Frame's
4063 *     attributes and, in particular, by any Format attribute string
4064 *     that has been set for the axis. A suitable default format will
4065 *     be applied if necessary.
4066 
4067 *  Parameters:
4068 *     this
4069 *        Pointer to the Frame.
4070 *     axis
4071 *        The number of the Frame axis for which formatting is to be
4072 *        performed (axis numbering starts at zero for the first axis).
4073 *     value
4074 *        The coordinate value to be formatted.
4075 
4076 *  Returned Value:
4077 *     A pointer to a null-terminated string containing the formatted
4078 *     value.
4079 
4080 *  Notes:
4081 *     - The returned string pointer may point at memory allocated
4082 *     within the Frame, or at static memory. The contents of the
4083 *     string may be over-written or the pointer may become invalid
4084 *     following a further invocation of the same function or any
4085 *     modification of the Frame. A copy of the string should
4086 *     therefore be made if necessary.
4087 *     - A NULL pointer will be returned if this function is invoked
4088 *     with the global error status set, or if it should fail for any
4089 *     reason.
4090 *-
4091 
4092 *  Implementation Notes:
4093 *     - This function implements the basic astFormat method available
4094 *     via the protected interface to the Frame class. The public
4095 *     interface to this method is provided by the astFormatId_
4096 *     function.
4097 */
4098 
4099 /* Local Variables: */
4100    AstAxis *ax;                  /* Pointer to Axis object */
4101    const char *result;           /* Pointer value to return */
4102    int digits_set;               /* Axis Digits attribute set? */
4103 
4104 /* Check the global error status. */
4105    if ( !astOK ) return NULL;
4106 
4107 /* Validate the axis index and obtain a pointer to the required Axis. */
4108    (void) astValidateAxis( this, axis, 1, "astFormat" );
4109    ax = astGetAxis( this, axis );
4110 
4111 /* Test if any Axis attributes which may affect the result are undefined (i.e.
4112    have not been explicitly set). If so, we over-ride them, giving them
4113    temporary values dictated by the Frame. Only the Digits attribute is
4114    relevant here. */
4115    digits_set = astTestAxisDigits( ax );
4116    if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) );
4117 
4118 /* Format the value. */
4119    result = astAxisFormat( ax, value );
4120 
4121 /* Clear any Axis attributes that were temporarily over-ridden. */
4122    if ( !digits_set ) astClearAxisDigits( ax );
4123 
4124 /* Annul the Axis pointer. */
4125    ax = astAnnul( ax );
4126 
4127 /* If an error occurred, clear the result value. */
4128    if ( !astOK ) result = NULL;
4129 
4130 /* Return the result. */
4131    return result;
4132 }
4133 
FrameGrid(AstFrame * this,int size,const double * lbnd,const double * ubnd,int * status)4134 static AstPointSet *FrameGrid( AstFrame *this, int size, const double *lbnd,
4135                                const double *ubnd, int *status ){
4136 /*
4137 *+
4138 *  Name:
4139 *     astFrameGrid
4140 
4141 *  Purpose:
4142 *     Return a grid of points covering a rectangular area of a Frame.
4143 
4144 *  Type:
4145 *     Protected virtual function.
4146 
4147 *  Synopsis:
4148 *     #include "frame.h"
4149 *     AstPointSet *astFrameGrid( AstFrame *this_frame, int size,
4150 *                                const double *lbnd, const double *ubnd )
4151 
4152 *  Class Membership:
4153 *     Frame method.
4154 
4155 *  Description:
4156 *     This function returns a PointSet containing positions spread
4157 *     approximately evenly throughtout a specified rectangular area of
4158 *     the Frame.
4159 
4160 *  Parameters:
4161 *     this
4162 *        Pointer to the Frame.
4163 *     size
4164 *        The preferred number of points in the returned PointSet. The
4165 *        actual number of points in the returned PointSet may be
4166 *        different, but an attempt is made to stick reasonably closely to
4167 *        the supplied value.
4168 *     lbnd
4169 *        Pointer to an array holding the lower bound of the rectangular
4170 *        area on each Frame axis. The array should have one element for
4171 *        each Frame axis.
4172 *     ubnd
4173 *        Pointer to an array holding the upper bound of the rectangular
4174 *        area on each Frame axis. The array should have one element for
4175 *        each Frame axis.
4176 
4177 *  Returned Value:
4178 *     A pointer to a new PointSet holding the grid of points.
4179 
4180 *  Notes:
4181 *     - A NULL pointer is returned if an error occurs.
4182 *-
4183 */
4184 
4185 /* Local Variables: */
4186    AstPointSet *result;
4187    const char *unit;
4188    double **ptr;
4189    double *gmean;
4190    double *step;
4191    int *maxi;
4192    int *nsame;
4193    int *ntick;
4194    int *pi;
4195    int bad;
4196    int iax;
4197    int ipp;
4198    int jax;
4199    int naxes;
4200    int np;
4201    int ntick0;
4202 
4203 /* Initialise. */
4204    result = NULL;
4205 
4206 /* Check the global error status. */
4207    if ( !astOK ) return result;
4208 
4209 /* Get the number of axes in the Frame. */
4210    naxes = astGetNaxes( this );
4211 
4212 /* Allocate an array to hold the number of ticks along each axis. */
4213    ntick = astMalloc( sizeof(int)*naxes );
4214 
4215 /* Allocate an array to hold the geometric mean of the lengths of the
4216    axes that have the same units as the current axis. */
4217    gmean = astMalloc( naxes*sizeof(double) );
4218 
4219 /* Allocate an array to hold the number of axes that share the same unit. */
4220    nsame = astMalloc( naxes*sizeof(int) );
4221    if( astOK ) {
4222 
4223 /* For each axis, find the total number of axes in the Frame that have
4224    the same unit string. Also, find the product of the lengths of these
4225    axes. */
4226       bad = 0;
4227       for( iax = 0; iax < naxes; iax++ ) {
4228          nsame[ iax ] = 1;
4229 
4230          if( ubnd[ iax ] == AST__BAD &&
4231              lbnd[ iax ] == AST__BAD ) {
4232             bad = 1;
4233             break;
4234          }
4235 
4236          gmean[ iax ] = ubnd[ iax ] - lbnd[ iax ];
4237          unit = astGetUnit( this, iax );
4238          for( jax = 0; jax < naxes; jax++ ) {
4239             if( jax != iax ) {
4240                if( astOK && !strcmp( unit, astGetUnit( this, jax ) ) ) {
4241                   nsame[ iax ]++;
4242                   gmean[ iax ] *= ubnd[ jax ] - lbnd[ jax ];
4243                }
4244             }
4245          }
4246       }
4247 
4248 /* Do nothing if any bad bounds were supplied, or if the size is less
4249    than 1. */
4250       if( !bad && size >= 1 ) {
4251 
4252 /* Get the nominal number of ticks per axis. */
4253          ntick0 = pow( size, 1.0/(double)naxes );
4254          if( ntick0 < 2 ) ntick0 = 2;
4255 
4256 /* Convert the dimension products into geometric means. */
4257          for( iax = 0; iax < naxes; iax++ ) {
4258             gmean[ iax ] = pow( fabs(gmean[ iax ]), 1.0/(double)nsame[ iax ] );
4259          }
4260 
4261 /* The number of ticks to use on each axis is equal to the nominal number
4262    multiplied by the ratio of the axis length to the geometric mean of the
4263    axis lengths that sahare the same unit string. This gives more ticks
4264    on the longer axes within any group of common-unit axes, whilst
4265    retaining the overall number of ticks (roughly). Also find the total
4266    number of points. */
4267          np = 1;
4268          for( iax = 0; iax < naxes; iax++ ) {
4269             ntick[ iax ] = ntick0*( ubnd[ iax ] - lbnd[ iax ] )/gmean[ iax ];
4270             if( ntick[ iax ] < 2 ) ntick[ iax ] = 2;
4271             np *= ntick[ iax ];
4272          }
4273 
4274 /* Create a PointSet large enough to hold this many points. */
4275          result = astPointSet( np, naxes, " ", status );
4276          ptr = astGetPoints( result );
4277 
4278 /* Allocate memory to hold the max indices on each axis. */
4279          maxi = astMalloc( sizeof( int )*(size_t) naxes );
4280 
4281 /* Allocate memory to hold the indices of the current position.*/
4282          pi = astMalloc( sizeof( int )*(size_t) naxes );
4283 
4284 /* Allocate memory to hold the step size for each axis. */
4285          step = astMalloc( sizeof( double )*(size_t) naxes );
4286          if( astOK ) {
4287 
4288 /* For every axis, set up the step size, initialise the current position to
4289    the lower bound, and store a modified upper limit which includes some
4290    safety marging to allow for rounding errors. */
4291             for( iax = 0; iax < naxes; iax++ ) {
4292                step[ iax ] = ( ubnd[ iax ] - lbnd[ iax ] )/( ntick[ iax ] - 1 );
4293                pi[ iax ] = 0;
4294                maxi[ iax ] = ntick[ iax ] - 1;
4295             }
4296 
4297 /* Initialise the index of the next position to store. */
4298             ipp = 0;
4299 
4300 /* Loop round adding points to the array until the whole volume has been
4301    done. */
4302             iax = 0;
4303             while( iax < naxes ) {
4304 
4305 /* Add the current point to the supplied array, and increment the index of
4306    the next point to add. */
4307                for( iax = 0; iax < naxes; iax++ ) {
4308                   ptr[ iax ][ ipp ] = lbnd[ iax ] + pi[ iax ]*step[ iax ];
4309                }
4310                ipp++;
4311 
4312 /* We now move the current position on to the next sample */
4313                iax = 0;
4314                while( iax < naxes ) {
4315                   pi[ iax ]++;
4316                   if( pi[ iax ] > maxi[ iax ] ) {
4317                      pi[ iax ] = 0;
4318                      iax++;
4319                   } else {
4320                      break;
4321                   }
4322                }
4323             }
4324          }
4325 
4326 /* Free resources. */
4327          maxi = astFree( maxi );
4328          pi = astFree( pi );
4329          step = astFree( step );
4330 
4331 /* Report error if supplied values were bad. */
4332       } else if( astOK ) {
4333          if( bad ) {
4334             astError( AST__ATTIN, "astFrameGrid(%s): One of more of the "
4335                       "supplied bounds is AST__BAD (programming error).",
4336                       status, astGetClass( this ) );
4337          } else if( size < 1 ) {
4338             astError( AST__ATTIN, "astFrameGrid(%s): The supplied grid "
4339                       "size (%d) is invalid (programming error).",
4340                       status, astGetClass( this ), size );
4341          }
4342       }
4343    }
4344 
4345 /* Free resources. */
4346    ntick = astFree( ntick );
4347    nsame = astFree( nsame );
4348    gmean = astFree( gmean );
4349 
4350 /* Annul the returned PointSet if an error has occurred. */
4351    if( !astOK ) result = astAnnul( result );
4352 
4353 /* Return the PointSet holding the grid. */
4354    return result;
4355 }
4356 
Gap(AstFrame * this,int axis,double gap,int * ntick,int * status)4357 static double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status ) {
4358 /*
4359 *+
4360 *  Name:
4361 *     astGap
4362 
4363 *  Purpose:
4364 *     Find a "nice" gap for tabulating Frame axis values.
4365 
4366 *  Type:
4367 *     Protected virtual function.
4368 
4369 *  Synopsis:
4370 *     #include "frame.h"
4371 *     double astGap( AstFrame *this, int axis, double gap, int *ntick )
4372 
4373 *  Class Membership:
4374 *     Frame method.
4375 
4376 *  Description:
4377 *     This function returns a gap size which produces a nicely spaced
4378 *     series of formatted values for a Frame axis, the returned gap
4379 *     size being as close as possible to the supplied target gap
4380 *     size. It also returns a convenient number of divisions into
4381 *     which the gap can be divided.
4382 
4383 *  Parameters:
4384 *     this
4385 *        Pointer to the Frame.
4386 *     axis
4387 *        The number of the axis (zero-based) for which a gap is to be found.
4388 *     gap
4389 *        The target gap size.
4390 *     ntick
4391 *        Address of an int in which to return a convenient number of
4392 *        divisions into which the gap can be divided.
4393 
4394 *  Returned Value:
4395 *     The nice gap size.
4396 
4397 *  Notes:
4398 *     - A value of zero is returned if the target gap size is zero.
4399 *     - A negative gap size is returned if the supplied gap size is negative.
4400 *     - A value of zero will be returned if this function is invoked
4401 *     with the global error status set, or if it should fail for any
4402 *     reason.
4403 *-
4404 */
4405 
4406 /* Local Variables: */
4407    AstAxis *ax;                  /* Pointer to Axis object */
4408    double result;                /* The nice gap value */
4409 
4410 /* Check the global error status. */
4411    if ( !astOK ) return 0.0;
4412 
4413 /* Validate the axis index and obtain a pointer to the required
4414    Axis. */
4415    (void) astValidateAxis( this, axis, 1, "astGap" );
4416    ax = astGetAxis( this, axis );
4417 
4418 /* Find the gap. */
4419    result = astAxisGap( ax, gap, ntick );
4420 
4421 /* Annul the Axis pointer. */
4422    ax = astAnnul( ax );
4423 
4424 /* If an error occurred, clear the result value. */
4425    if ( !astOK ) result = 0.0;
4426 
4427 /* Return the result. */
4428    return result;
4429 }
4430 
GetActiveUnit(AstFrame * this,int * status)4431 static int GetActiveUnit( AstFrame *this, int *status ){
4432 /*
4433 *++
4434 *  Name:
4435 c     astGetActiveUnit
4436 f     AST_GETACTIVEUNIT
4437 
4438 *  Purpose:
4439 *     Determines how the Unit attribute will be used.
4440 
4441 *  Type:
4442 *     Public virtual function.
4443 
4444 *  Synopsis:
4445 c     #include "frame.h"
4446 c     int astGetActiveUnit( AstFrame *this )
4447 f     RESULT = AST_GETACTIVEUNIT( THIS, STATUS )
4448 
4449 *  Class Membership:
4450 *     Frame method.
4451 
4452 *  Description:
4453 c     This function
4454 f     This routine
4455 *     returns the current value of the ActiveUnit flag for a Frame. See
4456 c     the description of the astSetActiveUnit function
4457 f     the description of the AST_SETACTIVEUNIT routine
4458 *     for a description of the ActiveUnit flag.
4459 
4460 *  Parameters:
4461 c     this
4462 f     THIS = INTEGER (Given)
4463 *        Pointer to the Frame.
4464 f     STATUS = INTEGER (Given and Returned)
4465 f        The global status.
4466 
4467 *  Returned Value:
4468 c     astGetActiveUnit
4469 f     AST_GETACTIVEUNIT = LOGICAL
4470 *        The current value of the ActiveUnit flag.
4471 
4472 *  Notes:
4473 c     - A zero value will be returned if this function is
4474 c     invoked with the AST error status set, or if it should fail for
4475 f     - A value of .FALSE. will be returned if this function is
4476 f     invoked with STATUS set to an error value, or if it should fail for
4477 *     any reason.
4478 *--
4479 */
4480 
4481 /* Local Variables: */
4482    AstAxis *ax;        /* Pointer to axis structure */
4483    int i;              /* Index of axis in Frame */
4484    int has_skyaxis;    /* Does Frame contain any SkyAxes? */
4485    int nax;            /* Number of axes in Frame */
4486    int result;         /* The returned value */
4487 
4488 /* Initialise. */
4489    result = 0;
4490 
4491 /* Check the global error status. */
4492    if ( !astOK ) return result;
4493 
4494 /* See if the Frame contains a SkyAxis. */
4495    has_skyaxis = 0;
4496    nax = astGetNaxes( this );
4497    for( i = 0; i < nax; i++ ) {
4498       ax = astGetAxis( this, i );
4499       if( astIsASkyAxis( ax ) ) has_skyaxis = 1;
4500       ax = astAnnul( ax );
4501    }
4502 
4503 /* If the Frame contains a SkyAxis the ActiveUnit flag is always zero. */
4504    if( !has_skyaxis ) {
4505 
4506 /* Otherwise, get the value from the Frame. If it has not yet been assigned a
4507    value return the value zero. */
4508       result = this->active_unit;
4509       if( result == -INT_MAX ) result = 0;
4510    }
4511 
4512 /* Return the result. */
4513    return result;
4514 }
4515 
GetAttrib(AstObject * this_object,const char * attrib,int * status)4516 static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
4517 /*
4518 *  Name:
4519 *     GetAttrib
4520 
4521 *  Purpose:
4522 *     Get the value of a specified attribute for a Frame.
4523 
4524 *  Type:
4525 *     Private function.
4526 
4527 *  Synopsis:
4528 *     #include "frame.h"
4529 *     const char *GetAttrib( AstObject *this, const char *attrib, int *status )
4530 
4531 *  Class Membership:
4532 *     Frame member function (over-rides the protected astGetAttrib
4533 *     method inherited from the Mapping class).
4534 
4535 *  Description:
4536 *     This function returns a pointer to the value of a specified
4537 *     attribute for a Frame, formatted as a character string.
4538 
4539 *  Parameters:
4540 *     this
4541 *        Pointer to the Frame.
4542 *     attrib
4543 *        Pointer to a null-terminated string containing the name of
4544 *        the attribute whose value is required. This name should be in
4545 *        lower case, with all white space removed.
4546 *     status
4547 *        Pointer to the inherited status variable.
4548 
4549 *  Returned Value:
4550 *     - Pointer to a null-terminated string containing the attribute
4551 *     value.
4552 
4553 *  Notes:
4554 *     - This function uses one-based axis numbering so that it is
4555 *     suitable for external (public) use.
4556 *     - The returned string pointer may point at memory allocated
4557 *     within the Frame, or at static memory. The contents of the
4558 *     string may be over-written or the pointer may become invalid
4559 *     following a further invocation of the same function or any
4560 *     modification of the Frame. A copy of the string should
4561 *     therefore be made if necessary.
4562 *     - A NULL pointer will be returned if this function is invoked
4563 *     with the global error status set, or if it should fail for any
4564 *     reason.
4565 */
4566 
4567 /* Local Variables: */
4568    astDECLARE_GLOBALS            /* Declare the thread specific global data */
4569    AstAxis *ax;                  /* Pointer to Axis */
4570    AstFrame *pfrm;               /* Pointer to primary Frame containing axis */
4571    AstFrame *this;               /* Pointer to the Frame structure */
4572    AstSystemType system;         /* System code */
4573    char pfrm_attrib[ 100 ];      /* Primary Frame attribute */
4574    char *axis_attrib;            /* Pointer to axis attribute name */
4575    const char *old_attrib;       /* Pointer to supplied attribute name string */
4576    const char *result;           /* Pointer value to return */
4577    double dval;                  /* Double attibute value */
4578    double epoch;                 /* Epoch attribute value (as MJD) */
4579    int axis;                     /* Frame axis number */
4580    int axis_nc;                  /* No. characters in axis attribute name */
4581    int digits;                   /* Digits attribute value */
4582    int direction;                /* Direction attribute value */
4583    int free_axis_attrib;         /* Should axis_attrib be freed? */
4584    int has_axis;                 /* Does attrib name include axis specifier? */
4585    int len;                      /* Length of attrib string */
4586    int match_end;                /* MatchEnd attribute value */
4587    int max_axes;                 /* MaxAxes attribute value */
4588    int min_axes;                 /* MinAxes attribute value */
4589    int naxes;                    /* Naxes attribute value */
4590    int nc;                       /* No. characters read by astSscanf */
4591    int oldrep;                   /* Original error reporting state */
4592    int paxis;                    /* Axis index within primary frame */
4593    int permute;                  /* Permute attribute value */
4594    int preserve_axes;            /* PreserveAxes attribute value */
4595    int used;                     /* Could the setting string be used? */
4596 
4597 /* Initialise. */
4598    result = NULL;
4599 
4600 /* Check the global error status. */
4601    if ( !astOK ) return result;
4602 
4603 /* Get a pointer to the structure holding thread-specific global data. */
4604    astGET_GLOBALS(this_object);
4605 
4606 /* Obtain a pointer to the Frame structure. */
4607    this = (AstFrame *) this_object;
4608 
4609 /* Set a flag indicating if the attribute name includes an axis
4610    specifier. */
4611    has_axis = ( strchr( attrib, '(' ) != NULL );
4612 
4613 /* A flag indicating that we do not need to free the axis_attrib memory. */
4614    free_axis_attrib = 0;
4615 
4616 /* Initialise things to avoid compiler warnings. */
4617    axis_attrib = NULL;
4618    old_attrib = NULL;
4619 
4620 /* Jump back to here if we are trying the same attribute but with an explicit
4621    axis "(1)" added to the end of the name. */
4622 L1:
4623 
4624 /* Obtain the length of the attrib string. */
4625    len = strlen( attrib );
4626 
4627 /* Save the number of axes in the Frame for later use. */
4628    naxes = astGetNaxes( this );
4629 
4630 /* Compare "attrib" with each recognised attribute name in turn,
4631    obtaining the value of the required attribute. If necessary, write
4632    the value into "getattrib_buff" as a null-terminated string in an appropriate
4633    format.  Set "result" to point at the result string. */
4634 
4635 /* Digits. */
4636 /* ------- */
4637    if ( !strcmp( attrib, "digits" ) ) {
4638       digits = astGetDigits( this );
4639       if ( astOK ) {
4640          (void) sprintf( getattrib_buff, "%d", digits );
4641          result = getattrib_buff;
4642       }
4643 
4644 /* Digits(axis). */
4645 /* ------------- */
4646    } else if ( nc = 0,
4647                ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) )
4648                && ( nc >= len ) ) {
4649 
4650 /* There is no function to obtain the Digits attribute value for an
4651    axis directly, so obtain a pointer to the Axis and use this to
4652    obtain the value. Use the Frame's Digits attribute instead if the
4653    Axis attribute value is not set. */
4654       (void) astValidateAxis( this, axis - 1, 1, "astGetDigits(axis)" );
4655       ax = astGetAxis( this, axis - 1 );
4656       if ( astTestAxisDigits( ax ) ) {
4657          digits = astGetAxisDigits( ax );
4658       } else {
4659          digits = astGetDigits( this );
4660       }
4661       ax = astAnnul( ax );
4662       if ( astOK ) {
4663          (void) sprintf( getattrib_buff, "%d", digits );
4664          result = getattrib_buff;
4665       }
4666 
4667 
4668 /* Direction(axis). */
4669 /* ---------------- */
4670    } else if ( nc = 0,
4671                ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) )
4672                && ( nc >= len ) ) {
4673       direction = astGetDirection( this, axis - 1 );
4674       if ( astOK ) {
4675          (void) sprintf( getattrib_buff, "%d", direction );
4676          result = getattrib_buff;
4677       }
4678 
4679 /* Epoch. */
4680 /* ------ */
4681    } else if ( !strcmp( attrib, "epoch" ) ) {
4682       epoch = astGetEpoch( this );
4683       if ( astOK ) {
4684 
4685 /* Format the Epoch as decimal years. Use a Besselian epoch if it will
4686    be less than 1984.0, otherwise use a Julian epoch. */
4687          result = astFmtDecimalYr( ( epoch < palEpj2d( 1984.0 ) ) ?
4688                                    palEpb( epoch ) : palEpj( epoch ), DBL_DIG );
4689       }
4690 
4691 /* Top(axis). */
4692 /* ---------- */
4693    } else if ( nc = 0,
4694                ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) )
4695                && ( nc >= len ) ) {
4696       dval = astGetTop( this, axis -1 );
4697       if ( astOK ) {
4698          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
4699          result = getattrib_buff;
4700       }
4701 
4702 /* Bottom(axis). */
4703 /* ---------- */
4704    } else if ( nc = 0,
4705                ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) )
4706                && ( nc >= len ) ) {
4707       dval = astGetBottom( this, axis -1 );
4708       if ( astOK ) {
4709          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
4710          result = getattrib_buff;
4711       }
4712 
4713 /* Domain. */
4714 /* ------- */
4715    } else if ( !strcmp( attrib, "domain" ) ) {
4716       result = astGetDomain( this );
4717 
4718 /* Format(axis). */
4719 /* ------------- */
4720    } else if ( nc = 0,
4721                ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) )
4722                && ( nc >= len ) ) {
4723       result = astGetFormat( this, axis - 1 );
4724 
4725 /* Label(axis). */
4726 /* ------------ */
4727    } else if ( nc = 0,
4728                ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) )
4729                && ( nc >= len ) ) {
4730       result = astGetLabel( this, axis - 1 );
4731 
4732 /* MatchEnd. */
4733 /* --------- */
4734    } else if ( !strcmp( attrib, "matchend" ) ) {
4735       match_end = astGetMatchEnd( this );
4736       if ( astOK ) {
4737          (void) sprintf( getattrib_buff, "%d", match_end );
4738          result = getattrib_buff;
4739       }
4740 
4741 /* MaxAxes. */
4742 /* -------- */
4743    } else if ( !strcmp( attrib, "maxaxes" ) ) {
4744       max_axes = astGetMaxAxes( this );
4745       if ( astOK ) {
4746          (void) sprintf( getattrib_buff, "%d", max_axes );
4747          result = getattrib_buff;
4748       }
4749 
4750 /* MinAxes. */
4751 /* -------- */
4752    } else if ( !strcmp( attrib, "minaxes" ) ) {
4753       min_axes = astGetMinAxes( this );
4754       if ( astOK ) {
4755          (void) sprintf( getattrib_buff, "%d", min_axes );
4756          result = getattrib_buff;
4757       }
4758 
4759 /* Naxes. */
4760 /* -----_ */
4761    } else if ( !strcmp( attrib, "naxes" ) ) {
4762       (void) sprintf( getattrib_buff, "%d", naxes );
4763       result = getattrib_buff;
4764 
4765 /* Permute. */
4766 /* -------- */
4767    } else if ( !strcmp( attrib, "permute" ) ) {
4768       permute = astGetPermute( this );
4769       if ( astOK ) {
4770          (void) sprintf( getattrib_buff, "%d", permute );
4771          result = getattrib_buff;
4772       }
4773 
4774 /* PreserveAxes. */
4775 /* ------------- */
4776    } else if ( !strcmp( attrib, "preserveaxes" ) ) {
4777       preserve_axes = astGetPreserveAxes( this );
4778       if ( astOK ) {
4779          (void) sprintf( getattrib_buff, "%d", preserve_axes );
4780          result = getattrib_buff;
4781       }
4782 
4783 /* Symbol(axis). */
4784 /* ------------- */
4785    } else if ( nc = 0,
4786                ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) )
4787                && ( nc >= len ) ) {
4788       result = astGetSymbol( this, axis - 1 );
4789 
4790 /* AlignSystem. */
4791 /* ------------ */
4792 /* Obtain the AlignSystem code and convert to a string. */
4793    } else if ( !strcmp( attrib, "alignsystem" ) ) {
4794       system = astGetAlignSystem( this );
4795       if ( astOK ) {
4796          result = astSystemString( this, system );
4797 
4798 /* Report an error if the value was not recognised. */
4799          if ( !result ) {
4800             astError( AST__SCSIN,
4801                      "astGetAttrib(%s): Corrupt %s contains invalid "
4802                      "AlignSystem identification code (%d).", status,
4803                      astGetClass( this ), astGetClass( this ), (int) system );
4804          }
4805       }
4806 
4807 /* System. */
4808 /* ------- */
4809 /* Obtain the System code and convert to a string. */
4810    } else if ( !strcmp( attrib, "system" ) ) {
4811       system = astGetSystem( this );
4812       if ( astOK ) {
4813          result = astSystemString( this, system );
4814 
4815 /* Report an error if the value was not recognised. */
4816          if ( !result ) {
4817             astError( AST__SCSIN,
4818                      "astGetAttrib(%s): Corrupt %s contains invalid "
4819                      "System identification code (%d).", status,
4820                      astGetClass( this ), astGetClass( this ), (int) system );
4821          }
4822       }
4823 
4824 /* Title. */
4825 /* ------ */
4826    } else if ( !strcmp( attrib, "title" ) ) {
4827       result = astGetTitle( this );
4828 
4829 /* Unit(axis). */
4830 /* ----------- */
4831    } else if ( nc = 0,
4832                ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) )
4833                && ( nc >= len ) ) {
4834       result = astGetUnit( this, axis - 1 );
4835 
4836 /* NormUnit(axis). */
4837 /* --------------- */
4838    } else if ( nc = 0,
4839                ( 1 == astSscanf( attrib, "normunit(%d)%n", &axis, &nc ) )
4840                && ( nc >= len ) ) {
4841       result = astGetNormUnit( this, axis - 1 );
4842 
4843 /* ObsLat. */
4844 /* ------- */
4845    } else if ( !strcmp( attrib, "obslat" ) ) {
4846       dval = astGetObsLat( this );
4847       if ( astOK ) {
4848 
4849 /* If not already created, create an FK5 J2000 SkyFrame which will be used
4850    for formatting and unformatting ObsLon and ObsLat values. */
4851          if( !skyframe ) {
4852             astBeginPM;
4853             skyframe = astSkyFrame("system=FK5,equinox=J2000,format(2)=dms.2", status );
4854             astEndPM;
4855          }
4856 
4857 /* Display absolute value preceded by "N" or "S" as appropriate. */
4858          if( dval < 0 ) {
4859             (void) sprintf( getattrib_buff, "S%s",  astFormat( skyframe, 1, -dval ) );
4860          } else {
4861             (void) sprintf( getattrib_buff, "N%s",  astFormat( skyframe, 1, dval ) );
4862          }
4863          result = getattrib_buff;
4864       }
4865 
4866 /* ObsLon. */
4867 /* ------- */
4868    } else if ( !strcmp( attrib, "obslon" ) ) {
4869       dval = astGetObsLon( this );
4870       if ( astOK ) {
4871 
4872 /* Put into range +/- PI. */
4873          dval = palDrange( dval );
4874 
4875 /* If not already created, create an FK5 J2000 SkyFrame which will be used
4876    for formatting and unformatting ObsLon and ObsLat values. */
4877          if( !skyframe ) {
4878             astBeginPM;
4879             skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status );
4880             astEndPM;
4881          }
4882 
4883 /* Display absolute value preceded by "E" or "W" as appropriate. */
4884          if( dval < 0 ) {
4885             (void) sprintf( getattrib_buff, "W%s",  astFormat( skyframe, 1, -dval ) );
4886          } else {
4887             (void) sprintf( getattrib_buff, "E%s",  astFormat( skyframe, 1, dval ) );
4888          }
4889          result = getattrib_buff;
4890 
4891       }
4892 
4893 /* ObsAlt. */
4894 /* ------- */
4895    } else if ( !strcmp( attrib, "obsalt" ) ) {
4896       dval = astGetObsAlt( this );
4897       if ( astOK ) {
4898          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
4899          result = getattrib_buff;
4900       }
4901 
4902 /* Dut1. */
4903 /* ---- */
4904    } else if ( !strcmp( attrib, "dut1" ) ) {
4905       dval = astGetDut1( this );
4906       if ( astOK ) {
4907          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
4908          result = getattrib_buff;
4909       }
4910 
4911 /* Other axis attributes. */
4912 /* ---------------------- */
4913 /* If the attribute was not identified above, but appears to refer to
4914    a Frame axis, then it may refer to an Axis object of a derived type
4915    (which has additional attributes not recognised here). */
4916    } else if ( !free_axis_attrib && ( nc = 0,
4917                ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n",
4918                                       &axis_nc, &axis, &nc ) )
4919                && ( nc >= len ) ) ) {
4920 
4921 /* Validate the axis index and extract the attribute name. */
4922       (void) astValidateAxis( this, axis - 1, 1, "astGet" );
4923       axis_attrib = astString( attrib, axis_nc );
4924 
4925 /* Obtain a pointer to the Axis object. */
4926       ax = astGetAxis( this, axis - 1 );
4927       if( astOK ) {
4928 
4929 /* Assume that we will be able to use the attribute name. */
4930          used = 1;
4931 
4932 /* Temporarily switch off error reporting so that if the following attempt
4933    to access the axis attribute fails, we can try to interpret the
4934    attribute name as an attribute of the primary Frame containing the
4935    specified axis. Any errors reported in this context will simply be
4936    ignored, in particularly they are not deferred for later delivery. */
4937          oldrep = astReporting( 0 );
4938 
4939 /* Use the Axis astGetAttrib method to obtain the result. */
4940          result = astGetAttrib( ax, axis_attrib );
4941 
4942 /* If the above call failed with a status of AST__BADAT, indicating that
4943    the attribute name was not recognised, clear the status so that we can
4944    try to interpret the attribute name as an attribute of the primary Frame
4945    containing the specified axis. */
4946          if( astStatus == AST__BADAT ) {
4947             astClearStatus;
4948 
4949 /* Find the primary Frame containing the specified axis. */
4950             astPrimaryFrame( this, axis - 1, &pfrm, &paxis );
4951 
4952 /* Only attempt to use the primary Frame if it is not the same as "this"
4953    - otherwise we could end up in an infinite loop. */
4954             if( pfrm != this ) {
4955 
4956 /* astPrimaryFrame returns the original - unpermuted - axis index within
4957    the primary Frame. So we need to take into account any axis permutation
4958    which has been applied to the primary Frame when forming the attribute name
4959    to use below. Find the permuted (external) axis index which corresponds to
4960    the internal (unpermuted) axis index "paxis". */
4961                paxis = astValidateAxis( pfrm, paxis, 0, "astGet" );
4962 
4963 /* Modify the attribute name to refer to the axis numbering of the
4964    primary frame. */
4965                sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 );
4966 
4967 /* Attempt to use the Axis astGetAttrib method to obtain the result. */
4968                result = astGetAttrib( pfrm, pfrm_attrib );
4969 
4970 /* If this failed, clear the status and indicate that we have not managed to
4971    use the attribute name. */
4972                if( !astOK ) {
4973                   astClearStatus;
4974                   used = 0;
4975                }
4976 
4977             } else {
4978                used =  0;
4979             }
4980 
4981 /* If not found attempt to get the attribute value from the Axis, omitting
4982    the axis index. */
4983             if( ! used ) {
4984                result = astGetAttrib( pfrm, axis_attrib );
4985                if( !astOK ) {
4986                   astClearStatus;
4987                } else {
4988                   used = 1;
4989                }
4990             }
4991 
4992 /* Annul the primary Frame pointer. */
4993             pfrm = astAnnul( pfrm );
4994          }
4995 
4996 /* Re-instate the original error reporting state. */
4997          astReporting( oldrep );
4998 
4999 /* If we could not use the attribute name, attempt to get the axis
5000    attribute again, this time retaining the error report. This is done
5001    to ensure the user gets an appropriate error message. */
5002          if( !used ) result = astGetAttrib( ax, axis_attrib );
5003       }
5004 
5005 /* Annul the Axis pointer and free the memory holding the attribute
5006    name. */
5007       ax = astAnnul( ax );
5008       axis_attrib = astFree( axis_attrib );
5009 
5010 /* Not recognised. */
5011 /* --------------- */
5012 /* If the attribute is still not recognised, and the Frame has only 1 axis,
5013    and the attribute name does not already include an axis specifier, try
5014    again after appending "(1)" to the end of the attribute name. */
5015    } else if( !has_axis && naxes == 1 ) {
5016 
5017 /* Take a copy of the supplied name, allowing 3 extra characters for the
5018    axis specifier "(1)". */
5019       axis_attrib = astMalloc( len + 4 );
5020       if( axis_attrib ) memcpy( axis_attrib, attrib, len );
5021 
5022 /* Indicate we should free the axis_attrib memory. */
5023       free_axis_attrib = 1;
5024 
5025 /* Add in the axis specifier. */
5026       strcpy( axis_attrib + len, "(1)" );
5027 
5028 /* Use the new attribute name instead of the supplied name. */
5029       old_attrib = attrib;
5030       attrib = axis_attrib;
5031 
5032 /* Indicate the attribute name now has an axis specifier. */
5033       has_axis = 1;
5034 
5035 /* Jump back to try interpreting the new attribute name. */
5036       goto L1;
5037 
5038 /* Not recognised. */
5039 /* --------------- */
5040 /* If the attribute name is still not recognised, pass it on to the parent
5041    method for further interpretation. First re-instate the original attrib
5042    name string if it was changed above. */
5043    } else {
5044       if( free_axis_attrib ) {
5045          attrib = old_attrib;
5046          axis_attrib = astFree( axis_attrib );
5047       }
5048       result = (*parent_getattrib)( this_object, attrib, status );
5049    }
5050 
5051 /* Return the result. */
5052    return result;
5053 }
5054 
GetAxis(AstFrame * this,int axis,int * status)5055 static AstAxis *GetAxis( AstFrame *this, int axis, int *status ) {
5056 /*
5057 *+
5058 *  Name:
5059 *     astGetAxis
5060 
5061 *  Purpose:
5062 *     Obtain a pointer to a specified Axis from a Frame.
5063 
5064 *  Type:
5065 *     Protected virtual function.
5066 
5067 *  Synopsis:
5068 *     #include "frame.h"
5069 *     AstAxis *astGetAxis( AstFrame *this, int axis )
5070 
5071 *  Class Membership:
5072 *     Frame method.
5073 
5074 *  Description:
5075 *     This function returns a pointer to the Axis object associated
5076 *     with one of the axes of a Frame. This object describes the
5077 *     quantity which is represented along that axis.
5078 
5079 *  Parameters:
5080 *     this
5081 *        Pointer to the Frame.
5082 *     axis
5083 *        The number of the axis (zero-based) for which an Axis pointer is
5084 *        required.
5085 
5086 *  Returned Value:
5087 *     A pointer to the requested Axis object.
5088 
5089 *  Notes:
5090 *     - The reference count of the requested Axis object will be
5091 *     incremented by one to reflect the additional pointer returned by
5092 *     this function.
5093 *     - A NULL pointer will be returned if this function is invoked
5094 *     with the global error status set, or if it should fail for any
5095 *     reason.
5096 *-
5097 */
5098 
5099 /* Local Variables: */
5100    AstAxis *result;              /* Pointer to Axis */
5101 
5102 /* Check the global error status. */
5103    if ( !astOK ) return NULL;
5104 
5105 /* Initialise. */
5106    result = NULL;
5107 
5108 /* Validate and permute the axis index. */
5109    axis = astValidateAxis( this, axis, 1, "astGetAxis" );
5110 
5111 /* If OK, clone the required Axis pointer. */
5112    if ( astOK ) result = astClone( this->axis[ axis ] );
5113 
5114 /* Return the result. */
5115    return result;
5116 }
5117 
GetDefaultLabel(int axis,int * status)5118 static const char *GetDefaultLabel( int axis, int *status ) {
5119 /*
5120 *  Name:
5121 *     GetDefaultLabel
5122 
5123 *  Purpose:
5124 *     Return a pointer to a default axis Label string.
5125 
5126 *  Type:
5127 *     Private function.
5128 
5129 *  Synopsis:
5130 *     #include "frame.h"
5131 *     const char *GetDefaultLabel( int axis, int *status )
5132 
5133 *  Class Membership:
5134 *     Frame member function
5135 
5136 *  Description:
5137 *     This function returns a pointer to a string holding a default axis
5138 *     Label value.
5139 
5140 *  Parameters:
5141 *     axis
5142 *        Zero based axis index.
5143 *     status
5144 *        Pointer to the inherited status variable.
5145 
5146 *  Returned Value:
5147 *     - Pointer to a static null-terminated string containing the attribute
5148 *     value.
5149 
5150 */
5151 
5152 /* Local Variables: */
5153    astDECLARE_GLOBALS            /* Declare the thread specific global data */
5154 
5155 /* Get a pointer to the structure holding thread-specific global data. */
5156    astGET_GLOBALS(NULL);
5157 
5158 /* Format the axis index, putting the string in a global buffer. */
5159    (void) sprintf( label_buff, "Axis %d", axis + 1 );
5160 
5161 /* Return a pointer to the global buffer. */
5162    return label_buff;
5163 }
5164 
GetDefaultSymbol(AstFrame * this,int axis,int * status)5165 static const char *GetDefaultSymbol( AstFrame *this, int axis, int *status ) {
5166 /*
5167 *  Name:
5168 *     GetDefaultSymbol
5169 
5170 *  Purpose:
5171 *     Return a pointer to a default axis Symbol string.
5172 
5173 *  Type:
5174 *     Private function.
5175 
5176 *  Synopsis:
5177 *     #include "frame.h"
5178 *     const char *GetDefaultSymbol( AstFrame *this, int axis, int *status )
5179 
5180 *  Class Membership:
5181 *     Frame member function
5182 
5183 *  Description:
5184 *     This function returns a pointer to a string holding a default axis
5185 *     Symbol value.
5186 
5187 *  Parameters:
5188 *     this
5189 *        Pointer to the Frame.
5190 *     axis
5191 *        Zero based axis index.
5192 *     status
5193 *        Pointer to the inherited status variable.
5194 
5195 *  Returned Value:
5196 *     - Pointer to a static null-terminated string containing the attribute
5197 *     value.
5198 
5199 */
5200 
5201 /* Local Variables: */
5202    astDECLARE_GLOBALS            /* Declare the thread specific global data */
5203 
5204 /* Get a pointer to the structure holding thread-specific global data. */
5205    astGET_GLOBALS(this);
5206 
5207 /* Note we use "sprintf" once to determine how many characters are
5208    produced by the "%d" format string and then limit the number of
5209    characters used from the Domain string in the second invocation of
5210    "sprintf" so that the total length of the default Symbol string
5211    does not exceed SYMBOL_BUFF_LEN characters. */
5212    (void) sprintf( symbol_buff, "%.*s%d",
5213                    SYMBOL_BUFF_LEN - sprintf( symbol_buff, "%d", axis + 1 ),
5214                    astTestDomain( this ) ? astGetDomain( this ) : "x",
5215                    axis + 1 );
5216 
5217 /* Use the AddUnderscores function to replace any white space in the Symbol
5218    string with underscore characters. */
5219    AddUnderscores( symbol_buff, status );
5220 
5221 /* Return a pointer to the global buffer. */
5222    return symbol_buff;
5223 }
5224 
GetDefaultTitle(AstFrame * this,int * status)5225 static const char *GetDefaultTitle( AstFrame *this, int *status ) {
5226 /*
5227 *  Name:
5228 *     GetDefaultTitle
5229 
5230 *  Purpose:
5231 *     Return a pointer to a default Title string.
5232 
5233 *  Type:
5234 *     Private function.
5235 
5236 *  Synopsis:
5237 *     #include "frame.h"
5238 *     const char *GetDefaultTitle( AstFrame *this, int *status )
5239 
5240 *  Class Membership:
5241 *     Frame member function
5242 
5243 *  Description:
5244 *     This function returns a pointer to a string holding a default Title value.
5245 
5246 *  Parameters:
5247 *     this
5248 *        Pointer to the Frame.
5249 *     status
5250 *        Pointer to the inherited status variable.
5251 
5252 *  Returned Value:
5253 *     - Pointer to a static null-terminated string containing the attribute
5254 *     value.
5255 
5256 */
5257 
5258 /* Local Variables: */
5259    astDECLARE_GLOBALS            /* Declare the thread specific global data */
5260 
5261 /* Get a pointer to the structure holding thread-specific global data. */
5262    astGET_GLOBALS(this);
5263 
5264 /* Create the Title value and put it in the global buffer. */
5265    (void) sprintf( title_buff, "%d-d coordinate system", astGetNaxes( this ) );
5266 
5267 /* Return a pointer to the global buffer. */
5268    return title_buff;
5269 }
5270 
GetFrameFlags(AstFrame * this,int * status)5271 static int GetFrameFlags( AstFrame *this, int *status ){
5272 /*
5273 *+
5274 *  Name:
5275 *     astGetFrameFlags
5276 
5277 *  Purpose:
5278 *     Return the bit mask of flags associated with a Frame.
5279 
5280 *  Type:
5281 *     Protected function.
5282 
5283 *  Synopsis:
5284 *     #include "frame.h"
5285 *     int *astGetFrameFlags( astFrame *this )
5286 
5287 *  Class Membership:
5288 *     Frame virtual function.
5289 
5290 *  Description:
5291 *     This function returns a bit mask holding the current set of flags
5292 *     associated with a Frame. See astSetFrameFlags for details of these
5293 *     flags.
5294 
5295 *  Parameters:
5296 *     this
5297 *        The Frame.
5298 
5299 *  Returned Value:
5300 *     The bit mask.
5301 
5302 *  Notes:
5303 *     - Zero is returned if this function is invoked with
5304 *     the global error status set or if it should fail for any reason.
5305 *-
5306 */
5307 
5308 /* Check the global error status. */
5309    if ( !astOK ) return 0;
5310 
5311 /* Return the result. */
5312    return this->flags;
5313 }
5314 
GetIsLinear(AstMapping * this_mapping,int * status)5315 static int GetIsLinear( AstMapping *this_mapping, int *status ){
5316 /*
5317 *  Name:
5318 *     GetIsLinear
5319 
5320 *  Purpose:
5321 *     Return the value of the IsLinear attribute for a Frame.
5322 
5323 *  Type:
5324 *     Private function.
5325 
5326 *  Synopsis:
5327 *     #include "mapping.h"
5328 *     void GetIsLinear( AstMapping *this, int *status )
5329 
5330 *  Class Membership:
5331 *     Frame member function (over-rides the protected astGetIsLinear
5332 *     method inherited from the Mapping class).
5333 
5334 *  Description:
5335 *     This function returns the value of the IsLinear attribute for a
5336 *     Frame, which is always one because a Frame is treated like a UnitMap.
5337 
5338 *  Parameters:
5339 *     this
5340 *        Pointer to the Frame.
5341 *     status
5342 *        Pointer to the inherited status variable.
5343 */
5344    return 1;
5345 }
5346 
GetIsSimple(AstMapping * this_mapping,int * status)5347 static int GetIsSimple( AstMapping *this_mapping, int *status ){
5348 /*
5349 *  Name:
5350 *     GetIsSimple
5351 
5352 *  Purpose:
5353 *     Return the value of the IsSimple attribute for a Frame.
5354 
5355 *  Type:
5356 *     Private function.
5357 
5358 *  Synopsis:
5359 *     #include "mapping.h"
5360 *     void GetIsSimple( AstMapping *this, int *status )
5361 
5362 *  Class Membership:
5363 *     Frame member function (over-rides the protected astGetIsSimple
5364 *     method inherited from the Mapping class).
5365 
5366 *  Description:
5367 *     This function returns the value of the IsSimple attribute for a
5368 *     Frame, which is always zero because Frames are not immutable (unlike
5369 *     non-Frame Mappings).
5370 
5371 *  Parameters:
5372 *     this
5373 *        Pointer to the Frame.
5374 *     status
5375 *        Pointer to the inherited status variable.
5376 */
5377    return 0;
5378 }
5379 
GetNaxes(AstFrame * this,int * status)5380 static int GetNaxes( AstFrame *this, int *status ) {
5381 /*
5382 *+
5383 *  Name:
5384 *     astGetNaxes
5385 
5386 *  Purpose:
5387 *     Determine how many axes a Frame has.
5388 
5389 *  Type:
5390 *     Protected virtual function.
5391 
5392 *  Synopsis:
5393 *     #include "frame.h"
5394 *     int astGetNaxes( AstFrame *this )
5395 
5396 *  Class Membership:
5397 *     Frame method.
5398 
5399 *  Description:
5400 *     This function returns the number of axes for a Frame.
5401 
5402 *  Parameters:
5403 *     this
5404 *        Pointer to the Frame.
5405 
5406 *  Returned Value:
5407 *     The number of Frame axes.
5408 
5409 *  Notes:
5410 *     - A value of zero will be returned if this function is invoked
5411 *     with the global error status set, or if it should fail for any
5412 *     reason.
5413 *-
5414 */
5415 
5416 /* Check the global error status. */
5417    if ( !astOK ) return 0;
5418 
5419 /* Return the number of Frame axes. */
5420    return this->naxes;
5421 }
5422 
GetNin(AstMapping * this_mapping,int * status)5423 static int GetNin( AstMapping *this_mapping, int *status ) {
5424 /*
5425 *  Name:
5426 *     GetNin
5427 
5428 *  Purpose:
5429 *     Get the number of input coordinates for a Frame.
5430 
5431 *  Type:
5432 *     Private function.
5433 
5434 *  Synopsis:
5435 *     #include "frame.h"
5436 *     int GetNin( AstMapping *this, int *status )
5437 
5438 *  Class Membership:
5439 *     Frame member function (over-rides the astGetNin method inherited
5440 *     from the Mapping class).
5441 
5442 *  Description:
5443 *     This function returns the number of input coordinate values
5444 *     required per point by a Frame, when used as a Mapping (i.e. the
5445 *     number of dimensions of the space in which input points reside).
5446 
5447 *  Parameters:
5448 *     this
5449 *        Pointer to the Frame.
5450 *     status
5451 *        Pointer to the inherited status variable.
5452 
5453 *  Returned Value:
5454 *     Number of coordinate values required.
5455 
5456 *  Notes:
5457 *     - A value of zero will be returned if this function is invoked
5458 *     with the global error status set, or if it should fail for any
5459 *     reason.
5460 */
5461 
5462 /* Local Variables: */
5463    AstFrame *this;               /* Pointer to Frame structure */
5464    int result;                   /* Result value to return */
5465 
5466 /* Initialise. */
5467    result = 0;
5468 
5469 /* Check the global error status. */
5470    if ( !astOK ) return result;
5471 
5472 /* Obtain a pointer to the Frame structure. */
5473    this = (AstFrame *) this_mapping;
5474 
5475 /* Return the number of Frame axes. */
5476    result = astGetNaxes( this );
5477 
5478 /* Return the result. */
5479    return result;
5480 }
5481 
GetNout(AstMapping * this_mapping,int * status)5482 static int GetNout( AstMapping *this_mapping, int *status ) {
5483 /*
5484 *  Name:
5485 *     GetNout
5486 
5487 *  Purpose:
5488 *     Get the number of output coordinates for a Frame.
5489 
5490 *  Type:
5491 *     Private function.
5492 
5493 *  Synopsis:
5494 *     #include "frame.h"
5495 *     int GetNout( AstMapping *this, int *status )
5496 
5497 *  Class Membership:
5498 *     Frame member function (over-rides the astGetNout method
5499 *     inherited from the Mapping class).
5500 
5501 *  Description:
5502 *     This function returns the number of output coordinate values
5503 *     generated per point by a Frame, when used as a Mapping (i.e. the
5504 *     number of dimensions of the space in which output points
5505 *     reside).
5506 
5507 *  Parameters:
5508 *     this
5509 *        Pointer to the Frame.
5510 *     status
5511 *        Pointer to the inherited status variable.
5512 
5513 *  Returned Value:
5514 *     Number of coordinate values generated.
5515 
5516 *  Notes:
5517 *     - A value of zero will be returned if this function is invoked
5518 *     with the global error status set, or if it should fail for any
5519 *     reason.
5520 */
5521 
5522 /* Local Variables: */
5523    AstFrame *this;               /* Pointer to Frame structure */
5524    int result;                   /* Result value to return */
5525 
5526 /* Initialise. */
5527    result = 0;
5528 
5529 /* Check the global error status. */
5530    if ( !astOK ) return result;
5531 
5532 /* Obtain a pointer to the Frame structure. */
5533    this = (AstFrame *) this_mapping;
5534 
5535 /* Return the number of Frame axes. */
5536    result = astGetNaxes( this );
5537 
5538 /* Return the result. */
5539    return result;
5540 }
5541 
GetObjSize(AstObject * this_object,int * status)5542 static int GetObjSize( AstObject *this_object, int *status ) {
5543 /*
5544 *  Name:
5545 *     GetObjSize
5546 
5547 *  Purpose:
5548 *     Return the in-memory size of an Object.
5549 
5550 *  Type:
5551 *     Private function.
5552 
5553 *  Synopsis:
5554 *     #include "frame.h"
5555 *     int GetObjSize( AstObject *this, int *status )
5556 
5557 *  Class Membership:
5558 *     Frame member function (over-rides the astGetObjSize protected
5559 *     method inherited from the parent class).
5560 
5561 *  Description:
5562 *     This function returns the in-memory size of the supplied Frame,
5563 *     in bytes.
5564 
5565 *  Parameters:
5566 *     this
5567 *        Pointer to the Frame.
5568 *     status
5569 *        Pointer to the inherited status variable.
5570 
5571 *  Returned Value:
5572 *     The Object size, in bytes.
5573 
5574 *  Notes:
5575 *     - A value of zero will be returned if this function is invoked
5576 *     with the global status set, or if it should fail for any reason.
5577 */
5578 
5579 /* Local Variables: */
5580    AstFrame *this;            /* Pointer to Frame structure */
5581    int axis;                  /* Axis index */
5582    int result;                /* Result value to return */
5583 
5584 /* Initialise. */
5585    result = 0;
5586 
5587 /* Check the global error status. */
5588    if ( !astOK ) return result;
5589 
5590 /* Obtain a pointers to the FrameSet structure. */
5591    this = (AstFrame *) this_object;
5592 
5593 /* Invoke the GetObjSize method inherited from the parent class, and then
5594    add on any components of the class structure defined by this class
5595    which are stored in dynamically allocated memory. */
5596    result = (*parent_getobjsize)( this_object, status );
5597    result += astGetObjSize( this->variants );
5598    result += astTSizeOf( this->domain );
5599    result += astTSizeOf( this->title );
5600    result += astTSizeOf( this->axis );
5601    result += astTSizeOf( this->perm );
5602 
5603    for ( axis = 0; axis < this->naxes; axis++ ) {
5604       result += astGetObjSize( this->axis[ axis ] );
5605    }
5606 
5607 /* If an error occurred, clear the result value. */
5608    if ( !astOK ) result = 0;
5609 
5610 /* Return the result, */
5611    return result;
5612 }
5613 
GetPerm(AstFrame * this,int * status)5614 static const int *GetPerm( AstFrame *this, int *status ) {
5615 /*
5616 *+
5617 *  Name:
5618 *     astGetPerm
5619 
5620 *  Purpose:
5621 *     Access the axis permutation array for a Frame.
5622 
5623 *  Type:
5624 *     Protected virtual function.
5625 
5626 *  Synopsis:
5627 *     #include "frame.h"
5628 *     const int *astGetPerm( AstFrame *this )
5629 
5630 *  Class Membership:
5631 *     Frame method.
5632 
5633 *  Description:
5634 *     This function returns a pointer to the axis permutation array
5635 *     for a Frame. This array constitutes a lookup-table that converts
5636 *     between an axis number supplied externally and the corresponding
5637 *     index in the Frame's internal axis arrays.
5638 
5639 *  Parameters:
5640 *     this
5641 *        Pointer to the Frame.
5642 
5643 *  Returned Value:
5644 *     Pointer to the Frame's axis permutation array (a constant array
5645 *     of int).  Each element of this contains the (zero-based)
5646 *     internal axis index to be used in place of the external index
5647 *     which is used to address the permutation array. If the Frame has
5648 *     zero axes, this pointer will be NULL.
5649 
5650 *  Notes:
5651 *     - This protected method is provided to assist class
5652 *     implementations which need to implement axis-dependent
5653 *     extensions to Frame methods, and which therefore need to know
5654 *     how a Frames's external axis index is converted for internal
5655 *     use.
5656 *     - The pointer returned by this function gives direct access to
5657 *     data internal to the Frame object. It remains valid only so long
5658 *     as the Frame exists. The permutation array contents may be
5659 *     modified by other functions which operate on the Frame and this
5660 *     may render the returned pointer invalid.
5661 *     - A NULL pointer will be returned if this function is invoked
5662 *     with the global error status set, or if it should fail for any
5663 *     reason.
5664 *-
5665 */
5666 
5667 /* Check the global error status. */
5668    if ( !astOK ) return NULL;
5669 
5670 /* Return a pointer to the axis permutation array. */
5671    return this->perm;
5672 }
5673 
GetFrameVariants(AstFrame * this,int * status)5674 static AstFrameSet *GetFrameVariants( AstFrame *this, int *status ){
5675 /*
5676 *+
5677 *  Name:
5678 *     astGetFrameVariants
5679 
5680 *  Purpose:
5681 *     Returns the FrameSet holding the available Frame variants.
5682 
5683 *  Type:
5684 *     Protected  virtual function.
5685 
5686 *  Synopsis:
5687 *     #include "frame.h"
5688 *     AstFrameSet *astGetFrameVariants( AstFrame *this )
5689 
5690 *  Class Membership:
5691 *     Frame method.
5692 
5693 *  Description:
5694 *     This function returns a pointer to any FrameSet previously stored
5695 *     in the Frame using method astSetVariants.
5696 
5697 *  Parameters:
5698 *     this
5699 *        Pointer to the Frame.
5700 
5701 *  Returned Value:
5702 *     astGetFrameVariants
5703 *        A pointer to the FrameSet. It should be annulled using astAnnul
5704 *        when no longer needed. NULL will be returned if no FrameSet is
5705 *        stored in the Frame.
5706 
5707 *  Notes:
5708 *     - A NULL value will be returned if this function is invoked with the
5709 *     AST error status set, or if it should fail for any reason.
5710 *-
5711 */
5712 
5713 /* Local Variables: */
5714    AstFrameSet *result;
5715 
5716 /* Initialise. */
5717    result = NULL;
5718 
5719 /* Check the global error status. */
5720    if ( !astOK ) return result;
5721 
5722 /* Get a clone of any FrameSet pointer. */
5723    if( this->variants ) result = astClone( this->variants );
5724 
5725 /* Return the result. */
5726    return result;
5727 }
5728 
astInitFrameVtab_(AstFrameVtab * vtab,const char * name,int * status)5729 void astInitFrameVtab_(  AstFrameVtab *vtab, const char *name, int *status ) {
5730 /*
5731 *+
5732 *  Name:
5733 *     astInitFrameVtab
5734 
5735 *  Purpose:
5736 *     Initialise a virtual function table for a Frame.
5737 
5738 *  Type:
5739 *     Protected function.
5740 
5741 *  Synopsis:
5742 *     #include "frame.h"
5743 *     void astInitFrameVtab( AstFrameVtab *vtab, const char *name )
5744 
5745 *  Class Membership:
5746 *     Frame vtab initialiser.
5747 
5748 *  Description:
5749 *     This function initialises the component of a virtual function
5750 *     table which is used by the Frame class.
5751 
5752 *  Parameters:
5753 *     vtab
5754 *        Pointer to the virtual function table. The components used by
5755 *        all ancestral classes will be initialised if they have not already
5756 *        been initialised.
5757 *     name
5758 *        Pointer to a constant null-terminated character string which contains
5759 *        the name of the class to which the virtual function table belongs (it
5760 *        is this pointer value that will subsequently be returned by the Object
5761 *        astClass function).
5762 *-
5763 */
5764 
5765 /* Local Variables: */
5766    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
5767    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
5768    AstMappingVtab *mapping;      /* Pointer to Mapping component of Vtab */
5769 
5770 /* Check the local error status. */
5771    if ( !astOK ) return;
5772 
5773 /* Get a pointer to the thread specific global data structure. */
5774    astGET_GLOBALS(NULL);
5775 
5776 /* Initialize the component of the virtual function table used by the
5777    parent class. */
5778    astInitMappingVtab( (AstMappingVtab *) vtab, name );
5779 
5780 /* Store a unique "magic" value in the virtual function table. This
5781    will be used (by astIsAFrame ) to determine if an object belongs
5782    to this class.  We can conveniently use the address of the (static)
5783    class_check variable to generate this unique value. */
5784    vtab->id.check = &class_check;
5785    vtab->id.parent = &(((AstMappingVtab *) vtab)->id);
5786 
5787 /* Initialise member function pointers. */
5788 /* ------------------------------------ */
5789 /* Store pointers to the member functions (implemented here) that provide
5790    virtual methods for this class. */
5791    vtab->Abbrev = Abbrev;
5792    vtab->CheckPerm = CheckPerm;
5793    vtab->ClearDigits = ClearDigits;
5794    vtab->ClearDirection = ClearDirection;
5795    vtab->ClearDomain = ClearDomain;
5796    vtab->ClearFormat = ClearFormat;
5797    vtab->ClearLabel = ClearLabel;
5798    vtab->ClearMatchEnd = ClearMatchEnd;
5799    vtab->ClearMaxAxes = ClearMaxAxes;
5800    vtab->ClearMinAxes = ClearMinAxes;
5801    vtab->ClearPermute = ClearPermute;
5802    vtab->ClearPreserveAxes = ClearPreserveAxes;
5803    vtab->ClearSymbol = ClearSymbol;
5804    vtab->ClearTitle = ClearTitle;
5805    vtab->ClearUnit = ClearUnit;
5806    vtab->Convert = Convert;
5807    vtab->ConvertX = ConvertX;
5808    vtab->Angle = Angle;
5809    vtab->Distance = Distance;
5810    vtab->Fields = Fields;
5811    vtab->FindFrame = FindFrame;
5812    vtab->MatchAxes = MatchAxes;
5813    vtab->MatchAxesX = MatchAxesX;
5814    vtab->Format = Format;
5815    vtab->Gap = Gap;
5816    vtab->GetAxis = GetAxis;
5817    vtab->GetDigits = GetDigits;
5818    vtab->GetDirection = GetDirection;
5819    vtab->GetDomain = GetDomain;
5820    vtab->GetFormat = GetFormat;
5821    vtab->GetLabel = GetLabel;
5822    vtab->GetMatchEnd = GetMatchEnd;
5823    vtab->GetMaxAxes = GetMaxAxes;
5824    vtab->GetMinAxes = GetMinAxes;
5825    vtab->GetNaxes = GetNaxes;
5826    vtab->GetPerm = GetPerm;
5827    vtab->GetPermute = GetPermute;
5828    vtab->GetPreserveAxes = GetPreserveAxes;
5829    vtab->GetSymbol = GetSymbol;
5830    vtab->GetTitle = GetTitle;
5831    vtab->GetUnit = GetUnit;
5832    vtab->GetNormUnit = GetNormUnit;
5833    vtab->Intersect = Intersect;
5834    vtab->IsUnitFrame = IsUnitFrame;
5835    vtab->Match = Match;
5836    vtab->Norm = Norm;
5837    vtab->NormBox = NormBox;
5838    vtab->AxDistance = AxDistance;
5839    vtab->AxOffset = AxOffset;
5840    vtab->AxIn = AxIn;
5841    vtab->AxAngle = AxAngle;
5842    vtab->FrameGrid = FrameGrid;
5843    vtab->Offset = Offset;
5844    vtab->Offset2 = Offset2;
5845    vtab->Resolve = Resolve;
5846    vtab->ResolvePoints = ResolvePoints;
5847    vtab->LineDef = LineDef;
5848    vtab->LineContains = LineContains;
5849    vtab->LineCrossing = LineCrossing;
5850    vtab->LineOffset = LineOffset;
5851    vtab->Overlay = Overlay;
5852    vtab->PermAxes = PermAxes;
5853    vtab->PickAxes = PickAxes;
5854    vtab->PrimaryFrame = PrimaryFrame;
5855    vtab->SetAxis = SetAxis;
5856    vtab->SetDigits = SetDigits;
5857    vtab->SetDirection = SetDirection;
5858    vtab->SetDomain = SetDomain;
5859    vtab->SetFormat = SetFormat;
5860    vtab->SetLabel = SetLabel;
5861    vtab->SetMatchEnd = SetMatchEnd;
5862    vtab->SetMaxAxes = SetMaxAxes;
5863    vtab->SetMinAxes = SetMinAxes;
5864    vtab->SetPermute = SetPermute;
5865    vtab->SetPreserveAxes = SetPreserveAxes;
5866    vtab->SetSymbol = SetSymbol;
5867    vtab->SetTitle = SetTitle;
5868    vtab->SetUnit = SetUnit;
5869    vtab->SubFrame = SubFrame;
5870    vtab->TestDigits = TestDigits;
5871    vtab->TestDirection = TestDirection;
5872    vtab->TestDomain = TestDomain;
5873    vtab->TestFormat = TestFormat;
5874    vtab->TestLabel = TestLabel;
5875    vtab->TestMatchEnd = TestMatchEnd;
5876    vtab->TestMaxAxes = TestMaxAxes;
5877    vtab->TestMinAxes = TestMinAxes;
5878    vtab->TestPermute = TestPermute;
5879    vtab->TestPreserveAxes = TestPreserveAxes;
5880    vtab->TestSymbol = TestSymbol;
5881    vtab->TestTitle = TestTitle;
5882    vtab->TestUnit = TestUnit;
5883    vtab->Unformat = Unformat;
5884    vtab->ValidateAxis = ValidateAxis;
5885    vtab->ValidateAxisSelection = ValidateAxisSelection;
5886    vtab->ValidateSystem = ValidateSystem;
5887    vtab->SystemString = SystemString;
5888    vtab->SystemCode = SystemCode;
5889 
5890    vtab->GetFrameFlags = GetFrameFlags;
5891    vtab->SetFrameFlags = SetFrameFlags;
5892 
5893    vtab->TestActiveUnit = TestActiveUnit;
5894    vtab->GetActiveUnit = GetActiveUnit;
5895    vtab->SetActiveUnit = SetActiveUnit;
5896 
5897    vtab->GetFrameVariants = GetFrameVariants;
5898    vtab->SetFrameVariants = SetFrameVariants;
5899 
5900    vtab->ClearSystem = ClearSystem;
5901    vtab->GetSystem = GetSystem;
5902    vtab->SetSystem = SetSystem;
5903    vtab->TestSystem = TestSystem;
5904 
5905    vtab->ClearAlignSystem = ClearAlignSystem;
5906    vtab->GetAlignSystem = GetAlignSystem;
5907    vtab->SetAlignSystem = SetAlignSystem;
5908    vtab->TestAlignSystem = TestAlignSystem;
5909 
5910    vtab->ClearTop = ClearTop;
5911    vtab->GetTop = GetTop;
5912    vtab->SetTop = SetTop;
5913    vtab->TestTop = TestTop;
5914 
5915    vtab->ClearBottom = ClearBottom;
5916    vtab->GetBottom = GetBottom;
5917    vtab->SetBottom = SetBottom;
5918    vtab->TestBottom = TestBottom;
5919 
5920    vtab->ClearEpoch = ClearEpoch;
5921    vtab->GetEpoch = GetEpoch;
5922    vtab->SetEpoch = SetEpoch;
5923    vtab->TestEpoch = TestEpoch;
5924 
5925    vtab->ClearObsLat = ClearObsLat;
5926    vtab->TestObsLat = TestObsLat;
5927    vtab->GetObsLat = GetObsLat;
5928    vtab->SetObsLat = SetObsLat;
5929 
5930    vtab->ClearObsLon = ClearObsLon;
5931    vtab->TestObsLon = TestObsLon;
5932    vtab->GetObsLon = GetObsLon;
5933    vtab->SetObsLon = SetObsLon;
5934 
5935    vtab->ClearObsAlt = ClearObsAlt;
5936    vtab->TestObsAlt = TestObsAlt;
5937    vtab->GetObsAlt = GetObsAlt;
5938    vtab->SetObsAlt = SetObsAlt;
5939 
5940    vtab->ClearDut1 = ClearDut1;
5941    vtab->GetDut1 = GetDut1;
5942    vtab->SetDut1 = SetDut1;
5943    vtab->TestDut1 = TestDut1;
5944 
5945 /* Save the inherited pointers to methods that will be extended, and
5946    replace them with pointers to the new member functions. */
5947    object = (AstObjectVtab *) vtab;
5948 
5949    parent_getobjsize = object->GetObjSize;
5950    object->GetObjSize = GetObjSize;
5951    parent_clearattrib = object->ClearAttrib;
5952    object->ClearAttrib = ClearAttrib;
5953    parent_getattrib = object->GetAttrib;
5954    object->GetAttrib = GetAttrib;
5955    parent_setattrib = object->SetAttrib;
5956    object->SetAttrib = SetAttrib;
5957    parent_testattrib = object->TestAttrib;
5958    object->TestAttrib = TestAttrib;
5959 
5960    parent_cleanattribs = object->CleanAttribs;
5961    object->CleanAttribs = CleanAttribs;
5962 
5963 #if defined(THREAD_SAFE)
5964    parent_managelock = object->ManageLock;
5965    object->ManageLock = ManageLock;
5966 #endif
5967 
5968 /* Store replacement pointers for methods which will be over-ridden by
5969    new member functions implemented here. */
5970    mapping = (AstMappingVtab *) vtab;
5971 
5972    object->Equal = Equal;
5973    mapping->GetIsLinear = GetIsLinear;
5974    mapping->GetIsSimple = GetIsSimple;
5975    mapping->GetNin = GetNin;
5976    mapping->GetNout = GetNout;
5977    mapping->ReportPoints = ReportPoints;
5978    mapping->Transform = Transform;
5979    mapping->MapSplit = MapSplit;
5980    mapping->DoNotSimplify = DoNotSimplify;
5981 
5982 /* Declare the copy constructor, destructor and class dump
5983    function. */
5984    astSetCopy( vtab, Copy );
5985    astSetDelete( vtab, Delete );
5986    astSetDump( vtab, Dump, "Frame", "Coordinate system description" );
5987 
5988 /* If we have just initialised the vtab for the current class, indicate
5989    that the vtab is now initialised, and store a pointer to the class
5990    identifier in the base "object" level of the vtab. */
5991    if( vtab == &class_vtab ) {
5992       class_init = 1;
5993       astSetVtabClassIdentifier( vtab, &(vtab->id) );
5994    }
5995 }
5996 
Intersect(AstFrame * this,const double a1[2],const double a2[2],const double b1[2],const double b2[2],double cross[2],int * status)5997 static void Intersect( AstFrame *this, const double a1[2],
5998                        const double a2[2], const double b1[2],
5999                        const double b2[2], double cross[2],
6000                        int *status ) {
6001 /*
6002 *++
6003 *  Name:
6004 c     astIntersect
6005 f     AST_INTERSECT
6006 
6007 *  Purpose:
6008 *     Find the point of intersection between two geodesic curves.
6009 
6010 *  Type:
6011 *     Public virtual function.
6012 
6013 *  Synopsis:
6014 c     #include "frame.h"
6015 c     void astIntersect( AstFrame *this, const double a1[2],
6016 c                        const double a2[2], const double b1[2],
6017 c                        const double b2[2], double cross[2] )
6018 f     CALL AST_INTERSECT( THIS, A1, A2, B1, B2, CROSS, STATUS )
6019 
6020 *  Class Membership:
6021 *     Frame method.
6022 
6023 *  Description:
6024 c     This function
6025 f     This routine
6026 *     finds the coordinate values at the point of intersection between
6027 *     two geodesic curves. Each curve is specified by two points on
6028 *     the curve.  It can only be used with 2-dimensional Frames.
6029 *
6030 *     For example, in a basic Frame, it will find the point of
6031 *     intersection between two straight lines. But for a SkyFrame it
6032 *     will find an intersection of two great circles.
6033 
6034 *  Parameters:
6035 c     this
6036 f     THIS = INTEGER (Given)
6037 *        Pointer to the Frame.
6038 c     a1
6039 f     A1( 2 ) = DOUBLE PRECISION (Given)
6040 c        An array of double, with one element for each Frame axis
6041 f        An array with one element for each Frame axis
6042 *        (Naxes attribute). This should contain the coordinates of the
6043 *        first point on the first geodesic curve.
6044 c     a2
6045 f     A2( 2 ) = DOUBLE PRECISION (Given)
6046 c        An array of double, with one element for each Frame axis
6047 f        An array with one element for each Frame axis
6048 *        (Naxes attribute). This should contain the coordinates of a
6049 *        second point on the first geodesic curve. It should not be
6050 *        co-incident with the first point.
6051 c     b1
6052 f     B1( 2 ) = DOUBLE PRECISION (Given)
6053 c        An array of double, with one element for each Frame axis
6054 f        An array with one element for each Frame axis
6055 *        (Naxes attribute). This should contain the coordinates of the
6056 *        first point on the second geodesic curve.
6057 c     b2
6058 f     B2( 2 ) = DOUBLE PRECISION (Given)
6059 c        An array of double, with one element for each Frame axis
6060 f        An array with one element for each Frame axis
6061 *        (Naxes attribute). This should contain the coordinates of a
6062 *        second point on the second geodesic curve. It should not be
6063 *        co-incident with the first point.
6064 c     cross
6065 f     CROSS( 2 ) = DOUBLE PRECISION (Returned)
6066 c        An array of double, with one element for each Frame axis
6067 f        An array with one element for each Frame axis
6068 *        in which the coordinates of the required intersection will
6069 *        be returned.
6070 f     STATUS = INTEGER (Given and Returned)
6071 f        The global status.
6072 
6073 *  Notes:
6074 *     - For SkyFrames each curve will be a great circle, and in general
6075 *     each pair of curves will intersect at two diametrically opposite
6076 *     points on the sky. The returned position is the one which is
6077 *     closest to point
6078 c     "a1".
6079 f     A1.
6080 *     - This function will return "bad" coordinate values (AST__BAD)
6081 *     if any of the input coordinates has this value, or if the two
6082 *     points defining either geodesic are co-incident, or if the two
6083 *     curves do not intersect.
6084 c     - The geodesic curve used by this function is the path of
6085 f     - The geodesic curve used by this routine is the path of
6086 *     shortest distance between two points, as defined by the
6087 c     astDistance function.
6088 f     AST_DISTANCE function.
6089 *     - An error will be reported if the Frame is not 2-dimensional.
6090 *--
6091 */
6092 
6093 /* Local Variables: */
6094    double ca;                    /* Y axis intercept of line a */
6095    double cb;                    /* Y axis intercept of line b */
6096    double dxa;                   /* X range spanned by line a */
6097    double dxb;                   /* X range spanned by line b */
6098    double ma;                    /* Gradient of line a */
6099    double mb;                    /* Gradient of line b */
6100    int naxes;                    /* Number of Frame axes */
6101 
6102 /* Check the global error status. */
6103    if ( !astOK ) return;
6104 
6105 /* Initialize bad values. */
6106    cross[ 0 ] = AST__BAD;
6107    cross[ 1 ] = AST__BAD;
6108 
6109 /* Determine the number of Frame axes. */
6110    naxes = astGetNaxes( this );
6111 
6112 /* Report an error if the Frame is not 2 dimensional. */
6113    if( naxes != 2 && astOK ) {
6114       astError( AST__NAXIN, "astIntersect(%s): Invalid number of Frame axes (%d)."
6115                 " astIntersect can only be used with 2 dimensonal Frames.", status,
6116                 astGetClass( this ), naxes );
6117    }
6118 
6119 /* Check that all supplied values are OK. */
6120    if ( ( a1[ 0 ] != AST__BAD ) && ( a1[ 1 ] != AST__BAD ) &&
6121         ( a2[ 0 ] != AST__BAD ) && ( a2[ 1 ] != AST__BAD ) &&
6122         ( b1[ 0 ] != AST__BAD ) && ( b1[ 1 ] != AST__BAD ) &&
6123         ( b2[ 0 ] != AST__BAD ) && ( b2[ 1 ] != AST__BAD ) ) {
6124 
6125 /* Find the x increments spanned by the two lines. */
6126 
6127 /* Check the first line is not vertical. */
6128       dxa = a2[ 0 ] - a1[ 0 ];
6129       dxb = b2[ 0 ] - b1[ 0 ];
6130       if( dxa != 0.0 ) {
6131 
6132 /* Find the gradient and Y axis intercept of the first line. */
6133          ma = ( a2[ 1 ] - a1[ 1 ] )/dxa;
6134          ca = a1[ 1 ] - a1[ 0 ]*ma;
6135 
6136 /* Check the second line is not vertical. */
6137          if( dxb != 0.0 ) {
6138 
6139 /* Find the gradient and Y axis intercept of the second line. */
6140             mb = ( b2[ 1 ] - b1[ 1 ] )/dxb;
6141             cb = b1[ 1 ] - b1[ 0 ]*mb;
6142 
6143 /* Check the lines are not parallel. */
6144             if( ma != mb ) {
6145 
6146 /* Find the intersection of the two lines. */
6147                cross[ 0 ] = ( cb -ca )/( ma - mb );
6148                cross[ 1 ] = ( ( ma + mb )*cross[ 0 ] + ca + cb )/2;
6149             }
6150 
6151 /* If the second line is vertical but the first is not. */
6152          } else if( b1[ 1 ] != b2[ 1 ] ){
6153             cross[ 0 ] = b1[ 0 ];
6154             cross[ 1 ] = ma*b1[ 0 ] + ca;
6155          }
6156 
6157 /* First line is vertical but second is not. */
6158       } else if( dxb != 0.0 && a1[ 1 ] != a2[ 1 ] ){
6159 
6160 /* Find the gradient and Y axis intercept of the second line. */
6161          mb = ( b2[ 1 ] - b1[ 1 ] )/dxb;
6162          cb = b1[ 1 ] - b1[ 0 ]*mb;
6163 
6164 /* Find the intercection. */
6165          cross[ 0 ] = a1[ 0 ];
6166          cross[ 1 ] = mb*a1[ 0 ] + cb;
6167       }
6168    }
6169 }
6170 
IsUnitFrame(AstFrame * this,int * status)6171 static int IsUnitFrame( AstFrame *this, int *status ){
6172 /*
6173 *+
6174 *  Name:
6175 *     astIsUnitFrame
6176 
6177 *  Purpose:
6178 *     Is this Frame equivalent to a UnitMap?
6179 
6180 *  Type:
6181 *     Protected virtual function.
6182 
6183 *  Synopsis:
6184 *     #include "frame.h"
6185 *     int astIsUnitFrame( AstFrame *this )
6186 
6187 *  Class Membership:
6188 *     Frame method.
6189 
6190 *  Description:
6191 *     This function returns a flag indicating if the supplied Frame is
6192 *     equivalent to a UnitMap when treated as a Mapping (note, the Frame
6193 *     class inherits from Mapping and therefore every Frame is also a Mapping).
6194 
6195 *  Parameters:
6196 *     this
6197 *        Pointer to the Frame.
6198 
6199 *  Returned Value:
6200 *     A non-zero value is returned if the supplied Frame is equivalent to
6201 *     a UnitMap when treated as a Mapping.
6202 
6203 *-
6204 */
6205 
6206 /* Check the local error status. */
6207    if( !astOK ) return 0;
6208 
6209 /* The base Frame class is always equivalent to a UnitMap. */
6210    return 1;
6211 }
6212 
LineContains(AstFrame * this,AstLineDef * l,int def,double * point,int * status)6213 static int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) {
6214 /*
6215 *+
6216 *  Name:
6217 *     astLineContains
6218 
6219 *  Purpose:
6220 *     Determine if a line contains a point.
6221 
6222 *  Type:
6223 *     Protected virtual function.
6224 
6225 *  Synopsis:
6226 *     #include "frame.h"
6227 *     int astLineContains( AstFrame *this, AstLineDef *l, int def, double *point )
6228 
6229 *  Class Membership:
6230 *     Frame method.
6231 
6232 *  Description:
6233 *     This function determines if the supplied point is on the supplied
6234 *     line within the supplied Frame. The start point of the line is
6235 *     considered to be within the line, but the end point is not. The tests
6236 *     are that the point of closest approach of the line to the point should
6237 *     be between the start and end, and that the distance from the point to
6238 *     the point of closest aproach should be less than 1.0E-7 of the length
6239 *     of the line.
6240 
6241 *  Parameters:
6242 *     this
6243 *        Pointer to the Frame.
6244 *     l
6245 *        Pointer to the structure defining the line.
6246 *     def
6247 *        Should be set non-zero if the "point" array was created by a
6248 *        call to astLineCrossing (in which case it may contain extra
6249 *        information following the axis values),and zero otherwise.
6250 *     point
6251 *        Point to an array containing the axis values of the point to be
6252 *        tested, possibly followed by extra cached information (see "def").
6253 
6254 *  Returned Value:
6255 *     A non-zero value is returned if the line contains the point.
6256 
6257 *  Notes:
6258 *     - The pointer supplied for "l" should have been created using the
6259 *     astLineDef method. These structures contained cached information about
6260 *     the lines which improve the efficiency of this method when many
6261 *     repeated calls are made. An error will be reported if the structure
6262 *     does not refer to the Frame specified by "this".
6263 *     - Zero will be returned if this function is invoked with the global
6264 *     error status set, or if it should fail for any reason.
6265 *-
6266 */
6267 
6268 /* Local Variables: */
6269    int result;
6270    double dx, dy, p;
6271 
6272 /* Initialise. */
6273    result = 0;
6274 
6275 /* Check the global error status. */
6276    if ( !astOK ) return result;
6277 
6278 /* Check that the line refers to the supplied Frame. */
6279    if( l->frame != this ) {
6280       astError( AST__INTER, "astLineContains(%s): The supplied line does "
6281                 "not relate to the supplied %s (AST internal programming "
6282                 "error).", status, astGetClass( this ), astGetClass( this ) );
6283 
6284 /* If the point is good, find the offsets from the start of the line. */
6285    } else if( point[ 0 ] != AST__BAD && point[ 1 ] != AST__BAD ) {
6286       dx = point[ 0 ] - l->start[ 0 ];
6287       dy = point[ 1 ] - l->start[ 1 ];
6288 
6289 /* Check the nearest point on the line is between the start and end.
6290    Exclude the end point. */
6291       p = dx*l->dir[ 0 ] + dy*l->dir[ 1 ];
6292       if( p >= 0.0 && p < l->length ) {
6293 
6294 /* Check the distance from the point to the nearest point on the line is not
6295    further than 1.0E-7 of the length of the line. */
6296          if( fabs( dx*l->q[ 0 ] + dy*l->q[ 1 ] ) <= 1.0E-7*l->length ) {
6297             result = 1;
6298          }
6299       }
6300    }
6301 
6302 /* Return zero if an error occurred. */
6303    if( !astOK ) result = 0;
6304 
6305 /* Return a pointer to the output structure. */
6306    return result;
6307 }
6308 
LineCrossing(AstFrame * this,AstLineDef * l1,AstLineDef * l2,double ** cross,int * status)6309 static int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
6310                          double **cross, int *status ) {
6311 /*
6312 *+
6313 *  Name:
6314 *     astLineCrossing
6315 
6316 *  Purpose:
6317 *     Determine if two lines cross.
6318 
6319 *  Type:
6320 *     Protected virtual function.
6321 
6322 *  Synopsis:
6323 *     #include "frame.h"
6324 *     int astLineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
6325 *                          double **cross )
6326 
6327 *  Class Membership:
6328 *     Frame method.
6329 
6330 *  Description:
6331 *     This function determines if the two suplied line segments cross,
6332 *     and if so returns the axis values at the point where they cross.
6333 *     A flag is also returned indicating if the crossing point occurs
6334 *     within the length of both line segments, or outside one or both of
6335 *     the line segments.
6336 
6337 *  Parameters:
6338 *     this
6339 *        Pointer to the Frame.
6340 *     l1
6341 *        Pointer to the structure defining the first line.
6342 *     l2
6343 *        Pointer to the structure defining the second line.
6344 *     cross
6345 *        Pointer to a location at which to put a pointer to a dynamically
6346 *        alocated array containing the axis values at the crossing. If
6347 *        NULL is supplied no such array is returned. Otherwise, the returned
6348 *        array should be freed using astFree when no longer needed. If the
6349 *        lines are parallel (i.e. do not cross) then AST__BAD is returned for
6350 *        all axis values. Note usable axis values are returned even if the
6351 *        lines cross outside the segment defined by the start and end points
6352 *        of the lines. The order of axes in the returned array will take
6353 *        account of the current axis permutation array if appropriate. Note,
6354 *        sub-classes such as SkyFrame may append extra values to the end
6355 *        of the basic frame axis values. A NULL pointer is returned if an
6356 *        error occurs.
6357 
6358 *  Returned Value:
6359 *     A non-zero value is returned if the lines cross at a point which is
6360 *     within the [start,end) segment of the lines that are flagged as
6361 *     finite (if a line is marked as infinite any crossing is assumed to
6362 *     be within the bounds of the line). If the crossing point is outside
6363 *     this segment on either (inifinte) line, or if the lines are parallel,
6364 *     zero is returned. Note, the start point is considered to be inside
6365 *     the length of the segment, but the end point is outside.
6366 
6367 *  Notes:
6368 *     - The pointers supplied for "l1" and "l2" should have been created
6369 *     using the astLineDef method. These structures contained cached
6370 *     information about the lines which improve the efficiency of this method
6371 *     when many repeated calls are made. An error will be reported if
6372 *     either structure does not refer to the Frame specified by "this".
6373 *     - Zero will be returned if this function is invoked with the global
6374 *     error status set, or if it should fail for any reason.
6375 *-
6376 */
6377 
6378 /* Local Variables: */
6379    double *crossing;          /* Returned array */
6380    double den;                /* Denominator */
6381    double dx;                 /* Offset in start X values */
6382    double dy;                 /* Offset in start Y values */
6383    double t1;                 /* Distance from start of line 1 to crossing */
6384    double t2;                 /* Distance from start of line 2 to crossing */
6385    int result;                /* Returned value */
6386 
6387 /* Check the global error status. */
6388    if ( !astOK ) return 0;
6389 
6390 /* Initialise. */
6391    result = 0;
6392    crossing = astMalloc( sizeof(double)*2 );
6393 
6394 /* Check that both lines refer to the supplied Frame. */
6395    if( l1->frame != this ) {
6396       astError( AST__INTER, "astLineCrossing(%s): First supplied line does "
6397                 "not relate to the supplied %s (AST internal programming "
6398                 "error).", status, astGetClass( this ), astGetClass( this ) );
6399 
6400    } else if( l2->frame != this ) {
6401       astError( AST__INTER, "astLineCrossing(%s): Second supplied line does "
6402                 "not relate to the supplied %s (AST internal programming "
6403                 "error).", status, astGetClass( this ), astGetClass( this ) );
6404 
6405    } else if( crossing ){
6406 
6407 /* Each of the lines can be represented as "p = start + t.v" where start is
6408    the start position, v is the unit vector pointing from start to end,
6409    and t is the scalar distance from the start position. So to find the
6410    intersection put "start1 + t1.v1 = start2 + t2.v2" and solve for t1
6411    and t2. */
6412       den = (l1->dir[ 0 ])*(l2->dir[ 1 ]) - (l2->dir[ 0 ])*(l1->dir[ 1 ]);
6413       if( den != 0.0 ) {
6414          dx = l2->start[ 0 ] - l1->start[ 0 ];
6415          dy = l2->start[ 1 ] - l1->start[ 1 ];
6416          t1 = ( l2->dir[ 1 ]*dx - l2->dir[ 0 ]*dy )/den;
6417          t2 = ( l1->dir[ 1 ]*dx - l1->dir[ 0 ]*dy )/den;
6418 
6419 /* Store the crossing point, using the smaller t value to redue error. */
6420          if( fabs( t1 ) < fabs( t2 ) ) {
6421             crossing[ 0 ] = l1->start[ 0 ] + t1*l1->dir[ 0 ];
6422             crossing[ 1 ] = l1->start[ 1 ] + t1*l1->dir[ 1 ];
6423          } else {
6424             crossing[ 0 ] = l2->start[ 0 ] + t2*l2->dir[ 0 ];
6425             crossing[ 1 ] = l2->start[ 1 ] + t2*l2->dir[ 1 ];
6426          }
6427 
6428 /* See if the intersection is within the length of both lines (excluding
6429    the end points). If a line is flagged as infinite, set the "t" parameter
6430    to zero to make it look like the crossing is within the line. */
6431          if( l1->infinite ) t1 = 0.0;
6432          if( l2->infinite ) t2 = 0.0;
6433 
6434          if( t1 >= 0.0 && t1 < l1->length &&
6435              t2 >= 0.0 && t2 < l2->length ) result = 1;
6436 
6437       } else {
6438          crossing[ 0 ] = AST__BAD;
6439          crossing[ 1 ] = AST__BAD;
6440       }
6441    }
6442 
6443 /* Return zero if an error occurred. */
6444    if( !astOK ) {
6445       crossing = astFree( crossing );
6446       result = 0;
6447    }
6448 
6449 /* Return the crossing pointer. */
6450    if( cross ) {
6451       *cross = crossing;
6452    } else if( crossing ){
6453       crossing = astFree( crossing );
6454    }
6455 
6456 /* Return a pointer to the output structure. */
6457    return result;
6458 }
6459 
LineDef(AstFrame * this,const double start[2],const double end[2],int * status)6460 static AstLineDef *LineDef( AstFrame *this, const double start[2],
6461                             const double end[2], int *status ) {
6462 /*
6463 *+
6464 *  Name:
6465 *     astLineDef
6466 
6467 *  Purpose:
6468 *     Creates a structure describing a line segment in a 2D Frame.
6469 
6470 *  Type:
6471 *     Protected virtual function.
6472 
6473 *  Synopsis:
6474 *     #include "frame.h"
6475 *     AstLineDef *astLineDef( AstFrame *this, const double start[2],
6476 *                             const double end[2] )
6477 
6478 *  Class Membership:
6479 *     Frame method.
6480 
6481 *  Description:
6482 *     This function creates a structure containing information describing a
6483 *     given line segment within the supplied 2D Frame. This may include
6484 *     information which allows other methods such as astLineCrossing to
6485 *     function more efficiently. Thus the returned structure acts as a
6486 *     cache to store intermediate values used by these other methods.
6487 
6488 *  Parameters:
6489 *     this
6490 *        Pointer to the Frame. Must have 2 axes.
6491 *     start
6492 *        An array of 2 doubles marking the start of the line segment.
6493 *     end
6494 *        An array of 2 doubles marking the end of the line segment.
6495 
6496 *  Returned Value:
6497 *     Pointer to the memory structure containing the description of the
6498 *     line. This structure should be freed using astFree when no longer
6499 *     needed. A NULL pointer is returned (without error) if any of the
6500 *     supplied axis values are AST__BAD.
6501 
6502 *  Notes:
6503 *     - A null pointer will be returned if this function is invoked
6504 *     with the global error status set, or if it should fail for any
6505 *     reason.
6506 *-
6507 */
6508 
6509 /* Local Variables: */
6510    AstLineDef *result;           /* Pointer to output structure */
6511 
6512 /* Initialise. */
6513    result = NULL;
6514 
6515 /* Check the global error status. */
6516    if ( !astOK ) return result;
6517 
6518 /* Check the Frame has 2 axes. */
6519    if( astGetNaxes( this ) != 2 ) {
6520       astError( AST__INTER, "astLineDef(%s): The supplied %s is not 2 "
6521                 "dimensional (internal AST proramming error).", status,
6522                  astGetClass( this ), astGetClass( this ) );
6523    }
6524 
6525 /* Check the axis values are good */
6526    if( start[ 0 ] != AST__BAD && start[ 1 ] != AST__BAD &&
6527        end[ 0 ] != AST__BAD && end[ 1 ] != AST__BAD ) {
6528 
6529 /* Allocate memory for the returned structure. */
6530       result = astMalloc( sizeof( AstLineDef ) );
6531       if( result ) {
6532 
6533 /* Store the supplied axis values in the returned structure. */
6534          result->start[ 0 ] = start[ 0 ];
6535          result->start[ 1 ] = start[ 1 ];
6536          result->end[ 0 ] = end[ 0 ];
6537          result->end[ 1 ] = end[ 1 ];
6538 
6539 /* Store the length of the line segment. */
6540          result->length = astDistance( this, start, end );
6541 
6542 /* Store a unit vector pointing from the start to the end. */
6543          if( result->length > 0.0 ) {
6544             result->dir[ 0 ] = ( end[ 0 ] - start[ 0 ] )/result->length;
6545             result->dir[ 1 ] = ( end[ 1 ] - start[ 1 ] )/result->length;
6546          } else {
6547             result->dir[ 0 ] = 1.0;
6548             result->dir[ 1 ] = 0.0;
6549          }
6550 
6551 /* Store a unit vector perpendicular to the line, such that the vector
6552    points to the left, as vewied from the observer, when moving from the
6553    start to the end of the line. */
6554          result->q[ 0 ] = -result->dir[ 1 ];
6555          result->q[ 1 ] = result->dir[ 0 ];
6556 
6557 /* Store a pointer to the defining Frame. */
6558          result->frame = this;
6559 
6560 /* Indicate that the line is considered to be terminated at the start and
6561    end points. */
6562          result->infinite = 0;
6563       }
6564    }
6565 
6566 /* Free the returned pointer if an error occurred. */
6567    if( !astOK ) result = astFree( result );
6568 
6569 /* Return a pointer to the output structure. */
6570    return result;
6571 }
6572 
LineOffset(AstFrame * this,AstLineDef * line,double par,double prp,double point[2],int * status)6573 static void LineOffset( AstFrame *this, AstLineDef *line, double par,
6574                         double prp, double point[2], int *status ){
6575 /*
6576 *+
6577 *  Name:
6578 *     astLineOffset
6579 
6580 *  Purpose:
6581 *     Find a position close to a line.
6582 
6583 *  Type:
6584 *     Protected virtual function.
6585 
6586 *  Synopsis:
6587 *     #include "frame.h"
6588 *     void LineOffset( AstFrame *this, AstLineDef *line, double par,
6589 *                      double prp, double point[2] )
6590 
6591 *  Class Membership:
6592 *     Frame method.
6593 
6594 *  Description:
6595 *     This function returns a position formed by moving a given distance along
6596 *     the supplied line, and then a given distance away from the supplied line.
6597 
6598 *  Parameters:
6599 *     this
6600 *        Pointer to the Frame.
6601 *     line
6602 *        Pointer to the structure defining the line.
6603 *     par
6604 *        The distance to move along the line from the start towards the end.
6605 *     prp
6606 *        The distance to move at right angles to the line. Positive
6607 *        values result in movement to the left of the line, as seen from
6608 *        the observer, when moving from start towards the end.
6609 
6610 *  Notes:
6611 *     - The pointer supplied for "line" should have been created using the
6612 *     astLineDef method. This structure contains cached information about the
6613 *     line which improves the efficiency of this method when many repeated
6614 *     calls are made. An error will be reported if the structure does not
6615 *     refer to the Frame specified by "this".
6616 *-
6617 */
6618 
6619 /* Check the global error status. */
6620    if ( !astOK ) return;
6621 
6622 /* Check that the line refers to the supplied Frame. */
6623    if( line->frame != this ) {
6624       astError( AST__INTER, "astLineOffset(%s): The supplied line does "
6625                 "not relate to the supplied %s (AST internal programming "
6626                 "error).", status, astGetClass( this ), astGetClass( this ) );
6627 
6628 /* This implementation uses simple flat geometry. */
6629    } else {
6630       point[ 0 ] = line->start[ 0 ] + par*line->dir[ 0 ] + prp*line->q[ 0 ];
6631       point[ 1 ] = line->start[ 1 ] + par*line->dir[ 1 ] + prp*line->q[ 1 ];
6632    }
6633 }
6634 
6635 #if defined(THREAD_SAFE)
ManageLock(AstObject * this_object,int mode,int extra,AstObject ** fail,int * status)6636 static int ManageLock( AstObject *this_object, int mode, int extra,
6637                        AstObject **fail, int *status ) {
6638 /*
6639 *  Name:
6640 *     ManageLock
6641 
6642 *  Purpose:
6643 *     Manage the thread lock on an Object.
6644 
6645 *  Type:
6646 *     Private function.
6647 
6648 *  Synopsis:
6649 *     #include "object.h"
6650 *     AstObject *ManageLock( AstObject *this, int mode, int extra,
6651 *                            AstObject **fail, int *status )
6652 
6653 *  Class Membership:
6654 *     CmpMap member function (over-rides the astManageLock protected
6655 *     method inherited from the parent class).
6656 
6657 *  Description:
6658 *     This function manages the thread lock on the supplied Object. The
6659 *     lock can be locked, unlocked or checked by this function as
6660 *     deteremined by parameter "mode". See astLock for details of the way
6661 *     these locks are used.
6662 
6663 *  Parameters:
6664 *     this
6665 *        Pointer to the Object.
6666 *     mode
6667 *        An integer flag indicating what the function should do:
6668 *
6669 *        AST__LOCK: Lock the Object for exclusive use by the calling
6670 *        thread. The "extra" value indicates what should be done if the
6671 *        Object is already locked (wait or report an error - see astLock).
6672 *
6673 *        AST__UNLOCK: Unlock the Object for use by other threads.
6674 *
6675 *        AST__CHECKLOCK: Check that the object is locked for use by the
6676 *        calling thread (report an error if not).
6677 *     extra
6678 *        Extra mode-specific information.
6679 *     fail
6680 *        If a non-zero function value is returned, a pointer to the
6681 *        Object that caused the failure is returned at "*fail". This may
6682 *        be "this" or it may be an Object contained within "this". Note,
6683 *        the Object's reference count is not incremented, and so the
6684 *        returned pointer should not be annulled. A NULL pointer is
6685 *        returned if this function returns a value of zero.
6686 *     status
6687 *        Pointer to the inherited status variable.
6688 
6689 *  Returned Value:
6690 *    A local status value:
6691 *        0 - Success
6692 *        1 - Could not lock or unlock the object because it was already
6693 *            locked by another thread.
6694 *        2 - Failed to lock a POSIX mutex
6695 *        3 - Failed to unlock a POSIX mutex
6696 *        4 - Bad "mode" value supplied.
6697 
6698 *  Notes:
6699 *     - This function attempts to execute even if an error has already
6700 *     occurred.
6701 */
6702 
6703 /* Local Variables: */
6704    AstFrame *this;       /* Pointer to Frame structure */
6705    int i;                /* Loop count */
6706    int result;           /* Returned status value */
6707 
6708 /* Initialise */
6709    result = 0;
6710 
6711 /* Check the supplied pointer is not NULL. */
6712    if( !this_object ) return result;
6713 
6714 /* Obtain a pointers to the Frame structure. */
6715    this = (AstFrame *) this_object;
6716 
6717 /* Invoke the ManageLock method inherited from the parent class. */
6718    if( !result ) result = (*parent_managelock)( this_object, mode, extra,
6719                           fail, status );
6720 
6721 /* Invoke the astManageLock method on any Objects contained within
6722    the supplied Object. */
6723    for( i = 0; i < this->naxes; i++ ) {
6724       if( !result ) result = astManageLock( this->axis[ i ], mode, extra,
6725                                             fail );
6726    }
6727    if( this->variants && !result ) result = astManageLock( this->variants, mode,
6728                                                            extra, fail );
6729 
6730    return result;
6731 
6732 }
6733 #endif
6734 
MapSplit(AstMapping * this_map,int nin,const int * in,AstMapping ** map,int * status)6735 static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){
6736 /*
6737 *  Name:
6738 *     MapSplit
6739 
6740 *  Purpose:
6741 *     Create a Mapping representing a subset of the inputs of an existing
6742 *     Frame.
6743 
6744 *  Type:
6745 *     Private function.
6746 
6747 *  Synopsis:
6748 *     #include "frame.h"
6749 *     int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status )
6750 
6751 *  Class Membership:
6752 *     Frame method (over-rides the protected astMapSplit method
6753 *     inherited from the Mapping class).
6754 
6755 *  Description:
6756 *     This function creates a new Mapping by picking specified inputs from
6757 *     an existing Frame. This is only possible if the specified inputs
6758 *     correspond to some subset of the Frame outputs. That is, there
6759 *     must exist a subset of the Frame outputs for which each output
6760 *     depends only on the selected Frame inputs, and not on any of the
6761 *     inputs which have not been selected. If this condition is not met
6762 *     by the supplied Frame, then a NULL Mapping is returned.
6763 
6764 *  Parameters:
6765 *     this
6766 *        Pointer to the Frame to be split (the Frame is not actually
6767 *        modified by this function).
6768 *     nin
6769 *        The number of inputs to pick from "this".
6770 *     in
6771 *        Pointer to an array of indices (zero based) for the inputs which
6772 *        are to be picked. This array should have "nin" elements. If "Nin"
6773 *        is the number of inputs of the supplied Frame, then each element
6774 *        should have a value in the range zero to Nin-1.
6775 *     map
6776 *        Address of a location at which to return a pointer to the new
6777 *        Mapping. This Mapping will have "nin" inputs (the number of
6778 *        outputs may be different to "nin"). A NULL pointer will be
6779 *        returned if the supplied Frame has no subset of outputs which
6780 *        depend only on the selected inputs.
6781 *     status
6782 *        Pointer to the inherited status variable.
6783 
6784 *  Returned Value:
6785 *     A pointer to a dynamically allocated array of ints. The number of
6786 *     elements in this array will equal the number of outputs for the
6787 *     returned Mapping. Each element will hold the index of the
6788 *     corresponding output in the supplied Frame. The array should be
6789 *     freed using astFree when no longer needed. A NULL pointer will
6790 *     be returned if no output Mapping can be created.
6791 
6792 *  Notes:
6793 *     - If this function is invoked with the global error status set,
6794 *     or if it should fail for any reason, then NULL values will be
6795 *     returned as the function value and for the "map" pointer.
6796 */
6797 
6798 /* Local Variables: */
6799    int *result;         /* Returned pointer */
6800 
6801 /* Initialise */
6802    result = NULL;
6803    *map = NULL;
6804 
6805 /* Check the global error status. */
6806    if ( !astOK ) return result;
6807 
6808 /* Pick the selected axes from the Frame. */
6809    *map = (AstMapping *) astPickAxes( (AstFrame *) this_map, nin, in, NULL );
6810 
6811 /* Return a copy of the supplied axis array.*/
6812    result = astStore( NULL, in, sizeof( int )*(size_t) nin );
6813 
6814 /* Free returned resources if an error has occurred. */
6815    if( !astOK ) {
6816       result = astFree( result );
6817       *map = astAnnul( *map );
6818    }
6819 
6820 /* Return the list of output indices. */
6821    return result;
6822 }
6823 
Match(AstFrame * template,AstFrame * target,int matchsub,int ** template_axes,int ** target_axes,AstMapping ** map,AstFrame ** result,int * status)6824 static int Match( AstFrame *template, AstFrame *target, int matchsub,
6825                   int **template_axes, int **target_axes,
6826                   AstMapping **map, AstFrame **result, int *status ) {
6827 /*
6828 *+
6829 *  Name:
6830 *     astMatch
6831 
6832 *  Purpose:
6833 *     Determine if conversion is possible between two coordinate systems.
6834 
6835 *  Type:
6836 *     Protected virtual function.
6837 
6838 *  Synopsis:
6839 *     #include "frame.h"
6840 *     int astMatch( AstFrame *template, AstFrame *target, int matchsub,
6841 *                   int **template_axes, int **target_axes,
6842 *                   AstMapping **map, AstFrame **result )
6843 
6844 *  Class Membership:
6845 *     Frame method.
6846 
6847 *  Description:
6848 *     This function matches a "template" frame to a "target" frame and
6849 *     determines whether it is possible to convert coordinates between
6850 *     them.  If it is, a mapping that performs the transformation is
6851 *     returned along with a new Frame that describes the coordinate
6852 *     system that results when this mapping is applied to the "target"
6853 *     coordinate system. In addition, information is returned to allow
6854 *     the axes in this "result" Frame to be associated with the
6855 *     corresponding axes in the "target" and "template" Frames from
6856 *     which they are derived.
6857 
6858 *  Parameters:
6859 *     template
6860 *        Pointer to the template Frame. This describes the coordinate
6861 *        system (or set of possible coordinate systems) into which we
6862 *        wish to convert our coordinates.
6863 *     target
6864 *        Pointer to the target Frame. This describes the coordinate
6865 *        system in which we already have coordinates.
6866 *     matchsub
6867 *        If zero then a match only occurs if the template is of the same
6868 *        class as the target, or of a more specialised class. If non-zero
6869 *        then a match can occur even if this is not the case (i.e. if the
6870 *        target is of a more specialised class than the template). In
6871 *        this latter case, the target is cast down to the class of the
6872 *        template. NOTE, this argument is handled by the global method
6873 *        wrapper function "astMatch_", rather than by the class-specific
6874 *        implementations of this method.
6875 *     template_axes
6876 *        Address of a location where a pointer to int will be returned
6877 *        if the requested coordinate conversion is possible. This
6878 *        pointer will point at a dynamically allocated array of
6879 *        integers with one element for each axis of the "result" Frame
6880 *        (see below). It must be freed by the caller (using astFree)
6881 *        when no longer required.
6882 *
6883 *        For each axis in the result Frame, the corresponding element
6884 *        of this array will return the (zero-based) index of the
6885 *        template Frame axis from which it is derived. If it is not
6886 *        derived from any template frame axis, a value of -1 will be
6887 *        returned instead.
6888 *     target_axes
6889 *        Address of a location where a pointer to int will be returned
6890 *        if the requested coordinate conversion is possible. This
6891 *        pointer will point at a dynamically allocated array of
6892 *        integers with one element for each axis of the "result" Frame
6893 *        (see below). It must be freed by the caller (using astFree)
6894 *        when no longer required.
6895 *
6896 *        For each axis in the result Frame, the corresponding element
6897 *        of this array will return the (zero-based) index of the
6898 *        target Frame axis from which it is derived. If it is not
6899 *        derived from any target Frame axis, a value of -1 will be
6900 *        returned instead.
6901 *     map
6902 *        Address of a location where a pointer to a new Mapping will
6903 *        be returned if the requested coordinate conversion is
6904 *        possible. If returned, the forward transformation of this
6905 *        Mapping may be used to convert coordinates between the
6906 *        "target" Frame and the "result" Frame (see below) and the
6907 *        inverse transformation will convert in the opposite
6908 *        direction.
6909 *     result
6910 *        Address of a location where a pointer to a new Frame will be
6911 *        returned if the requested coordinate conversion is
6912 *        possible. If returned, this Frame describes the coordinate
6913 *        system that results from applying the returned Mapping
6914 *        (above) to the "target" coordinate system. In general, this
6915 *        Frame will combine attributes from (and will therefore be
6916 *        more specific than) both the target and the template
6917 *        Frames. In particular, when the template allows the
6918 *        possibility of transformaing to any one of a set of
6919 *        alternative coordinate systems, the "result" Frame will
6920 *        indicate which of the alternatives was used.
6921 
6922 *  Returned Value:
6923 *     A non-zero value is returned if the requested coordinate
6924 *     conversion is possible. Otherwise zero is returned (this will
6925 *     not in itself result in an error condition).
6926 
6927 *  Notes:
6928 *     - By default, the "result" frame will have its number of axes
6929 *     and axis order determined by the "template" Frame. However, if
6930 *     the PreserveAxes attribute of the template frame is non-zero,
6931 *     then the axis count and axis order of the "target" frame will be
6932 *     used instead.
6933 *     - The template_axes and target_axes arrays are provided so that
6934 *     if the caller needs to permute the target and/or template axes
6935 *     before invoking this function, it is possible to deduce how the
6936 *     result axes should be permuted so as to correspond with the
6937 *     original template/target axis order.
6938 *     - For result axes that do not correspond with a template and/or
6939 *     target axis (where a value of -1 is returned in the
6940 *     template_axes and/or target_axes arrays), the caller has no
6941 *     clear way of knowing where these axes should appear in any
6942 *     permuted order. In this case, the relative position of these
6943 *     axes within the result Frame (with respect to axes that do have
6944 *     template/target axis associations) will be used to convey this
6945 *     information. Such axes should be taken to be associated either
6946 *     with the next preceding or following axis (depending on the
6947 *     AST__MATCHEND flag of the template frame) which does have an
6948 *     association.
6949 *     - If the result Frame has zero axes, then NULL pointer values
6950 *     will be returned for *template_axes and *target_axes.
6951 *     - A value of zero will be returned if this function is invoked
6952 *     with the global error status set, or if it should fail for any
6953 *     reason.
6954 *-
6955 
6956 *  Implementation Notes:
6957 *     This implementation addresses the matching of a Frame class
6958 *     object to other types of Frames (i.e. the target may be from a
6959 *     derived class). A Frame will match any other type of Frame with
6960 *     an acceptable number of axes but will not distinguish axis order
6961 *     (i.e. it will match the axes in whatever order they are
6962 *     given). If the template Frame has a value set for its Domain
6963 *     attribute, then it will only match another Frame with the same
6964 *     Domain.
6965 */
6966 
6967 /* Local Variables: */
6968    char *template_domain;        /* Pointer to copy of template domain */
6969    const char *ptr;              /* Pointer to domain string */
6970    const char *target_domain;    /* Pointer to target domain string */
6971    int match;                    /* Template matches target? */
6972    int match_end;                /* Match final axes of target? */
6973    int max_axes;                 /* Maximum acceptable number of axes */
6974    int min_axes;                 /* Minimum acceptable nu,ber of axes */
6975    int preserve_axes;            /* Preserve target axes? */
6976    int result_axis;              /* Loop counter for result axes */
6977    int result_naxes;             /* Number of result axes */
6978    int target_naxes;             /* Number of target axes */
6979    int template_naxes;           /* Number of template axes */
6980 
6981 /* Initialise the returned values. */
6982    *template_axes = NULL;
6983    *target_axes = NULL;
6984    *map = NULL;
6985    *result = NULL;
6986    match = 0;
6987 
6988 /* Check the global error status. */
6989    if ( !astOK ) return match;
6990 
6991 /* The first requirement for a match is that the target object is a Frame. This
6992    is already known to be true, as it forms part of the argument validation
6993    for this function. */
6994 
6995 /* The second requirement is that the number of target axes is acceptable.
6996    Obtain the number of target axes and the minimum and maximum number of axes
6997    that the template will match. */
6998    target_naxes = astGetNaxes( target );
6999    min_axes = astGetMinAxes( template );
7000    max_axes = astGetMaxAxes( template );
7001 
7002 /* Test if the number of target axes is acceptable. */
7003    if ( astOK ) {
7004       match = ( ( target_naxes >= min_axes ) && ( target_naxes <= max_axes ) );
7005    }
7006 
7007 /* The third requirement is that if the template has its Domain
7008    attribute defined, then the target must also have the same Domain
7009    (although it need not be set - the default will do). First check if
7010    the template has a domain. */
7011    if ( astOK && match ) {
7012       if ( astTestDomain( template ) ) {
7013 
7014 /* Obtain a pointer to the template domain. Then allocate memory and
7015    make a copy of it (this is necessary as we will next inquire the
7016    domain of the target and may over-write the buffer holding the
7017    template's domain). */
7018          ptr = astGetDomain( template );
7019          if ( astOK ) {
7020             template_domain = astStore( NULL, ptr,
7021                                         strlen( ptr ) + (size_t) 1 );
7022 
7023 /* Obtain a pointer to the target domain. */
7024             target_domain = astGetDomain( target );
7025 
7026 /* Compare the domain strings for equality. Then free the memory
7027    allocated above. */
7028             match = astOK && !strcmp( template_domain, target_domain );
7029             template_domain = astFree( template_domain );
7030          }
7031       }
7032    }
7033 
7034 /* If the template matches, obtain the values of the template's PreserveAxes
7035    and MatchEnd attributes and determine the number of template axes. */
7036    if ( astOK && match ) {
7037       preserve_axes = astGetPreserveAxes( template );
7038       match_end = astGetMatchEnd( template );
7039       template_naxes = astGetNaxes( template );
7040 
7041 /* If the PreserveAxes attribute is non-zero, the target axes should be
7042    preserved, so the number of result axes equals the number of target axes.
7043    Otherwise the number of template axes is used. */
7044       result_naxes = preserve_axes ? target_naxes : template_naxes;
7045 
7046 /* Allocate memory for the arrays of axis associations to be returned. */
7047       *template_axes = astMalloc( sizeof( int ) * (size_t) result_naxes );
7048       *target_axes = astMalloc( sizeof( int ) * (size_t) result_naxes );
7049       if ( astOK ) {
7050 
7051 /* Loop through each of the result axes. */
7052          for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) {
7053 
7054 /* Set up the axis associations. By default, associate the first result axis
7055    with the first template/target axis. */
7056             (*template_axes)[ result_axis ] = result_axis;
7057             (*target_axes)[ result_axis ] = result_axis;
7058 
7059 /* However, if the MatchEnd attribute is non-zero, associate the last result
7060    axis with the last template/target axis (this only makes a difference if
7061    there is a difference in the number of axes). */
7062             if ( match_end ) {
7063                (*template_axes)[ result_axis ] +=
7064                                                template_naxes - result_naxes;
7065                (*target_axes)[ result_axis ] += target_naxes - result_naxes;
7066             }
7067 
7068 /* If any of the associations would be with a template/target axis that doesn't
7069    exist, then use an axis index of -1 for the association instead. */
7070             if ( ( (*template_axes)[ result_axis ] < 0 ) ||
7071                  ( (*template_axes)[ result_axis ] >= template_naxes ) ) {
7072                (*template_axes)[ result_axis ] = -1;
7073 	    }
7074             if ( ( (*target_axes)[ result_axis ] < 0 ) ||
7075                  ( (*target_axes)[ result_axis ] >= target_naxes ) ) {
7076                (*target_axes)[ result_axis ] = -1;
7077 	    }
7078          }
7079 
7080 /* Use the target's astSubFrame method to select the required axes from it,
7081    overlaying the template's attributes on to the resulting Frame. This process
7082    also generates the required Mapping between the target and result Frames. */
7083          match = astSubFrame( target, template,
7084                               result_naxes, *target_axes, *template_axes,
7085                               map, result );
7086       }
7087    }
7088 
7089 /* If an error occurred, free any allocated memory and reset the result. */
7090    if ( !astOK || !match ) {
7091       *template_axes = astFree( *template_axes );
7092       *target_axes = astFree( *target_axes );
7093       match = 0;
7094    }
7095 
7096 /* Return the result. */
7097    return match;
7098 }
7099 
MatchAxes(AstFrame * frm1,AstFrame * frm2,int * axes,int * status)7100 static void MatchAxes( AstFrame *frm1, AstFrame *frm2, int *axes,
7101                        int *status ) {
7102 /*
7103 *++
7104 *  Name:
7105 c     astMatchAxes
7106 f     AST_MATCHAXES
7107 
7108 *  Purpose:
7109 *     Find any corresponding axes in two Frames.
7110 
7111 *  Type:
7112 *     Public virtual function.
7113 
7114 *  Synopsis:
7115 c     #include "frame.h"
7116 c     void astMatchAxes( AstFrame *frm1, AstFrame *frm2, int *axes )
7117 f     CALL AST_MATCHAXES( FRM1, FRM2, AXES, STATUS )
7118 
7119 *  Class Membership:
7120 *     Frame method.
7121 
7122 *  Description:
7123 *     This function looks for corresponding axes within two supplied
7124 *     Frames. An array of integers is returned that contains an element
7125 *     for each axis in the second supplied Frame. An element in this array
7126 *     will be set to zero if the associated axis within the second Frame
7127 *     has no corresponding axis within the first Frame. Otherwise, it
7128 *     will be set to the index (a non-zero positive integer) of the
7129 *     corresponding axis within the first supplied Frame.
7130 
7131 *  Parameters:
7132 c     frm1
7133 f     FRM1 = INTEGER (Given)
7134 *        Pointer to the first Frame.
7135 c     frm2
7136 f     FRM2 = INTEGER (Given)
7137 *        Pointer to the second Frame.
7138 c     axes
7139 f     AXES = INTEGER( * ) (Returned)
7140 c        Pointer to an
7141 f        An
7142 *        integer array in which to return the indices of the axes (within
7143 *        the first Frame) that correspond to each axis within the second
7144 *        Frame. Axis indices start at 1. A value of zero will be stored
7145 *        in the returned array for each axis in the second Frame that has
7146 *        no corresponding axis in the first Frame.
7147 *
7148 *        The number of elements in this array must be greater than or
7149 *        equal to the number of axes in the second Frame.
7150 f     STATUS = INTEGER (Given and Returned)
7151 f        The global status.
7152 
7153 *  Applicability:
7154 *     Frame
7155 *        This function applies to all Frames.
7156 
7157 *  Notes:
7158 *     -  Corresponding axes are identified by the fact that a Mapping can
7159 *     be found between them using
7160 c     astFindFrame or astConvert.
7161 f     AST_FINDFRAME or AST_CONVERT.
7162 *     Thus, "corresponding axes" are not necessarily identical. For
7163 *     instance, SkyFrame axes in two Frames will match even if they
7164 *     describe different celestial coordinate systems
7165 *--
7166 
7167 * Implementation Notes:
7168 *    This function is simply a wrap-up for the protected astMatchAxesX
7169 *    method which performs the required processing but swaps the order
7170 *    of the first two arguments. This is a trick to allow the
7171 *    astMatchAxes method to be over-ridden by derived classes on the
7172 *    basis of the class of either of the first two arguments.
7173 *
7174 *    In practice, each class that represents an encapsulated Frame (e.g.
7175 *    FrameSet, Region, etc) should over-ride this method, extracting a
7176 *    Frame from the supplied "frm1" pointer, and then invoking
7177 *    astMatchAxesX.
7178 
7179 */
7180 
7181 /* Check the global error status. */
7182    if ( !astOK ) return;
7183 
7184 /* Invoke the "astMatchAxesX" method with the first two arguments
7185    swapped. */
7186    astMatchAxesX( frm2, frm1, axes );
7187 }
7188 
MatchAxesX(AstFrame * frm2,AstFrame * frm1,int * axes,int * status)7189 static void MatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes,
7190                         int *status ) {
7191 /*
7192 *+
7193 *  Name:
7194 *     astMatchAxesX
7195 
7196 *  Purpose:
7197 *     Find any corresponding axes in two Frames.
7198 
7199 *  Type:
7200 *     Protected virtual function.
7201 
7202 *  Synopsis:
7203 *     #include "frame.h"
7204 *     void astMatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes )
7205 
7206 *  Class Membership:
7207 *     Frame method.
7208 
7209 *  Description:
7210 *     This function performs the processing for the public astMatchAxes
7211 *     method and has exactly the same interface except that the order
7212 *     of the first two arguments is swapped. This is a trick to allow
7213 *     the astMatchAxes method to be over-ridden by derived classes on
7214 *     the basis of the class of either of its first two arguments.
7215 *
7216 *     See the astMatchAxes method for details of the interface.
7217 *-
7218 */
7219 
7220 /* Local Variables: */
7221    AstFrame *pfrm;
7222    AstFrame *resfrm;
7223    AstMapping *resmap;
7224    int *frm1_axes;
7225    int *pfrm_axes;
7226    int ifirst;
7227    int max_axes;
7228    int min_axes;
7229    int nax2;
7230    int pax;
7231    int preserve_axes;
7232 
7233 /* Check the global error status. */
7234    if ( !astOK ) return;
7235 
7236 /* Temporarily ensure that the PreserveAxes attribute is non-zero in
7237    the second supplied Frame. This means thte result Frame returned by
7238    astMatch below will have the axis count and order of the target Frame
7239    (i.e. "pfrm"). */
7240    if( astTestPreserveAxes( frm1 ) ) {
7241       preserve_axes = astGetPreserveAxes( frm1 ) ? 1 : 0;
7242    } else {
7243       preserve_axes = -1;
7244    }
7245    astSetPreserveAxes( frm1, 1 );
7246 
7247 /* Temporarily ensure that the MaxAxes and MinAxes attributes in the
7248    second supplied Frame are set so the Frame can be used as a template
7249    in astMatch for matching any number of axes. */
7250    if( astTestMaxAxes( frm1 ) ) {
7251       max_axes = astGetMaxAxes( frm1 );
7252    } else {
7253       max_axes = -1;
7254    }
7255    astSetMaxAxes( frm1, 10000 );
7256 
7257    if( astTestMinAxes( frm1 ) ) {
7258       min_axes = astGetMinAxes( frm1 );
7259    } else {
7260       min_axes = -1;
7261    }
7262    astSetMinAxes( frm1, 1 );
7263 
7264 /* Get the number of axes in the frm2 Frame. */
7265    nax2 = astGetNaxes( frm2 );
7266 
7267 /* Loop round the axes in the frm2 Frame. */
7268    for( ifirst = 0; ifirst < nax2; ifirst++ ) {
7269 
7270 /* Identify the primary Frame defining the current axis in the frm2
7271    Frame. */
7272       astPrimaryFrame( frm2, ifirst, &pfrm, &pax );
7273 
7274 /* Attempt to find a sub-frame within the frm1 Frame that corresponds to
7275    this primary Frame. */
7276       if( astMatch( frm1, pfrm, 1, &frm1_axes, &pfrm_axes, &resmap, &resfrm ) ) {
7277 
7278 /* Store the one-based index within "frm1" of the corresponding axis. */
7279          axes[ ifirst ] = frm1_axes[ pax ] + 1;
7280 
7281 /* Free resources */
7282          frm1_axes = astFree( frm1_axes );
7283          pfrm_axes = astFree( pfrm_axes );
7284          resmap = astAnnul( resmap );
7285          resfrm = astAnnul( resfrm );
7286 
7287 /* If no corresponding axis was found store zero in the returned array. */
7288       } else {
7289          axes[ ifirst ] = 0;
7290       }
7291 
7292 /* Free resouces. */
7293       pfrm = astAnnul( pfrm );
7294    }
7295 
7296 /* Re-instate the original attribute values in the frm1 Frame. */
7297    if( preserve_axes == -1 ) {
7298       astClearPreserveAxes( frm1 );
7299    } else {
7300       astSetPreserveAxes( frm1, preserve_axes );
7301    }
7302 
7303    if( max_axes == -1 ) {
7304       astClearMaxAxes( frm1 );
7305    } else {
7306       astSetMaxAxes( frm1, max_axes );
7307    }
7308 
7309    if( min_axes == -1 ) {
7310       astClearMinAxes( frm1 );
7311    } else {
7312       astSetMinAxes( frm1, min_axes );
7313    }
7314 }
7315 
NewUnit(AstAxis * ax,const char * old_units,const char * new_units,const char * method,const char * class,int * status)7316 static void NewUnit( AstAxis *ax, const char *old_units, const char *new_units,
7317                      const char *method, const char *class, int *status ) {
7318 /*
7319 *  Name:
7320 *     NewUnit
7321 
7322 *  Purpose:
7323 *     Modify an Axis Label and Symbol to reflect a new Unit value.
7324 
7325 *  Type:
7326 *     Private function.
7327 
7328 *  Synopsis:
7329 *     #include "frame.h"
7330 *     void NewUnit( AstAxis *ax, const char *old_units, const char *new_units,
7331 *                   const char *method, const char *class )
7332 
7333 *  Class Membership:
7334 *     Frame method.
7335 
7336 *  Description:
7337 *     This function modifies the Label and Symbol attributes of an Axis
7338 *     to reflect a new Unit value. This function should only be called if
7339 *     the ActiveUnit flag of the parent Frame is non-zero (this is not
7340 *     checked within this function).
7341 *
7342 *     If the axis has a set label, then we may be able to modify it to
7343 *     correctly describe the axis in the supplied new units. For instance,
7344 *     if the original units were "Hz", the original label was "frequency",
7345 *     and the new units are "log(Hz)", then the label is modified to become
7346 *     "log( frequency )".
7347 *
7348 *     The Axis Format attribute is cleared if the supplied units are
7349 *     different to the old units (because any set format is probably not
7350 *     going to be appropriate for a new system of units.
7351 
7352 *  Parameters:
7353 *     ax
7354 *        Pointer to the Axis.
7355 *     old_units
7356 *        The original units value.
7357 *     new_units
7358 *        The new units value.
7359 *     method
7360 *        Pointer to a constant null-terminated character string
7361 *        containing the name of the method that invoked this function
7362 *        to validate an axis selection. This method name is used
7363 *        solely for constructing error messages.
7364 *     class
7365 *        Pointer to a constant null-terminated character string
7366 *        containing the name of the class upon which this function
7367 *        was invoked. This is used solely for constructing error messages.
7368 
7369 *  Returned Value:
7370 *     void.
7371 */
7372 
7373 /* Local Variables: */
7374    AstMapping *map;              /* Pointer to units Mapping */
7375    char *new_lab;                /* Pointer to new axis label */
7376    char *new_sym;                /* Pointer to new axis symbol */
7377 
7378 /* Check the global error status. */
7379    if ( !astOK ) return;
7380 
7381 /* Check that the axis label is set. We relay on sub-classes to return
7382    appropriate default labels if the label is not set. */
7383    if( astTestAxisLabel( ax ) ) {
7384 
7385 /* See if it is possible to map the old units into the new units.
7386    If it is, then a Mapping is returned together with an appropriately
7387    modified label. */
7388       map = astUnitMapper( old_units, new_units, astGetAxisLabel( ax ),
7389                            &new_lab );
7390 
7391 /* If succesfull, annul the Mapping (which we do not need), and store the
7392    modified label in the Axis, finally freeing the memory used to hold
7393    the modified label. */
7394       if( map ) {
7395          map = astAnnul( map );
7396          if( new_lab ) {
7397             astSetAxisLabel( ax, new_lab );
7398             new_lab = astFree( new_lab );
7399          }
7400       }
7401    }
7402 
7403 /* Do the same for the axis symbol. */
7404    if( astTestAxisSymbol( ax ) ) {
7405       map = astUnitMapper( old_units, new_units, astGetAxisSymbol( ax ),
7406                            &new_sym );
7407       if( map ) {
7408          map = astAnnul( map );
7409          if( new_sym ) {
7410             astSetAxisSymbol( ax, new_sym );
7411             new_sym = astFree( new_sym );
7412          }
7413       }
7414    }
7415 
7416 /* If succesful, clear the axis format if the new and old units are
7417    different. */
7418    if( astOK ) {
7419       if( strcmp( old_units, new_units ) ) astClearAxisFormat( ax );
7420    }
7421 
7422 }
7423 
Norm(AstFrame * this,double value[],int * status)7424 static void Norm( AstFrame *this, double value[], int *status ) {
7425 /*
7426 *++
7427 *  Name:
7428 c     astNorm
7429 f     AST_NORM
7430 
7431 *  Purpose:
7432 *     Normalise a set of Frame coordinates.
7433 
7434 *  Type:
7435 *     Public virtual function.
7436 
7437 *  Synopsis:
7438 c     #include "frame.h"
7439 c     void astNorm( AstFrame *this, double value[] )
7440 f     CALL AST_NORM( THIS, VALUE, STATUS )
7441 
7442 *  Class Membership:
7443 *     Frame method.
7444 
7445 *  Description:
7446 c     This function normalises a set of Frame coordinate values which
7447 f     This routine normalises a set of Frame coordinate values which
7448 *     might be unsuitable for display (e.g. may lie outside the
7449 *     expected range) into a set of acceptable values suitable for
7450 *     display.
7451 
7452 *  Parameters:
7453 c     this
7454 f     THIS = INTEGER (Given)
7455 *        Pointer to the Frame.
7456 c     value
7457 f     VALUE( * ) = DOUBLE PRECISION (Given and Returned)
7458 c        An array of double, with one element for each Frame axis
7459 f        An array with one element for each Frame axis
7460 *        (Naxes attribute). Initially, this should contain a set of
7461 *        coordinate values representing a point in the space which the
7462 *        Frame describes. If these values lie outside the expected
7463 *        range for the Frame, they will be replaced with more
7464 *        acceptable (normalised) values. Otherwise, they will be
7465 *        returned unchanged.
7466 f     STATUS = INTEGER (Given and Returned)
7467 f        The global status.
7468 
7469 *  Notes:
7470 *     - For some classes of Frame, whose coordinate values are not
7471 *     constrained, this function will never modify the values
7472 *     supplied. However, for Frames whose axes represent cyclic
7473 *     quantities (such as angles or positions on the sky), coordinates
7474 *     will typically be wrapped into an appropriate standard range,
7475 *     such as zero to 2*pi.
7476 *     - The NormMap class is a Mapping which can be used to normalise a
7477 *     set of points using the
7478 c     astNorm function
7479 f     AST_NORM routine
7480 *     of a specified Frame.
7481 *     - It is intended to be possible to put any set of coordinates
7482 *     into a form suitable for display by using this function to
7483 *     normalise them, followed by appropriate formatting
7484 c     (using astFormat).
7485 f     (using AST_FORMAT).
7486 *--
7487 */
7488 
7489 /* Local Variables: */
7490    AstAxis *ax;                  /* Pointer to Axis object */
7491    int axis;                     /* Loop counter for axes */
7492    int naxes;                    /* Number of Frame axes */
7493 
7494 /* Check the global error status. */
7495    if ( !astOK ) return;
7496 
7497 /* Obtain the number of Frame axes. */
7498    naxes = astGetNaxes( this );
7499 
7500 /* Loop to process the coordinate for each axis in turn. */
7501    for ( axis = 0; axis < naxes; axis++ ) {
7502 
7503 /* Obtain a pointer to the relevant Frame Axis. */
7504       ax = astGetAxis( this, axis );
7505 
7506 /* Normalise the coordinate for this axis. */
7507       astAxisNorm( ax, value + axis );
7508 
7509 /* Annul the pointer to the Axis. */
7510       ax = astAnnul( ax );
7511 
7512 /* Quit looping if an error occurs. */
7513       if ( !astOK ) break;
7514    }
7515 }
7516 
NormBox(AstFrame * this,double lbnd[],double ubnd[],AstMapping * reg,int * status)7517 static void NormBox( AstFrame *this, double lbnd[], double ubnd[],
7518                      AstMapping *reg, int *status ) {
7519 /*
7520 *+
7521 *  Name:
7522 *     astNormBox
7523 
7524 *  Purpose:
7525 *     Extend a box to include effect of any singularities in the Frame.
7526 
7527 *  Type:
7528 *     Protected virtual function.
7529 
7530 *  Synopsis:
7531 *     #include "frame.h"
7532 *     void astNormBox( AstFrame *this, double lbnd[], double ubnd[],
7533 *                      AstMapping *reg )
7534 
7535 *  Class Membership:
7536 *     Frame method.
7537 
7538 *  Description:
7539 *     This function modifies a supplied box to include the effect of any
7540 *     singularities in the co-ordinate system represented by the Frame.
7541 *     For a normal Cartesian coordinate system, the box will be returned
7542 *     unchanged. Other classes of Frame may do other things. For instance,
7543 *     a SkyFrame will check to see if the box contains either the north
7544 *     or south pole and extend the box appropriately.
7545 
7546 *  Parameters:
7547 *     this
7548 *        Pointer to the Frame.
7549 *     lbnd
7550 *        An array of double, with one element for each Frame axis
7551 *        (Naxes attribute). Initially, this should contain a set of
7552 *        lower axis bounds for the box. They will be modified on exit
7553 *        to include the effect of any singularities within the box.
7554 *     ubnd
7555 *        An array of double, with one element for each Frame axis
7556 *        (Naxes attribute). Initially, this should contain a set of
7557 *        upper axis bounds for the box. They will be modified on exit
7558 *        to include the effect of any singularities within the box.
7559 *     reg
7560 *        A Mapping which should be used to test if any singular points are
7561 *        inside or outside the box. The Mapping should leave an input
7562 *        position unchanged if the point is inside the box, and should
7563 *        set all bad if the point is outside the box.
7564 *-
7565 */
7566 
7567 /* This base class returns the box limits unchanged. */
7568 }
7569 
Offset2(AstFrame * this,const double point1[2],double angle,double offset,double point2[2],int * status)7570 static double Offset2( AstFrame *this, const double point1[2], double angle,
7571                      double offset, double point2[2], int *status ){
7572 /*
7573 *++
7574 *  Name:
7575 c     astOffset2
7576 f     AST_OFFSET2
7577 
7578 *  Purpose:
7579 *     Calculate an offset along a geodesic curve in a 2D Frame.
7580 
7581 *  Type:
7582 *     Public virtual function.
7583 
7584 *  Synopsis:
7585 c     #include "frame.h"
7586 c     double astOffset2( AstFrame *this, const double point1[2], double angle,
7587 c                        double offset, double point2[2] );
7588 f     RESULT = AST_OFFSET2( THIS, POINT1, ANGLE, OFFSET, POINT2, STATUS )
7589 
7590 *  Class Membership:
7591 *     Frame method.
7592 
7593 *  Description:
7594 c     This function finds the Frame coordinate values of a point which
7595 f     This routine finds the Frame coordinate values of a point which
7596 *     is offset a specified distance along the geodesic curve at a
7597 *     given angle from a specified starting point. It can only be
7598 *     used with 2-dimensional Frames.
7599 *
7600 *     For example, in a basic Frame, this offset will be along the
7601 *     straight line joining two points. For a more specialised Frame
7602 *     describing a sky coordinate system, however, it would be along
7603 *     the great circle passing through two sky positions.
7604 
7605 *  Parameters:
7606 c     this
7607 f     THIS = INTEGER (Given)
7608 *        Pointer to the Frame.
7609 c     point1
7610 f     POINT1( * ) = DOUBLE PRECISION (Given)
7611 c        An array of double, with one element for each Frame axis
7612 f        An array with one element for each Frame axis
7613 *        (Naxes attribute). This should contain the coordinates of the
7614 *        point marking the start of the geodesic curve.
7615 c     angle
7616 f     ANGLE = DOUBLE PRECISION (Given)
7617 *        The angle (in radians) from the positive direction of the second
7618 *        axis, to the direction of the required position, as seen from
7619 *        the starting position. Positive rotation is in the sense of
7620 *        rotation from the positive direction of axis 2 to the positive
7621 *        direction of axis 1.
7622 c     offset
7623 f     OFFSET = DOUBLE PRECISION
7624 *        The required offset from the first point along the geodesic
7625 *        curve. If this is positive, it will be in the direction of the
7626 *        given angle. If it is negative, it will be in the opposite
7627 *        direction.
7628 c     point2
7629 f     POINT2( * ) = DOUBLE PRECISION (Returned)
7630 c        An array of double, with one element for each Frame axis
7631 f        An array with one element for each Frame axis
7632 *        in which the coordinates of the required point will be returned.
7633 f     STATUS = INTEGER (Given and Returned)
7634 f        The global status.
7635 
7636 *  Returned Value:
7637 c     astOffset2
7638 f     AST_OFFSET2 = DOUBLE PRECISION
7639 *        The direction of the geodesic curve at the end point. That is, the
7640 *        angle (in radians) between the positive direction of the second
7641 *        axis and the continuation of the geodesic curve at the requested
7642 *        end point. Positive rotation is in the sense of rotation from
7643 *        the positive direction of axis 2 to the positive direction of axis
7644 *        1.
7645 
7646 *  Notes:
7647 c     - The geodesic curve used by this function is the path of
7648 f     - The geodesic curve used by this routine is the path of
7649 *     shortest distance between two points, as defined by the
7650 c     astDistance function.
7651 f     AST_DISTANCE function.
7652 *     - An error will be reported if the Frame is not 2-dimensional.
7653 *     - This function will return "bad" coordinate values (AST__BAD)
7654 *     if any of the input coordinates has this value.
7655 *--
7656 */
7657 
7658 /* Local Variables: */
7659    int naxes;                    /* Number of Frame axes */
7660    double result;                /* Returned value */
7661 
7662 /* Check the global error status. */
7663    result = AST__BAD;
7664    if ( !astOK ) return result;
7665 
7666 /* Initialize bad values. */
7667    point2[ 0 ] = AST__BAD;
7668    point2[ 1 ] = AST__BAD;
7669 
7670 /* Determine the number of Frame axes. */
7671    naxes = astGetNaxes( this );
7672 
7673 /* Report an error if the Frame is not 2 dimensional. */
7674    if( naxes != 2 && astOK ) {
7675       astError( AST__NAXIN, "astOffset2(%s): Invalid number of Frame axes (%d)."
7676                 " astOffset2 can only be used with 2 dimensonal Frames.", status,
7677                 astGetClass( this ), naxes );
7678    }
7679 
7680 /* Check the supplied values. */
7681    if ( astOK && point1[ 0 ] != AST__BAD && point1[ 1 ] != AST__BAD &&
7682         angle != AST__BAD && offset != AST__BAD ) {
7683 
7684 /* Store the results. */
7685       point2[ 0 ] = point1[ 0 ] + sin( angle )*offset;
7686       point2[ 1 ] = point1[ 1 ] + cos( angle )*offset;
7687 
7688 /* The position angle of the curve does not vary in cartesian coordinates */
7689       result = angle;
7690 
7691    }
7692 
7693 /* Return the result. */
7694    return result;
7695 
7696 }
7697 
Offset(AstFrame * this,const double point1[],const double point2[],double offset,double point3[],int * status)7698 static void Offset( AstFrame *this, const double point1[],
7699                     const double point2[], double offset, double point3[], int *status ) {
7700 /*
7701 *++
7702 *  Name:
7703 c     astOffset
7704 f     AST_OFFSET
7705 
7706 *  Purpose:
7707 *     Calculate an offset along a geodesic curve.
7708 
7709 *  Type:
7710 *     Public virtual function.
7711 
7712 *  Synopsis:
7713 c     #include "frame.h"
7714 c     void astOffset( AstFrame *this,
7715 c                     const double point1[], const double point2[],
7716 c                     double offset, double point3[] )
7717 f     CALL AST_OFFSET( THIS, POINT1, POINT2, OFFSET, POINT3, STATUS )
7718 
7719 *  Class Membership:
7720 *     Frame method.
7721 
7722 *  Description:
7723 c     This function finds the Frame coordinate values of a point which
7724 f     This routine finds the Frame coordinate values of a point which
7725 *     is offset a specified distance along the geodesic curve between
7726 *     two other points.
7727 *
7728 *     For example, in a basic Frame, this offset will be along the
7729 *     straight line joining two points. For a more specialised Frame
7730 *     describing a sky coordinate system, however, it would be along
7731 *     the great circle passing through two sky positions.
7732 
7733 *  Parameters:
7734 c     this
7735 f     THIS = INTEGER (Given)
7736 *        Pointer to the Frame.
7737 c     point1
7738 f     POINT1( * ) = DOUBLE PRECISION (Given)
7739 c        An array of double, with one element for each Frame axis
7740 f        An array with one element for each Frame axis
7741 *        (Naxes attribute). This should contain the coordinates of the
7742 *        point marking the start of the geodesic curve.
7743 c     point2
7744 f     POINT2( * ) = DOUBLE PRECISION (Given)
7745 c        An array of double, with one element for each Frame axis
7746 f        An array with one element for each Frame axis.
7747 *        This should contain the coordinates of the point marking the
7748 *        end of the geodesic curve.
7749 c     offset
7750 f     OFFSET = DOUBLE PRECISION
7751 *        The required offset from the first point along the geodesic
7752 *        curve. If this is positive, it will be towards the second
7753 *        point. If it is negative, it will be in the opposite
7754 *        direction. This offset need not imply a position lying
7755 *        between the two points given, as the curve will be
7756 *        extrapolated if necessary.
7757 c     point3
7758 f     POINT3( * ) = DOUBLE PRECISION (Returned)
7759 c        An array of double, with one element for each Frame axis
7760 f        An array with one element for each Frame axis
7761 *        in which the coordinates of the required point will be returned.
7762 f     STATUS = INTEGER (Given and Returned)
7763 f        The global status.
7764 
7765 *  Notes:
7766 c     - The geodesic curve used by this function is the path of
7767 f     - The geodesic curve used by this routine is the path of
7768 *     shortest distance between two points, as defined by the
7769 c     astDistance function.
7770 f     AST_DISTANCE function.
7771 *     - This function will return "bad" coordinate values (AST__BAD)
7772 *     if any of the input coordinates has this value.
7773 *     - "Bad" coordinate values will also be returned if the two
7774 *     points supplied are coincident (or otherwise fail to uniquely
7775 *     specify a geodesic curve) but the requested offset is non-zero.
7776 *--
7777 */
7778 
7779 /* Local Variables: */
7780    double delta;                 /* Displacement along axis */
7781    double dist;                  /* Distance between points */
7782    double fract;                 /* Fraction of distance required */
7783    int axis;                     /* Loop counter for axes */
7784    int naxes;                    /* Number of Frame axes */
7785 
7786 /* Check the global error status. */
7787    if ( !astOK ) return;
7788 
7789 /* Determine the number of Frame axes. */
7790    naxes = astGetNaxes( this );
7791    if ( astOK ) {
7792 
7793 /* Loop to determine the Cartesian distance between points 1 and 2. */
7794       dist = 0.0;
7795       for ( axis = 0; axis < naxes; axis++ ) {
7796 
7797 /* If any of the coordinates supplied is bad, set the distance to be
7798    bad and quit looping. */
7799          if ( ( point1[ axis ] == AST__BAD ) ||
7800               ( point2[ axis ] == AST__BAD ) ) {
7801             dist = AST__BAD;
7802             break;
7803 
7804 /* Otherwise, accumulate the sum of squared displacements along each
7805    axis. */
7806          } else {
7807             delta = point1[ axis ] - point2[ axis ];
7808             dist += ( delta * delta );
7809          }
7810       }
7811 
7812 /* Take the square root to find the distance (if valid). */
7813       if ( dist != AST__BAD ) dist = sqrt( dist );
7814 
7815 /* If the distance between the points cannot be found, or the distance
7816    is zero but the required offset is non-zero, then set the result
7817    coordinates to be bad. */
7818       if ( ( dist == AST__BAD ) ||
7819            ( ( dist == 0.0 ) && ( offset != 0.0 ) ) ) {
7820          for ( axis = 0; axis < naxes; axis++ ) {
7821             point3[ axis ] = AST__BAD;
7822          }
7823 
7824 /* Otherwise, calculate what fraction of the distance between the
7825    points we need to move, and apply this fraction of the displacement
7826    along each axis. */
7827       } else {
7828          fract = ( dist == 0.0 ) ? 0.0 : offset / dist;
7829          for ( axis = 0; axis < naxes; axis++ ) {
7830             point3[ axis ] = point1[ axis ] +
7831                              fract * ( point2[ axis ] - point1[ axis ] );
7832          }
7833       }
7834    }
7835 }
7836 
Overlay(AstFrame * template,const int * template_axes,AstFrame * result,int * status)7837 static void Overlay( AstFrame *template, const int *template_axes,
7838                      AstFrame *result, int *status ) {
7839 /*
7840 *+
7841 *  Name:
7842 *     astOverlay
7843 
7844 *  Purpose:
7845 *     Overlay the attributes of a template Frame on to another Frame.
7846 
7847 *  Type:
7848 *     Protected virtual function.
7849 
7850 *  Synopsis:
7851 *     #include "frame.h"
7852 *     void astOverlay( AstFrame *template, const int *template_axes,
7853 *                      AstFrame *result )
7854 
7855 *  Class Membership:
7856 *     Frame method.
7857 
7858 *  Description:
7859 *     This function overlays attributes of one Frame (the "template") on to
7860 *     another Frame, so as to over-ride selected attributes of that second
7861 *     Frame. Normally only those attributes which have been specifically set
7862 *     in the template will be transferred. This implements a form of
7863 *     defaulting, in which a Frame acquires attributes from the template, but
7864 *     retains its original attributes (as the default) if new values have not
7865 *     previously been explicitly set in the template.
7866 
7867 *  Parameters:
7868 *     template
7869 *        Pointer to the template Frame, for which values should have been
7870 *        explicitly set for any attribute which is to be transferred.
7871 *     template_axes
7872 *        Pointer to an array of int, with one element for each axis of the
7873 *        "result" Frame (see below). For each axis in the result frame, the
7874 *        corresponding element of this array should contain the (zero-based)
7875 *        index of the template axis to which it corresponds. This array is used
7876 *        to establish from which template axis any axis-dependent attributes
7877 *        should be obtained.
7878 *
7879 *        If any axis in the result Frame is not associated with a template
7880 *        axis, the corresponding element of this array should be set to -1.
7881 *
7882 *        If a NULL pointer is supplied, the template and result axis
7883 *        indicies are assumed to be identical.
7884 *     result
7885 *        Pointer to the Frame which is to receive the new attribute values.
7886 *-
7887 */
7888 
7889 /* Local Variables: */
7890    AstAxis *result_ax;           /* Pointer to result Axis object */
7891    AstAxis *template_ax;         /* Pointer to template Axis object */
7892    AstSystemType sys;            /* System value */
7893    int result_axis;              /* Loop counter for result Frame axes */
7894    int result_naxes;             /* Number of result Frame axes */
7895    int template_axis;            /* Index of template Frame axis */
7896    int template_naxes;           /* Number of template Frame axes */
7897 
7898 /* Check the global error status. */
7899    if ( !astOK ) return;
7900 
7901 /* Define a macro that tests whether an attribute is set in the template and,
7902    if so, transfers its value to the target. */
7903 #define OVERLAY(attribute) \
7904    if ( astTest##attribute( template ) ) { \
7905       astSet##attribute( result, astGet##attribute( template ) ); \
7906    }
7907 
7908 /* Use the macro to transfer each Frame attribute in turn. */
7909    OVERLAY(Dut1);
7910    OVERLAY(Digits);
7911    OVERLAY(Domain);
7912    OVERLAY(Epoch);
7913    OVERLAY(Title);
7914    OVERLAY(ObsLat)
7915    OVERLAY(ObsLon)
7916    OVERLAY(ObsAlt)
7917 
7918 /* Transfer the ActiveUnit flag. */
7919    astSetActiveUnit( result, astGetActiveUnit( template ) );
7920 
7921 /* Only overlay the System and AlignSystem attribute if the values are
7922    valid for the result class. */
7923    if( astTestSystem( template ) ) {
7924       sys = astGetSystem( template );
7925       if( astValidateSystem( result, sys, "astOverlay" ) ) {
7926          astSetSystem( result, sys );
7927       }
7928    }
7929 
7930    if( astTestAlignSystem( template ) ) {
7931       sys = astGetAlignSystem( template );
7932       if( astValidateSystem( result, sys, "astOverlay" ) ) {
7933          astSetAlignSystem( result, sys );
7934       }
7935    }
7936 
7937 /* Now transfer attributes associated with individual axes. Obtain the number
7938    of axes in the template and result Frames. */
7939    template_naxes = astGetNaxes( template );
7940    result_naxes = astGetNaxes( result );
7941    if ( astOK ) {
7942 
7943 /* Loop through all the axes in the result Frame and determine to which
7944    template axis each one corresponds. Check that the resulting axis index is
7945    valid. If not, then the axis will not receive new attributes. */
7946       for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) {
7947          template_axis = template_axes ? template_axes[ result_axis ] : result_axis;
7948          if ( ( template_axis >= 0 ) && ( template_axis < template_naxes ) ) {
7949 
7950 /* Obtain pointers to the relevant Axis objects of each Frame and use the
7951    astAxisOverlay method of the template Axis to overlay attributes on to
7952    the result Axis. Annul the Axis pointers afterwards. */
7953             template_ax = astGetAxis( template, template_axis );
7954             result_ax = astGetAxis( result, result_axis );
7955             astAxisOverlay( template_ax, result_ax );
7956             template_ax = astAnnul( template_ax );
7957             result_ax = astAnnul( result_ax );
7958 
7959 /* Quit looping if an error occurs. */
7960             if ( !astOK ) break;
7961          }
7962       }
7963    }
7964 
7965 /* Undefine macros local to this function. */
7966 #undef OVERLAY
7967 }
7968 
PermAxes(AstFrame * this,const int perm[],int * status)7969 static void PermAxes( AstFrame *this, const int perm[], int *status ) {
7970 /*
7971 *+
7972 *  Name:
7973 *     astPermAxes
7974 
7975 *  Purpose:
7976 *     Permute the order of a Frame's axes.
7977 
7978 *  Type:
7979 *     Protected virtual function.
7980 
7981 *  Synopsis:
7982 *     #include "frame.h"
7983 *     void astPermAxes( AstFrame *this, const int perm[] )
7984 
7985 *  Class Membership:
7986 *     Frame method.
7987 
7988 *  Description:
7989 *     This function permutes the order in which a Frame's axes occur.
7990 
7991 *  Parameters:
7992 *     this
7993 *        Pointer to the Frame.
7994 *     perm
7995 *        An array of int (with one element for each axis of the Frame)
7996 *        which lists the axes in their new order. Each element of this
7997 *        array should be a (zero-based) axis index identifying the
7998 *        axes according to their old (un-permuted) order.
7999 
8000 *  Notes:
8001 *     - Only genuine permutations of the axis order are permitted, so
8002 *     each axis must be referenced exactly once in the "perm" array.
8003 *     - If more than one axis permutation is applied to a Frame, the
8004 *     effects are cumulative.
8005 *-
8006 
8007 *  Implementation Notes:
8008 *     - This function implements the basic astPermAxes method which is
8009 *     available via the protected interface to the Frame class. A
8010 *     public interface to this method is provided by the
8011 *     astPermAxesId_ function.
8012 */
8013 
8014 /* Local Variables: */
8015    int *old;                     /* Pointer to copy of old permutation array */
8016    int axis;                     /* Loop counter for Frame axes */
8017    int naxes;                    /* Number of Frame axes */
8018 
8019 /* Check the global error status. */
8020    if ( !astOK ) return;
8021 
8022 /* Validate the permutation array, to check that it describes a genuine
8023    permutation. */
8024    astCheckPerm( this, perm, "astPermAxes" );
8025 
8026 /* Obtain the number of Frame axes. */
8027    naxes = astGetNaxes( this );
8028 
8029 /* Allocate memory and use it to store a copy of the old permutation array for
8030    the Frame. */
8031    old = astStore( NULL, this->perm, sizeof( int ) * (size_t) naxes );
8032 
8033 /* Apply the new axis permutation cumulatively to the old one and store the
8034    result in the Frame. */
8035    if ( astOK ) {
8036       for ( axis = 0; axis < naxes; axis++ ) {
8037          this->perm[ axis ] = old[ perm[ axis ] ];
8038       }
8039    }
8040 
8041 /* Free the temporary copy of the old array. */
8042    old = astFree( old );
8043 }
8044 
PickAxes(AstFrame * this,int naxes,const int axes[],AstMapping ** map,int * status)8045 static AstFrame *PickAxes( AstFrame *this, int naxes, const int axes[],
8046                            AstMapping **map, int *status ) {
8047 /*
8048 *+
8049 *  Name:
8050 *     astPickAxes
8051 
8052 *  Purpose:
8053 *     Create a new Frame by picking axes from an existing one.
8054 
8055 *  Type:
8056 *     Protected virtual function.
8057 
8058 *  Synopsis:
8059 *     #include "frame.h"
8060 *     AstFrame *PickAxes( AstFrame *this, int naxes, const int axes[],
8061 *                         AstMapping **map )
8062 
8063 *  Class Membership:
8064 *     Frame method.
8065 
8066 *  Description:
8067 *     This function creates a new Frame whose axes are copies of axes
8068 *     picked from an existing Frame. Other Frame attributes are also
8069 *     copied to the new Frame. Zero or more of the original axes may
8070 *     be picked in any order, but each can be used only
8071 *     once. Additional axes (with default characteristics) may be
8072 *     included in the new Frame if required.
8073 *
8074 *     Optionally, a Mapping that converts between the original Frame's
8075 *     axes and those of the new Frame may also be returned.
8076 
8077 *  Parameters:
8078 *     this
8079 *        Pointer to the original Frame.
8080 *     naxes
8081 *        The number of axes required in the new Frame.
8082 *     axes
8083 *        Pointer to an array of int with naxes elements. This should
8084 *        contain (zero based) axis indices specifying the axes which
8085 *        are to be included in the new Frame, in the order
8086 *        required. Each axis index may occur only once.
8087 *
8088 *        If additional (default) axes are also to be included, the
8089 *        corresponding elements of this array should be set to -1.
8090 *     map
8091 *        Address of a location to receive a pointer to a new
8092 *        Mapping. This will be a PermMap (or a UnitMap as a special
8093 *        case) that describes the axis permutation that has taken
8094 *        place between the original and new Frames.  The forward
8095 *        transformation will convert from the original Frame's axes to
8096 *        the new one's, and vice versa.
8097 *
8098 *        If this Mapping is not required, a NULL value may be supplied
8099 *        for this parameter.
8100 
8101 *  Returned Value:
8102 *     Pointer to the new Frame.
8103 
8104 *  Notes:
8105 *     - The class of object returned may differ from that of the
8106 *     original Frame, depending on which axes are selected. For
8107 *     example, if a single axis is picked from a SkyFrame (which
8108 *     always has two axes), the resulting Frame cannot be a valid
8109 *     SkyFrame, so will revert to the parent class (Frame) instead.
8110 *     - The new Frame contains a deep copy of all the data selected
8111 *     from the original Frame. Modifying the new Frame will therefore
8112 *     not affect the original one.
8113 *     - A NULL pointer will be returned if this function is invoked
8114 *     with the global error status set, or if it should fail for any
8115 *     reason.
8116 *-
8117 
8118 *  Implementation Notes:
8119 *     - This function implements the basic astPickAxes method
8120 *     available via the protected interface to the Frame class. The
8121 *     public interface to this method is provided by the
8122 *     astPickAxesId_ function.
8123 */
8124 
8125 /* Local Variables: */
8126    AstFrame *frame;              /* Pointer to Frame to be returned */
8127    AstMapping *mapping;          /* Pointer to Mapping to be returned */
8128 
8129 /* Check the global error status. */
8130    if ( !astOK ) return NULL;
8131 
8132 /* Initialise the returned pointers. */
8133    frame = NULL;
8134    if ( map ) *map = NULL;
8135 
8136 /* Check that a valid set of axes is being selected . */
8137    astValidateAxisSelection( this, naxes, axes, "astPickAxes" );
8138 
8139 /* Create the required new Frame by selecting the axes. This also returns a
8140    Mapping which transforms between the original Frame and the new one. */
8141    astSubFrame( this, NULL, naxes, axes, NULL, &mapping, &frame );
8142    if ( astOK ) {
8143 
8144 /* Return the Mapping pointer if required. */
8145       if ( map ) {
8146          *map = mapping;
8147 
8148 /* Otherwise annul the Mapping. If an error occurs, also annul the Frame. */
8149       } else {
8150          mapping = astAnnul( mapping );
8151          if ( !astOK ) frame = astAnnul( frame );
8152       }
8153    }
8154 
8155 /* Return the pointer to the new Frame. */
8156    return frame;
8157 }
8158 
PrimaryFrame(AstFrame * this,int axis1,AstFrame ** frame,int * axis2,int * status)8159 static void PrimaryFrame( AstFrame *this, int axis1,
8160                           AstFrame **frame, int *axis2, int *status ) {
8161 /*
8162 *+
8163 *  Name:
8164 *     astPrimaryFrame
8165 
8166 *  Purpose:
8167 *     Uniquely identify a primary Frame and one of its axes.
8168 
8169 *  Type:
8170 *     Protected virtual function.
8171 
8172 *  Synopsis:
8173 *     #include "frame.h"
8174 *     void astPrimaryFrame( AstFrame *this, int axis1, AstFrame **frame,
8175 *                           int *axis2 )
8176 
8177 *  Class Membership:
8178 *     Frame method.
8179 
8180 *  Description:
8181 *     This function returns information about the underlying (primary) Frame
8182 *     corresponding to a specified axis, when given what may be a compound
8183 *     Frame composed of more than one simpler one.
8184 
8185 *  Parameters:
8186 *     this
8187 *        Pointer to the Frame.
8188 *     axis1
8189 *        An axis index (zero-based) identifying the Frame axis for which
8190 *        information is required.
8191 *     frame
8192 *        Address of a location to receive a pointer to the underlying (primary)
8193 *        frame to which the requested axis belongs (i.e. this will not be a
8194 *        compound Frame).
8195 *     axis2
8196 *        Pointer to an int which is to receive the (zero-based) axis
8197 *        index within "frame" which identifies the axis being referred
8198 *        to, using the axis order that applied when the primary Frame
8199 *        was originally constructed (i.e. this function undoes all
8200 *        subsequent axis pemutations and the effects of combining
8201 *        Frames, in order to reveal the original underlying axis
8202 *        order).
8203 
8204 *  Notes:
8205 *     -  This protected method is provided so that class implementations can
8206 *     distinguish the axes of frames from one another (e.g. can distinguish
8207 *     a longitude axis as being different from a latitide axis) even after
8208 *     their order has been permuted and they have been combined with axes from
8209 *     other Frames.
8210 *     -  The reference count of the primary Frame will be incremented by one to
8211 *     reflect the new pointer returned.
8212 *-
8213 */
8214 
8215 /* Check the global error status. */
8216    if ( !astOK ) return;
8217 
8218 /* Initialise the returned values. */
8219    *frame = NULL;
8220    *axis2 = 0;
8221 
8222 /* Validate and permute the axis index supplied. */
8223    axis1 = astValidateAxis( this, axis1, 1, "astPrimaryFrame" );
8224 
8225 /* Since "this" is a primary Frame (i.e. is not compound), simply clone a
8226    pointer to it. */
8227    if ( astOK ) *frame = astClone( this );
8228 
8229 /* Return the permuted axis index, which refers to the original axis order. */
8230    if ( astOK ) *axis2 = axis1;
8231 }
8232 
astReadDateTime_(const char * value,int * status)8233 double astReadDateTime_( const char *value, int *status ) {
8234 /*
8235 *+
8236 *  Name:
8237 *     astReadDateTime
8238 
8239 *  Purpose:
8240 *     Read a date/time string.
8241 
8242 *  Type:
8243 *     Private function.
8244 
8245 *  Synopsis:
8246 *     #include "frame.h"
8247 *     double astReadDateTime( const char *value )
8248 
8249 *  Class Membership:
8250 *     Frame member function.
8251 
8252 *  Description:
8253 *     This function reads a date/time string in a variety of formats and
8254 *     returns the resulting time as a Modified Julian Date. If the string
8255 *     cannot be interpreted as a date/time or contains invalid values, an
8256 *     error is reported.
8257 
8258 *  Parameters:
8259 *     value
8260 *        Pointer to a null terminated string containing the value to be read.
8261 
8262 *  Returned Value:
8263 *     The time as a Modified Julian date.
8264 
8265 *  Date/Time Formats:
8266 *     The date/time formats supported by this function are listed below. These
8267 *     are interpreted in a case-insensitive manner and the function is
8268 *     generally flexible about the presence of additional white space and the
8269 *     use of alternative field delimiters.
8270 *
8271 *     Besselian Epoch
8272 *        Expressed in decimal years, with or without decimal places
8273 *        ("B1950" or "B1976.13", for example).
8274 *     Julian Epoch
8275 *        Expressed in decimal years, with or without decimal places
8276 *        ("J2000" or "J2100.9", for example).
8277 *     Year
8278 *        Decimal years, with or without decimal places ("1996.8" for example).
8279 *        Such values are interpreted as a Besselian epoch (see above) if less
8280 *        than 1984.0 and as a Julian epoch otherwise.
8281 *     Julian Date
8282 *        With or without decimal places ("JD 2454321.9" for example).
8283 *     Modified Julian Date
8284 *        With or without decimal places ("MJD 54321.4" for example).
8285 *     Gregorian Calendar Date
8286 *        With the month expressed as an integer or 3-character
8287 *        abbreviation, and with optional decimal places to represent a
8288 *        fraction of a day ("1996-10-2" or "1996-Oct-2.6" for
8289 *        example). If no fractional part of a day is given, the time
8290 *        refers to the start of the day (zero hours).
8291 *     Gregorian Date and Time
8292 *        Any calendar date (as above) but with a fraction of a day expressed
8293 *        as hours, minutes and seconds ("1996-Oct-2 12:13:56.985" for example).
8294 *        The date and time can be separated by a space or by a "T" (as used
8295 *        by ISO8601).
8296 
8297 *  Notes:
8298 *     -  The date/time value is interpreted as a calendar date and time, not
8299 *     linked to any particular time system. Thus, interpretation of hours,
8300 *     minutes and seconds is done in the obvious manner assuming 86400 seconds
8301 *     in a day. No allowance for is made, for instance, for leap seconds or for
8302 *     the varying length of a second in some time systems.
8303 *     -  A value of AST__BAD is returned if this function is invoked with the
8304 *     global error status set or if it should fail for any reason.
8305 *-
8306 */
8307 
8308 /* Local Vaiables: */
8309    char cmonth[ 4 ];             /* Buffer for name of month */
8310    char sep1[ 2 ];               /* Year/month separator string */
8311    char sep2[ 2 ];               /* Month/day separator string */
8312    char sep3[ 2 ];               /* Hour/minute separator string */
8313    char sep4[ 2 ];               /* Minute/second separator string */
8314    char *cc;                     /* Pointer to copy of remaining text */
8315    const char *v;                /* Pointer into value string */
8316    const char *p;                /* Pointer to date/time separator */
8317    double day;                   /* Day number plus fraction of whole day */
8318    double epoch;                 /* Epoch stored as decimal years */
8319    double hms;                   /* Hours, min & sec as fraction of a day */
8320    double jd;                    /* Julian Date */
8321    double mjd;                   /* Modified Julian Date */
8322    double result;                /* Result to be returned */
8323    double sec;                   /* Seconds and fractions of a second */
8324    int hour;                     /* Number of hours */
8325    int iday;                     /* Number of whole days */
8326    int l;                        /* Length of string remaining */
8327    int len;                      /* Length of string */
8328    int match;                    /* Date/time string has correct form? */
8329    int minute;                   /* Number of minutes */
8330    int month;                    /* Number of months */
8331    int nc;                       /* Number of characters read from string */
8332    int stat;                     /* Status return from SLALIB functions */
8333    int year;                     /* Number of years */
8334 
8335 /* Check the global error status. */
8336    if ( !astOK ) return AST__BAD;
8337 
8338 /* Initialise. */
8339    result = AST__BAD;
8340 
8341 /* Obtain the length of the input string. */
8342    len = (int) strlen( value );
8343 
8344 /* Attempt to read the string using each recognised format in turn. */
8345 
8346 /* Besselian epoch in decimal years (e.g. "B1950.0"). */
8347 /* ================================================== */
8348    if ( nc = 0,
8349         ( 1 == astSscanf( value, " %*1[Bb] %lf %n", &epoch, &nc ) )
8350         && ( nc >= len ) ) {
8351 
8352 /* Convert to Modified Julian Date. */
8353       result = palEpb2d( epoch );
8354 
8355 /* Julian epoch in decimal years (e.g. "J2000.0"). */
8356 /* =============================================== */
8357    } else if ( nc = 0,
8358                ( 1 == astSscanf( value, " %*1[Jj] %lf %n", &epoch, &nc ) )
8359                && ( nc >= len ) ) {
8360 
8361 /* Convert to Modified Julian Date. */
8362       result = palEpj2d( epoch );
8363 
8364 /* Decimal years (e.g. "1976.2"). */
8365 /* ============================== */
8366    } else if ( nc = 0,
8367                ( 1 == astSscanf( value, " %lf %n", &epoch, &nc ) )
8368                && ( nc >= len ) ) {
8369 
8370 /* Convert to Modified Julian Date, treating the epoch as Julian or Besselian
8371    depending on whether it is 1984.0 or later. */
8372       result = ( epoch < 1984.0 ) ? palEpb2d( epoch ) : palEpj2d( epoch );
8373 
8374 /* Modified Julian Date (e.g. "MJD 54321.0"). */
8375 /* ============================================ */
8376    } else if ( nc = 0,
8377                ( 1 == astSscanf( value, " %*1[Mm] %*1[Jj] %*1[Dd] %lf %n",
8378                               &mjd, &nc ) ) && ( nc >= len ) ) {
8379 
8380 /* Use the result directly. */
8381       result = mjd;
8382 
8383 /* Julian Date (e.g. "JD 2454321.5"). */
8384 /* ==================================== */
8385    } else if ( nc = 0,
8386                ( 1 == astSscanf( value, " %*1[Jj] %*1[Dd] %lf %n",
8387                               &jd, &nc ) ) && ( nc >= len ) ) {
8388 
8389 /* Convert to Modified Julian Date. */
8390       result = jd - 2400000.5;
8391 
8392 /* Gregorian calendar date (e.g. "1996-10-2" or "1996-Oct-2"). */
8393 /* =========================================================== */
8394 /* This format also allows day fractions expressed as decimal days, e.g:
8395 
8396       "1996-Oct-2.5001"
8397 
8398    or as hours, minutes and seconds, e.g:
8399 
8400       "1996-Oct-2 12:14:30.52"
8401 
8402    Various alternative field delimiters are also allowed. */
8403    } else {
8404 
8405 /* Note that the method used to parse this format relies heavily on
8406    conditional execution controlled by "&&" and "||" operators. Initialise
8407    the variables used. */
8408       v = value;
8409       l = len;
8410       *cmonth = '\0';
8411       year = month = iday = hour = minute = 0;
8412       day = sec = 0.0;
8413 
8414 /* Identify the year and month. */
8415 /* ---------------------------- */
8416 /* Try to match an initial " 1996 - 10 -" or " 1996 10 " or similar. */
8417       match =
8418          ( nc = 0, ( 4 == astSscanf( v, " %d %1[:/-] %2d %1[:/-]%n",
8419                                   &year, sep1, &month, sep2, &nc ) ) );
8420       match = match ||
8421          ( nc = 0, ( 4 == astSscanf( v, " %d%1[ ] %2d%1[ ]%n",
8422                                   &year, sep1, &month, sep2, &nc ) ) );
8423 
8424 /* If that failed, allow " 1996 - Oct -" or " 1996 Oct " or similar. */
8425       match = match ||
8426          ( nc = 0, ( 4 == astSscanf( v,
8427                                   " %d %1[:/-] %3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
8428                                   "abcdefghijklmnopqrstuvwxyz] %1[:/-]%n",
8429                                   &year, sep1, cmonth, sep2, &nc ) ) );
8430       match = match ||
8431          ( nc = 0, ( 4 == astSscanf( v,
8432                                   " %d%1[ ] %3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
8433                                   "abcdefghijklmnopqrstuvwxyz]%1[ ]%n",
8434                                   &year, sep1, cmonth, sep2, &nc ) ) );
8435 
8436 /* Alternative field separators are permitted above, but ensure that
8437    they are both the same. */
8438       match = match && ( *sep1 == *sep2 );
8439 
8440 /* Identify the day and fraction of day. */
8441 /*-------------------------------------- */
8442 /* If the above matched correctly, modify the string pointer "v" to
8443    the next character to be interpreted and decrement the remaining
8444    string length. */
8445       if ( match ) {
8446          v += nc;
8447          l -= nc;
8448 
8449 /* ISO8601 format uses the litter T as a delimiter between the date and time.
8450    If there is a T in the remaining string, take a copy and change the T to
8451    a space. */
8452          p = strchr( v, 'T' );
8453          if( p ) {
8454             cc = astStore( NULL, v, l + 1 );
8455             cc[ p - v ] = ' ';
8456             v = cc;
8457          } else {
8458             cc = NULL;
8459          }
8460 
8461 /* We now try to match the following characters but without reading
8462    any values.  This is done to ensure the string has the correct form
8463    (e.g. exclude "-" signs and exponents in numbers, which are
8464    otherwise hard to detect). */
8465 
8466 /* Try to match " 12.3456 " or similar. */
8467          match =
8468             ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789].%*[0123456789] %n",
8469                                      &nc ) )
8470                       && ( nc == l ) );
8471 
8472 /* If that failed, then try to match " 12. " or similar. */
8473          match = match ||
8474             ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789]. %n", &nc ) )
8475                       && ( nc == l ) );
8476 
8477 /* If that also failed, then try to match just " 12 " or similar. */
8478          match = match ||
8479             ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789] %n", &nc ) )
8480                       && ( nc == l ) );
8481 
8482 /* If any of the above patterns matched, now read the data (the day number)
8483    as a double value. */
8484          if ( match ) {
8485             match = ( nc = 0, ( 1 == astSscanf( v, " %lf %n", &day, &nc ) )
8486                               && ( nc == l ) );
8487 
8488 /* If none of the above matched, then look to see if the day fraction has been
8489    given in hours, minutes and seconds by trying to match " 12 03 : 45 :" or
8490    " 12 13 45 " or similar. */
8491          } else {
8492             match =
8493                ( nc = 0, ( 5 == astSscanf( v,
8494                                         " %2d%*1[ ] %2d %1[:/-] %2d %1[:/-]%n",
8495                                         &iday, &hour, sep3, &minute, sep4,
8496                                         &nc ) ) );
8497             match = match ||
8498                ( nc = 0, ( 5 == astSscanf( v, " %2d%*1[ ] %2d%1[ ] %2d%1[ ]%n",
8499                                         &iday, &hour, sep3, &minute, sep4,
8500                                         &nc ) ) );
8501 
8502 /* Alternative field separators are permitted above, but ensure that
8503    they are both the same. */
8504             match = match && ( *sep3 == *sep4 );
8505 
8506 /* If the day number was read as an integer, convert it to double. */
8507             if ( match ) day = (double) iday;
8508 
8509 /* If no match, see if we can get a match without a trailing seconds field. */
8510             if( !match ) {
8511                match =
8512                   ( nc = 0, ( 4 == astSscanf( v,
8513                                         " %2d%*1[ ] %2d %1[:/-] %2d %n",
8514                                         &iday, &hour, sep3, &minute, &nc ) &&
8515                                         ( nc == l ) ) );
8516                match = match ||
8517                   ( nc = 0, ( 4 == astSscanf( v, " %2d%*1[ ] %2d%1[ ] %2d %n",
8518                                         &iday, &hour, sep3, &minute, &nc ) &&
8519                                         ( nc == l ) ) );
8520 
8521 /* If the day number was read as an integer, convert it to double. */
8522                if ( match ) day = (double) iday;
8523 
8524 /* Otherwise, identify the seconds field. */
8525 /* -------------------------------------- */
8526 /* If hours and minutes fields have been matched, now look for the
8527    final seconds (and fractions of seconds) field. This is similar to
8528    the day/fraction field (see earlier) in that we first check that it
8529    has the correct form before reading its value. */
8530 
8531 /* Adjust the string pointer and remaining string length. */
8532             } else {
8533                v += nc;
8534                l -= nc;
8535 
8536 /* Try to match " 12.3456 " or similar. */
8537                match =
8538                   ( nc = 0, ( 0 == astSscanf( v,
8539                                           " %*2[0123456789].%*[0123456789] %n",
8540                                            &nc ) )
8541                             && ( nc == l ) );
8542 
8543 /* If that failed, then try to match " 12. " or similar. */
8544                match = match ||
8545                   ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789]. %n", &nc ) )
8546                             && ( nc == l ) );
8547 
8548 /* If that also failed, then try to match just " 12 " or similar. */
8549                match = match ||
8550                   ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789] %n", &nc ) )
8551                             && ( nc == l ) );
8552 
8553 /* If any of the above patterns matched, now read the data (the number of
8554    seconds) as a double value. */
8555                if ( match ) {
8556                   match = ( nc = 0, ( 1 == astSscanf( v, " %lf %n", &sec, &nc ) )
8557                                     && ( nc == l ) );
8558                }
8559             }
8560          }
8561 
8562 /* Free resources */
8563          if( cc ) cc = astFree( cc );
8564 
8565       }
8566 
8567 /* Interpret the values that were read. */
8568 /* ------------------------------------ */
8569 /* We execute this if all of the above text matching was successful,
8570    transferred the required number of data values, and consumed the
8571    entire input string. */
8572       if ( match ) {
8573 
8574 /* See if the month was given as a character string (e.g. "Oct") instead of
8575    a number. If so, define local variables for use in converting it. */
8576          if ( *cmonth ) {
8577             char lcmonth[ 4 ];      /* Lower case copy of month string */
8578             const char *ptr;        /* Pointer result from look up */
8579             const char *table =     /* Month look up table */
8580                        "jan feb mar apr may jun jul aug sep oct nov dec";
8581             int i;                  /* Loop counter for characters */
8582 
8583 /* Convert the month string to lower case. */
8584             for ( i = 0; cmonth[ i ]; i++ ) {
8585                lcmonth[ i ] = tolower( cmonth[ i ] );
8586             }
8587             lcmonth[ i ] = '\0';
8588 
8589 /* Look the month up in the table of months and generate the required month
8590    number. */
8591             if ( ( ptr = strstr( table, lcmonth ) ) ) {
8592                month = 1 + ( ptr - table ) / 4;
8593 
8594 /* If the lookup failed, report an error. */
8595    	    } else {
8596                astError( AST__DTERR, "Month value \"%s\" is invalid.", status,
8597                          cmonth );
8598             }
8599          }
8600 
8601 /* If OK, extract the integral day number and convert years, months and days
8602    to a Modified Julian Date. */
8603          if ( astOK ) {
8604             iday = (int) day;
8605             palCaldj( year, month, iday, &mjd, &stat );
8606 
8607 /* Examine the return status from the conversion and report an appropriate
8608    error if necessary. */
8609             switch ( stat ) {
8610             case 1:
8611                astError( AST__DTERR, "Year value (%d) is invalid.", status, year );
8612                break;
8613             case 2:
8614                astError( AST__DTERR, "Month value (%d) is invalid.", status, month );
8615                break;
8616             case 3:
8617                astError( AST__DTERR, "Day value (%.*g) is invalid.", status, DBL_DIG,
8618                          day );
8619                break;
8620 
8621 /* If conversion to MJD was successful, add any fractional part of a day to the
8622    result. */
8623             default:
8624                mjd += ( day - (double) iday );
8625 
8626 /* Convert hours, minutes and seconds to a fraction of a day (this will give
8627    zero if none of these quantities was supplied). */
8628                palDtf2d( hour, minute, sec, &hms, &stat );
8629 
8630 /* Examine the return status from the conversion and report an appropriate
8631    error if necessary. */
8632                switch ( stat ) {
8633                case 1:
8634                   astError( AST__DTERR, "Hour value (%d) is invalid.", status, hour );
8635                   break;
8636                case 2:
8637                   astError( AST__DTERR, "Minute value (%d) is invalid.", status,
8638                             minute );
8639                   break;
8640                case 3:
8641                   astError( AST__DTERR, "Seconds value (%.*g) is invalid.", status,
8642                             DBL_DIG, sec );
8643                   break;
8644 
8645 /* Add the fraction of a day derived from hours, minutes and seconds fields to
8646    the result. */
8647                default:
8648                   mjd += hms;
8649                   break;
8650                }
8651                break;
8652             }
8653 
8654 /* Return the result, if no error occurred. */
8655             if ( astOK ) result = mjd;
8656          }
8657 
8658 /* If none of the supported date/time formats matched, then report an error. */
8659       } else {
8660          astError( AST__DTERR, "Date/time does not have the correct form." , status);
8661       }
8662    }
8663 
8664 /* Return the result. */
8665    return result;
8666 }
8667 
ReportPoints(AstMapping * this_mapping,int forward,AstPointSet * in_points,AstPointSet * out_points,int * status)8668 static void ReportPoints( AstMapping *this_mapping, int forward,
8669                           AstPointSet *in_points, AstPointSet *out_points, int *status ) {
8670 /*
8671 *  Name:
8672 *     ReportPoints
8673 
8674 *  Purpose:
8675 *     Report the effect of transforming a set of points using a Frame.
8676 
8677 *  Type:
8678 *     Private function.
8679 
8680 *  Synopsis:
8681 *     #include "mapping.h"
8682 *     void ReportPoints( AstMapping *this, int forward,
8683 *                        AstPointSet *in_points, AstPointSet *out_points, int *status )
8684 
8685 *  Class Membership:
8686 *     Frame member function (over-rides the protected astReportPoints
8687 *     method inherited from the Mapping class).
8688 
8689 *  Description:
8690 *     This function reports the coordinates of a set of points before
8691 *     and after being transformed by a Frame, by writing them to
8692 *     standard output.
8693 
8694 *  Parameters:
8695 *     this
8696 *        Pointer to the Frame.
8697 *     forward
8698 *        A non-zero value indicates that the Frame's forward
8699 *        coordinate transformation has been applied, while a zero
8700 *        value indicates the inverse transformation.
8701 *     in_points
8702 *        Pointer to a PointSet which is associated with the
8703 *        coordinates of a set of points before the Frame was applied.
8704 *     out_points
8705 *        Pointer to a PointSet which is associated with the
8706 *        coordinates of the same set of points after the Frame has
8707 *        been applied.
8708 *     status
8709 *        Pointer to the inherited status variable.
8710 */
8711 
8712 /* Local Variables: */
8713    AstFrame *this;               /* Pointer to the Frame structure */
8714    double **ptr_in;              /* Pointer to array of input data pointers */
8715    double **ptr_out;             /* Pointer to array of output data pointers */
8716    int coord;                    /* Loop counter for coordinates */
8717    int ncoord_in;                /* Number of input coordinates per point */
8718    int ncoord_out;               /* Number of output coordinates per point */
8719    int npoint;                   /* Number of points to report */
8720    int npoint_in;                /* Number of input points */
8721    int npoint_out;               /* Number of output points */
8722    int point;                    /* Loop counter for points */
8723 
8724 /* Check the global error status. */
8725    if ( !astOK ) return;
8726 
8727 /* Obtain a pointer to the Frame structure. */
8728    this = (AstFrame *) this_mapping;
8729 
8730 /* Obtain the numbers of points and coordinates associated with each
8731    PointSet. */
8732    npoint_in = astGetNpoint( in_points );
8733    npoint_out = astGetNpoint( out_points );
8734    ncoord_in = astGetNcoord( in_points );
8735    ncoord_out = astGetNcoord( out_points );
8736 
8737 /* Obtain the pointers that give access to the coordinate data
8738    associated with each PointSet. */
8739    ptr_in = astGetPoints( in_points );
8740    ptr_out = astGetPoints( out_points );
8741 
8742 /* In the event that both PointSets don't contain equal numbers of
8743    points (this shouldn't actually happen), simply use the minimum
8744    number. */
8745    npoint = ( npoint_in < npoint_out ) ? npoint_in : npoint_out;
8746 
8747 /* Loop to report the effect of the transformation on each point in
8748    turn. */
8749    for ( point = 0; point < npoint; point++ ) {
8750 
8751 /* Report the input coordinates (in parentheses and separated by
8752    commas). Format each value for display using the Frame's astFormat
8753    method. */
8754       printf( "(" );
8755       for ( coord = 0; coord < ncoord_in; coord++ ) {
8756          printf( "%s%s", coord ? ", " : "",
8757                  astFormat( this, coord, ptr_in[ coord ][ point ] ) );
8758       }
8759 
8760 /* Similarly report the output coordinates. */
8761       printf( ") --> (" );
8762       for ( coord = 0; coord < ncoord_out; coord++ ) {
8763          printf( "%s%s", coord ? ", " : "",
8764                  astFormat( this, coord, ptr_out[ coord ][ point ] ) );
8765       }
8766       printf( ")\n" );
8767    }
8768 }
8769 
Resolve(AstFrame * this,const double point1[],const double point2[],const double point3[],double point4[],double * d1,double * d2,int * status)8770 static void Resolve( AstFrame *this, const double point1[],
8771                        const double point2[], const double point3[],
8772                        double point4[], double *d1, double *d2, int *status ){
8773 /*
8774 *++
8775 *  Name:
8776 c     astResolve
8777 f     AST_RESOLVE
8778 
8779 *  Purpose:
8780 *     Resolve a vector into two orthogonal components
8781 
8782 *  Type:
8783 *     Public virtual function.
8784 
8785 *  Synopsis:
8786 c     #include "frame.h"
8787 c     void astResolve( AstFrame *this, const double point1[],
8788 c                      const double point2[], const double point3[],
8789 c                      double point4[], double *d1, double *d2 );
8790 f     CALL AST_RESOLVE( THIS, POINT1, POINT2, POINT3, POINT4, D1, D2,
8791 f                       STATUS )
8792 
8793 *  Class Membership:
8794 *     Frame method.
8795 
8796 *  Description:
8797 c     This function resolves a vector into two perpendicular components.
8798 f     This routine resolves a vector into two perpendicular components.
8799 *     The vector from point 1 to point 2 is used as the basis vector.
8800 *     The vector from point 1 to point 3 is resolved into components
8801 *     parallel and perpendicular to this basis vector. The lengths of the
8802 *     two components are returned, together with the position of closest
8803 *     aproach of the basis vector to point 3.
8804 
8805 *  Parameters:
8806 c     this
8807 f     THIS = INTEGER (Given)
8808 *        Pointer to the Frame.
8809 c     point1
8810 f     POINT1( * ) = DOUBLE PRECISION (Given)
8811 c        An array of double, with one element for each Frame axis
8812 f        An array with one element for each Frame axis
8813 *        (Naxes attribute). This marks the start of the basis vector,
8814 *        and of the vector to be resolved.
8815 c     point2
8816 f     POINT2( * ) = DOUBLE PRECISION (Given)
8817 c        An array of double, with one element for each Frame axis
8818 f        An array with one element for each Frame axis
8819 *        (Naxes attribute). This marks the end of the basis vector.
8820 c     point3
8821 f     POINT3( * ) = DOUBLE PRECISION (Given)
8822 c        An array of double, with one element for each Frame axis
8823 f        An array with one element for each Frame axis
8824 *        (Naxes attribute). This marks the end of the vector to be
8825 *        resolved.
8826 c     point4
8827 f     POINT4( * ) = DOUBLE PRECISION (Returned)
8828 c        An array of double, with one element for each Frame axis
8829 f        An array with one element for each Frame axis
8830 *        in which the coordinates of the point of closest approach of the
8831 *        basis vector to point 3 will be returned.
8832 c     d1
8833 f     D1 = DOUBLE PRECISION (Returned)
8834 c        The address of a location at which to return the distance from
8835 f        The distance from
8836 *        point 1 to point 4 (that is, the length of the component parallel
8837 *        to the basis vector). Positive values are in the same sense as
8838 *        movement from point 1 to point 2.
8839 c     d2
8840 f     D2 = DOUBLE PRECISION (Returned)
8841 c        The address of a location at which to return the distance from
8842 f        The distance from
8843 *        point 4 to point 3 (that is, the length of the component
8844 *        perpendicular to the basis vector). The value is always positive.
8845 f     STATUS = INTEGER (Given and Returned)
8846 f        The global status.
8847 
8848 *  Notes:
8849 c     - Each vector used in this function is the path of
8850 f     - Each vector used in this routine is the path of
8851 *     shortest distance between two points, as defined by the
8852 c     astDistance function.
8853 f     AST_DISTANCE function.
8854 *     - This function will return "bad" coordinate values (AST__BAD)
8855 *     if any of the input coordinates has this value, or if the required
8856 *     output values are undefined.
8857 *--
8858 */
8859 
8860 /* Local Variables: */
8861    double bv;                    /* Length of basis vector */
8862    double c;                     /* Component length */
8863    double dp;                    /* Dot product */
8864    int axis;                     /* Loop counter for axes */
8865    int naxes;                    /* Number of Frame axes */
8866    int ok;                       /* OK to proceed? */
8867 
8868 /* Check the global error status. */
8869    *d1 = AST__BAD;
8870    *d2 = AST__BAD;
8871    if ( !astOK ) return;
8872 
8873 /* Determine the number of Frame axes. */
8874    naxes = astGetNaxes( this );
8875 
8876 /* Initialize bad values, and check if the supplied vectors are good. */
8877    ok = 1;
8878    for( axis = 0; axis < naxes; axis++ ){
8879       point4[ axis ] = AST__BAD;
8880       if( point1[ axis ] == AST__BAD ||
8881           point2[ axis ] == AST__BAD ||
8882           point3[ axis ] == AST__BAD ) ok = 0;
8883    }
8884 
8885 /* Check the supplied values. */
8886    if ( ok ) {
8887 
8888 /* Find the dot product of the basis vector with the vector joining point 1
8889    and point 3. At the same time form the squared length of the basis
8890    vector. */
8891       dp = 0.0;
8892       bv = 0.0;
8893       for( axis = 0; axis < naxes; axis++ ){
8894          c = point2[ axis ] - point1[ axis ];
8895          dp += c * ( point3[ axis ] - point1[ axis ] );
8896          bv += c * c;
8897       }
8898 
8899 /* Check the basis vector does not have zero length, and convert the
8900    squared length into a length. */
8901       if( bv > 0.0 ) {
8902          bv = sqrt( bv );
8903 
8904 /* The dot product is the required distance d1 multiplied by the length
8905    of the basis vector. Form the distance d1. */
8906          *d1 = dp/bv;
8907 
8908 /* Offset away from point 1 towards point 2 by a distance of d1. */
8909          for( axis = 0; axis < naxes; axis++ ){
8910             point4[ axis ] = point1[ axis ] +
8911                              (*d1/bv)*( point2[ axis ] - point1[ axis ] );
8912          }
8913 
8914 /* Finally, form the required length d2. */
8915          *d2 = 0.0;
8916          for( axis = 0; axis < naxes; axis++ ){
8917             c = ( point3[ axis ] - point4[ axis ] );
8918             *d2 += c*c;
8919          }
8920          *d2 = sqrt( *d2 );
8921 
8922       }
8923    }
8924 
8925    return;
8926 
8927 }
8928 
ResolvePoints(AstFrame * this,const double point1[],const double point2[],AstPointSet * in,AstPointSet * out,int * status)8929 static AstPointSet *ResolvePoints( AstFrame *this, const double point1[],
8930                                    const double point2[], AstPointSet *in,
8931                                    AstPointSet *out, int *status ) {
8932 /*
8933 *+
8934 *  Name:
8935 *     astResolvePoints
8936 
8937 *  Purpose:
8938 *     Resolve a set of vectors into orthogonal components
8939 
8940 *  Type:
8941 *     Protected virtual function.
8942 
8943 *  Synopsis:
8944 *     #include "frame.h"
8945 *     AstPointSet *astResolvePoints( AstFrame *this, const double point1[],
8946 *                                    const double point2[], AstPointSet *in,
8947 *                                    AstPointSet *out )
8948 
8949 *  Class Membership:
8950 *     Frame method.
8951 
8952 *  Description:
8953 *     This function takes a Frame and a set of vectors encapsulated
8954 *     in a PointSet, and resolves each one into two orthogonal components,
8955 *     returning these two components in another PointSet.
8956 *
8957 *     This is exactly the same as the public astResolve method, except
8958 *     that this method allows many vectors to be processed in a single call,
8959 *     thus reducing the computational cost of overheads of many
8960 *     individual calls to astResolve.
8961 
8962 *  Parameters:
8963 *     this
8964 *        Pointer to the Frame.
8965 *     point1
8966 *        An array of double, with one element for each Frame axis
8967 *        (Naxes attribute). This marks the start of the basis vector,
8968 *        and of the vectors to be resolved.
8969 *     point2
8970 *        An array of double, with one element for each Frame axis
8971 *        (Naxes attribute). This marks the end of the basis vector.
8972 *     in
8973 *        Pointer to the PointSet holding the ends of the vectors to be
8974 *        resolved.
8975 *     out
8976 *        Pointer to a PointSet which will hold the length of the two
8977 *        resolved components. A NULL value may also be given, in which
8978 *        case a new PointSet will be created by this function.
8979 
8980 *  Returned Value:
8981 *     Pointer to the output (possibly new) PointSet. The first axis will
8982 *     hold the lengths of the vector components parallel to the basis vector.
8983 *     These values will be signed (positive values are in the same sense as
8984 *     movement from point 1 to point 2. The second axis will hold the lengths
8985 *     of the vector components perpendicular to the basis vector. These
8986 *     values will be signed only if the Frame is 2-dimensional, in which
8987 *     case a positive value indicates that rotation from the basis vector
8988 *     to the tested vector is in the same sense as rotation from the first
8989 *     to the second axis of the Frame.
8990 
8991 *  Notes:
8992 *     - The number of coordinate values per point in the input
8993 *     PointSet must match the number of axes in the supplied Frame.
8994 *     - If an output PointSet is supplied, it must have space for
8995 *     sufficient number of points and 2 coordinate values per point.
8996 *     - A null pointer will be returned if this function is invoked
8997 *     with the global error status set, or if it should fail for any
8998 *     reason.
8999 *     - We assume flat geometry throughout this function. Other classes,
9000 *     (e.g. SkyFrame) will override this method using more appropriate
9001 *     geometry.
9002 *-
9003 */
9004 
9005 /* Local Variables: */
9006    AstPointSet *result;          /* Pointer to output PointSet */
9007    double **ptr_in;              /* Pointers to input axis values */
9008    double **ptr_out;             /* Pointers to returned axis values */
9009    double *basisv;               /* Pointer to array holding basis vector */
9010    double *d1;                   /* Pointer to next parallel component value */
9011    double *d2;                   /* Pointer to next perpendicular component value */
9012    double *ip;                   /* Pointer to next input axis value */
9013    double bv;                    /* Length of basis vector */
9014    double c;                     /* Constant value */
9015    double d;                     /* Component length */
9016    double dp;                    /* Dot product */
9017    double x1;                    /* First axis of basis vector */
9018    double x2;                    /* First axis of test vector */
9019    double y1;                    /* Second axis of basis vector */
9020    double y2;                    /* Second axis of test vector */
9021    int axis;                     /* Loop counter for axes */
9022    int ipoint;                   /* Index of next point */
9023    int nax;                      /* Number of Frame axes */
9024    int ncoord_in;                /* Number of input PointSet coordinates */
9025    int ncoord_out;               /* Number of coordinates in output PointSet */
9026    int npoint;                   /* Number of points to transform */
9027    int npoint_out;               /* Number of points in output PointSet */
9028    int ok;                       /* OK to proceed? */
9029 
9030 /* Initialise. */
9031    result = NULL;
9032 
9033 /* Check the global error status. */
9034    if ( !astOK ) return result;
9035 
9036 /* Obtain the number of axes in the Frame. */
9037    nax = astGetNaxes( this );
9038 
9039 /* Obtain the number of input vectors to resolve and the number of coordinate
9040    values per vector. */
9041    npoint = astGetNpoint( in );
9042    ncoord_in = astGetNcoord( in );
9043 
9044 /* If OK, check that the number of input coordinates matches the number
9045    required by the Frame. Report an error if these numbers do not match. */
9046    if ( astOK && ( ncoord_in != nax ) ) {
9047       astError( AST__NCPIN, "astResolvePoints(%s): Bad number of coordinate "
9048                 "values (%d) in input %s.", status, astGetClass( this ), ncoord_in,
9049                 astGetClass( in ) );
9050       astError( AST__NCPIN, "The %s given requires %d coordinate value(s) for "
9051                 "each input point.", status, astGetClass( this ), nax );
9052    }
9053 
9054 /* If still OK, and a non-NULL pointer has been given for the output PointSet,
9055    then obtain the number of points and number of coordinates per point for
9056    this PointSet. */
9057    if ( astOK && out ) {
9058       npoint_out = astGetNpoint( out );
9059       ncoord_out = astGetNcoord( out );
9060 
9061 /* Check that the dimensions of this PointSet are adequate to accommodate the
9062    output coordinate values and report an error if they are not. */
9063       if ( astOK ) {
9064          if ( npoint_out < npoint ) {
9065             astError( AST__NOPTS, "astResolvePoints(%s): Too few points (%d) in "
9066                       "output %s.", status, astGetClass( this ), npoint_out,
9067                       astGetClass( out ) );
9068             astError( AST__NOPTS, "The %s needs space to hold %d transformed "
9069                       "point(s).", status, astGetClass( this ), npoint );
9070          } else if ( ncoord_out < 2 ) {
9071             astError( AST__NOCTS, "astResolvePoints(%s): Too few coordinate "
9072                       "values per point (%d) in output %s.", status,
9073                       astGetClass( this ), ncoord_out, astGetClass( out ) );
9074             astError( AST__NOCTS, "The %s supplied needs space to store 2 "
9075                       "coordinate value(s) per transformed point.", status,
9076                       astGetClass( this ) );
9077          }
9078       }
9079    }
9080 
9081 /* If all the validation stages are passed successfully, and a NULL output
9082    pointer was given, then create a new PointSet to encapsulate the output
9083    coordinate data. */
9084    if ( astOK ) {
9085       if ( !out ) {
9086          result = astPointSet( npoint, 2, "", status );
9087 
9088 /* Otherwise, use the PointSet supplied. */
9089       } else {
9090          result = out;
9091       }
9092    }
9093 
9094 /* Get pointers to the input and output axis values */
9095    ptr_in = astGetPoints( in );
9096    ptr_out = astGetPoints( result );
9097 
9098 /* Store points to the first two axis arrays in the returned PointSet. */
9099    d1 = ptr_out[ 0 ];
9100    d2 = ptr_out[ 1 ];
9101 
9102 /* Allocate work space. */
9103    basisv = astMalloc( sizeof( double )*(size_t) nax );
9104 
9105 /* If the Frame has only one axis, then the supplied basic vector is
9106    irrelevant - the returned perpendicular distances are always zero and
9107    the returned parallel distances are just the distances from point1
9108    to each input point. */
9109    if( nax < 2 && basisv ) {
9110       ip = ptr_in[ 0 ];
9111       for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++, ip++ ) {
9112          *d1 = astAxDistance( this, 1, point1[0], *ip );
9113          *d2 = 0.0;
9114       }
9115 
9116 /* Now deal with Frames which have 2 or more axes */
9117    } else if( basisv ){
9118 
9119 /* Check if the supplied positions defining the basis vector are good.
9120    Store the basis vector, and get its squared length. */
9121       ok = 1;
9122       bv = 0.0;
9123       for( axis = 0; axis < nax; axis++ ){
9124          if( point1[ axis ] == AST__BAD ||
9125              point2[ axis ] == AST__BAD ) {
9126             ok = 0;
9127             break;
9128          } else {
9129             basisv[ axis ] =  point2[ axis ] - point1[ axis ];
9130             bv += basisv[ axis ]*basisv[ axis ];
9131          }
9132       }
9133 
9134 /* Check the basis vector does not have zero length, and convert the
9135    squared length into a length. */
9136       if( ok && bv > 0.0 ) {
9137          bv = sqrt( bv );
9138       } else {
9139          ok = 0;
9140       }
9141 
9142 /* Store points to the first two axis arrays in the returned PointSet. */
9143       d1 = ptr_out[ 0 ];
9144       d2 = ptr_out[ 1 ];
9145 
9146 /* Check supplied values can be used */
9147       if( ok ) {
9148 
9149 /* Loop round each supplied vector. */
9150          for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) {
9151 
9152 /* Find the dot product of the basis vector with the vector joining point 1
9153    and the end of the current vector. */
9154             ok = 1;
9155             dp = 0.0;
9156             for( axis = 0; axis < nax; axis++ ){
9157                d = ptr_in[ axis ][ ipoint ] - point1[ axis ];
9158                if( d != AST__BAD ) {
9159                   dp += basisv[ axis ] * d;
9160                } else {
9161                   ok = 0;
9162                   break;
9163                }
9164             }
9165 
9166 /* If this input position is good... */
9167             if( ok ) {
9168 
9169 /* The dot product is the required parallel component length multiplied by the
9170    length of the basis vector. Form the distance d1. */
9171                *d1 = dp/bv;
9172 
9173 /* Offset away from point 1 towards point 2 by a distance of d1, and form the
9174    required length d2. */
9175                c = *d1/bv;
9176                if( nax > 2 ) {
9177                   *d2 = 0.0;
9178                   for( axis = 0; axis < nax; axis++ ){
9179                      d = ptr_in[ axis ][ ipoint ] -
9180                          ( point1[ axis ] + c*basisv[ axis ] );
9181                      *d2 += d*d;
9182                   }
9183                   *d2 = sqrt( *d2 );
9184 
9185 /* If the Frame is 2 dimensional, we can give a sign the the perpendicular
9186    component. */
9187                } else {
9188                   x1 = c*basisv[ 0 ];
9189                   y1 = c*basisv[ 1 ];
9190                   x2 = ptr_in[ 0 ][ ipoint ] - ( point1[ 0 ] + x1 );
9191                   y2 = ptr_in[ 1 ][ ipoint ] - ( point1[ 1 ] + y1 );
9192                   *d2 = sqrt( x2*x2 + y2*y2 );
9193                   if( x1*y2 - x2*y1 < 0.0 ) *d2 = -(*d2);
9194                }
9195 
9196 /* If this input vector is bad, put bad values in the output */
9197             } else {
9198                *d1 = AST__BAD;
9199                *d2 = AST__BAD;
9200             }
9201          }
9202 
9203 /* If supplied values cannot be used, fill the returned PointSet with bad
9204    values */
9205       } else {
9206          for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) {
9207             *d1 = AST__BAD;
9208             *d2 = AST__BAD;
9209          }
9210       }
9211    }
9212 
9213 /* Free resources */
9214    basisv = astFree( basisv );
9215 
9216 /* Annul the returned PointSet if an error occurred. */
9217    if( !astOK ) result = astAnnul( result );
9218 
9219 /* Return a pointer to the output PointSet. */
9220    return result;
9221 }
9222 
SetActiveUnit(AstFrame * this,int value,int * status)9223 static void SetActiveUnit( AstFrame *this, int value, int *status ){
9224 /*
9225 *++
9226 *  Name:
9227 c     astSetActiveUnit
9228 f     AST_SETACTIVEUNIT
9229 
9230 *  Purpose:
9231 *     Specify how the Unit attribute should be used.
9232 
9233 *  Type:
9234 *     Public virtual function.
9235 
9236 *  Synopsis:
9237 c     #include "frame.h"
9238 c     void astSetActiveUnit( AstFrame *this, int value )
9239 f     CALL AST_SETACTIVEUNIT( THIS, VALUE, STATUS )
9240 
9241 *  Class Membership:
9242 *     Frame method.
9243 
9244 *  Description:
9245 c     This function
9246 f     This routine
9247 *     sets the current value of the ActiveUnit flag for a Frame, which
9248 *     controls how the Frame behaves when it is used (by
9249 c     astFindFrame or astConvert)
9250 f     AST_FINDFRAME or AST_CONVERT)
9251 *     to match another Frame. If the ActiveUnit flag is set in both
9252 *     template and target Frames then the returned Mapping takes into account
9253 *     any differences in axis units. The default value for simple Frames is
9254 *     zero, which preserves the behaviour of versions of AST prior to
9255 *     version 2.0.
9256 *
9257 *     If the ActiveUnit flag of either Frame is
9258 c     zero,
9259 f     .FALSE.,
9260 *     then the Mapping will ignore any difference in the Unit attributes of
9261 *     corresponding template and target axes. In this mode, the Unit
9262 *     attributes are purely descriptive commentary for the benefit of
9263 *     human readers and do not influence the Mappings between Frames.
9264 *     This is the behaviour which all Frames had in older version of AST,
9265 *     prior to the introduction of this attribute.
9266 *
9267 *     If the ActiveUnit flag of both Frames is
9268 c     non-zero,
9269 f     .TRUE.,
9270 *     then the Mapping from template to target will take account of any
9271 *     difference in the axis Unit attributes, where-ever possible. For
9272 *     instance, if corresponding target and template axes have Unit strings of
9273 *     "km" and "m", then the FrameSet class will use a ZoomMap to connect
9274 *     them which introduces a scaling of 1000. If no Mapping can be found
9275 *     between the corresponding units string, then an error is reported.
9276 *     In this mode, it is assumed that values of the Unit attribute conform
9277 *     to the syntax for units strings described in the FITS WCS Paper I
9278 *     "Representations of world coordinates in FITS" (Greisen & Calabretta).
9279 *     Particularly, any of the named unit symbols, functions, operators or
9280 *     standard multiplier prefixes listed within that paper can be used within
9281 *     a units string. A units string may contain symbols for unit which are
9282 *     not listed in the FITS paper, but transformation to any other units
9283 *     will then not be possible (except to units which depend only on the
9284 *     same unknown units - thus "flops" can be transformed to "Mflops"
9285 *     even though "flops" is not a standard FITS unit symbol).
9286 *
9287 *     A range of common non-standard variations of unit names and multiplier
9288 *     prefixes are also allowed, such as adding an "s" to the end of Angstrom,
9289 *     using a lower case "a" at the start of "angstrom", "micron" instead of
9290 *     "um", "sec" instead of "s", etc.
9291 *
9292 c     If the ActiveUnit flag is non-zero, setting a new Unit value for an
9293 f     If the ActiveUnit flag is .TRUE., setting a new Unit value for an
9294 *     axis may also change its Label and Symbol attributes. For instance, if
9295 *     an axis has Unit "Hz" and Label "frequency", then changing its Unit to
9296 *     "log(Hz)" will change its Label to "log( frequency )". In addition,
9297 *     the Axis Format attribute will be cleared when-ever a new value
9298 *     is assigned to the Unit attribute.
9299 *
9300 c     Note, if a non-zero value is set for the ActiveUnit flag, then changing a
9301 f     Note, if a .TRUE. value is set for the ActiveUnit flag, then changing a
9302 *     Unit value for the current Frame within a FrameSet will result in the
9303 *     Frame being re-mapped (that is, the Mappings which define the
9304 *     relationships between Frames within the FrameSet will be modified to
9305 *     take into account the change in Units).
9306 
9307 *  Parameters:
9308 c     this
9309 f     THIS = INTEGER (Given)
9310 *        Pointer to the Frame.
9311 c     value
9312 f     VALUE = LOGICAL (Given)
9313 *        The new value to use.
9314 f     STATUS = INTEGER (Given and Returned)
9315 f        The global status.
9316 
9317 *  Applicability:
9318 *     SkyFrame
9319 c        The ActiveUnit flag for a SkyFrame is always 0 (any value
9320 c        supplied using this function is ignored).
9321 f        The ActiveUnit flag for a SkyFrame is always .FALSE. (any value
9322 f        supplied using this routine is ignored).
9323 *     SpecFrame
9324 c        The ActiveUnit flag for a SpecFrame is always 1 (any value
9325 c        supplied using this function is ignored).
9326 f        The ActiveUnit flag for a SpecFrame is always .TRUE. (any value
9327 f        supplied using this routine is ignored).
9328 *     FluxFrame
9329 c        The ActiveUnit flag for a FluxFrame is always 1 (any value
9330 c        supplied using this function is ignored).
9331 f        The ActiveUnit flag for a FluxFrame is always .TRUE. (any value
9332 f        supplied using this routine is ignored).
9333 *     CmpFrame
9334 c        The default ActiveUnit flag for a CmpFrame is 1 if both of the
9335 c        component Frames are using active units, and zero otherwise. When
9336 f        The default ActiveUnit flag for a CmpFrame is .TRUE. if both of the
9337 f        component Frames are using active units, and .FALSE. otherwise. When
9338 *        a new value is set for the ActiveUnit flag, the flag value
9339 *        is propagated to the component Frames. This change will be
9340 *        reflected through all references to the component Frames, not
9341 *        just those encapsulated within the CmpFrame.
9342 *     Region:
9343 *        Regions always use active units if possible.
9344 
9345 *  Notes:
9346 *     - The ActiveUnit flag resembles a Frame attribute, except that it
9347 *     cannot be tested or cleared, and it cannot be accessed using the
9348 c     generic astGet<X> and astSet<X> functions.
9349 f     generic AST_GET<X> and AST_SET<X> routines.
9350 c     - The astGetActiveUnit function can be used to retrieve the current
9351 f     - The AST_GETACTIVEUNIT routine can be used to retrieve the current
9352 *     value of the ActiveUnit flag.
9353 
9354 *--
9355 */
9356 
9357 /* Check the global error status. */
9358    if ( !astOK ) return;
9359 
9360 /* Store a value of 1 for the Frame component if the supplied value is
9361    non-zero. */
9362    this->active_unit = ( value ) ? 1 : 0;
9363 }
9364 
SetAttrib(AstObject * this_object,const char * setting,int * status)9365 static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
9366 /*
9367 *  Name:
9368 *     SetAttrib
9369 
9370 *  Purpose:
9371 *     Set an attribute value for a Frame.
9372 
9373 *  Type:
9374 *     Private function.
9375 
9376 *  Synopsis:
9377 *     #include "frame.h"
9378 *     void SetAttrib( AstObject *this, const char *setting, int *status )
9379 
9380 *  Class Membership:
9381 *     Frame member function (over-rides the astSetAttrib method inherited
9382 *     from the Mapping class).
9383 
9384 *  Description:
9385 *     This function assigns an attribute value for a Frame, the
9386 *     attribute and its value being specified by means of a string of
9387 *     the form:
9388 *
9389 *        "attribute= value "
9390 *
9391 *     Here, "attribute" specifies the attribute name and should be in
9392 *     lower case with no white space present. The value to the right
9393 *     of the "=" should be a suitable textual representation of the
9394 *     value to be assigned and this will be interpreted according to
9395 *     the attribute's data type.  White space surrounding the value is
9396 *     only significant for string attributes.
9397 
9398 *  Parameters:
9399 *     this
9400 *        Pointer to the Frame.
9401 *     setting
9402 *        Pointer to a null terminated string specifying the new attribute
9403 *        value.
9404 *     status
9405 *        Pointer to the inherited status variable.
9406 
9407 *  Notes:
9408 *     - This function uses one-based axis numbering so that it is
9409 *     suitable for external (public) use.
9410 */
9411 
9412 /* Local Vaiables: */
9413    AstAxis *ax;                  /* Pointer to Axis */
9414    AstFrame *pfrm;               /* Pointer to primary Frame containing axis */
9415    AstFrame *this;               /* Pointer to the Frame structure */
9416    AstSystemType system_code;    /* System code */
9417    char pfrm_attrib[ 100 ];      /* Primary Frame attribute */
9418    char *pfrm_setting;           /* Primary Frame attribute */
9419    char *axis_setting;           /* Pointer to axis attribute setting string */
9420    const char *equals;           /* Pointer to equals sign */
9421    const char *old_setting;      /* Pointer to supplied setting string */
9422    const char *op;               /* Pointer to opening parenthesis */
9423    double dval;                  /* Double attibute value */
9424    double mjd;                   /* Epoch as a Modified Julian Date */
9425    int axis;                     /* Index for the Frame axis */
9426    int axis_nc;                  /* No. characters in axis attribute name */
9427    int axis_value;               /* Offset of value to be assigned to axis */
9428    int digits;                   /* Number of digits of precision */
9429    int direction;                /* Axis direction flag */
9430    int domain;                   /* Offset of Domain string */
9431    int epoch;                    /* Offset of Epoch string */
9432    int format;                   /* Offset of axis Format string */
9433    int free_axis_setting;        /* Should axis_setting be freed? */
9434    int has_axis;                 /* Does setting include an axis specifier? */
9435    int ival;                     /* Integer attribute value */
9436    int label;                    /* Offset of axis Label string */
9437    int len;                      /* Length of setting string */
9438    int match_end;                /* Match final axes of target? */
9439    int max_axes;                 /* Maximum number of axes matched */
9440    int min_axes;                 /* Minimum number of axes matched */
9441    int nc;                       /* Number of characters read by astSscanf */
9442    int off2;                     /* Modified offset of attribute value */
9443    int off;                      /* Offset of attribute value */
9444    int oldrep;                   /* Original error reporting state */
9445    int paxis;                    /* Axis index within primary frame */
9446    int permute;                  /* Permute axes in order to match? */
9447    int preserve_axes;            /* Preserve matched target axes? */
9448    int sign;                     /* Sign of longitude value */
9449    int symbol;                   /* Offset of axis Symbol string */
9450    int system;                   /* Offset of System string */
9451    int title;                    /* Offset of Title string */
9452    int unit;                     /* Offset of axis Unit string */
9453    int used;                     /* Could the setting string be used? */
9454 
9455 /* Check the global error status. */
9456    if ( !astOK ) return;
9457 
9458 /* Obtain a pointer to the Frame structure. */
9459    this = (AstFrame *) this_object;
9460 
9461 /* Find the offset to the first equal sign in the setting string. */
9462    equals = strchr( setting, '=' );
9463 
9464 /* Set a flag indicating if the attribute name includes an axis
9465    specifier. */
9466    op = strchr( setting, '(' );
9467    has_axis = ( !op || op > equals ) ? 0 : 1;
9468 
9469 /* A flag indicating that we do not need to free the axis_setting memory. */
9470    free_axis_setting = 0;
9471 
9472 /* Initialise things to avoid compiler warnings. */
9473    axis_setting = NULL;
9474    old_setting = NULL;
9475 
9476 /* Jump back to here if we are trying the same attribute setting but with
9477    an explicit axis "(1)" added to the attribute name. */
9478 L1:
9479 
9480 /* Obtain the length of the setting string. */
9481    len = strlen( setting );
9482 
9483 /* Test for each recognised attribute in turn, using "astSscanf" to parse the
9484    setting string and extract the attribute value (or an offset to it in the
9485    case of string values). In each case, use the value set in "nc" to check
9486    that the entire string was matched. Once a value has been obtained, use the
9487    appropriate method to set it. */
9488 
9489 /* Digits. */
9490 /* ------- */
9491    if ( nc = 0,
9492         ( 1 == astSscanf( setting, "digits= %d %n", &digits, &nc ) )
9493         && ( nc >= len ) ) {
9494       astSetDigits( this, digits );
9495 
9496 /* Digits(axis). */
9497 /* ------------- */
9498    } else if ( nc = 0,
9499                ( 2 == astSscanf( setting, "digits(%d)= %d %n",
9500                               &axis, &digits, &nc ) )
9501                && ( nc >= len ) ) {
9502 
9503 /* There is no function to set the Digits attribute value for an axis
9504    directly, so obtain a pointer to the Axis and use this to set the
9505    attribute. */
9506       (void) astValidateAxis( this, axis - 1, 1, "astSetDigits(axis)" );
9507       ax = astGetAxis( this, axis - 1 );
9508       astSetAxisDigits( ax, digits );
9509       ax = astAnnul( ax );
9510 
9511 /* Direction(axis). */
9512 /* ---------------- */
9513    } else if ( nc = 0,
9514                ( 2 == astSscanf( setting, "direction(%d)= %d %n",
9515                               &axis, &direction, &nc ) )
9516                && ( nc >= len ) ) {
9517       astSetDirection( this, axis - 1, direction );
9518 
9519 /* Epoch. */
9520 /* ------ */
9521    } else if ( nc = 0,
9522         ( 0 == astSscanf( setting, "epoch=%n%*[^\n]%n", &epoch, &nc ) )
9523         && ( nc >= len ) ) {
9524 
9525 /* Convert the Epoch value to a Modified Julian Date before use. */
9526       mjd = astReadDateTime( setting + epoch );
9527       if ( astOK ) {
9528          astSetEpoch( this, mjd );
9529 
9530 /* Report contextual information if the conversion failed. */
9531       } else {
9532          astError( AST__ATTIN, "astSetAttrib(%s): Invalid epoch value "
9533                    "\"%s\" given for coordinate system.", status,
9534                    astGetClass( this ), setting + epoch );
9535       }
9536 
9537 /* Top(axis). */
9538 /* ---------- */
9539    } else if ( nc = 0,
9540                ( 2 == astSscanf( setting, "top(%d)= %lg %n",
9541                               &axis, &dval, &nc ) )
9542                && ( nc >= len ) ) {
9543       astSetTop( this, axis - 1, dval );
9544 
9545 /* Bottom(axis). */
9546 /* ------------- */
9547    } else if ( nc = 0,
9548                ( 2 == astSscanf( setting, "bottom(%d)= %lg %n",
9549                               &axis, &dval, &nc ) )
9550                && ( nc >= len ) ) {
9551       astSetBottom( this, axis - 1, dval );
9552 
9553 /* Domain. */
9554 /* ------- */
9555    } else if ( nc = 0,
9556                ( 0 == astSscanf( setting, "domain=%n%*[^\n]%n", &domain, &nc ) )
9557                && ( nc >= len ) ) {
9558       astSetDomain( this, setting + domain );
9559 
9560 /* Format(axis). */
9561 /* ------------- */
9562    } else if ( nc = 0,
9563                ( 1 == astSscanf( setting, "format(%d)=%n%*[^\n]%n",
9564                               &axis, &format, &nc ) )
9565                && ( nc >= len ) ) {
9566       astSetFormat( this, axis - 1, setting + format );
9567 
9568 /* Label(axis). */
9569 /* ------------ */
9570    } else if ( nc = 0,
9571                ( 1 == astSscanf( setting, "label(%d)=%n%*[^\n]%n",
9572                               &axis, &label, &nc ) )
9573                && ( nc >= len ) ) {
9574       astSetLabel( this, axis - 1, setting + label );
9575 
9576 /* MatchEnd. */
9577 /* --------- */
9578    } else if ( nc = 0,
9579                ( 1 == astSscanf( setting, "matchend= %d %n", &match_end, &nc ) )
9580                && ( nc >= len ) ) {
9581       astSetMatchEnd( this, match_end );
9582 
9583 /* MaxAxes. */
9584 /* -------- */
9585    } else if ( nc = 0,
9586                ( 1 == astSscanf( setting, "maxaxes= %d %n", &max_axes, &nc ) )
9587                && ( nc >= len ) ) {
9588       astSetMaxAxes( this, max_axes );
9589 
9590 /* MinAxes. */
9591 /* -------- */
9592    } else if ( nc = 0,
9593                ( 1 == astSscanf( setting, "minaxes= %d %n", &min_axes, &nc ) )
9594                && ( nc >= len ) ) {
9595       astSetMinAxes( this, min_axes );
9596 
9597 /* Permute. */
9598 /* -------- */
9599    } else if ( nc = 0,
9600                ( 1 == astSscanf( setting, "permute= %d %n", &permute, &nc ) )
9601                && ( nc >= len ) ) {
9602       astSetPermute( this, permute );
9603 
9604 /* PreserveAxes. */
9605 /* ------------- */
9606    } else if ( nc = 0,
9607                ( 1 == astSscanf( setting, "preserveaxes= %d %n",
9608                               &preserve_axes, &nc ) )
9609                && ( nc >= len ) ) {
9610       astSetPreserveAxes( this, preserve_axes );
9611 
9612 /* Symbol(axis). */
9613 /* ------------- */
9614    } else if ( nc = 0,
9615                ( 1 == astSscanf( setting, "symbol(%d)=%n%*[^\n]%n",
9616                               &axis, &symbol, &nc ) )
9617                && ( nc >= len ) ) {
9618       astSetSymbol( this, axis - 1, setting + symbol );
9619 
9620 /* AlignSystem. */
9621 /* ------------ */
9622    } else if ( nc = 0,
9623                ( 0 == astSscanf( setting, "alignsystem= %n%*s %n", &system, &nc ) )
9624                && ( nc >= len ) ) {
9625 
9626 /* Convert the string to a System code before use. */
9627       system_code = astSystemCode( this, system + setting );
9628       if ( system_code != AST__BADSYSTEM ) {
9629          astSetAlignSystem( this, system_code );
9630 
9631 /* Report an error if the string value wasn't recognised. */
9632       } else {
9633          astError( AST__ATTIN,
9634                    "astSetAttrib(%s): Invalid AlignSystem description \"%s\".", status,
9635                    astGetClass( this ), system + setting );
9636       }
9637 
9638 /* System. */
9639 /* ------- */
9640    } else if ( nc = 0,
9641                ( 0 == astSscanf( setting, "system= %n%*s %n", &system, &nc ) )
9642                && ( nc >= len ) ) {
9643 
9644 /* Convert the string to a System code before use. */
9645       system_code = astSystemCode( this, system + setting );
9646       if ( system_code != AST__BADSYSTEM ) {
9647          astSetSystem( this, system_code );
9648 
9649 /* Report an error if the string value wasn't recognised. */
9650       } else {
9651          astError( AST__ATTIN,
9652                    "astSetAttrib(%s): Invalid System description \"%s\".", status,
9653                    astGetClass( this ), system + setting );
9654       }
9655 
9656 /* Title. */
9657 /* ------ */
9658    } else if ( nc = 0,
9659                ( 0 == astSscanf( setting, "title=%n%*[^\n]%n", &title, &nc ) )
9660                && ( nc >= len ) ) {
9661       astSetTitle( this, setting + title );
9662 
9663 /* Unit(axis). */
9664 /* ----------- */
9665    } else if ( nc = 0,
9666                ( 1 == astSscanf( setting, "unit(%d)=%n%*[^\n]%n",
9667                               &axis, &unit, &nc ) )
9668                & ( nc >= len ) ) {
9669       astSetUnit( this, axis - 1, setting + unit );
9670 
9671 /* ObsLat. */
9672 /* ------- */
9673    } else if ( nc = 0,
9674               ( 0 == astSscanf( setting, "obslat=%n%*s %n", &off, &nc ) )
9675               && ( nc >= 7 ) ) {
9676 
9677 /* If the first character in the value string is "N" or "S", remember the
9678    sign of the value and skip over the sign character. Default is north
9679    (+ve). */
9680       off2 = off;
9681       if( setting[ off ] == 'N' || setting[ off ] == 'n' ) {
9682          off2++;
9683          sign = +1;
9684       } else if( setting[ off ] == 'S' || setting[ off ] == 's' ) {
9685          off2++;
9686          sign = -1;
9687       } else {
9688          sign = +1;
9689       }
9690 
9691 /* If not already created, create an FK5 J2000 SkyFrame which will be used
9692    for formatting and unformatting ObsLon and ObsLat values. */
9693       if( !skyframe ) {
9694          astBeginPM;
9695          skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status );
9696          astEndPM;
9697       }
9698 
9699 /* Convert the string to a radians value before use. */
9700       ival = astUnformat( skyframe, 1, setting + off2, &dval );
9701       if ( ival == astChrLen( setting ) - off2  ) {
9702          astSetObsLat( this, dval*sign );
9703 
9704 /* Report an error if the string value wasn't recognised. */
9705       } else {
9706          astError( AST__ATTIN, "astSetAttrib(%s): Invalid value for "
9707                    "ObsLat (observers latitude) \"%s\".", status, astGetClass( this ),
9708                    setting + off );
9709       }
9710 
9711 /* ObsLon. */
9712 /* ------- */
9713    } else if ( nc = 0,
9714               ( 0 == astSscanf( setting, "obslon=%n%*s %n", &off, &nc ) )
9715               && ( nc >= 7 ) ) {
9716 
9717 /* If the first character in the value string is "E" or "W", remember the
9718    sign of the value and skip over the sign character. Default is east
9719    (+ve). */
9720       off2 = off;
9721       if( setting[ off ] == 'E' || setting[ off ] == 'e' ) {
9722          off2++;
9723          sign = +1;
9724       } else if( setting[ off ] == 'W' || setting[ off ] == 'w' ) {
9725          off2++;
9726          sign = -1;
9727       } else {
9728          sign = +1;
9729       }
9730 
9731 /* If not already created, create an FK5 J2000 SkyFrame which will be used
9732    for formatting and unformatting ObsLon and ObsLat values. */
9733       if( !skyframe ) {
9734          astBeginPM;
9735          skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status );
9736          astEndPM;
9737       }
9738 
9739 /* Convert the string to a radians value before use. */
9740       ival = astUnformat( skyframe, 1, setting + off2, &dval );
9741       if ( ival == astChrLen( setting ) - off2  ) {
9742          astSetObsLon( this, dval*sign );
9743 
9744 /* Report an error if the string value wasn't recognised. */
9745       } else {
9746          astError( AST__ATTIN, "astSetAttrib(%s): Invalid value for "
9747                    "ObsLon (observers longitude) \"%s\".", status, astGetClass( this ),
9748                    setting + off );
9749       }
9750 
9751 /* ObsAlt. */
9752 /* ------- */
9753    } else if ( nc = 0,
9754         ( 1 == astSscanf( setting, "obsalt= %lg %n", &dval, &nc ) )
9755         && ( nc >= len ) ) {
9756       astSetObsAlt( this, dval );
9757 
9758 /* Dut1. */
9759 /* ---- */
9760    } else if ( nc = 0,
9761         ( 1 == astSscanf( setting, "dut1= %lg %n", &dval, &nc ) )
9762         && ( nc >= len ) ) {
9763       astSetDut1( this, dval );
9764 
9765 
9766 /* Read-only attributes. */
9767 /* --------------------- */
9768 /* Define a macro to see if the setting string matches any of the
9769    read-only attributes of this class. */
9770 #define MATCH(attrib) \
9771         ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \
9772                   ( nc >= len ) )
9773 
9774 /* Use this macro to report an error if a read-only attribute has been
9775    specified. */
9776    } else if ( MATCH( "naxes" ) ||
9777                !strncmp( setting, "normunit", 8 ) ) {
9778       astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status,
9779                 setting, astGetClass( this ) );
9780       astError( AST__NOWRT, "This is a read-only attribute." , status);
9781 
9782 /* Other axis attributes. */
9783 /* ---------------------- */
9784 /* If the attribute was not identified above, but appears to refer to
9785    a Frame axis, then it may refer to an Axis object of a derived type
9786    (which has additional attributes not recognised here). */
9787    } else if ( !free_axis_setting && ( nc = 0,
9788                ( 1 == astSscanf( setting, "%*[^()]%n(%d)%n=%*[^\n]%n",
9789                                        &axis_nc, &axis, &axis_value, &nc ) )
9790                && ( nc >= len ) ) ) {
9791 
9792 /* Validate the axis index and copy the attribute setting string. */
9793       (void) astValidateAxis( this, axis - 1, 1, "astSet" );
9794       axis_setting = astString( setting, len );
9795       if ( astOK ) {
9796 
9797 /* Over-write the axis index in the copy with the value to be
9798    assigned. */
9799          (void) strcpy( axis_setting + axis_nc, setting + axis_value );
9800 
9801 /* Obtain a pointer to the Axis object. */
9802          ax = astGetAxis( this, axis - 1 );
9803          if( astOK ) {
9804 
9805 /* Assume that we will be able to use the setting. */
9806             used = 1;
9807 
9808 /* Temporarily switch off error reporting so that if the following attempt
9809    to access the axis attribute fails, we can try to interpret the
9810    attribute name as an attribute of the primary Frame containing the
9811    specified axis. Any errors reported in this context will simply be
9812    ignored, in particularly they are not deferred for later delivery. */
9813             oldrep = astReporting( 0 );
9814 
9815 /* Use the Axis astSetAttrib method
9816    to set the value. */
9817             astSetAttrib( ax, axis_setting );
9818 
9819 /* If the above call failed with a status of AST__BADAT, indicating that
9820    the attribute name was not recognised, clear the status so that we can
9821    try to interpret the attribute name as an attribute of the primary Frame
9822    containing the specified axis. */
9823             if( astStatus == AST__BADAT ) {
9824                astClearStatus;
9825 
9826 /* Find the primary Frame containing the specified axis. */
9827                astPrimaryFrame( this, axis - 1, &pfrm, &paxis );
9828 
9829 /* Only attempt to use the primary Frame if it is not the same as "this"
9830    - otherwise we could end up in an infinite loop. */
9831                if( pfrm != this ) {
9832 
9833 /* astPrimaryFrame returns the original - unpermuted - axis index within
9834    the primary Frame. So we need to take into account any axis permutation
9835    which has been applied to the primary Frame when forming the attribute name
9836    to use below. Find the permuted (external) axis index which corresponds to
9837    the internal (unpermuted) axis index "paxis". */
9838                   paxis = astValidateAxis( pfrm, paxis, 0, "astSet" );
9839 
9840 /* Modify the attribute name to refer to the axis numbering of the
9841    primary frame. */
9842                   sprintf( pfrm_attrib, "%.*s(%d)", axis_nc, setting, paxis + 1 );
9843 
9844 /* Create a setting string in which the attribute name refers to the axis
9845    numbering of the primary frame. */
9846                   pfrm_setting = NULL;
9847                   nc = 0;
9848                   pfrm_setting = astAppendString( pfrm_setting, &nc, pfrm_attrib );
9849                   pfrm_setting = astAppendString( pfrm_setting, &nc, setting + axis_value );
9850 
9851 /* Attempt to set the attribute within the primary Frame. */
9852                   astSetAttrib( pfrm, pfrm_setting );
9853 
9854 /* Free the memory. */
9855                   pfrm_setting = astFree( pfrm_setting );
9856 
9857 /* If this failed, clear the status and indicate that we have not managed to
9858    use the attribute setting. */
9859                   if( !astOK ) {
9860                      astClearStatus;
9861                      used = 0;
9862                   }
9863 
9864                } else {
9865                   used = 0;
9866                }
9867 
9868 /* If not found attempt to set the attribute value in the Axis, omitting
9869    the axis index. */
9870                if( ! used ) {
9871                   astSetAttrib( pfrm, axis_setting );
9872                   if( !astOK ) {
9873                      astClearStatus;
9874                   } else {
9875                      used = 1;
9876                   }
9877                }
9878 
9879 /* Free the setting string, and annul the primary Frame pointer. */
9880                pfrm = astAnnul( pfrm );
9881             }
9882 
9883 /* Re-instate the original error reporting state. */
9884             astReporting( oldrep );
9885 
9886 /* If we could not use the setting, attempt to set the axis attribute again,
9887    this time retaining the error report. This is done to ensure the user
9888    gets an appropriate error message. */
9889             if( !used ) astSetAttrib( ax, axis_setting );
9890          }
9891 
9892 /* Annul the Axis pointer and free the memory holding the attribute
9893    setting. */
9894          ax = astAnnul( ax );
9895       }
9896       axis_setting = astFree( axis_setting );
9897 
9898 /* Not recognised. */
9899 /* --------------- */
9900 /* If the attribute is still not recognised, and the Frame has only 1 axis,
9901    and the attribute name does not already include an axis specifier, try
9902    again after appending "(1)" to the end of the attribute name. */
9903    } else if( !has_axis && astGetNaxes( this ) == 1 && equals ) {
9904 
9905 /* Take a copy of the supplied setting, allowing 3 extra characters for the
9906    axis specifier "(1)". */
9907       axis_setting = astMalloc( len + 4 );
9908       if( axis_setting ) memcpy( axis_setting, setting, len );
9909 
9910 /* Indicate we should free the axis_setting memory. */
9911       free_axis_setting = 1;
9912 
9913 /* Add in the axis specifier. */
9914       strcpy( axis_setting + ( equals - setting ), "(1)" );
9915 
9916 /* Add in the equals sign and attribute value. */
9917       strcpy( axis_setting + ( equals - setting ) + 3, equals );
9918 
9919 /* Use the new setting instead of the supplied setting. */
9920       old_setting = setting;
9921       setting = axis_setting;
9922 
9923 /* Indicate the setting now has an axis specifier. */
9924       has_axis = 1;
9925 
9926 /* Jump back to try interpreting the new setting string. */
9927       goto L1;
9928 
9929 /* Not recognised. */
9930 /* --------------- */
9931 /* If the attribute is still not recognised, pass it on to the parent
9932    method for further interpretation. First re-instate the original setting
9933    string if it was changed above. */
9934    } else {
9935       if( free_axis_setting ) {
9936          setting = old_setting;
9937          axis_setting = astFree( axis_setting );
9938          free_axis_setting = 0;
9939       }
9940       (*parent_setattrib)( this_object, setting, status );
9941    }
9942 
9943    if( free_axis_setting ) axis_setting = astFree( axis_setting );
9944 
9945 /* Undefine macros local to this function. */
9946 #undef MATCH
9947 }
9948 
SetAxis(AstFrame * this,int axis,AstAxis * newaxis,int * status)9949 static void SetAxis( AstFrame *this, int axis, AstAxis *newaxis, int *status ) {
9950 /*
9951 *+
9952 *  Name:
9953 *     astSetAxis
9954 
9955 *  Purpose:
9956 *     Set a new Axis for a Frame.
9957 
9958 *  Type:
9959 *     Protected virtual function.
9960 
9961 *  Synopsis:
9962 *     #include "frame.h"
9963 *     void astSetAxis( AstFrame *this, int axis, AstAxis *newaxis )
9964 
9965 *  Class Membership:
9966 *     Frame method.
9967 
9968 *  Description:
9969 *     This function allows a new Axis object to be associated with one
9970 *     of the axes of a Frame, replacing the previous one. Each Axis
9971 *     object contains a description of the quantity represented along
9972 *     one of the Frame's axes, so this function allows this
9973 *     description to be exchanged for another one.
9974 
9975 *  Parameters:
9976 *     this
9977 *        Pointer to the Frame.
9978 *     axis
9979 *        The index (zero-based) of the axis whose associated Axis object is to
9980 *        be replaced.
9981 *     newaxis
9982 *        Pointer to the new Axis object.
9983 *-
9984 */
9985 
9986 /* Check the global error status. */
9987    if ( !astOK ) return;
9988 
9989 /* Validate and permute the axis index supplied. */
9990    axis = astValidateAxis( this, axis, 1, "astSetAxis" );
9991 
9992 /* If OK, annul the Frame's pointer to the old Axis object and clone a pointer
9993    to the new one to replace it. */
9994    if ( astOK ) {
9995       this->axis[ axis ] = astAnnul( this->axis[ axis ] );
9996       this->axis[ axis ] = astClone( newaxis );
9997    }
9998 }
9999 
SetFrameFlags(AstFrame * this,int flags,int * status)10000 static void SetFrameFlags( AstFrame *this, int flags, int *status ){
10001 /*
10002 *+
10003 *  Name:
10004 *     astSetFrameFlags
10005 
10006 *  Purpose:
10007 *     Store a new bit mask of flags in a Frame.
10008 
10009 *  Type:
10010 *     Protected function.
10011 
10012 *  Synopsis:
10013 *     #include "frame.h"
10014 *     void astSetFrameFlags( astFrame *this, int flags )
10015 
10016 *  Class Membership:
10017 *     Frame member function.
10018 
10019 *  Description:
10020 *     This function stores a new set of flags in a Frame. The flags can
10021 *     be retrieved using astGetFrameFlags.
10022 
10023 *  Parameters:
10024 *     this
10025 *        The Frame.
10026 *     flags
10027 *        A bit mask holding the flags. Currently, the following bits are
10028 *        used:
10029 *
10030 *        0 - Used to indicate if the Frame is currently involved in an
10031 *        attempt to restore the integrity of a FrameSet following
10032 *        changes to the attribute values of the Frame.
10033 
10034 *-
10035 */
10036 
10037 /* Check the global error status. */
10038    if ( !astOK ) return;
10039 
10040 /* Assign the new bit mask. */
10041    this->flags = flags;
10042 }
10043 
SetFrameVariants(AstFrame * this,AstFrameSet * variants,int * status)10044 static void SetFrameVariants( AstFrame *this, AstFrameSet *variants, int *status ){
10045 /*
10046 *+
10047 *  Name:
10048 *     astSetFrameVariants
10049 
10050 *  Purpose:
10051 *     Store a FrameSet holding alternative Frame properties.
10052 
10053 *  Type:
10054 *     Protected virtual function.
10055 
10056 *  Synopsis:
10057 *     #include "frame.h"
10058 *     void astSetVariants( AstFrame *this, AstFrameSet *variants )
10059 
10060 *  Class Membership:
10061 *     Frame method.
10062 
10063 *  Description:
10064 *     This function adds sets of alternative Frame properties to a Frame.
10065 
10066 *  Parameters:
10067 *     this
10068 *        Pointer to the Frame.
10069 *     variants
10070 *        Pointer to a FrameSet in which each Frame is of the same class
10071 *        and dimensionality as "this" and all Frames have unique Domain
10072 *        names.
10073 
10074 *  Notes:
10075 *     - A clone of the supplied FrameSet pointer is stored in the Frame.
10076 *-
10077 */
10078 
10079 /* Check the global error status. */
10080    if ( !astOK ) return;
10081 
10082 /* Annul any variants FrameSet already stored in the Frame. */
10083    if( this->variants ) this->variants = astAnnul( this->variants );
10084 
10085 /* Store a clone of ht esupplied FrameSet pointer. */
10086    if( variants ) this->variants = astClone( variants );
10087 
10088 }
10089 
SetUnit(AstFrame * this,int axis,const char * unit,int * status)10090 static void SetUnit( AstFrame *this, int axis, const char *unit, int *status ) {
10091 /*
10092 *  Name:
10093 *     SetUnit
10094 
10095 *  Purpose:
10096 *     Set a value for the Unit attribute of a Frame.
10097 
10098 *  Type:
10099 *     Protected virtual function.
10100 
10101 *  Synopsis:
10102 *     #include "frame.h"
10103 *     void SetUnit( AstFrame *this, int axis, const char *unit, int *status )
10104 
10105 *  Class Membership:
10106 *     Frame method.
10107 
10108 *  Description:
10109 *     This function sets the Unit value for a Frame.
10110 
10111 *  Parameters:
10112 *     this
10113 *        Pointer to the Frame.
10114 *     axis
10115 *        The number of the axis (zero-based) for which the Unit value is to
10116 *        be set.
10117 *     unit
10118 *        The new value to be set.
10119 *     status
10120 *        Pointer to the inherited status variable.
10121 
10122 *  Returned Value:
10123 *     void.
10124 */
10125 
10126 /* Local Variables: */
10127    AstAxis *ax;                  /* Pointer to Axis object */
10128    char *c;                      /* Copy of supplied string */
10129    const char *oldunit;          /* Pointer to old units string */
10130    int l;                        /* Used length of supplied string */
10131 
10132 /* Check the global error status. */
10133    if ( !astOK ) return;
10134 
10135 /* Get a copy of the supplied string which excludes trailing spaces. */
10136    l = astChrLen( unit );
10137    c = astStore( NULL, unit, (size_t) (l + 1) );
10138    if( astOK ) {
10139       c[ l ] = 0;
10140 
10141 /* Validate the axis index and obtain a pointer to the required Axis. */
10142    (void) astValidateAxis( this, axis, 1, "astSetUnit" );
10143       ax = astGetAxis( this, axis );
10144 
10145 /* The new unit may require the Label and/or Symbol to be changed, but
10146    only if the Frames ActiveUnit flag is set. */
10147       if( astGetActiveUnit( this ) ) {
10148 
10149 /* Get the existing Axis unit, using the astGetUnit method (rather than
10150    astGetAxisUnit) in order to get any default value in the case where
10151    the Unit attribute is not set. */
10152          oldunit = astGetUnit( this, axis );
10153 
10154 /* Assign the new Unit value. This modifies labels and/or Symbols if
10155    necessary. */
10156          NewUnit( ax, oldunit, c, "astSetUnit", astGetClass( this ), status );
10157       }
10158 
10159 /* Set the Axis Unit attribute value. */
10160       astSetAxisUnit( ax, c );
10161 
10162 /* Annul the Axis pointer. */
10163       ax = astAnnul( ax );
10164    }
10165 
10166 /* Free the string copy */
10167    c = astFree( c );
10168 
10169 }
10170 
SubFrame(AstFrame * target,AstFrame * template,int result_naxes,const int * target_axes,const int * template_axes,AstMapping ** map,AstFrame ** result,int * status)10171 static int SubFrame( AstFrame *target, AstFrame *template,
10172                      int result_naxes, const int *target_axes,
10173                      const int *template_axes, AstMapping **map,
10174                      AstFrame **result, int *status ) {
10175 /*
10176 *+
10177 *  Name:
10178 *     astSubFrame
10179 
10180 *  Purpose:
10181 *     Select axes from a Frame and convert to the new coordinate system.
10182 
10183 *  Type:
10184 *     Protected virtual function.
10185 
10186 *  Synopsis:
10187 *     #include "frame.h"
10188 *     int astSubFrame( AstFrame *target, AstFrame *template,
10189 *                      int result_naxes, const int *target_axes,
10190 *                      const int *template_axes, AstMapping **map,
10191 *                      AstFrame **result )
10192 
10193 *  Class Membership:
10194 *     Frame method.
10195 
10196 *  Description:
10197 *     This function selects a requested sub-set (or super-set) of the axes from
10198 *     a "target" Frame and creates a new Frame with copies of the selected
10199 *     axes assembled in the requested order. It then optionally overlays the
10200 *     attributes of a "template" Frame on to the result. It returns both the
10201 *     resulting Frame and a Mapping that describes how to convert between the
10202 *     coordinate systems described by the target and result Frames. If
10203 *     necessary, this Mapping takes account of any differences in the Frames'
10204 *     attributes due to the influence of the template.
10205 
10206 *  Parameters:
10207 *     target
10208 *        Pointer to the target Frame, from which axes are to be selected.
10209 *     template
10210 *        Pointer to the template Frame, from which new attributes for the
10211 *        result Frame are to be obtained. Optionally, this may be NULL, in
10212 *        which case no overlaying of template attributes will be performed.
10213 *     result_naxes
10214 *        Number of axes to be selected from the target Frame. This number may
10215 *        be greater than or less than the number of axes in this Frame (or
10216 *        equal).
10217 *     target_axes
10218 *        Pointer to an array of int with result_naxes elements, giving a list
10219 *        of the (zero-based) axis indices of the axes to be selected from the
10220 *        target Frame. The order in which these are given determines the order
10221 *        in which the axes appear in the result Frame. If any of the values in
10222 *        this array is set to -1, the corresponding result axis will not be
10223 *        derived from the target Frame, but will be assigned default attributes
10224 *        instead.
10225 *     template_axes
10226 *        Pointer to an array of int with result_naxes elements. This should
10227 *        contain a list of the template axes (given as zero-based axis indices)
10228 *        with which the axes of the result Frame are to be associated. This
10229 *        array determines which axes are used when overlaying axis-dependent
10230 *        attributes of the template on to the result. If any element of this
10231 *        array is set to -1, the corresponding result axis will not receive any
10232 *        template attributes.
10233 *
10234 *        If the template argument is given as NULL, this array is not used and
10235 *        a NULL pointer may also be supplied here.
10236 *     map
10237 *        Address of a location to receive a pointer to the returned Mapping.
10238 *        The forward transformation of this Mapping will describe how to
10239 *        convert coordinates from the coordinate system described by the target
10240 *        Frame to that described by the result Frame. The inverse
10241 *        transformation will convert in the opposite direction.
10242 *     result
10243 *        Address of a location to receive a pointer to the result Frame.
10244 
10245 *  Returned Value:
10246 *     A non-zero value is returned if coordinate conversion is
10247 *     possible between the target and the result Frame. Otherwise zero
10248 *     is returned and *map and *result are returned as NULL (but this
10249 *     will not in itself result in an error condition). In general,
10250 *     coordinate conversion should always be possible if no template
10251 *     Frame is supplied but may not always be possible otherwise.
10252 
10253 *  Notes:
10254 *     - A value of zero will be returned if this function is invoked
10255 *     with the global error status set, or if it should fail for any
10256 *     reason.
10257 
10258 *  Implementation Deficiencies:
10259 *     - Any axis selection is currently permitted. Probably this
10260 *     should be restricted so that each axis can only be selected
10261 *     once. The astValidateAxisSelection method will do this but
10262 *     currently there are bugs in the CmpFrame class that cause axis
10263 *     selections which will not pass this test. Install the validation
10264 *     when these are fixed.
10265 *-
10266 
10267 *  Implementation Notes:
10268 *     - This implementation addresses the selection of axes from a
10269 *     Frame class object. This simply results in another object of the
10270 *     same class and a Mapping which describes an axis permutation (or
10271 *     a unit Mapping as a special case). Changes of Frame attributes
10272 *     have no significance for coordinate values in this class, so do
10273 *     not affect the Mapping returned.
10274 */
10275 
10276 /* Local Variables: */
10277    AstAxis *newaxis;             /* Pointer to new Axis object */
10278    AstFrame *tempframe;          /* Pointer to temporary Frame */
10279    AstMapping *aumap;            /* A units Mapping for a single axis */
10280    AstMapping *numap;            /* The new total units Mapping */
10281    AstMapping *umap;             /* The total units Mapping */
10282    int *inperm;                  /* Pointer to permutation array */
10283    int *outperm;                 /* Pointer to permutation array */
10284    int match;                    /* Coordinate conversion possible? */
10285    int result_axis;              /* Result Frame axis index */
10286    int target_axis;              /* Target Frame axis index */
10287    int target_naxes;             /* Number of target Frame axes */
10288    int unit;                     /* Unit Mapping appropriate? */
10289    int uunit;                    /* Is the "umap" Mapping a UnitMap? */
10290 
10291 /* Initialise the returned values. */
10292    *map = NULL;
10293    *result = NULL;
10294    match = 0;
10295 
10296 /* Check the global error status. */
10297    if ( !astOK ) return match;
10298 
10299 /* Obtain the number of target Frame axes. */
10300    target_naxes = astGetNaxes( target );
10301 
10302 /* Ensure we do not attempt to use a negative number of result axes. */
10303    if ( result_naxes < 0 ) result_naxes = 0;
10304 
10305 /* Create a temporary new Frame with the required number of axes. This will
10306    have a default Axis object associated with each of its axes. We will
10307    replace these where necessary with copies of the actual Axis objects we
10308    require. */
10309    tempframe = astFrame( result_naxes, "", status );
10310 
10311 /* Allocate memory to store two permutation arrays. These will be used to
10312    construct the Mapping that relates the target and result Frames. */
10313    inperm = astMalloc( sizeof( int ) * (size_t) target_naxes );
10314    outperm = astMalloc( sizeof( int ) * (size_t) result_naxes );
10315    if ( astOK ) {
10316 
10317 /* Initialise the array that associates each target axis with the corresponding
10318    result axis (filling it with the value -1 initially signifies no
10319    associations). */
10320       for ( target_axis = 0; target_axis < target_naxes; target_axis++ ) {
10321          inperm[ target_axis ] = -1;
10322       }
10323 
10324 /* Loop through each axis in the result Frame and obtain the index of the axis
10325    in the target Frame from which it is to be derived. */
10326       for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) {
10327          target_axis = target_axes[ result_axis ];
10328 
10329 /* Check if the resulting axis index is valid. If not, this result axis is not
10330    to be derived from any target axis, and it will therefore be left with its
10331    default attributes. Make an entry in the appropriate permutation array to
10332    indicate that this result axis is unassociated. */
10333          if ( ( target_axis < 0 ) || ( target_axis >= target_naxes ) ) {
10334             outperm[ result_axis ] = -1;
10335 
10336 /* Otherwise, obtain a pointer to the target Axis object and modify the
10337    temporary Frame so that its axis is associated with the same Axis object.
10338    Annul the Axis pointer afterwards. */
10339          } else {
10340             newaxis = astGetAxis( target, target_axis );
10341             astSetAxis( tempframe, result_axis, newaxis );
10342             newaxis = astAnnul( newaxis );
10343 
10344 /* Update both permutation arrays to record the association between the target
10345    and result axes. */
10346             outperm[ result_axis ] = target_axis;
10347             inperm[ target_axis ] = result_axis;
10348          }
10349 
10350 /* Quit looping if an error occurs. */
10351          if ( !astOK ) break;
10352       }
10353 
10354 /* So far, we have only modified pointers in the temporary Frame to refer to
10355    the target Frame's Axis objects. Since we will next modify these objects'
10356    attributes, we must make a deep copy of the entire temporary Frame so that
10357    we do not modify the target's axes. This copy now becomes our result Frame.
10358    Annul the temporary one. */
10359       if ( astOK ) {
10360          *result = astCopy( tempframe );
10361          tempframe = astAnnul( tempframe );
10362 
10363 /* Invoke the target "astOverlay" method to overlay any remaining
10364    attributes from the target Frame which are not associated with
10365    individual axes (e.g.  the Frame's Title and Domain). */
10366          astOverlay( target, target_axes, *result );
10367 
10368 /* If a template Frame was supplied, also invoke its astOverlay method to
10369    overlay its attributes on the result Frame. (Note that in this particular
10370    case this has no effect other than transferring attributes. In general,
10371    however, i.e. in derived classes, this process is vital to determining the
10372    mapping below, whose main purpose is to convert between the target and
10373    result Frames. These will have different attributes as a result of the
10374    influence that the template has here.) */
10375          if ( template ) astOverlay( template, template_axes, *result );
10376 
10377 /* We will next generate the Mapping that relates the target and result
10378    Frames. If appropriate this should be a unit Mapping (UnitMap), so test if
10379    the number of axes in both Frames is equal. */
10380          unit = ( target_naxes == result_naxes );
10381 
10382 /* If so, check the contents of one of the permutation arrays to see if all
10383    result axes are associated with the corresponding target axis (the converse
10384    then also follows). If not, note this fact and quit checking. */
10385          if ( unit ) {
10386             for ( result_axis = 0; result_axis < result_naxes;
10387                                    result_axis++ ) {
10388                if ( outperm[ result_axis ] != result_axis ) {
10389                   unit = 0;
10390                   break;
10391 	       }
10392 	    }
10393 	 }
10394 
10395 /* If a unit Mapping is appropriate, then construct it. */
10396          if ( unit ) {
10397             *map = (AstMapping *) astUnitMap( result_naxes, "", status );
10398 
10399 /* Otherwise, construct a Mapping describing the axis permutation we have
10400    produced. */
10401          } else {
10402             *map = (AstMapping *) astPermMap( target_naxes, inperm,
10403                                               result_naxes, outperm, NULL,
10404                                               "", status );
10405          }
10406 
10407 /* Note that coordinate conversion is possible. */
10408          match = 1;
10409 
10410 /* If the ActiveUnit flag in both template and result Frame is non-zero, we
10411    now modify the Mapping to take account of any differences in the Units
10412    attributes of the target and results Frames. */
10413          if( template && astGetActiveUnit( template ) &&
10414                          astGetActiveUnit( *result ) ) {
10415 
10416 /* Loop round the axes of the results Frame, accumulating a parallel CmpMap
10417    ("umap") in which each Mapping is the 1-D Mapping which transforms the
10418    Units of the corresponding target axis into the Units of the results
10419    axis. */
10420             umap = NULL;
10421             uunit = 1;
10422             for( result_axis = 0; result_axis < result_naxes; result_axis++ ) {
10423 
10424 /* Find the index of the corresponding target axis. */
10425                if( unit ) {
10426                   target_axis = result_axis;
10427                } else {
10428                   target_axis = outperm[ result_axis ];
10429                }
10430 
10431 /* Get the Unit string for both axes, and attempt to find a Mapping which
10432    transforms values in the target units into the corresponding value in the
10433    results units. If this results axis does not have a corresponding
10434    target axis, then indicate that no units mapping can be found. */
10435                if( target_axis > -1 ) {
10436                   aumap = astUnitMapper( astGetUnit( target, target_axis ),
10437                                          astGetUnit( *result, result_axis ),
10438                                          NULL, NULL );
10439                } else {
10440                   aumap = NULL;
10441                }
10442 
10443 /* If no Mapping could be found, annull the Mapping and leave the loop.
10444    Otherwise, see if the Mapping is a UnitMap. If not, set a flag to indicate
10445    that we have at least one non-unit map. */
10446                if( !aumap ) {
10447                   if( umap ) umap = astAnnul( umap );
10448                   match = 0;
10449                   break;
10450                } else {
10451                   if( !astIsAUnitMap( aumap ) ) uunit = 0;
10452                }
10453 
10454 /* Add this Mapping into the parallel CmpMap. */
10455                if( umap ) {
10456                   numap = (AstMapping *) astCmpMap( umap, aumap, 0, "", status );
10457                   umap = astAnnul( umap );
10458                   aumap = astAnnul( aumap );
10459                   umap = numap;
10460                } else {
10461                   umap = aumap;
10462                }
10463             }
10464 
10465 /* If the resulting CmpMap is not just a UnitMap, add it in series with
10466    the current results mapping, and then simplify it. */
10467             if( !uunit && umap ) {
10468                numap = (AstMapping *) astCmpMap( *map, umap, 1, "", status );
10469                (void) astAnnul( *map );
10470                *map = numap;
10471             }
10472 
10473 /* Annul the CmpMap containing the units Mappings. */
10474             if( umap ) umap = astAnnul( umap );
10475 
10476 /* If the units could not bve matched annul the returned mapping. */
10477             if( !match && *map ) *map = astAnnul( *map );
10478          }
10479       }
10480    }
10481 
10482 /* Free the memory used for the permutation arrays. */
10483    inperm = astFree( inperm );
10484    outperm = astFree( outperm );
10485 
10486 /* If an error occurred, annul the returned objects and reset the returned
10487    value. */
10488    if ( !astOK ) {
10489       *map = astAnnul( *map );
10490       *result = astAnnul( *result );
10491       match = 0;
10492    }
10493 
10494 /* Return the result. */
10495    return match;
10496 }
10497 
SystemCode(AstFrame * this,const char * system,int * status)10498 static AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) {
10499 /*
10500 *+
10501 *  Name:
10502 *     astSystemCode
10503 
10504 *  Purpose:
10505 *     Convert a string into a coordinate system type code.
10506 
10507 *  Type:
10508 *     Protected virtual function.
10509 
10510 *  Synopsis:
10511 *     #include "frame.h"
10512 *     AstSystemType SystemCode( AstFrame *this, const char *system )
10513 
10514 *  Class Membership:
10515 *     Frame method.
10516 
10517 *  Description:
10518 *     This function converts a string used for the external description of
10519 *     a coordinate system into a Frame coordinate system type code (System
10520 *     attribute value). It is the inverse of the astSystemString function.
10521 
10522 *  Parameters:
10523 *     this
10524 *        Pointer to the Frame.
10525 *     system
10526 *        Pointer to a constant null-terminated string containing the
10527 *        external description of the coordinate system.
10528 
10529 *  Returned Value:
10530 *     The System type code.
10531 
10532 *  Notes:
10533 *     - A value of AST__BADSYSTEM is returned if the coordinate system
10534 *     description was not recognised. This does not produce an error.
10535 *     - A value of AST__BADSYSTEM is also returned if this function
10536 *     is invoked with the global error status set or if it should fail
10537 *     for any reason.
10538 *-
10539 */
10540 
10541 /* Local Variables: */
10542    AstSystemType result;      /* Result value to return */
10543 
10544 /* Initialise. */
10545    result = AST__BADSYSTEM;
10546 
10547 /* Check the global error status. */
10548    if ( !astOK ) return result;
10549 
10550 /* Match the "system" string against each possibility and assign the
10551    result. The basic Frame class only supports a single system
10552    "Cartesian". */
10553    if ( astChrMatch( "Cartesian", system ) ) {
10554       result = AST__CART;
10555    }
10556 
10557 /* Return the result. */
10558    return result;
10559 }
10560 
SystemString(AstFrame * this,AstSystemType system,int * status)10561 static const char *SystemString( AstFrame *this, AstSystemType system, int *status ) {
10562 /*
10563 *+
10564 *  Name:
10565 *     astSystemString
10566 
10567 *  Purpose:
10568 *     Convert a coordinate system type code into a string.
10569 
10570 *  Type:
10571 *     Protected virtual function.
10572 
10573 *  Synopsis:
10574 *     #include "frame.h"
10575 *     const char *astSystemString( AstFrame *this, AstSystemType system )
10576 
10577 *  Class Membership:
10578 *     Frame method.
10579 
10580 *  Description:
10581 *     This function converts a Frame coordinate system type code
10582 *     (System attribute value) into a string suitable for use as an
10583 *     external representation of the coordinate system type.
10584 
10585 *  Parameters:
10586 *     this
10587 *        Pointer to the Frame.
10588 *     system
10589 *        The coordinate system type code.
10590 
10591 *  Returned Value:
10592 *     Pointer to a constant null-terminated string containing the
10593 *     textual equivalent of the type code supplied.
10594 
10595 *  Notes:
10596 *     - A NULL pointer value is returned if the coordinate system
10597 *     code was not recognised. This does not produce an error.
10598 *     - A NULL pointer value is also returned if this function is
10599 *     invoked with the global error status set or if it should fail
10600 *     for any reason.
10601 *-
10602 */
10603 
10604 /* Local Variables: */
10605    const char *result;        /* Pointer value to return */
10606 
10607 /* Initialise. */
10608    result = NULL;
10609 
10610 /* Check the global error status. */
10611    if ( !astOK ) return result;
10612 
10613 /* Match the "system" value against each possibility and convert to a
10614    string pointer. (Where possible, return the same string as would be
10615    used in the FITS WCS representation of the coordinate system). A basic
10616    Frame only allows a single System value, "Cartesian". */
10617    switch ( system ) {
10618    case AST__CART:
10619       result = "Cartesian";
10620       break;
10621    }
10622 
10623 /* Return the result pointer. */
10624    return result;
10625 
10626 }
10627 
TestActiveUnit(AstFrame * this,int * status)10628 static int TestActiveUnit( AstFrame *this, int *status ){
10629 /*
10630 *+
10631 *  Name:
10632 *     astTestActiveUnit
10633 
10634 *  Purpose:
10635 *     Determines if the ActiveUnit flag is set.
10636 
10637 *  Type:
10638 *     Protected virtual function.
10639 
10640 *  Synopsis:
10641 *     #include "frame.h"
10642 *     int astTestActiveUnit( AstFrame *this )
10643 
10644 *  Class Membership:
10645 *     Frame method.
10646 
10647 *  Description:
10648 *     This function tests the current value of the ActiveUnit flag for a
10649 *     Frame. See the description of the astSetActiveUnit function for a
10650 *     description of the ActiveUnit flag.
10651 
10652 *  Parameters:
10653 *     this
10654 *        Pointer to the Frame.
10655 
10656 *  Returned Value:
10657 *     Non-zero if the flag has been set. Zero otherwise.
10658 
10659 *  Notes:
10660 *     - A zero value will be returned if this function is
10661 *     invoked with the AST error status set, or if it should fail for
10662 *     any reason.
10663 *--
10664 */
10665 
10666 /* Local Variables: */
10667    int result;         /* The returned value */
10668 
10669 /* Initialise. */
10670    result = 0;
10671 
10672 /* Check the global error status. */
10673    if ( !astOK ) return result;
10674 
10675 /* Return the result. */
10676    return ( this->active_unit != -INT_MAX );
10677 }
10678 
TestAttrib(AstObject * this_object,const char * attrib,int * status)10679 static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
10680 /*
10681 *  Name:
10682 *     TestAttrib
10683 
10684 *  Purpose:
10685 *     Test if a specified attribute value is set for a Frame.
10686 
10687 *  Type:
10688 *     Private function.
10689 
10690 *  Synopsis:
10691 *     #include "frame.h"
10692 *     int TestAttrib( AstObject *this, const char *attrib, int *status )
10693 
10694 *  Class Membership:
10695 *     Frame member function (over-rides the astTestAttrib protected
10696 *     method inherited from the Mapping class).
10697 
10698 *  Description:
10699 *     This function returns a boolean result (0 or 1) to indicate whether
10700 *     a value has been set for one of a Frame's attributes.
10701 
10702 *  Parameters:
10703 *     this
10704 *        Pointer to the Frame.
10705 *     attrib
10706 *        Pointer to a null terminated string specifying the attribute
10707 *        name.  This should be in lower case with no surrounding white
10708 *        space.
10709 *     status
10710 *        Pointer to the inherited status variable.
10711 
10712 *  Returned Value:
10713 *     One if a value has been set, otherwise zero.
10714 
10715 *  Notes:
10716 *     - This function uses one-based axis numbering so that it is
10717 *     suitable for external (public) use.
10718 *     - A value of zero will be returned if this function is invoked
10719 *     with the global status set, or if it should fail for any reason.
10720 */
10721 
10722 /* Local Variables: */
10723    AstAxis *ax;                  /* Pointer to Axis */
10724    AstFrame *pfrm;               /* Pointer to primary Frame containing axis */
10725    AstFrame *this;               /* Pointer to the Frame structure */
10726    char pfrm_attrib[ 100 ];      /* Primary Frame attribute */
10727    char *axis_attrib;            /* Pointer to axis attribute name */
10728    const char *old_attrib;       /* Pointer to supplied attribute name string */
10729    int axis;                     /* Frame axis number */
10730    int axis_nc;                  /* No. characters in axis attribute name */
10731    int free_axis_attrib;         /* Should axis_attrib be freed? */
10732    int has_axis;                 /* Does attrib name include axis specifier? */
10733    int len;                      /* Length of attrib string */
10734    int nc;                       /* No. characters read by astSscanf */
10735    int oldrep;                   /* Original error reporting state */
10736    int paxis;                    /* Axis index within primary frame */
10737    int result;                   /* Result value to return */
10738    int used;                     /* Could the setting string be used? */
10739 
10740 /* Initialise. */
10741    result = 0;
10742 
10743 /* Check the global error status. */
10744    if ( !astOK ) return result;
10745 
10746 /* Obtain a pointer to the Frame structure. */
10747    this = (AstFrame *) this_object;
10748 
10749 /* Set a flag indicating if the attribute name includes an axis
10750    specifier. */
10751    has_axis = ( strchr( attrib, '(' ) != NULL );
10752 
10753 /* A flag indicating that we do not need to free the axis_attrib memory. */
10754    free_axis_attrib = 0;
10755 
10756 /* Initialise things to avoid compiler warnings. */
10757    axis_attrib = NULL;
10758    old_attrib = NULL;
10759 
10760 /* Jump back to here if we are trying the same attribute but with an explicit
10761    axis "(1)" added to the end of the name. */
10762 L1:
10763 
10764 /* Obtain the length of the attrib string. */
10765    len = strlen( attrib );
10766 
10767 /* Check the attribute name and test the appropriate attribute. */
10768 
10769 /* Digits. */
10770 /* ------- */
10771    if ( !strcmp( attrib, "digits" ) ) {
10772       result = astTestDigits( this );
10773 
10774 /* Digits(axis). */
10775 /* ------------- */
10776    } else if ( nc = 0,
10777                ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) )
10778                && ( nc >= len ) ) {
10779 
10780 /* There is no function to test the Digits attribute for an axis
10781    directly, so obtain a pointer to the Axis and use this to test the
10782    attribute. */
10783       (void) astValidateAxis( this, axis - 1, 1, "astTestDigits(axis)" );
10784       ax = astGetAxis( this, axis - 1 );
10785       result = astTestAxisDigits( ax );
10786       ax = astAnnul( ax );
10787 
10788 /* Direction(axis). */
10789 /* ---------------- */
10790    } else if ( nc = 0,
10791                ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) )
10792                && ( nc >= len ) ) {
10793       result = astTestDirection( this, axis - 1 );
10794 
10795 /* Epoch. */
10796 /* ------ */
10797    } else if ( !strcmp( attrib, "epoch" ) ) {
10798       result = astTestEpoch( this );
10799 
10800 /* Bottom(axis). */
10801 /* ------------- */
10802    } else if ( nc = 0,
10803                ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) )
10804                && ( nc >= len ) ) {
10805       result = astTestBottom( this, axis - 1 );
10806 
10807 /* Top(axis). */
10808 /* ---------- */
10809    } else if ( nc = 0,
10810                ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) )
10811                && ( nc >= len ) ) {
10812       result = astTestTop( this, axis - 1 );
10813 
10814 /* Domain. */
10815 /* ------- */
10816    } else if ( !strcmp( attrib, "domain" ) ) {
10817       result = astTestDomain( this );
10818 
10819 /* Format(axis). */
10820 /* ------------- */
10821    } else if ( nc = 0,
10822                ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) )
10823                && ( nc >= len ) ) {
10824       result = astTestFormat( this, axis - 1 );
10825 
10826 /* Label(axis). */
10827 /* ------------ */
10828    } else if ( nc = 0,
10829                ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) )
10830                && ( nc >= len ) ) {
10831       result = astTestLabel( this, axis - 1 );
10832 
10833 /* MatchEnd. */
10834 /* --------- */
10835    } else if ( !strcmp( attrib, "matchend" ) ) {
10836       result = astTestMatchEnd( this );
10837 
10838 /* MaxAxes. */
10839 /* -------- */
10840    } else if ( !strcmp( attrib, "maxaxes" ) ) {
10841       result = astTestMaxAxes( this );
10842 
10843 /* MinAxes. */
10844 /* -------- */
10845    } else if ( !strcmp( attrib, "minaxes" ) ) {
10846       result = astTestMinAxes( this );
10847 
10848 /* Permute. */
10849 /* -------- */
10850    } else if ( !strcmp( attrib, "permute" ) ) {
10851       result = astTestPermute( this );
10852 
10853 /* PreserveAxes. */
10854 /* ------------- */
10855    } else if ( !strcmp( attrib, "preserveaxes" ) ) {
10856       result = astTestPreserveAxes( this );
10857 
10858 /* Symbol(axis). */
10859 /* ------------- */
10860    } else if ( nc = 0,
10861                ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) )
10862                && ( nc >= len ) ) {
10863       result = astTestSymbol( this, axis - 1 );
10864 
10865 /* AlignSystem. */
10866 /* ------------ */
10867    } else if ( !strcmp( attrib, "alignsystem" ) ) {
10868       result = astTestAlignSystem( this );
10869 
10870 /* System. */
10871 /* ------- */
10872    } else if ( !strcmp( attrib, "system" ) ) {
10873       result = astTestSystem( this );
10874 
10875 /* Title. */
10876 /* ------ */
10877    } else if ( !strcmp( attrib, "title" ) ) {
10878       result = astTestTitle( this );
10879 
10880 /* Unit(axis). */
10881 /* ----------- */
10882    } else if ( nc = 0,
10883                ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) )
10884                && ( nc >= len ) ) {
10885       result = astTestUnit( this, axis - 1 );
10886 
10887 /* ObsLat. */
10888 /* ------- */
10889    } else if ( !strcmp( attrib, "obslat" ) ) {
10890       result = astTestObsLat( this );
10891 
10892 /* ObsLon. */
10893 /* ------- */
10894    } else if ( !strcmp( attrib, "obslon" ) ) {
10895       result = astTestObsLon( this );
10896 
10897 /* ObsAlt. */
10898 /* ------- */
10899    } else if ( !strcmp( attrib, "obsalt" ) ) {
10900       result = astTestObsAlt( this );
10901 
10902 /* Dut1. */
10903 /* ---- */
10904    } else if ( !strcmp( attrib, "dut1" ) ) {
10905       result = astTestDut1( this );
10906 
10907 /* Read-only attributes. */
10908 /* --------------------- */
10909 /* Test if the attribute name matches any of the read-only attributes
10910    of this class. If it does, then return zero. */
10911    } else if ( !strcmp( attrib, "naxes" ) ||
10912                !strncmp( attrib, "normunit", 8 ) ) {
10913       result = 0;
10914 
10915 /* Other axis attributes. */
10916 /* ---------------------- */
10917 /* If the attribute was not identified above, but appears to refer to
10918    a Frame axis, then it may refer to an Axis object of a derived type
10919    (which has additional attributes not recognised here). */
10920    } else if ( !free_axis_attrib && ( nc = 0,
10921                ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n",
10922                                       &axis_nc, &axis, &nc ) )
10923                && ( nc >= len ) ) ) {
10924 
10925 /* Validate the axis index and extract the attribute name. */
10926       (void) astValidateAxis( this, axis - 1, 1, "astTest" );
10927       axis_attrib = astString( attrib, axis_nc );
10928 
10929 /* Obtain a pointer to the Axis object. */
10930       ax = astGetAxis( this, axis - 1 );
10931       if( astOK ) {
10932 
10933 /* Assume that we will be able to use the attribute name. */
10934          used = 1;
10935 
10936 /* Temporarily switch off error reporting so that if the following attempt
10937    to access the axis attribute fails, we can try to interpret the
10938    attribute name as an attribute of the primary Frame containing the
10939    specified axis. Any errors reported in this context will simply be
10940    ignored, in particularly they are not deferred for later delivery. */
10941          oldrep = astReporting( 0 );
10942 
10943 /* Use the Axis astTestAttrib method to test the attribute value. */
10944          result = astTestAttrib( ax, axis_attrib );
10945 
10946 /* If the above call failed with a status of AST__BADAT, indicating that
10947    the attribute name was not recognised, clear the status so that we can
10948    try to interpret the attribute name as an attribute of the primary Frame
10949    containing the specified axis. */
10950          if( astStatus == AST__BADAT ) {
10951             astClearStatus;
10952 
10953 /* Find the primary Frame containing the specified axis. */
10954             astPrimaryFrame( this, axis - 1, &pfrm, &paxis );
10955 
10956 /* Only attempt to use the primary Frame if it is not the same as "this"
10957    - otherwise we could end up in an infinite loop. */
10958             if( pfrm != this ) {
10959 
10960 /* astPrimaryFrame returns the original - unpermuted - axis index within
10961    the primary Frame. So we need to take into account any axis permutation
10962    which has been applied to the primary Frame when forming the attribute name
10963    to use below. Find the permuted (external) axis index which corresponds to
10964    the internal (unpermuted) axis index "paxis". */
10965                paxis = astValidateAxis( pfrm, paxis, 0, "astTest" );
10966 
10967 /* Modify the attribute name to refer to the axis numbering of the
10968    primary frame. */
10969                sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 );
10970 
10971 /* Attempt to test the attribute as an attribute of the primary Frame. */
10972                result = astTestAttrib( pfrm, pfrm_attrib );
10973 
10974 /* If this failed, clear the status and indicate that we have not managed to
10975    use the attribute name. */
10976                if( !astOK ) {
10977                   astClearStatus;
10978                   used = 0;
10979                }
10980 
10981             } else {
10982                used = 0;
10983             }
10984 
10985 /* If not found attempt to test the attribute value in the Axis, omitting
10986    the axis index. */
10987             if( ! used ) {
10988                result = astTestAttrib( pfrm, axis_attrib );
10989                if( !astOK ) {
10990                   astClearStatus;
10991                } else {
10992                   used = 1;
10993                }
10994             }
10995 
10996 /* Annul the primary Frame pointer. */
10997             pfrm = astAnnul( pfrm );
10998          }
10999 
11000 /* Re-instate the original error reporting state. */
11001          astReporting( oldrep );
11002 
11003 /* If we could not use the attribute name, attempt to test the axis
11004    attribute again, this time retaining the error report. This is done
11005    to ensure the user gets an appropriate error message. */
11006          if( !used ) result = astTestAttrib( ax, axis_attrib );
11007       }
11008 
11009 /* Annul the Axis pointer and free the memory holding the attribute
11010    name. */
11011       ax = astAnnul( ax );
11012       axis_attrib = astFree( axis_attrib );
11013 
11014 /* Not recognised. */
11015 /* --------------- */
11016 /* If the attribute is still not recognised, and the Frame has only 1 axis,
11017    and the attribute name does not already include an axis specifier, try
11018    again after appending "(1)" to the end of the attribute name. */
11019    } else if( !has_axis && astGetNaxes( this ) == 1 ) {
11020 
11021 /* Take a copy of the supplied name, allowing 3 extra characters for the
11022    axis specifier "(1)". */
11023       axis_attrib = astMalloc( len + 4 );
11024       if( axis_attrib ) memcpy( axis_attrib, attrib, len );
11025 
11026 /* Indicate we should free the axis_attrib memory. */
11027       free_axis_attrib = 1;
11028 
11029 /* Add in the axis specifier. */
11030       strcpy( axis_attrib + len, "(1)" );
11031 
11032 /* Use the new attribute name instead of the supplied name. */
11033       old_attrib = attrib;
11034       attrib = axis_attrib;
11035 
11036 /* Indicate the attribute name now has an axis specifier. */
11037       has_axis = 1;
11038 
11039 /* Jump back to try interpreting the new attribute name. */
11040       goto L1;
11041 
11042 /* Not recognised. */
11043 /* --------------- */
11044 /* If the attribute name is still not recognised, pass it on to the parent
11045    method for further interpretation. First re-instate the original attrib
11046    name string if it was changed above. */
11047    } else {
11048       if( free_axis_attrib ) {
11049          attrib = old_attrib;
11050          axis_attrib = astFree( axis_attrib );
11051       }
11052       result = (*parent_testattrib)( this_object, attrib, status );
11053    }
11054 
11055 /* Return the result, */
11056    return result;
11057 }
11058 
Transform(AstMapping * this_mapping,AstPointSet * in,int forward,AstPointSet * out,int * status)11059 static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in,
11060                                int forward, AstPointSet *out, int *status ) {
11061 /*
11062 *  Name:
11063 *     Transform
11064 
11065 *  Purpose:
11066 *     Use a Frame to transform a set of points.
11067 
11068 *  Type:
11069 *     Private function.
11070 
11071 *  Synopsis:
11072 *     #include "frame.h"
11073 *     AstPointSet *Transform( AstMapping *this, AstPointSet *in,
11074 *                             int forward, AstPointSet *out, int *status )
11075 
11076 *  Class Membership:
11077 *     Frame member function (over-rides the astTransform method inherited
11078 *     from the Mapping class).
11079 
11080 *  Description:
11081 *     This function takes a Frame and a set of points encapsulated in a
11082 *     PointSet and transforms the points so as to perform the identity
11083 *     transformation (i.e. simply copies the coordinate values).
11084 
11085 *  Parameters:
11086 *     this
11087 *        Pointer to the Frame.
11088 *     in
11089 *        Pointer to the PointSet holding the input coordinate data.
11090 *     forward
11091 *        A non-zero value indicates that the forward coordinate transformation
11092 *        should be applied, while a zero value requests the inverse
11093 *        transformation. In this case, both transformations are equivalent.
11094 *     out
11095 *        Pointer to a PointSet which will hold the transformed (output)
11096 *        coordinate values. A NULL value may also be given, in which case a
11097 *        new PointSet will be created by this function.
11098 *     status
11099 *        Pointer to the inherited status variable.
11100 
11101 *  Returned Value:
11102 *     Pointer to the output (possibly new) PointSet.
11103 
11104 *  Notes:
11105 *     -  A null pointer will be returned if this function is invoked with the
11106 *     global error status set, or if it should fail for any reason.
11107 *     -  The number of coordinate values per point in the input PointSet must
11108 *     match the number of coordinates for the Frame being applied. This number
11109 *     will be equal to the number of Frame axes.
11110 *     -  If an output PointSet is supplied, it must have space for sufficient
11111 *     number of points and coordinate values per point to accommodate the
11112 *     result. Any excess space will be ignored.
11113 */
11114 
11115 /* Local Variables: */
11116    AstFrame *this;               /* Pointer to the Frame structure */
11117    AstPointSet *result;          /* Pointer value to be returned */
11118    AstUnitMap *unitmap;          /* Pointer to temporary UnitMap */
11119 
11120 /* Check the global error status. */
11121    if ( !astOK ) return NULL;
11122 
11123 /* Obtain a pointer to the Frame structure. */
11124    this = (AstFrame *) this_mapping;
11125 
11126 /* Create a unit Mapping with one coordinate for each Frame axis. */
11127    unitmap = astUnitMap( astGetNaxes( this ), "", status );
11128 
11129 /* Use the Mapping to transform (i.e. copy) the coordinate values. */
11130    result = astTransform( unitmap, in, forward, out );
11131 
11132 /* Annul the Mapping. */
11133    unitmap = astAnnul( unitmap );
11134 
11135 /* If an error occurred and a new PointSet may have been created, then annul
11136    the result. In any case, ensure that a NULL pointer is returned. */
11137    if ( !astOK ) {
11138       if ( !out ) result = astAnnul( result );
11139       result = NULL;
11140    }
11141 
11142 /* Return the result pointer. */
11143    return result;
11144 }
11145 
Unformat(AstFrame * this,int axis,const char * string,double * value,int * status)11146 static int Unformat( AstFrame *this, int axis, const char *string,
11147                      double *value, int *status ) {
11148 /*
11149 *+
11150 *  Name:
11151 *     astUnformat
11152 
11153 *  Purpose:
11154 *     Read a formatted coordinate value for a Frame axis.
11155 
11156 *  Type:
11157 *     Protected virtual function.
11158 
11159 *  Synopsis:
11160 *     #include "frame.h"
11161 *     int astUnformat( AstFrame *this, int axis, const char *string,
11162 *                      double *value )
11163 
11164 *  Class Membership:
11165 *     Frame method.
11166 
11167 *  Description:
11168 *     This function reads a formatted coordinate value for a Frame
11169 *     axis (supplied as a string) and returns the equivalent numerical
11170 *     value as a double. It also returns the number of characters read
11171 *     from the string.
11172 
11173 *  Parameters:
11174 *     this
11175 *        Pointer to the Frame.
11176 *     axis
11177 *        The number of the Frame axis for which the coordinate value
11178 *        is to be read (axis numbering starts at zero for the first
11179 *        axis).
11180 *     string
11181 *        Pointer to a constant null-terminated string containing the
11182 *        formatted coordinate value.
11183 *     value
11184 *        Pointer to a double in which the coordinate value read will be
11185 *        returned.
11186 
11187 *  Returned Value:
11188 *     The number of characters read from the string to obtain the
11189 *     coordinate value.
11190 
11191 *  Notes:
11192 *     - Any white space at the beginning of the string will be
11193 *     skipped, as also will any trailing white space following the
11194 *     coordinate value read. The function's return value will reflect
11195 *     this.
11196 *     - A function value of zero (and no coordinate value) will be
11197 *     returned, without error, if the string supplied does not contain
11198 *     a suitably formatted value.
11199 *     - The string "<bad>" is recognised as a special case and will
11200 *     generate the value AST__BAD, without error. The test for this
11201 *     string is case-insensitive and permits embedded white space.
11202 *     - A function result of zero will be returned and no coordinate
11203 *     value will be returned via the "value" pointer if this function
11204 *     is invoked with the global error status set, or if it should
11205 *     fail for any reason.
11206 *-
11207 
11208 *  Implementation Notes:
11209 *     - This function implements the basic astUnformat method
11210 *     available via the protected interface to the Frame class. The
11211 *     public interface to this method is provided by the
11212 *     astUnformatId_ function.
11213 */
11214 
11215 /* Local Variables: */
11216    AstAxis *ax;                  /* Pointer to Axis object */
11217    const char *label;            /* Pointer to axis label string */
11218    double coord;                 /* Coordinate value read */
11219    int digits_set;               /* Axis Digits attribute set? */
11220    int nc;                       /* Number of characters read */
11221    int status_value;             /* AST error status */
11222 
11223 /* Initialise. */
11224    nc = 0;
11225 
11226 /* Check the global error status. */
11227    if ( !astOK ) return nc;
11228 
11229 /* Validate the axis index and obtain a pointer to the required Axis. */
11230    (void) astValidateAxis( this, axis, 1, "astUnformat" );
11231    ax = astGetAxis( this, axis );
11232 
11233 /* Test if any Axis attributes which may affect the result are
11234    undefined (i.e. have not been explicitly set). If so, we over-ride
11235    them, giving them temporary values dictated by the Frame. Only the
11236    Digits attribute is potentially relevant here. */
11237    digits_set = astTestAxisDigits( ax );
11238    if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) );
11239 
11240 /* Read the coordinate value. */
11241    if ( astOK ) {
11242       nc = astAxisUnformat( ax, string, &coord );
11243 
11244 /* If an error occurred, save and temporarily clear the global error
11245    status while the axis Label string is obtained. Then restore the
11246    original error status value afterwards. */
11247       if ( !astOK ) {
11248          status_value = astStatus;
11249          astClearStatus;
11250          label = astGetLabel( this, axis );
11251          astSetStatus( status_value );
11252 
11253 /* Report a contextual error message containing the axis label. */
11254          astError( status_value, "%s(%s): Unable to read \"%s\" value.", status,
11255                    "astUnformat", astGetClass( this ), label );
11256       }
11257    }
11258 
11259 /* Clear any Axis attributes that were temporarily over-ridden. */
11260    if ( !digits_set ) astClearAxisDigits( ax );
11261 
11262 /* Annul the Axis pointer. */
11263    ax = astAnnul( ax );
11264 
11265 /* If an error occurred, clear the count of characters read. */
11266    if ( !astOK ) {
11267       nc = 0;
11268 
11269 /* Otherwise, if characters were read, return the coordinate value. */
11270    } else if ( nc ) {
11271       *value = coord;
11272    }
11273 
11274 /* Return the number of characters read. */
11275    return nc;
11276 }
11277 
ValidateAxis(AstFrame * this,int axis,int fwd,const char * method,int * status)11278 static int ValidateAxis( AstFrame *this, int axis, int fwd, const char *method,
11279                          int *status ) {
11280 /*
11281 *+
11282 *  Name:
11283 *     astValidateAxis
11284 
11285 *  Purpose:
11286 *     Validate and permute a Frame's axis index.
11287 
11288 *  Type:
11289 *     Protected virtual function.
11290 
11291 *  Synopsis:
11292 *     #include "frame.h"
11293 *     int astValidateAxis( AstFrame *this, int axis, int fwd,
11294 *                          const char *method )
11295 
11296 *  Class Membership:
11297 *     Frame method.
11298 
11299 *  Description:
11300 *     This function checks the validity of an index (zero-based) which
11301 *     is to be used to address one of the coordinate axes of a
11302 *     Frame. If the index is valid, it is permuted using the axis
11303 *     permutation array associated with the Frame and the (zero-based)
11304 *     permuted axis index is returned.  This gives the location of the
11305 *     required axis information within the Frame's internal arrays. If
11306 *     the axis index supplied is not valid, an error is reported and
11307 *     the global error status is set.
11308 
11309 *  Parameters:
11310 *     this
11311 *        Pointer to the Frame.
11312 *     axis
11313 *        The axis index (zero-based) to be checked. To be valid, it
11314 *        must lie between zero and (naxes-1) inclusive, where "naxes"
11315 *        is the number of coordinate axes associated with the Frame.
11316 *     fwd
11317 *        If non-zero, the suppplied axis index is assumed to be an
11318 *        "external" axis index, and the corresponding "internal" axis index
11319 *        is returned as the function value. Otherwise, the suppplied axis
11320 *        index is assumed to be an "internal" axis index, and the
11321 *        corresponding "external" axis index is returned as the function
11322 *        value.
11323 *     method
11324 *        Pointer to a constant null-terminated character string
11325 *        containing the name of the method that invoked this function
11326 *        to validate an axis index. This method name is used solely
11327 *        for constructing error messages.
11328 
11329 *  Returned Value:
11330 *     The permuted axis index - either "internal" or "external" as
11331 *     specified by "fwd".
11332 
11333 *  Notes:
11334 *     - A value of zero will be returned if this function is invoked
11335 *     with the global error status set, or if it should fail for any
11336 *     reason.
11337 *     - Error messages issued by this function refer to the public
11338 *     numbering system used for axes which is one-based (zero-based axis
11339 *     indices are used internally).
11340 *-
11341 */
11342 
11343 /* Local Variables: */
11344    const int *perm;              /* Pointer to axis permutation array */
11345    int naxes;                    /* Number of Frame axes */
11346    int result;                   /* Permuted axis index */
11347 
11348 /* Initialise. */
11349    result = 0;
11350 
11351 /* Determine the number of Frame axes. */
11352    naxes = astGetNaxes( this );
11353    if ( astOK ) {
11354 
11355 /* If the Frame has no axes, report an error (note we convert to
11356    one-based axis numbering in the error message). */
11357       if ( naxes == 0 ) {
11358          astError( AST__AXIIN, "%s(%s): Invalid attempt to use an axis index "
11359                    "(%d) for a %s which has no axes.", status, method,
11360                    astGetClass( this ), axis + 1, astGetClass( this ) );
11361 
11362 /* Otherwise, check the axis index for validity and report an error if
11363    it is not valid (again, use one-based axis numbering). */
11364       } else if ( ( axis < 0 ) || ( axis >= naxes ) ) {
11365          astError( AST__AXIIN, "%s(%s): Axis index (%d) invalid - it should "
11366                    "be in the range 1 to %d.", status, method, astGetClass( this ),
11367                    axis + 1, naxes );
11368 
11369 /* If the axis index was valid, obtain the axis permutation array and
11370    use this to generate the permuted axis value. */
11371       } else {
11372          perm = astGetPerm( this );
11373          if( perm ) {
11374 
11375 /* External to internal is a simple look-up. */
11376             if( fwd ) {
11377                result = perm[ axis ];
11378 
11379 /* Internal to external requires a search through the permutation array. */
11380             } else {
11381                for( result = 0; result < naxes; result++ ) {
11382                   if( perm[ result ] == axis ) break;
11383                }
11384             }
11385          }
11386       }
11387    }
11388 
11389 /* Return the result. */
11390    return result;
11391 }
11392 
ValidateAxisSelection(AstFrame * this,int naxes,const int * axes,const char * method,int * status)11393 static void ValidateAxisSelection( AstFrame *this, int naxes, const int *axes,
11394                                    const char *method, int *status ) {
11395 /*
11396 *+
11397 *  Name:
11398 *     astValidateAxisSelection
11399 
11400 *  Purpose:
11401 *     Check that a set of axes selected from a Frame is valid.
11402 
11403 *  Type:
11404 *     Protected virtual function.
11405 
11406 *  Synopsis:
11407 *     #include "frame.h"
11408 *     void astValidateAxisSelection( AstFrame *this, int naxes,
11409 *                                    const int *axes, const char *method )
11410 
11411 *  Class Membership:
11412 *     Frame method.
11413 
11414 *  Description:
11415 *     This function checks the validity of an array of (zero-based)
11416 *     axis indices that specify a set of axes to be selected from a
11417 *     Frame. To be valid, no axis should be selected more than
11418 *     once. In assessing this, any axis indices that do not refer to
11419 *     valid Frame axes (e.g. are set to -1) are ignored.
11420 *
11421 *     If the axis selection is valid, this function returns without further
11422 *     action. Otherwise, an error is reported and the global error status is
11423 *     set.
11424 
11425 *  Parameters:
11426 *     this
11427 *        Pointer to the Frame.
11428 *     naxes
11429 *        The number of axes to be selected (may be zero).
11430 *     axes
11431 *        Pointer to an array of int with naxes elements that contains the
11432 *        (zero based) axis indices to be checked.
11433 *     method
11434 *        Pointer to a constant null-terminated character string
11435 *        containing the name of the method that invoked this function
11436 *        to validate an axis selection. This method name is used
11437 *        solely for constructing error messages.
11438 *-
11439 */
11440 
11441 /* Local Variables: */
11442    int *count;                   /* Pointer to temporary array of counts */
11443    int axis;                     /* Loop counter for selected axes */
11444    int frame_axis;               /* Loop counter for Frame axes */
11445    int frame_naxes;              /* Number of Frame axes */
11446    int valid;                    /* Axis selection valid? */
11447 
11448 /* Check the global error status. */
11449    if ( !astOK ) return;
11450 
11451 /* Check to see if no axes have been selected. If so, there is nothing to
11452    do. */
11453    if ( naxes ) {
11454 
11455 /* Initialise. */
11456       valid = 1;
11457 
11458 /* Obtain the number of Frame axes and allocate an array of int with
11459    one element for each Frame axis. This will store a count of the
11460    number of times each axis is selected. */
11461       frame_naxes = astGetNaxes( this );
11462       count = astMalloc( sizeof( int ) * (size_t) frame_naxes );
11463       if ( astOK ) {
11464 
11465 /* Initialise the array of counts to zero. */
11466          for ( frame_axis = 0; frame_axis < frame_naxes; frame_axis++ ) {
11467             count[ frame_axis ] = 0;
11468          }
11469 
11470 /* Loop through each selected axis. */
11471          for ( axis = 0; axis < naxes; axis++ ) {
11472             frame_axis = axes[ axis ];
11473 
11474 /* Check if the selected axis index is valid for the Frame. If so, increment
11475    the selection count for that Frame axis. */
11476             if ( ( frame_axis >= 0 ) && ( frame_axis < frame_naxes ) ) {
11477                count[ frame_axis ]++;
11478             }
11479          }
11480 
11481 /* Loop through the count array and check that no Frame axis was selected
11482    more than once. If it was, clear the "valid" flag and quit checking. */
11483          for ( frame_axis = 0; frame_axis < frame_naxes; frame_axis++ ) {
11484             if ( count[ frame_axis ] > 1 ) {
11485                valid = 0;
11486                break;
11487             }
11488          }
11489       }
11490 
11491 /* Free the temporary count array. */
11492       count = astFree( count );
11493 
11494 /* If no error has occurred, but the axis selection is not valid, then report
11495    an error. */
11496       if ( astOK && !valid ) {
11497          astError( AST__SELIN, "%s(%s): Invalid axis selection - each axis "
11498                    "may be selected only once.", status, method, astGetClass( this ) );
11499       }
11500    }
11501 }
11502 
ValidateSystem(AstFrame * this,AstSystemType system,const char * method,int * status)11503 static int ValidateSystem( AstFrame *this, AstSystemType system, const char *method, int *status ) {
11504 /*
11505 *+
11506 *  Name:
11507 *     astValidateSystem
11508 
11509 *  Purpose:
11510 *     Validate a value for a Frame's System attribute.
11511 
11512 *  Type:
11513 *     Protected virtual function.
11514 
11515 *  Synopsis:
11516 *     #include "frame.h"
11517 *     int astValidateSystem( AstFrame *this, AstSystemType system,
11518 *                            const char *method )
11519 
11520 *  Class Membership:
11521 *     Frame method.
11522 
11523 *  Description:
11524 *     This function checks the validity of the supplied system value.
11525 *     If the value is valid, it is returned unchanged. Otherwise, an
11526 *     error is reported and a value of AST__BADSYSTEM is returned.
11527 
11528 *  Parameters:
11529 *     this
11530 *        Pointer to the Frame.
11531 *     system
11532 *        The system value to be checked.
11533 *     method
11534 *        Pointer to a constant null-terminated character string
11535 *        containing the name of the method that invoked this function
11536 *        to validate an axis index. This method name is used solely
11537 *        for constructing error messages.
11538 
11539 *  Returned Value:
11540 *     The validated system value.
11541 
11542 *  Notes:
11543 *     - A value of AST_BADSYSTEM will be returned if this function is invoked
11544 *     with the global error status set, or if it should fail for any
11545 *     reason.
11546 *-
11547 */
11548 
11549 /* Local Variables: */
11550    AstSystemType result;              /* Validated system value */
11551 
11552 /* Initialise. */
11553    result = AST__BADSYSTEM;
11554 
11555 /* Check the global error status. */
11556    if ( !astOK ) return result;
11557 
11558 /* If the value is out of bounds, report an error. */
11559    if ( system < FIRST_SYSTEM || system > LAST_SYSTEM ) {
11560          astError( AST__AXIIN, "%s(%s): Bad value (%d) given for the System "
11561                    "or AlignSystem attribute of a %s.", status, method,
11562                    astGetClass( this ), (int) system, astGetClass( this ) );
11563 
11564 /* Otherwise, return the supplied value. */
11565    } else {
11566       result = system;
11567    }
11568 
11569 /* Return the result. */
11570    return result;
11571 }
11572 
11573 /* Functions which access class attributes. */
11574 /* ---------------------------------------- */
11575 /* Implement member functions to access the attributes associated with
11576    the axes of a Frame using the private macros defined for this
11577    purpose at the start of this file. */
11578 
11579 /*
11580 *att++
11581 *  Name:
11582 *     Naxes
11583 
11584 *  Purpose:
11585 *     Number of Frame axes.
11586 
11587 *  Type:
11588 *     Public attribute.
11589 
11590 *  Synopsis:
11591 *     Integer, read-only.
11592 
11593 *  Description:
11594 *     This is a read-only attribute giving the number of axes in a
11595 *     Frame (i.e. the number of dimensions of the coordinate space
11596 *     which the Frame describes). This value is determined when the
11597 *     Frame is created.
11598 
11599 *  Applicability:
11600 *     Frame
11601 *        All Frames have this attribute.
11602 *     FrameSet
11603 *        The Naxes attribute of a FrameSet is the same as that of its
11604 *        current Frame (as specified by the Current attribute).
11605 *     CmpFrame
11606 *        The Naxes attribute of a CmpFrame is equal to the sum of the
11607 *        Naxes values of its two component Frames.
11608 *att--
11609 */
11610 
11611 
11612 /*
11613 *att++
11614 *  Name:
11615 *     Direction(axis)
11616 
11617 *  Purpose:
11618 *     Display axis in conventional direction?
11619 
11620 *  Type:
11621 *     Public attribute.
11622 
11623 *  Synopsis:
11624 *     Integer (boolean).
11625 
11626 *  Description:
11627 *     This attribute is a boolean value which suggests how the axes of
11628 *     a Frame should be displayed (e.g.) in graphical output. By
11629 *     default, it has the value one, indicating that they should be
11630 *     shown in the conventional sense (increasing left to right for an
11631 *     abscissa, and bottom to top for an ordinate). If set to zero,
11632 *     this attribute indicates that the direction should be reversed,
11633 *     as would often be done for an astronomical magnitude or a right
11634 *     ascension axis.
11635 
11636 *  Applicability:
11637 *     Frame
11638 *        The default Direction value supplied by the Frame class is 1,
11639 *        indicating that all axes should be displayed in the
11640 *        conventional direction.
11641 *     SkyFrame
11642 *        The SkyFrame class re-defines the default Direction value to
11643 *        suggest that certain axes (e.g. right ascension) should be
11644 *        plotted in reverse when appropriate.
11645 *     FrameSet
11646 *        The Direction attribute of a FrameSet axis is the same as
11647 *        that of its current Frame (as specified by the Current
11648 *        attribute).
11649 *     Plot
11650 *        The Direction attribute of the base Frame in a Plot is set to
11651 *        indicate the sense of the two graphics axes, as implied by the
11652 *        graphics bounding box supplied when the Plot was created.
11653 
11654 *  Notes:
11655 *     - When specifying this attribute by name, it should be
11656 *     subscripted with the number of the Frame axis to which it
11657 *     applies.
11658 *     - The Direction attribute does not directly affect the behaviour
11659 *     of the AST library. Instead, it serves as a hint to applications
11660 *     programs about the orientation in which they may wish to display
11661 *     any data associated with the Frame. Applications are free to
11662 *     ignore this hint if they wish.
11663 *att--
11664 */
11665 /* This simply provides an interface to the Axis methods for accessing
11666    the Direction flag. */
11667 MAKE_CLEAR(Direction)
11668 MAKE_GET(Direction,int,0,0,0)
MAKE_SET(Direction,int)11669 MAKE_SET(Direction,int)
11670 MAKE_TEST(Direction)
11671 
11672 /*
11673 *att++
11674 *  Name:
11675 *     Dut1
11676 
11677 *  Purpose:
11678 *     The UT1-UTC correction.
11679 
11680 *  Type:
11681 *     Public attribute.
11682 
11683 *  Synopsis:
11684 *     Floating point.
11685 
11686 *  Description:
11687 *     This attribute is used when calculating the Local Apparent Sidereal
11688 *     Time corresponding to SkyFrame's Epoch value (used when converting
11689 *     positions to or from the "AzEl" system). It should be set to the
11690 *     difference, in seconds, between the UT1 and UTC timescales at the
11691 *     moment in time represented by the SkyFrame's Epoch attribute. The
11692 *     value to use is unpredictable and depends on changes in the earth's
11693 *     rotation speed. Values for UT1-UTC can be obtained from the
11694 *     International Earth Rotation and Reference Systems Service
11695 *     (IERS) at http://www.iers.org/.
11696 *
11697 *     Currently, the correction is always less than 1 second. This is
11698 *     ensured by the occasional introduction of leap seconds into the UTC
11699 *     timescale. Therefore no great error will usually result if no value
11700 *     is assigned to this attribute (in which case a default value of
11701 *     zero is used). However, it is possible that a decision may be taken
11702 *     at some time in the future to abandon the introduction of leap
11703 *     seconds, in which case the DUT correction could grow to significant
11704 *     sizes.
11705 
11706 *  Applicability:
11707 *     Frame
11708 *        All Frames have this attribute.
11709 
11710 *att--
11711 */
11712 /* The UT1-UTC correction, in seconds. Has a value of AST__BAD when not set
11713    yielding a default value of 0.0. */
11714 astMAKE_CLEAR(Frame,Dut1,dut1,AST__BAD)
11715 astMAKE_GET(Frame,Dut1,double,0.0,(this->dut1 == AST__BAD ? 0.0 : this->dut1))
11716 astMAKE_SET(Frame,Dut1,double,dut1,value)
11717 astMAKE_TEST(Frame,Dut1,( this->dut1 != AST__BAD ))
11718 
11719 
11720 
11721 /*
11722 *att++
11723 *  Name:
11724 *     Epoch
11725 
11726 *  Purpose:
11727 *     Epoch of observation.
11728 
11729 *  Type:
11730 *     Public attribute.
11731 
11732 *  Synopsis:
11733 *     Floating point.
11734 
11735 *  Description:
11736 *     This attribute is used to qualify the coordinate systems described by
11737 *     a Frame, by giving the moment in time when the coordinates are known
11738 *     to be correct. Often, this will be the date of observation, and is
11739 *     important in cases where coordinates systems move with respect to each
11740 *     other over the course of time.
11741 *
11742 *     The Epoch attribute is stored as a Modified Julian Date, but
11743 *     when setting its value it may be given in a variety of
11744 *     formats. See the "Input Formats" section (below) for details.
11745 *     Strictly, the Epoch value should be supplied in the TDB timescale,
11746 *     but for some purposes (for instance, for converting sky positions
11747 *     between different types of equatorial system) the timescale is not
11748 *     significant, and UTC may be used.
11749 
11750 *  Input Formats:
11751 *     The formats accepted when setting an Epoch value are listed
11752 *     below. They are all case-insensitive and are generally tolerant
11753 *     of extra white space and alternative field delimiters:
11754 *
11755 *     - Besselian Epoch: Expressed in decimal years, with or without
11756 *     decimal places ("B1950" or "B1976.13" for example).
11757 *
11758 *     - Julian Epoch: Expressed in decimal years, with or without
11759 *     decimal places ("J2000" or "J2100.9" for example).
11760 *
11761 *     - Year: Decimal years, with or without decimal places ("1996.8"
11762 *     for example).  Such values are interpreted as a Besselian epoch
11763 *     (see above) if less than 1984.0 and as a Julian epoch otherwise.
11764 *
11765 *     - Julian Date: With or without decimal places ("JD 2454321.9" for
11766 *     example).
11767 *
11768 *     - Modified Julian Date: With or without decimal places
11769 *     ("MJD 54321.4" for example).
11770 *
11771 *     - Gregorian Calendar Date: With the month expressed either as an
11772 *     integer or a 3-character abbreviation, and with optional decimal
11773 *     places to represent a fraction of a day ("1996-10-2" or
11774 *     "1996-Oct-2.6" for example). If no fractional part of a day is
11775 *     given, the time refers to the start of the day (zero hours).
11776 *
11777 *     - Gregorian Date and Time: Any calendar date (as above) but with
11778 *     a fraction of a day expressed as hours, minutes and seconds
11779 *     ("1996-Oct-2 12:13:56.985" for example). The date and time can be
11780 *     separated by a space or by a "T" (as used by ISO8601 format).
11781 
11782 *  Output Format:
11783 *     When enquiring Epoch values, the format used is the "Year"
11784 *     format described under "Input Formats". This is a value in
11785 *     decimal years which will be a Besselian epoch if less than
11786 *     1984.0 and a Julian epoch otherwise.  By omitting any character
11787 *     prefix, this format allows the Epoch value to be obtained as
11788 *     either a character string or a floating point value.
11789 
11790 *  Applicability:
11791 *     Frame
11792 *        All Frames have this attribute. The basic Frame class provides
11793 *        a default of J2000.0 (Julian) but makes no use of the Epoch value.
11794 *        This is because the Frame class does not distinguish between
11795 *        different Cartesian coordinate systems (see the System attribute).
11796 *     CmpFrame
11797 *        The default Epoch value for a CmpFrame is selected as follows;
11798 *        if the Epoch attribute has been set in the first component Frame
11799 *        then the Epoch value from the first component Frame is used as
11800 *        the default for the CmpFrame. Otherwise, if the Epoch attribute has
11801 *        been set in the second component Frame then the Epoch value from the
11802 *        second component Frame is used as the default for the CmpFrame.
11803 *        Otherwise, the default Epoch value from the first component
11804 *        Frame is used as the default for the CmpFrame. When the Epoch
11805 *        attribute of a CmpFrame is set or cleared, it is also set or
11806 *        cleared in the two component Frames.
11807 *     FrameSet
11808 *        The Epoch attribute of a FrameSet is the same as that of its current
11809 *        Frame (as specified by the Current attribute).
11810 *     SkyFrame
11811 *        The coordinates of sources within a SkyFrame can changed with time
11812 *        for various reasons, including: (i) changing aberration of light
11813 *        caused by the observer's velocity (e.g. due to the Earth's motion
11814 *        around the Sun), (ii) changing gravitational deflection by the Sun
11815 *        due to changes in the observer's position with time, (iii) fictitious
11816 *        motion due to rotation of non-inertial coordinate systems (e.g. the
11817 *        old FK4 system), and (iv) proper motion of the source itself (although
11818 *        this last effect is not handled by the SkyFrame class because it
11819 *        affects individual sources rather than the coordinate system as
11820 *        a whole).
11821 *
11822 *        The default Epoch value in a SkyFrame is B1950.0 (Besselian) for the
11823 *        old FK4-based coordinate systems (see the System attribute) and
11824 *        J2000.0 (Julian) for all others.
11825 *
11826 *        Care must be taken to distinguish the Epoch value, which relates to
11827 *        motion (or apparent motion) of the source, from the superficially
11828 *        similar Equinox value. The latter is used to qualify a coordinate
11829 *        system which is itself in motion in a (notionally) predictable way
11830 *        as a result of being referred to a slowly moving reference plane
11831 *        (e.g. the equator).
11832 *
11833 *        See the description of the System attribute for details of which
11834 *        qualifying attributes apply to each celestial coordinate system.
11835 *     TimeFrame
11836 *        A TimeFrame describes a general time axis and so cannot be completely
11837 *        characterised by a single Epoch value. For this reason the TimeFrame
11838 *        class makes no use of the Epoch attribute. However, user code can
11839 *        still make use of the attribute if necessary to represent a "typical"
11840 *        time spanned by the TimeFrame. The default Epoch value for a TimeFrame
11841 *        will be the TDB equivalent of the current value of the TimeFrame's
11842 *        TimeOrigin attribute. If no value has been set for TimeOrigin,
11843 *        then the default Epoch value is J2000.0.
11844 
11845 
11846 The coordinates of sources within a SkyFrame can changed with time
11847 *att--
11848 */
11849 /* Clear the Epoch value by setting it to AST__BAD. */
11850 astMAKE_CLEAR(Frame,Epoch,epoch,AST__BAD)
11851 
11852 /* Provide a default value of J2000.0 setting. */
11853 astMAKE_GET(Frame,Epoch,double,AST__BAD,(
11854            ( this->epoch != AST__BAD ) ? this->epoch : palEpj2d( 2000.0 )))
11855 
11856 /* Allow any Epoch value to be set. */
11857 astMAKE_SET(Frame,Epoch,double,epoch,value)
11858 
11859 /* An Epoch value is set if it is not equal to AST__BAD. */
11860 astMAKE_TEST(Frame,Epoch,( this->epoch != AST__BAD ))
11861 
11862 /*
11863 *att++
11864 *  Name:
11865 *     Top(axis)
11866 
11867 *  Purpose:
11868 *     Highest axis value to display
11869 
11870 *  Type:
11871 *     Public attribute.
11872 
11873 *  Synopsis:
11874 *     Floating point.
11875 
11876 *  Description:
11877 *     This attribute gives the highest axis value to be displayed (for
11878 c     instance, by the astGrid method).
11879 f     instance, by the AST_GRID method).
11880 
11881 *  Applicability:
11882 *     Frame
11883 *        The default supplied by the Frame class is to display all axis
11884 *        values, without any limit.
11885 *     SkyFrame
11886 *        The SkyFrame class re-defines the default Top value to +90 degrees
11887 *        for latitude axes, and 180 degrees for co-latitude axes. The
11888 *        default for longitude axes is to display all axis values.
11889 
11890 *  Notes:
11891 *     - When specifying this attribute by name, it should be
11892 *     subscripted with the number of the Frame axis to which it
11893 *     applies.
11894 *att--
11895 */
11896 /* This simply provides an interface to the Axis methods for accessing
11897    the Top value. */
11898 MAKE_CLEAR(Top)
11899 MAKE_GET(Top,double,DBL_MAX,0,DBL_MAX)
11900 MAKE_SET(Top,double)
11901 MAKE_TEST(Top)
11902 
11903 /*
11904 *att++
11905 *  Name:
11906 *     Bottom(axis)
11907 
11908 *  Purpose:
11909 *     Lowest axis value to display
11910 
11911 *  Type:
11912 *     Public attribute.
11913 
11914 *  Synopsis:
11915 *     Floating point.
11916 
11917 *  Description:
11918 *     This attribute gives the lowest axis value to be displayed (for
11919 c     instance, by the astGrid method).
11920 f     instance, by the AST_GRID method).
11921 
11922 *  Applicability:
11923 *     Frame
11924 *        The default supplied by the Frame class is to display all axis
11925 *        values, without any limit.
11926 *     SkyFrame
11927 *        The SkyFrame class re-defines the default Bottom value to -90 degrees
11928 *        for latitude axes, and 0 degrees for co-latitude axes. The
11929 *        default for longitude axes is to display all axis values.
11930 
11931 *  Notes:
11932 *     - When specifying this attribute by name, it should be
11933 *     subscripted with the number of the Frame axis to which it
11934 *     applies.
11935 *att--
11936 */
11937 /* This simply provides an interface to the Axis methods for accessing
11938    the Bottom value. */
11939 MAKE_CLEAR(Bottom)
11940 MAKE_GET(Bottom,double,-DBL_MAX,0,-DBL_MAX)
11941 MAKE_SET(Bottom,double)
11942 MAKE_TEST(Bottom)
11943 
11944 /*
11945 *att++
11946 *  Name:
11947 *     Format(axis)
11948 
11949 *  Purpose:
11950 *     Format specification for axis values.
11951 
11952 *  Type:
11953 *     Public attribute.
11954 
11955 *  Synopsis:
11956 *     String.
11957 
11958 *  Description:
11959 *     This attribute specifies the format to be used when displaying
11960 *     coordinate values associated with a particular Frame axis
11961 *     (i.e. to convert values from binary to character form). It is
11962 c     interpreted by the astFormat function and determines the
11963 f     interpreted by the AST_FORMAT function and determines the
11964 *     formatting which it applies.
11965 *
11966 *     If no Format value is set for a Frame axis, a default value is
11967 *     supplied instead. This is based on the value of the Digits, or
11968 *     Digits(axis), attribute and is chosen so that it displays the
11969 *     requested number of digits of precision.
11970 
11971 *  Applicability:
11972 *     Frame
11973 *        The Frame class interprets this attribute as a format
11974 *        specification string to be passed to the C "printf" function
11975 *        (e.g. "%1.7G") in order to format a single coordinate value
11976 *        (supplied as a double precision number).
11977 c
11978 c        When supplying a value for this attribute, beware that the
11979 c        "%" character may be interpreted directly as a format
11980 c        specification by some printf-like functions (such as
11981 c        astSet). You may need to double it (i.e. use "%%") to avoid
11982 c        this.
11983 *     SkyFrame
11984 *        The SkyFrame class re-defines the syntax and default value of
11985 *        the Format string to allow the formatting of sexagesimal
11986 *        values as appropriate for the particular celestial coordinate
11987 *        system being represented. The syntax of SkyFrame Format
11988 *        strings is described (below) in the "SkyFrame Formats"
11989 *        section.
11990 *     FrameSet
11991 *        The Format attribute of a FrameSet axis is the same as that
11992 *        of its current Frame (as specified by the Current
11993 *        attribute). Note that the syntax of the Format string is also
11994 *        determined by the current Frame.
11995 *     TimeFrame
11996 *        The TimeFrame class extends the syntax of the Format string to
11997 *        allow the formatting of TimeFrame axis values as Gregorian calendar
11998 *        dates and times. The syntax of TimeFrame Format strings is described
11999 *        (below) in the "TimeFrame Formats" section.
12000 
12001 *  SkyFrame Formats:
12002 *     The Format string supplied for a SkyFrame should contain zero or
12003 *     more of the following characters. These may occur in any order,
12004 *     but the following is recommended for clarity:
12005 *
12006 *     - "+": Indicates that a plus sign should be prefixed to positive
12007 *     values. By default, no plus sign is used.
12008 *
12009 *     - "z": Indicates that leading zeros should be prefixed to the
12010 *     value so that the first field is of constant width, as would be
12011 *     required in a fixed-width table (leading zeros are always
12012 *     prefixed to any fields that follow). By default, no leading
12013 *     zeros are added.
12014 *
12015 *     - "i": Use the standard ISO field separator (a colon) between
12016 *     fields. This is the default behaviour.
12017 *
12018 *     - "b": Use a blank to separate fields.
12019 *
12020 *     - "l": Use a letter ("h"/"d", "m" or "s" as appropriate) to
12021 *     separate fields.
12022 *
12023 *     - "g": Use a letter and symbols to separate fields ("h"/"d", "m" or "s",
12024 *     etc, as appropriate), but include escape sequences in the formatted
12025 *     value so that the Plot class will draw the separators as small
12026 *     super-scripts.
12027 c     The default escape sequences are optimised for the pgplot graphics
12028 c     package, but new escape sequences may be specified using function
12029 c     astSetSkyDelim.
12030 *
12031 *     - "d": Include a degrees field. Expressing the angle purely in
12032 *     degrees is also the default if none of "h", "m", "s" or "t" are
12033 *     given.
12034 *
12035 *     - "h": Express the angle as a time and include an hours field
12036 *     (where 24 hours correspond to 360 degrees). Expressing the angle
12037 *     purely in hours is also the default if "t" is given without
12038 *     either "m" or "s".
12039 *
12040 *     - "m": Include a minutes field. By default this is not included.
12041 *
12042 *     - "s": Include a seconds field. By default this is not included.
12043 *     This request is ignored if "d" or "h" is given, unless a minutes
12044 *     field is also included.
12045 *
12046 *     - "t": Express the angle as a time (where 24 hours correspond to
12047 *     360 degrees). This option is ignored if either "d" or "h" is
12048 *     given and is intended for use where the value is to be expressed
12049 *     purely in minutes and/or seconds of time (with no hours
12050 *     field). If "t" is given without "d", "h", "m" or "s" being
12051 *     present, then it is equivalent to "h".
12052 *
12053 *     - ".": Indicates that decimal places are to be given for the
12054 *     final field in the formatted string (whichever field this
12055 *     is). The "." should be followed immediately by an unsigned
12056 *     integer which gives the number of decimal places required, or by an
12057 *     asterisk. If an asterisk is supplied, a default number of decimal
12058 *     places is used which is based on the value of the Digits
12059 *     attribute.
12060 *
12061 *     All of the above format specifiers are case-insensitive. If
12062 *     several characters make conflicting requests (e.g. if both "i"
12063 *     and "b" appear), then the character occurring last takes
12064 *     precedence, except that "d" and "h" always override "t".
12065 *
12066 *     If the format string starts with a percentage sign (%), then the
12067 *     whole format string is assumed to conform to the syntax defined by
12068 *     the Frame class, and the axis values is formated as a decimal
12069 *     radians value.
12070 
12071 *  TimeFrame Formats:
12072 *     The Format string supplied for a TimeFrame should either use the
12073 *     syntax defined by the base Frame class (i.e. a C "printf" format
12074 *     string), or the extended "iso" syntax described below (the default
12075 *     value is inherited from the Frame class):
12076 *
12077 *     - C "printf" syntax: If the Format string is a C "printf" format
12078 *     description such as "%1.7G", the TimeFrame axis value will be
12079 *     formatted without change as a floating point value using this format.
12080 *     The formatted string will thus represent an offset from the zero point
12081 *     specified by the TimeFrame's TimeOrigin attribute, measured in
12082 *     units given by the TimeFrame's Unit attribute.
12083 *
12084 *     - "iso" syntax: This is used to format a TimeFrame axis value as a
12085 *     Gregorian date followed by an optional time of day. If the Format
12086 *     value commences with the string "iso" then the TimeFrame axis value
12087 *     will be converted to an absolute MJD, including the addition of the
12088 *     current TimeOrigin value, and then formatted as a Gregorian date
12089 *     using the format "yyyy-mm-dd". Optionally, the Format value may
12090 *     include an integer precision following the "iso" specification (e.g.
12091 *     "iso.2"), in which case the time of day will be appended to the
12092 *     formatted date (if no time of day is included, the date field is
12093 *     rounded to the nearest day). The integer value in the Format string
12094 *     indicates the number of decimal places to use in the seconds field. For
12095 *     instance, a Format value of "iso.0" produces a time of day of the form
12096 *     "hh:mm:ss", and a Format value of "iso.2" produces a time of day of the
12097 *     form "hh:mm:ss.ss". The date and time fields will be separated by a
12098 *     space unless 'T' is appended to the end of string, in which case
12099 *     the letter T (upper case) will be used as the separator. The value of
12100 *     the Digits attribute is ignored when using this "iso" format.
12101 
12102 *  Notes:
12103 *     - When specifying this attribute by name, it should be
12104 *     subscripted with the number of the Frame axis to which it
12105 *     applies.
12106 *att--
12107 */
12108 /* This simply provides an interface to the Axis methods for accessing
12109    the Format string. */
12110 MAKE_CLEAR(Format)
12111 MAKE_GET(Format,const char *,NULL,0,0)
12112 MAKE_SET(Format,const char *)
12113 MAKE_TEST(Format)
12114 
12115 /*
12116 *att++
12117 *  Name:
12118 *     Label(axis)
12119 
12120 *  Purpose:
12121 *     Axis label.
12122 
12123 *  Type:
12124 *     Public attribute.
12125 
12126 *  Synopsis:
12127 *     String.
12128 
12129 *  Description:
12130 *     This attribute specifies a label to be attached to each axis of
12131 *     a Frame when it is represented (e.g.) in graphical output.
12132 *
12133 *     If a Label value has not been set for a Frame axis, then a
12134 *     suitable default is supplied.
12135 
12136 *  Applicability:
12137 *     Frame
12138 *        The default supplied by the Frame class is the string "Axis
12139 *        <n>", where <n> is 1, 2, etc. for each successive axis.
12140 *     SkyFrame
12141 *        The SkyFrame class re-defines the default Label value
12142 *        (e.g. to "Right ascension" or "Galactic latitude") as
12143 *        appropriate for the particular celestial coordinate system
12144 *        being represented.
12145 *     TimeFrame
12146 *        The TimeFrame class re-defines the default Label value as
12147 *        appropriate for the particular time system being represented.
12148 *     FrameSet
12149 *        The Label attribute of a FrameSet axis is the same as that of
12150 *        its current Frame (as specified by the Current attribute).
12151 
12152 *  Notes:
12153 *     - Axis labels are intended purely for interpretation by human
12154 *     readers and not by software.
12155 *     - When specifying this attribute by name, it should be
12156 *     subscripted with the number of the Frame axis to which it
12157 *     applies.
12158 *att--
12159 */
12160 /* This provides an interface to the Axis methods for accessing the
12161    Label string, but provides an alternative default Label based on
12162    the axis number.  This default string is written to the static
12163    "label_buff" buffer and a pointer to this is returned if
12164    required. */
12165 MAKE_CLEAR(Label)
12166 MAKE_GET(Label,const char *,NULL,1,GetDefaultLabel( axis, status ))
12167 MAKE_SET(Label,const char *)
12168 MAKE_TEST(Label)
12169 
12170 /*
12171 *att++
12172 *  Name:
12173 *     Symbol(axis)
12174 
12175 *  Purpose:
12176 *     Axis symbol.
12177 
12178 *  Type:
12179 *     Public attribute.
12180 
12181 *  Synopsis:
12182 *     String.
12183 
12184 *  Description:
12185 *     This attribute specifies a short-form symbol to be used to
12186 *     represent coordinate values for a particular axis of a
12187 *     Frame. This might be used (e.g.) in algebraic expressions where
12188 *     a full description of the axis would be inappropriate. Examples
12189 *     include "RA" and "Dec" (for Right Ascension and Declination).
12190 *
12191 *     If a Symbol value has not been set for a Frame axis, then a
12192 *     suitable default is supplied.
12193 
12194 *  Applicability:
12195 *     Frame
12196 *        The default Symbol value supplied by the Frame class is the
12197 *        string "<Domain><n>", where <n> is 1, 2, etc. for successive
12198 *        axes, and <Domain> is the value of the Frame's Domain
12199 *        attribute (truncated if necessary so that the final string
12200 *        does not exceed 15 characters). If no Domain value has been
12201 *        set, "x" is used as the <Domain> value in constructing this
12202 *        default string.
12203 *     SkyFrame
12204 *        The SkyFrame class re-defines the default Symbol value
12205 *        (e.g. to "RA" or "Dec") as appropriate for the particular
12206 *        celestial coordinate system being represented.
12207 *     TimeFrame
12208 *        The TimeFrame class re-defines the default Symbol value as
12209 *        appropriate for the particular time system being represented.
12210 *     FrameSet
12211 *        The Symbol attribute of a FrameSet axis is the same as that
12212 *        of its current Frame (as specified by the Current attribute).
12213 
12214 *  Notes:
12215 *     - When specifying this attribute by name, it should be
12216 *     subscripted with the number of the Frame axis to which it
12217 *     applies.
12218 *att--
12219 */
12220 /* This provides an interface to the Axis methods for accessing the
12221    Symbol string, but provides an alternative default Symbol based on
12222    the axis number and the Frame's Domain (if defined, otherwise "x"
12223    is used). This default string is written to the static
12224    "symbol_buff" buffer and a pointer to this is returned if
12225    required. */
12226 MAKE_CLEAR(Symbol)
12227 MAKE_GET(Symbol,const char *,NULL,1,GetDefaultSymbol( this, axis, status ) )
12228 MAKE_SET(Symbol,const char *)
12229 MAKE_TEST(Symbol)
12230 
12231 /*
12232 *att++
12233 *  Name:
12234 *     Unit(axis)
12235 
12236 *  Purpose:
12237 *     Axis physical units.
12238 
12239 *  Type:
12240 *     Public attribute.
12241 
12242 *  Synopsis:
12243 *     String.
12244 
12245 *  Description:
12246 *     This attribute contains a textual representation of the physical
12247 *     units used to represent coordinate values on a particular axis
12248 c     of a Frame. The astSetActiveUnit function controls how the Unit values
12249 f     of a Frame. The AST_SETACTIVEUNIT routine controls how the Unit values
12250 *     are used.
12251 
12252 *  Applicability:
12253 *     Frame
12254 *        The default supplied by the Frame class is an empty string.
12255 *     SkyFrame
12256 *        The SkyFrame class re-defines the default Unit value (e.g. to
12257 *        "hh:mm:ss.sss") to describe the character string returned by
12258 c        the astFormat function when formatting coordinate values.
12259 f        the AST_FORMAT function when formatting coordinate values.
12260 *     SpecFrame
12261 *        The SpecFrame class re-defines the default Unit value so that it
12262 *        is appropriate for the current System value. See the System
12263 *        attribute for details. An error will be reported if an attempt
12264 *        is made to use an inappropriate Unit.
12265 *     TimeFrame
12266 *        The TimeFrame class re-defines the default Unit value so that it
12267 *        is appropriate for the current System value. See the System
12268 *        attribute for details. An error will be reported if an attempt
12269 *        is made to use an inappropriate Unit (e.g. "km").
12270 *     FrameSet
12271 *        The Unit attribute of a FrameSet axis is the same as that of
12272 *        its current Frame (as specified by the Current attribute).
12273 
12274 *  Notes:
12275 *     - When specifying this attribute by name, it should be
12276 *     subscripted with the number of the Frame axis to which it
12277 *     applies.
12278 *att--
12279 */
12280 /* This simply provides an interface to the Axis methods for accessing
12281    the Unit string. */
12282 MAKE_GET(Unit,const char *,NULL,0,0)
12283 MAKE_TEST(Unit)
12284 
12285 /*
12286 *att++
12287 *  Name:
12288 *     NormUnit(axis)
12289 
12290 *  Purpose:
12291 *     Normalised Axis physical units.
12292 
12293 *  Type:
12294 *     Public attribute.
12295 
12296 *  Synopsis:
12297 *     String, read-only.
12298 
12299 *  Description:
12300 *     The value of this read-only attribute is derived from the current
12301 *     value of the Unit attribute. It will represent an equivalent system
12302 *     of units to the Unit attribute, but will potentially be simplified.
12303 *     For instance, if Unit is set to "s*(m/s)", the NormUnit value will
12304 *     be "m". If no simplification can be performed, the value of the
12305 *     NormUnit attribute will equal that of the Unit attribute.
12306 
12307 *  Applicability:
12308 *     Frame
12309 *        All Frames have this attribute.
12310 
12311 *  Notes:
12312 *     - When specifying this attribute by name, it should be
12313 *     subscripted with the number of the Frame axis to which it
12314 *     applies.
12315 *att--
12316 */
12317 /* This simply provides an interface to the Axis methods for accessing
12318    the Unit string. */
12319 MAKE_GET(NormUnit,const char *,NULL,0,0)
12320 
12321 /* Implement member functions to access the attributes associated with
12322    the Frame as a whole using the macros defined for this purpose in
12323    the "object.h" file. */
12324 
12325 /*
12326 *att++
12327 *  Name:
12328 *     Digits/Digits(axis)
12329 
12330 *  Purpose:
12331 *     Number of digits of precision.
12332 
12333 *  Type:
12334 *     Public attribute.
12335 
12336 *  Synopsis:
12337 *     Integer.
12338 
12339 *  Description:
12340 *     This attribute specifies how many digits of precision are
12341 *     required by default when a coordinate value is formatted for a
12342 c     Frame axis (e.g. using astFormat). Its value may be set either
12343 f     Frame axis (e.g. using AST_FORMAT). Its value may be set either
12344 *     for a Frame as a whole, or (by subscripting the attribute name
12345 *     with the number of an axis) for each axis individually. Any
12346 *     value set for an individual axis will over-ride the value for
12347 *     the Frame as a whole.
12348 *
12349 *     Note that the Digits value acts only as a means of determining a
12350 *     default Format string. Its effects are over-ridden if a Format
12351 *     string is set explicitly for an axis. However, if the Format
12352 *     attribute specifies the precision using the string ".*", then
12353 *     the Digits attribute is used to determine the number of decimal
12354 *     places to produce.
12355 
12356 *  Applicability:
12357 *     Frame
12358 *        The default Digits value supplied by the Frame class is 7. If
12359 *        a value less than 1 is supplied, then 1 is used instead.
12360 *     FrameSet
12361 *        The Digits attribute of a FrameSet (or one of its axes) is
12362 *        the same as that of its current Frame (as specified by the
12363 *        Current attribute).
12364 *     Plot
12365 *        The default Digits value used by the Plot class when drawing
12366 *        annotated axis labels is the smallest value which results in all
12367 *        adjacent labels being distinct.
12368 *     TimeFrame
12369 *        The Digits attribute is ignored when a TimeFrame formats a value
12370 *        as a date and time string (see the Format attribute).
12371 *att--
12372 */
12373 /* Clear the Digits value by setting it to -INT_MAX. */
12374 astMAKE_CLEAR(Frame,Digits,digits,-INT_MAX)
12375 
12376 /* Supply a default of 7 digits if no value has been set. */
12377 astMAKE_GET(Frame,Digits,int,0,( ( this->digits != -INT_MAX ) ? this->digits :
12378                                                                 7 ))
12379 
12380 /* Constrain the Digits value being set to be at least 1. */
12381 astMAKE_SET(Frame,Digits,int,digits,( value > 1 ? value : 1 ))
12382 
12383 /* The Digits value is set if it is not -INT_MAX. */
12384 astMAKE_TEST(Frame,Digits,( this->digits != -INT_MAX ))
12385 
12386 /*
12387 *att++
12388 *  Name:
12389 *     MatchEnd
12390 
12391 *  Purpose:
12392 *     Match trailing axes?
12393 
12394 *  Type:
12395 *     Public attribute.
12396 
12397 *  Synopsis:
12398 *     Integer (boolean).
12399 
12400 *  Description:
12401 *     This attribute is a boolean value which controls how a Frame
12402 c     behaves when it is used (by astFindFrame) as a template to match
12403 f     behaves when it is used (by AST_FINDFRAME) as a template to match
12404 *     another (target) Frame. It applies only in the case where a
12405 *     match occurs between template and target Frames with different
12406 *     numbers of axes.
12407 *
12408 *     If the MatchEnd value of the template Frame is zero, then the
12409 *     axes which occur first in the target Frame will be matched and
12410 *     any trailing axes (in either the target or template) will be
12411 *     disregarded. If it is non-zero, the final axes in each Frame
12412 *     will be matched and any un-matched leading axes will be
12413 *     disregarded instead.
12414 
12415 *  Applicability:
12416 *     Frame
12417 *        The default MatchEnd value for a Frame is zero, so that
12418 *        trailing axes are disregarded.
12419 *     FrameSet
12420 *        The MatchEnd attribute of a FrameSet is the same as that of
12421 *        its current Frame (as specified by the Current attribute).
12422 *att--
12423 */
12424 /* Clear the MatchEnd value by setting it to -INT_MAX. */
12425 astMAKE_CLEAR(Frame,MatchEnd,match_end,-INT_MAX)
12426 
12427 /* Supply a default of 0 if no MatchEnd value has been set. */
12428 astMAKE_GET(Frame,MatchEnd,int,0,( ( this->match_end != -INT_MAX ) ?
12429                                    this->match_end : 0 ))
12430 
12431 /* Set a MatchEnd value of 1 if any non-zero value is supplied. */
12432 astMAKE_SET(Frame,MatchEnd,int,match_end,( value != 0 ))
12433 
12434 /* The MatchEnd value is set if it is not -INT_MAX. */
12435 astMAKE_TEST(Frame,MatchEnd,( this->match_end != -INT_MAX ))
12436 
12437 /*
12438 *att++
12439 *  Name:
12440 *     MaxAxes
12441 
12442 *  Purpose:
12443 *     Maximum number of Frame axes to match.
12444 
12445 *  Type:
12446 *     Public attribute.
12447 
12448 *  Synopsis:
12449 *     Integer.
12450 
12451 *  Description:
12452 *     This attribute controls how a Frame behaves when it is used (by
12453 c     astFindFrame) as a template to match another (target) Frame. It
12454 f     AST_FINDFRAME) as a template to match another (target) Frame. It
12455 *     specifies the maximum number of axes that the target Frame may
12456 *     have in order to match the template.
12457 *
12458 *     Normally, this value will equal the number of Frame axes, so
12459 *     that a template Frame will only match another Frame with the
12460 *     same number of axes as itself. By setting a different value,
12461 *     however, the matching process may be used to identify Frames
12462 *     with specified numbers of axes.
12463 
12464 *  Applicability:
12465 *     Frame
12466 *        The default MaxAxes value for a Frame is equal to the number
12467 *        of Frame axes (Naxes attribute).
12468 *     CmpFrame
12469 *        The MaxAxes attribute of a CmpFrame defaults to a large number
12470 *        (1000000) which is much larger than any likely number of axes in
12471 *        a Frame. Combined with the MinAxes default of zero (for a
12472 *        CmpFrame), this means that the default behaviour for a CmpFrame
12473 *        is to match any target Frame that consists of a subset of the
12474 *        axes in the template CmpFrame. To change this so that a CmpFrame
12475 *        will only match Frames that have the same number of axes, you
12476 *        should set the CmpFrame MaxAxes and MinAxes attributes to the
12477 *        number of axes in the CmpFrame.
12478 *     FrameSet
12479 *        The MaxAxes attribute of a FrameSet is the same as that of
12480 *        its current Frame (as specified by the Current attribute).
12481 
12482 *  Notes:
12483 *     - When setting a MaxAxes value, the value of the MinAxes
12484 *     attribute may also be silently changed so that it remains
12485 *     consistent with (i.e. does not exceed) the new value. The
12486 *     default MaxAxes value may also be reduced to remain consistent
12487 *     with the MinAxes value.
12488 *     - If a template Frame is used to match a target with a different
12489 *     number of axes, the MatchEnd attribute of the template is used
12490 *     to determine how the individual axes of each Frame should match.
12491 *att--
12492 */
12493 /* Clear the MaxAxes value by setting it to -INT_MAX. */
12494 astMAKE_CLEAR(Frame,MaxAxes,max_axes,-INT_MAX)
12495 
12496 /* Use the DefaultMaxAxes and ConsistentMaxAxes functions (defined earlier) for
12497    the Get and Set operations to ensure that MinAxes and MaxAxes values remain
12498    consistent. */
12499 astMAKE_GET(Frame,MaxAxes,int,0,DefaultMaxAxes( this, status ))
12500 astMAKE_SET(Frame,MaxAxes,int,max_axes,ConsistentMaxAxes( this, value, status ))
12501 
12502 /* The MaxAxes value is set if it is not -INT_MAX. */
12503 astMAKE_TEST(Frame,MaxAxes,( this->max_axes != -INT_MAX ))
12504 
12505 /*
12506 *att++
12507 *  Name:
12508 *     MinAxes
12509 
12510 *  Purpose:
12511 *     Minimum number of Frame axes to match.
12512 
12513 *  Type:
12514 *     Public attribute.
12515 
12516 *  Synopsis:
12517 *     Integer.
12518 
12519 *  Description:
12520 *     This attribute controls how a Frame behaves when it is used (by
12521 c     astFindFrame) as a template to match another (target) Frame. It
12522 f     AST_FINDFRAME) as a template to match another (target) Frame. It
12523 *     specifies the minimum number of axes that the target Frame may
12524 *     have in order to match the template.
12525 *
12526 *     Normally, this value will equal the number of Frame axes, so
12527 *     that a template Frame will only match another Frame with the
12528 *     same number of axes as itself. By setting a different value,
12529 *     however, the matching process may be used to identify Frames
12530 *     with specified numbers of axes.
12531 
12532 *  Applicability:
12533 *     Frame
12534 *        The default MinAxes value for a Frame is equal to the number
12535 *        of Frame axes (Naxes attribute).
12536 *     CmpFrame
12537 *        The MinAxes attribute of a CmpFrame defaults to zero. Combined
12538 *        with the MaxAxes default of 1000000 (for a CmpFrame), this means
12539 *        that the default behaviour for a CmpFrame is to match any target
12540 *        Frame that consists of a subset of the axes in the template
12541 *        CmpFrame. To change this so that a CmpFrame will only match Frames
12542 *        that have the same number of axes, you should set the CmpFrame
12543 *        MinAxes and MaxAxes attributes to the number of axes in the CmpFrame.
12544 *     FrameSet
12545 *        The MinAxes attribute of a FrameSet is the same as that of
12546 *        its current Frame (as specified by the Current attribute).
12547 
12548 *  Notes:
12549 *     - When setting a MinAxes value, the value of the MaxAxes
12550 *     attribute may also be silently changed so that it remains
12551 *     consistent with (i.e. is not less than) the new value. The
12552 *     default MinAxes value may also be reduced to remain consistent
12553 *     with the MaxAxes value.
12554 *     - If a template Frame is used to match a target with a different
12555 *     number of axes, the MatchEnd attribute of the template is used
12556 *     to determine how the individual axes of each Frame should match.
12557 *att--
12558 */
12559 /* Clear the MinAxes value by setting it to -INT_MAX. */
12560 astMAKE_CLEAR(Frame,MinAxes,min_axes,-INT_MAX)
12561 
12562 /* Use the DefaultMinAxes and ConsistentMinAxes functions (defined earlier) for
12563    the Get and Set operations to ensure that MinAxes and MaxAxes values remain
12564    consistent. */
12565 astMAKE_GET(Frame,MinAxes,int,0,DefaultMinAxes( this, status ))
12566 astMAKE_SET(Frame,MinAxes,int,min_axes,ConsistentMinAxes( this, value, status ))
12567 
12568 /* The MinAxes value is set if it is not -INT_MAX. */
12569 astMAKE_TEST(Frame,MinAxes,( this->min_axes != -INT_MAX ))
12570 
12571 /*
12572 *att++
12573 *  Name:
12574 *     Domain
12575 
12576 *  Purpose:
12577 *     Coordinate system domain.
12578 
12579 *  Type:
12580 *     Public attribute.
12581 
12582 *  Synopsis:
12583 *     String.
12584 
12585 *  Description:
12586 *     This attribute contains a string which identifies the physical
12587 *     domain of the coordinate system that a Frame describes.
12588 *
12589 *     The Domain attribute also controls how a Frame behaves when it is
12590 c     used (by astFindFrame) as a template to match another (target)
12591 f     used (by AST_FINDFRAME) as a template to match another (target)
12592 *     Frame. It does this by specifying the Domain that the target
12593 *     Frame should have in order to match the template. If the Domain
12594 *     value in the template Frame is set, then only targets with the
12595 *     same Domain value will be matched. If the template's Domain
12596 *     value is not set, however, then the target's Domain will be
12597 *     ignored.
12598 
12599 *  Applicability:
12600 *     Frame
12601 *        The default Domain value supplied by the Frame class is an
12602 *        empty string.
12603 *     SkyFrame
12604 *        The SkyFrame class re-defines the default Domain value to be
12605 *        "SKY".
12606 *     CmpFrame
12607 *        The CmpFrame class re-defines the default Domain value to be
12608 *        of the form "<dom1>-<dom2>", where <dom1> and <dom2> are the
12609 *        Domains of the two component Frames. If both these Domains are
12610 *        blank, then the string "CMP" is used as the default Domain name.
12611 *     FrameSet
12612 *        The Domain attribute of a FrameSet is the same as that of its
12613 *        current Frame (as specified by the Current attribute).
12614 *     SpecFrame
12615 *        The SpecFrame class re-defines the default Domain value to be
12616 *        "SPECTRUM".
12617 *     DSBSpecFrame
12618 *        The DSBSpecFrame class re-defines the default Domain value to be
12619 *        "DSBSPECTRUM".
12620 *     FluxFrame
12621 *        The FluxFrame class re-defines the default Domain value to be
12622 *        "FLUX".
12623 *     SpecFluxFrame
12624 *        The FluxFrame class re-defines the default Domain value to be
12625 *        "SPECTRUM-FLUX".
12626 *     TimeFrame
12627 *        The TimeFrame class re-defines the default Domain value to be
12628 *        "TIME".
12629 
12630 *  Notes:
12631 *     - All Domain values are converted to upper case and white space
12632 *     is removed before use.
12633 *att--
12634 */
12635 /* Clear the Domain value by freeing the allocated memory and
12636    assigning a NULL pointer. */
12637 astMAKE_CLEAR(Frame,Domain,domain,astFree( this->domain ))
12638 
12639 /* If the Domain value is not set, supply a default in the form of a
12640    pointer to the constant string "". */
12641 astMAKE_GET(Frame,Domain,const char *,NULL,( this->domain ? this->domain :
12642                                                             "" ))
12643 
12644 /* Set a Domain value by freeing any previously allocated memory,
12645    allocating new memory, storing the string, removing white space,
12646    converting to upper case and saving the pointer to the cleaned
12647    copy. */
12648 astMAKE_SET(Frame,Domain,const char *,domain,CleanDomain(
12649                                                 astStore( this->domain,
12650                                     value, strlen( value ) + (size_t) 1 ), status ))
12651 
12652 /* The Domain value is set if the pointer to it is not NULL. */
12653 astMAKE_TEST(Frame,Domain,( this->domain != NULL ))
12654 
12655 /*
12656 *att++
12657 *  Name:
12658 *     Permute
12659 
12660 *  Purpose:
12661 *     Permute axis order?
12662 
12663 *  Type:
12664 *     Public attribute.
12665 
12666 *  Synopsis:
12667 *     String.
12668 
12669 *  Description:
12670 *     This attribute is a boolean value which controls how a Frame
12671 c     behaves when it is used (by astFindFrame) as a template to match
12672 f     behaves when it is used (by AST_FINDFRAME) as a template to match
12673 *     another (target) Frame. It specifies whether the axis order of
12674 *     the target Frame may be permuted in order to obtain a match.
12675 *
12676 *     If the template's Permute value is zero, it will match a target
12677 *     only if it can do so without changing the order of its
12678 *     axes. Otherwise, it will attempt to permute the target's axes as
12679 *     necessary.
12680 *
12681 *     The default value is 1, so that axis permutation will be attempted.
12682 
12683 *  Applicability:
12684 *     Frame
12685 *        All Frames have this attribute. However, the Frame class
12686 *        effectively ignores this attribute and behaves as if it has
12687 *        the value 1. This is because the axes of a basic Frame are
12688 *        not distinguishable and will always match any other Frame
12689 *        whatever their order.
12690 *     SkyFrame
12691 *        Unlike a basic Frame, the SkyFrame class makes use of this
12692 *        attribute.
12693 *     FrameSet
12694 *        The Permute attribute of a FrameSet is the same as that of
12695 *        its current Frame (as specified by the Current attribute).
12696 *att--
12697 */
12698 /* Clear the Permute value by setting it to -INT_MAX. */
12699 astMAKE_CLEAR(Frame,Permute,permute,-INT_MAX)
12700 
12701 /* Supply a default of 1 if no Permute value has been set. */
12702 astMAKE_GET(Frame,Permute,int,0,( ( this->permute != -INT_MAX ) ?
12703                                   this->permute : 1 ))
12704 
12705 /* Set a Permute value of 1 if any non-zero value is supplied. */
12706 astMAKE_SET(Frame,Permute,int,permute,( value != 0 ))
12707 
12708 /* The Permute value is set if it is not -INT_MAX. */
12709 astMAKE_TEST(Frame,Permute,( this->permute != -INT_MAX ))
12710 
12711 /*
12712 *att++
12713 *  Name:
12714 *     PreserveAxes
12715 
12716 *  Purpose:
12717 *     Preserve axes?
12718 
12719 *  Type:
12720 *     Public attribute.
12721 
12722 *  Synopsis:
12723 *     Integer (boolean).
12724 
12725 *  Description:
12726 *     This attribute controls how a Frame behaves when it is used (by
12727 c     astFindFrame) as a template to match another (target) Frame. It
12728 f     AST_FINDFRAME) as a template to match another (target) Frame. It
12729 *     determines which axes appear (and in what order) in the "result"
12730 *     Frame produced.
12731 *
12732 *     If PreserveAxes is zero in the template Frame, then the result
12733 *     Frame will have the same number (and order) of axes as the
12734 *     template. If it is non-zero, however, the axes of the target
12735 *     Frame will be preserved, so that the result Frame will have the
12736 *     same number (and order) of axes as the target.
12737 *
12738 *     The default value is zero, so that target axes are not preserved
12739 *     and the result Frame resembles the template.
12740 
12741 *  Applicability:
12742 *     Frame
12743 *        All Frames have this attribute.
12744 *     FrameSet
12745 *        The PreserveAxes attribute of a FrameSet is the same as that
12746 *        of its current Frame (as specified by the Current attribute).
12747 *att--
12748 */
12749 /* Clear the PreserveAxes value by setting it to -INT_MAX. */
12750 astMAKE_CLEAR(Frame,PreserveAxes,preserve_axes,-INT_MAX)
12751 
12752 /* Supply a default of 0 if no PreserveAxes value has been set. */
12753 astMAKE_GET(Frame,PreserveAxes,int,0,( ( this->preserve_axes != -INT_MAX ) ?
12754                                        this->preserve_axes : 0 ))
12755 
12756 /* Set a PreserveAxes value of 1 if any non-zero value is supplied. */
12757 astMAKE_SET(Frame,PreserveAxes,int,preserve_axes,( value != 0 ))
12758 
12759 /* The PreserveAxes value is set if it is not -INT_MAX. */
12760 astMAKE_TEST(Frame,PreserveAxes,( this->preserve_axes != -INT_MAX ))
12761 
12762 /*
12763 *att++
12764 *  Name:
12765 *     AlignSystem
12766 
12767 *  Purpose:
12768 *     Coordinate system in which to align the Frame.
12769 
12770 *  Type:
12771 *     Public attribute.
12772 
12773 *  Synopsis:
12774 *     String.
12775 
12776 *  Description:
12777 *     This attribute controls how a Frame behaves when it is used (by
12778 c     astFindFrame or astConvert) as a template to match another (target)
12779 f     AST_FINDFRAME or AST_CONVERT) as a template to match another (target)
12780 *     Frame. It identifies the coordinate system in which the two Frames
12781 *     will be aligned by the match.
12782 *
12783 *     The values which may be assigned to this attribute, and its default
12784 *     value, depend on the class of Frame and are described in the
12785 *     "Applicability" section below. In general, the AlignSystem attribute
12786 *     will accept any of the values which may be assigned to the System
12787 *     attribute.
12788 *
12789 c     The Mapping returned by AST_FINDFRAME or AST_CONVERT will use the
12790 f     The Mapping returned by astFindFrame or astConvert will use the
12791 *     coordinate system specified by the AlignSystem attribute as an
12792 *     intermediate coordinate system. The total returned Mapping will first
12793 *     map positions from the first Frame into this intermediate coordinate
12794 *     system, using the attributes of the first Frame. It will then map
12795 *     these positions from the intermediate coordinate system into the
12796 *     second Frame, using the attributes of the second Frame.
12797 
12798 *  Applicability:
12799 *     Frame
12800 *        The AlignSystem attribute for a basic Frame always equals "Cartesian",
12801 *        and may not be altered.
12802 *     CmpFrame
12803 *        The AlignSystem attribute for a CmpFrame always equals "Compound",
12804 *        and may not be altered.
12805 *     FrameSet
12806 *        The AlignSystem attribute of a FrameSet is the same as that of its
12807 *        current Frame (as specified by the Current attribute).
12808 *     SkyFrame
12809 *        The default AlignSystem attribute for a SkyFrame is "ICRS".
12810 *     SpecFrame
12811 *        The default AlignSystem attribute for a SpecFrame is "Wave"
12812 *        (wavelength).
12813 *     TimeFrame
12814 *        The default AlignSystem attribute for a TimeFrame is "MJD".
12815 *att--
12816 */
12817 /* Clear the AlignSystem value by setting it to AST__BADSYSTEM. */
12818 astMAKE_CLEAR(Frame,AlignSystem,alignsystem,AST__BADSYSTEM)
12819 
12820 /* Provide a default AlignSystem of AST__CART. */
12821 astMAKE_GET(Frame,AlignSystem,AstSystemType,AST__BADSYSTEM,(
12822             ( this->alignsystem == AST__BADSYSTEM ) ? AST__CART : this->alignsystem ) )
12823 
12824 /* Validate the AlignSystem value being set and retain the original if the
12825    supplied value is not recognized. */
12826 astMAKE_SET(Frame,AlignSystem,AstSystemType,alignsystem,(
12827            (astValidateSystem( this, value, "astSetAlignSystem" ) != AST__BADSYSTEM) ?
12828             value : this->alignsystem ))
12829 
12830 /* The AlignSystem value is set if it is not AST__BADSYSTEM. */
12831 astMAKE_TEST(Frame,AlignSystem,( this->alignsystem != AST__BADSYSTEM ))
12832 
12833 /*
12834 *att++
12835 *  Name:
12836 *     System
12837 
12838 *  Purpose:
12839 *     Coordinate system used to describe positions within the domain
12840 
12841 *  Type:
12842 *     Public attribute.
12843 
12844 *  Synopsis:
12845 *     String.
12846 
12847 *  Description:
12848 *     In general it is possible for positions within a given physical
12849 *     domain to be described using one of several different coordinate
12850 *     systems. For instance, the SkyFrame class can use galactic
12851 *     coordinates, equatorial coordinates, etc, to describe positions on
12852 *     the sky. As another example, the SpecFrame class can use frequency,
12853 *     wavelength, velocity, etc, to describe a position within an
12854 *     electromagnetic spectrum. The System attribute identifies the particular
12855 *     coordinate system represented by a Frame. Each class of Frame
12856 *     defines a set of acceptable values for this attribute, as listed
12857 *     below (all are case insensitive). Where more than one alternative
12858 *     System value is shown, the first of will be returned when an
12859 *     enquiry is made.
12860 
12861 *  Applicability:
12862 *     Frame
12863 *        The System attribute for a basic Frame always equals "Cartesian",
12864 *        and may not be altered.
12865 *     CmpFrame
12866 *        The System attribute for a CmpFrame always equals "Compound",
12867 *        and may not be altered. In addition, the CmpFrame class allows
12868 *        the System attribute to be referenced for a component Frame by
12869 *        including the index of an axis within the required component
12870 *        Frame. For instance, "System(3)" refers to the System attribute
12871 *        of the component Frame which includes axis 3 of the CmpFrame.
12872 *     FrameSet
12873 *        The System attribute of a FrameSet is the same as that of its
12874 *        current Frame (as specified by the Current attribute).
12875 *     SkyFrame
12876 *        The SkyFrame class supports the following System values and
12877 *        associated celestial coordinate systems:
12878 *
12879 *        - "AZEL": Horizon coordinates. The longitude axis is azimuth
12880 *        such that geographic north has an azimuth of zero and geographic
12881 *        east has an azimuth of +PI/2 radians. The zenith has elevation
12882 *        +PI/2. When converting to and from other celestial coordinate
12883 *        systems, no corrections are applied for atmospheric refraction
12884 *        or polar motion (however, a correction for diurnal aberattion is
12885 *        applied). Note, unlike most other
12886 *        celestial coordinate systems, this system is right handed. Also,
12887 *        unlike other SkyFrame systems, the AzEl system is sensitive to
12888 *        the timescale in which the Epoch value is supplied. This is
12889 *        because of the gross diurnal rotation which this system undergoes,
12890 *        causing a small change in time to translate to a large rotation.
12891 *        When converting to or from an AzEl system, the Epoch value for
12892 *        both source and destination SkyFrames should be supplied in the
12893 *        TDB timescale. The difference between TDB and TT is between 1
12894 *        and 2 milliseconds, and so a TT value can usually be supplied in
12895 *        place of a TDB value. The TT timescale is related to TAI via
12896 *        TT = TAI + 32.184 seconds.
12897 *
12898 *        - "ECLIPTIC": Ecliptic coordinates (IAU 1980), referred to the
12899 *        ecliptic and mean equinox specified by the qualifying Equinox
12900 *        value.
12901 *
12902 *        - "FK4": The old FK4 (barycentric) equatorial coordinate system,
12903 *        which should be qualified by an Equinox value. The underlying
12904 *        model on which this is based is non-inertial and rotates slowly
12905 *        with time, so for accurate work FK4 coordinate systems should
12906 *        also be qualified by an Epoch value.
12907 *
12908 *        - "FK4-NO-E" or "FK4_NO_E": The old FK4 (barycentric) equatorial
12909 *        system but without the "E-terms of aberration" (e.g. some radio
12910 *        catalogues). This coordinate system should also be qualified by
12911 *        both an Equinox and an Epoch value.
12912 *
12913 *        - "FK5" or "EQUATORIAL": The modern FK5 (barycentric) equatorial
12914 *        coordinate system. This should be qualified by an Equinox value.
12915 *
12916 *        - "GALACTIC": Galactic coordinates (IAU 1958).
12917 *
12918 *        - "GAPPT", "GEOCENTRIC" or "APPARENT": The geocentric apparent
12919 *        equatorial coordinate system, which gives the apparent positions
12920 *        of sources relative to the true plane of the Earth's equator and
12921 *        the equinox (the coordinate origin) at a time specified by the
12922 *        qualifying Epoch value. (Note that no Equinox is needed to
12923 *        qualify this coordinate system because no model "mean equinox"
12924 *        is involved.)  These coordinates give the apparent right
12925 *        ascension and declination of a source for a specified date of
12926 *        observation, and therefore form an approximate basis for
12927 *        pointing a telescope. Note, however, that they are applicable to
12928 *        a fictitious observer at the Earth's centre, and therefore
12929 *        ignore such effects as atmospheric refraction and the (normally
12930 *        much smaller) aberration of light due to the rotational velocity
12931 *        of the Earth's surface.  Geocentric apparent coordinates are
12932 *        derived from the standard FK5 (J2000.0) barycentric coordinates
12933 *        by taking account of the gravitational deflection of light by
12934 *        the Sun (usually small), the aberration of light caused by the
12935 *        motion of the Earth's centre with respect to the barycentre
12936 *        (larger), and the precession and nutation of the Earth's spin
12937 *        axis (normally larger still).
12938 *
12939 *        - "HELIOECLIPTIC": Ecliptic coordinates (IAU 1980), referred to the
12940 *        ecliptic and mean equinox of J2000.0, in which an offset is added to
12941 *        the longitude value which results in the centre of the sun being at
12942 *        zero longitude at the date given by the Epoch attribute. Attempts to
12943 *        set a value for the Equinox attribute will be ignored, since this
12944 *        system is always referred to J2000.0.
12945 *
12946 *        - "ICRS": The Internation Celestial Reference System, realised
12947 *        through the Hipparcos catalogue. Whilst not an equatorial system
12948 *        by definition, the ICRS is very close to the FK5 (J2000) system
12949 *        and is usually treated as an equatorial system. The distinction
12950 *        between ICRS and FK5 (J2000) only becomes important when accuracies
12951 *        of 50 milli-arcseconds or better are required. ICRS need not be
12952 *        qualified by an Equinox value.
12953 *
12954 *        - "J2000": An equatorial coordinate system based on the mean
12955 *        dynamical equator and equinox of the J2000 epoch. The dynamical
12956 *        equator and equinox differ slightly from those used by the FK5
12957 *        model, and so a "J2000" SkyFrame will differ slightly from an
12958 *        "FK5(Equinox=J2000)" SkyFrame. The J2000 System need not be
12959 *        qualified by an Equinox value
12960 *
12961 *        - "SUPERGALACTIC": De Vaucouleurs Supergalactic coordinates.
12962 *
12963 *        - "UNKNOWN": Any other general spherical coordinate system. No
12964 *        Mapping can be created between a pair of SkyFrames if either of the
12965 *        SkyFrames has System set to "Unknown".
12966 *
12967 *        Currently, the default System value is "ICRS". However, this
12968 *        default may change in future as new astrometric standards
12969 *        evolve. The intention is to track the most modern appropriate
12970 *        standard. For this reason, you should use the default only if
12971 *        this is what you intend (and can tolerate any associated slight
12972 *        change in future). If you intend to use the ICRS system
12973 *        indefinitely, then you should specify it explicitly.
12974 *     SpecFrame
12975 *        The SpecFrame class supports the following System values and
12976 *        associated spectral coordinate systems (the default is "WAVE" -
12977 *        wavelength). They are all defined in FITS-WCS paper III:
12978 *
12979 *        - "FREQ": Frequency (GHz)
12980 *        - "ENER" or "ENERGY": Energy (J)
12981 *        - "WAVN" or "WAVENUM": Wave-number (1/m)
12982 *        - "WAVE" or "WAVELEN": Vacuum wave-length (Angstrom)
12983 *        - "AWAV" or "AIRWAVE": Wave-length in air (Angstrom)
12984 *        - "VRAD" or "VRADIO": Radio velocity (km/s)
12985 *        - "VOPT" or "VOPTICAL": Optical velocity (km/s)
12986 *        - "ZOPT" or "REDSHIFT": Redshift (dimensionless)
12987 *        - "BETA": Beta factor (dimensionless)
12988 *        - "VELO" or "VREL": Apparent radial ("relativistic") velocity (km/s)
12989 *
12990 *        The default value for the Unit attribute for each system is shown
12991 *        in parentheses. Note that the default value for the ActiveUnit flag
12992 c        is non-zero
12993 f        is .TRUE.
12994 *        for a SpecFrame, meaning that changes to the Unit attribute for
12995 *        a SpecFrame will result in the SpecFrame being re-mapped within
12996 *        its enclosing FrameSet in order to reflect the change in units
12997 c        (see astSetActiveUnit function for further information).
12998 f        (see AST_SETACTIVEUNIT routine for further information).
12999 *     TimeFrame
13000 *        The TimeFrame class supports the following System values and
13001 *        associated coordinate systems (the default is "MJD"):
13002 *
13003 *        - "MJD": Modified Julian Date (d)
13004 *        - "JD": Julian Date (d)
13005 *        - "JEPOCH": Julian epoch (yr)
13006 *        - "BEPOCH": Besselian (yr)
13007 *
13008 *        The default value for the Unit attribute for each system is shown
13009 *        in parentheses. Strictly, these systems should not allow changes
13010 *        to be made to the units. For instance, the usual definition of
13011 *        "MJD" and "JD" include the statement that the values will be in
13012 *        units of days. However, AST does allow the use of other units
13013 *        with all the above supported systems (except BEPOCH), on the
13014 *        understanding that conversion to the "correct" units involves
13015 *        nothing more than a simple scaling (1 yr = 365.25 d, 1 d = 24 h,
13016 *        1 h = 60 min, 1 min = 60 s). Besselian epoch values are defined
13017 *        in terms of tropical years of 365.2422 days, rather than the
13018 *        usual Julian year of 365.25 days. Therefore, to avoid any
13019 *        confusion, the Unit attribute is automatically cleared to "yr" when
13020 *        a System value of BEPOCH System is selected, and an error is
13021 *        reported if any attempt is subsequently made to change the Unit
13022 *        attribute.
13023 *
13024 *        Note that the default value for the ActiveUnit flag
13025 c        is non-zero
13026 f        is .TRUE.
13027 *        for a TimeFrame, meaning that changes to the Unit attribute for
13028 *        a TimeFrame will result in the TimeFrame being re-mapped within
13029 *        its enclosing FrameSet in order to reflect the change in units
13030 c        (see astSetActiveUnit function for further information).
13031 f        (see AST_SETACTIVEUNIT routine for further information).
13032 *     FluxFrame
13033 *        The FluxFrame class supports the following System values and
13034 *        associated systems for measuring observed value:
13035 *
13036 *        - "FLXDN": Flux per unit frequency (W/m^2/Hz)
13037 *        - "FLXDNW": Flux per unit wavelength (W/m^2/Angstrom)
13038 *        - "SFCBR": Surface brightness in frequency units (W/m^2/Hz/arcmin**2)
13039 *        - "SFCBRW": Surface brightness in wavelength units (W/m^2/Angstrom/arcmin**2)
13040 *
13041 *        The above lists specified the default units for each System. If an
13042 *        explicit value is set for the Unit attribute but no value is set
13043 *        for System, then the default System value is determined by the Unit
13044 *        string (if the units are not appropriate for describing any of the
13045 *        supported Systems then an error will be reported when an attempt is
13046 *        made to access the System value). If no value has been specified for
13047 *        either Unit or System, then System=FLXDN and Unit=W/m^2/Hz are
13048 *        used.
13049 *att--
13050 */
13051 /* Clear the System value by setting it to AST__BADSYSTEM. */
13052 astMAKE_CLEAR(Frame,System,system,AST__BADSYSTEM)
13053 
13054 /* Provide a default coordinate system of AST__CART. */
13055 astMAKE_GET(Frame,System,AstSystemType,AST__BADSYSTEM,(
13056             ( this->system == AST__BADSYSTEM ) ? AST__CART : this->system ) )
13057 
13058 /* Validate the System value being set and retain the original if the
13059    supplied value is not recognized. */
13060 astMAKE_SET(Frame,System,AstSystemType,system,(
13061            (astValidateSystem( this, value, "astSetSystem" ) != AST__BADSYSTEM) ?
13062             value : this->system ))
13063 
13064 /* The System value is set if it is not AST__BADSYSTEM. */
13065 astMAKE_TEST(Frame,System,( this->system != AST__BADSYSTEM ))
13066 
13067 /*
13068 *att++
13069 *  Name:
13070 *     Title
13071 
13072 *  Purpose:
13073 *     Frame title.
13074 
13075 *  Type:
13076 *     Public attribute.
13077 
13078 *  Synopsis:
13079 *     String.
13080 
13081 *  Description:
13082 *     This attribute holds a string which is used as a title in (e.g.)
13083 *     graphical output to describe the coordinate system which a Frame
13084 *     represents. Examples might be "Detector Coordinates" or
13085 *     "Galactic Coordinates".
13086 *
13087 *     If a Title value has not been set for a Frame, then a suitable
13088 *     default is supplied, depending on the class of the Frame.
13089 
13090 *  Applicability:
13091 *     Frame
13092 *        The default supplied by the Frame class is "<n>-d coordinate
13093 *        system", where <n> is the number of Frame axes (Naxes
13094 *        attribute).
13095 *     CmpFrame
13096 *        The CmpFrame class re-defines the default Title value to be
13097 *        "<n>-d compound coordinate system", where <n> is the number
13098 *        of CmpFrame axes (Naxes attribute).
13099 *     FrameSet
13100 *        The Title attribute of a FrameSet is the same as that of its
13101 *        current Frame (as specified by the Current attribute).
13102 
13103 *  Notes:
13104 *     - A Frame's Title is intended purely for interpretation by human
13105 *     readers and not by software.
13106 *att--
13107 */
13108 /* Clear the Title value by freeing the allocated memory and assigning
13109    a NULL pointer. */
13110 astMAKE_CLEAR(Frame,Title,title,astFree( this->title ))
13111 
13112 /* If the Title value is not set, write a default based on the number of Frame
13113    axes into the static "title_buff" buffer, and return a pointer to this
13114    buffer. */
13115 astMAKE_GET(Frame,Title,const char *,NULL,( this->title ?
13116                                             this->title : GetDefaultTitle( this, status ) ))
13117 
13118 /* Set a Title value by freeing any previously allocated memory, allocating
13119    new memory, storing the string and saving the pointer to the copy. */
13120 astMAKE_SET(Frame,Title,const char *,title,astStore( this->title, value,
13121                                            strlen( value ) + (size_t) 1 ))
13122 
13123 /* The Title value is set if the pointer to it is not NULL. */
13124 astMAKE_TEST(Frame,Title,( this->title != NULL ))
13125 
13126 /*
13127 *att++
13128 *  Name:
13129 *     ObsLat
13130 
13131 *  Purpose:
13132 *     The geodetic latitude of the observer
13133 
13134 *  Type:
13135 *     Public attribute.
13136 
13137 *  Synopsis:
13138 *     String.
13139 
13140 *  Description:
13141 *     This attribute specifies the geodetic latitude of the observer, in
13142 *     degrees, relative to the IAU 1976 reference ellipsoid. The basic Frame
13143 *     class makes no use of this attribute, but specialised subclasses of
13144 *     Frame may use it. For instance, the SpecFrame, SkyFrame and TimeFrame
13145 *     classes use it. The default value is zero.
13146 *
13147 *     The value is stored internally in radians, but is converted to and
13148 *     from a degrees string for access. Some example input formats are:
13149 *     "22:19:23.2", "22 19 23.2", "22:19.387", "22.32311", "N22.32311",
13150 *     "-45.6", "S45.6". As indicated, the sign of the latitude can
13151 *     optionally be indicated using characters "N" and "S" in place of the
13152 *     usual "+" and "-". When converting the stored value to a string, the
13153 *     format "[s]dd:mm:ss.ss" is used, when "[s]" is "N" or "S".
13154 
13155 *  Applicability:
13156 *     Frame
13157 *        All Frames have this attribute.
13158 *     SpecFrame
13159 *        Together with the ObsLon, Epoch, RefRA and RefDec attributes,
13160 *        it defines the Doppler shift introduced by the observers diurnal
13161 *        motion around the earths axis, which is needed when converting to
13162 *        or from the topocentric standard of rest. The maximum velocity
13163 *        error which can be caused by an incorrect value is 0.5 km/s. The
13164 *        default value for the attribute is zero.
13165 *     TimeFrame
13166 *        Together with the ObsLon attribute, it is used when converting
13167 *        between certain time scales (TDB, TCB, LMST, LAST)
13168 
13169 *att--
13170 */
13171 /* The geodetic latitude of the observer (radians). Clear the ObsLat value by
13172    setting it to AST__BAD, returning zero as the default value. Any value is
13173    acceptable. */
13174 astMAKE_CLEAR(Frame,ObsLat,obslat,AST__BAD)
13175 astMAKE_GET(Frame,ObsLat,double,0.0,((this->obslat!=AST__BAD)?this->obslat:0.0))
13176 astMAKE_SET(Frame,ObsLat,double,obslat,value)
13177 astMAKE_TEST(Frame,ObsLat,(this->obslat!=AST__BAD))
13178 
13179 
13180 /*
13181 *att++
13182 *  Name:
13183 *     ObsAlt
13184 
13185 *  Purpose:
13186 *     The geodetic altitude of the observer
13187 
13188 *  Type:
13189 *     Public attribute.
13190 
13191 *  Synopsis:
13192 *     String.
13193 
13194 *  Description:
13195 *     This attribute specifies the geodetic altitude of the observer, in
13196 *     metres, relative to the IAU 1976 reference ellipsoid. The basic Frame
13197 *     class makes no use of this attribute, but specialised subclasses of
13198 *     Frame may use it. For instance, the SpecFrame, SkyFrame and TimeFrame
13199 *     classes use it. The default value is zero.
13200 
13201 *  Applicability:
13202 *     Frame
13203 *        All Frames have this attribute.
13204 *     SpecFrame
13205 *        Together with the ObsLon, Epoch, RefRA and RefDec attributes,
13206 *        it defines the Doppler shift introduced by the observers diurnal
13207 *        motion around the earths axis, which is needed when converting to
13208 *        or from the topocentric standard of rest. The maximum velocity
13209 *        error which can be caused by an incorrect value is 0.5 km/s. The
13210 *        default value for the attribute is zero.
13211 *     TimeFrame
13212 *        Together with the ObsLon attribute, it is used when converting
13213 *        between certain time scales (TDB, TCB, LMST, LAST)
13214 
13215 *att--
13216 */
13217 /* The geodetic altitude of the observer (metres). Clear the ObsAlt value by
13218    setting it to AST__BAD, returning zero as the default value. Any value is
13219    acceptable. */
13220 astMAKE_CLEAR(Frame,ObsAlt,obsalt,AST__BAD)
13221 astMAKE_GET(Frame,ObsAlt,double,0.0,((this->obsalt!=AST__BAD)?this->obsalt:0.0))
13222 astMAKE_SET(Frame,ObsAlt,double,obsalt,value)
13223 astMAKE_TEST(Frame,ObsAlt,(this->obsalt!=AST__BAD))
13224 
13225 
13226 /*
13227 *att++
13228 *  Name:
13229 *     ObsLon
13230 
13231 *  Purpose:
13232 *     The geodetic longitude of the observer
13233 
13234 *  Type:
13235 *     Public attribute.
13236 
13237 *  Synopsis:
13238 *     String.
13239 
13240 *  Description:
13241 *     This attribute specifies the geodetic (or equivalently, geocentric)
13242 *     longitude of the observer, in degrees, measured positive eastwards.
13243 *     See also attribute ObsLat. The basic Frame class makes no use of this
13244 *     attribute, but specialised subclasses of Frame may use it. For instance,
13245 *     the SpecFrame, SkyFrame and TimeFrame classes use it. The default value
13246 *     is zero.
13247 *
13248 *     The value is stored internally in radians, but is converted to and
13249 *     from a degrees string for access. Some example input formats are:
13250 *     "155:19:23.2", "155 19 23.2", "155:19.387", "155.32311", "E155.32311",
13251 *     "-204.67689", "W204.67689". As indicated, the sign of the longitude can
13252 *     optionally be indicated using characters "E" and "W" in place of the
13253 *     usual "+" and "-". When converting the stored value to a string, the
13254 *     format "[s]ddd:mm:ss.ss" is used, when "[s]" is "E" or "W" and the
13255 *     numerical value is chosen to be less than 180 degrees.
13256 
13257 *  Applicability:
13258 *     Frame
13259 *        All Frames have this attribute.
13260 *     SpecFrame
13261 *        Together with the ObsLon, Epoch, RefRA and RefDec attributes,
13262 *        it defines the Doppler shift introduced by the observers diurnal
13263 *        motion around the earths axis, which is needed when converting to
13264 *        or from the topocentric standard of rest. The maximum velocity
13265 *        error which can be caused by an incorrect value is 0.5 km/s. The
13266 *        default value for the attribute is zero.
13267 *     TimeFrame
13268 *        Together with the ObsLon attribute, it is used when converting
13269 *        between certain time scales (TDB, TCB, LMST, LAST)
13270 
13271 *att--
13272 */
13273 /* The geodetic longitude of the observer (radians). Clear the ObsLon value by
13274    setting it to AST__BAD, returning zero as the default value. Any value is
13275    acceptable. */
13276 astMAKE_CLEAR(Frame,ObsLon,obslon,AST__BAD)
13277 astMAKE_GET(Frame,ObsLon,double,0.0,((this->obslon!=AST__BAD)?this->obslon:0.0))
13278 astMAKE_SET(Frame,ObsLon,double,obslon,value)
13279 astMAKE_TEST(Frame,ObsLon,(this->obslon!=AST__BAD))
13280 
13281 
13282 /* Copy constructor. */
13283 /* ----------------- */
13284 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
13285 /*
13286 *  Name:
13287 *     Copy
13288 
13289 *  Purpose:
13290 *     Copy constructor for Frame objects.
13291 
13292 *  Type:
13293 *     Private function.
13294 
13295 *  Synopsis:
13296 *     void Copy( const AstObject *objin, AstObject *objout, int *status )
13297 
13298 *  Description:
13299 *     This function implements the copy constructor for Frame objects.
13300 
13301 *  Parameters:
13302 *     objin
13303 *        Pointer to the object to be copied.
13304 *     objout
13305 *        Pointer to the object being constructed.
13306 *     status
13307 *        Pointer to the inherited status variable.
13308 
13309 *  Notes:
13310 *     -  This constructor makes a deep copy.
13311 */
13312 
13313 /* Local Variables: */
13314    AstFrame *in;                 /* Pointer to input Frame */
13315    AstFrame *out;                /* Pointer to output Frame */
13316    int axis;                     /* Loop counter for axes */
13317 
13318 /* Check the global error status. */
13319    if ( !astOK ) return;
13320 
13321 /* Obtain pointers to the input and output Frames. */
13322    in = (AstFrame *) objin;
13323    out = (AstFrame *) objout;
13324 
13325 /* For safety, first clear any references to the input memory from
13326    the output Frame. */
13327    out->axis = NULL;
13328    out->domain = NULL;
13329    out->perm = NULL;
13330    out->title = NULL;
13331    out->variants = NULL;
13332 
13333 /* If necessary, allocate memory in the output Frame and store a copy of the
13334    input Title and Domain strings. */
13335    if ( in->title ) out->title = astStore( NULL, in->title,
13336                                            strlen( in->title ) + (size_t) 1 );
13337    if ( in->domain ) out->domain = astStore( NULL, in->domain,
13338                                              strlen( in->domain ) +
13339                                              (size_t) 1 );
13340 
13341 /* Allocate memory to hold the output Frame's Axis object pointers and its axis
13342    permutation array. */
13343    out->axis = astMalloc( sizeof( AstAxis * ) * (size_t) in->naxes );
13344    out->perm = astMalloc( sizeof( int ) * (size_t) in->naxes );
13345 
13346 /* Make a copy of each of the input Frame's Axis objects, storing the pointer
13347    to each new Axis in the memory just allocated. Also copy the axis
13348    permutation array. */
13349    if ( astOK ) {
13350       for ( axis = 0; axis < in->naxes; axis++ ) {
13351          out->axis[ axis ] = astCopy( in->axis[ axis ] );
13352          out->perm[ axis ] = in->perm[ axis ];
13353       }
13354 
13355 /* If an error occurred while copying the Axis objects, then loop through the
13356    resulting array of pointers and make sure that all of them are properly
13357    annulled. */
13358       if ( !astOK ) {
13359          for ( axis = 0; axis < in->naxes; axis++ ) {
13360             out->axis[ axis ] = astAnnul( out->axis[ axis ] );
13361          }
13362       }
13363    }
13364 
13365 /* Other remaining objects */
13366    if( in->variants ) out->variants = astCopy( in->variants );
13367 
13368 /* If an error occurred, free any allocated memory. */
13369    if ( !astOK ) {
13370       out->axis = astFree( out->axis );
13371       out->domain = astFree( out->domain );
13372       out->perm = astFree( out->perm );
13373       out->title = astFree( out->title );
13374    }
13375 }
13376 
13377 /* Destructor. */
13378 /* ----------- */
Delete(AstObject * obj,int * status)13379 static void Delete( AstObject *obj, int *status ) {
13380 /*
13381 *  Name:
13382 *     Delete
13383 
13384 *  Purpose:
13385 *     Destructor for Frame objects.
13386 
13387 *  Type:
13388 *     Private function.
13389 
13390 *  Synopsis:
13391 *     void Delete( AstObject *obj, int *status )
13392 
13393 *  Description:
13394 *     This function implements the destructor for Frame objects.
13395 
13396 *  Parameters:
13397 *     obj
13398 *        Pointer to the object to be deleted.
13399 *     status
13400 *        Pointer to the inherited status variable.
13401 
13402 *  Notes:
13403 *     This function attempts to execute even if the global error status is
13404 *     set.
13405 */
13406 
13407 /* Local Variables: */
13408    AstFrame *this;               /* Pointer to Frame */
13409    int axis;                     /* Loop counter for Frame axes */
13410 
13411 /* Obtain a pointer to the Frame structure. */
13412    this = (AstFrame *) obj;
13413 
13414 /* Free the memory used for the Title and Domain strings if necessary. */
13415    this->title = astFree( this->title );
13416    this->domain = astFree( this->domain );
13417 
13418 /* If memory has been allocated to store pointers to the Frame's Axis objects,
13419    annul each of these pointers and then free the memory. */
13420    if ( this->axis ) {
13421       for ( axis = 0; axis < this->naxes; axis++ ) {
13422          this->axis[ axis ] = astAnnul( this->axis[ axis ] );
13423       }
13424       this->axis = astFree( this->axis );
13425    }
13426 
13427 /* Free memory used for the axis permutation array if necessary. */
13428    this->perm = astFree( this->perm );
13429 
13430 /* Other objects. */
13431     if( this->variants ) this->variants = astAnnul( this->variants );
13432 }
13433 
13434 /* Dump function. */
13435 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)13436 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
13437 /*
13438 *  Name:
13439 *     Dump
13440 
13441 *  Purpose:
13442 *     Dump function for Frame objects.
13443 
13444 *  Type:
13445 *     Private function.
13446 
13447 *  Synopsis:
13448 *     void Dump( AstObject *this, AstChannel *channel, int *status )
13449 
13450 *  Description:
13451 *     This function implements the Dump function which writes out data
13452 *     for the Frame class to an output Channel.
13453 
13454 *  Parameters:
13455 *     this
13456 *        Pointer to the Frame whose data are being written.
13457 *     channel
13458 *        Pointer to the Channel to which the data are being written.
13459 *     status
13460 *        Pointer to the inherited status variable.
13461 */
13462 
13463 /* Local Constants: */
13464 #define COMMENT_LEN 150          /* Maximum length of a comment string */
13465 #define KEY_LEN 50               /* Maximum length of a keyword */
13466 
13467 /* Local Variables: */
13468    AstAxis *ax;                  /* Pointer to Axis */
13469    AstFrame *cfrm;               /* Pointer to FrameSet's current Frame */
13470    AstFrame *this;               /* Pointer to the Frame structure */
13471    AstSystemType system;         /* System code */
13472    char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment strings */
13473    char key[ KEY_LEN + 1 ];      /* Buffer for keywords */
13474    const char *sval;             /* Pointer to string value */
13475    const char *lab;              /* Pointer to unit label */
13476    const int *perm;              /* Pointer to axis permutation array */
13477    double dval;                  /* Double attibute value */
13478    int *invperm;                 /* Pointer to inverse permutation array */
13479    int axis;                     /* Loop counter for Frame axes */
13480    int bessyr;                   /* Format as Besselian years (else Julian) */
13481    int digits_set;               /* Digits set explicitly for any axis? */
13482    int full;                     /* Full attribute value */
13483    int full_set;                 /* Full attribute set? */
13484    int helpful;                  /* Helpful to show value even if not set? */
13485    int isFrame;                  /* Is this a simple Frame? */
13486    int ival;                     /* Integer value */
13487    int naxes;                    /* Number of Frame axes */
13488    int set;                      /* Attribute value set? */
13489 
13490 /* Check the global error status. */
13491    if ( !astOK ) return;
13492 
13493 /* Obtain a pointer to the Frame structure. */
13494    this = (AstFrame *) this_object;
13495 
13496 /* Determine the number of Frame axes and a pointer to the Frame's
13497    axis permutation array (using methods, to allow for any over-ride
13498    by a derived class). */
13499    naxes = astGetNaxes( this );
13500    perm = astGetPerm( this );
13501 
13502 /* Some default attribute values are not helpful for a simple Frame. Note
13503    if this is a simple Frame, or if it is a FrameSet with a simple Frame
13504    as its current Frame., or if it is a CmpFrame. */
13505    if( !strcmp( astGetClass( this ), "Frame" ) ) {
13506       isFrame = 1;
13507    } else if( astIsAFrameSet( this ) ) {
13508       cfrm = astGetFrame( (AstFrameSet *) this, AST__CURRENT );
13509       isFrame = !strcmp( astGetClass( cfrm ), "Frame" );
13510       cfrm = astAnnul( cfrm );
13511    } else if( astIsACmpFrame( this ) ) {
13512       isFrame = 1;
13513    } else {
13514       isFrame = 0;
13515    }
13516 
13517 /* Allocate memory to hold an inverse axis permutation array and
13518    generate this array from the forward permutation values. This will
13519    be used to determine which axis should be enquired about (using
13520    possibly over-ridden methods) to obtain data to correspond with a
13521    particular internal value (i.e. instance variable) relating to an
13522    axis. This step is needed so that the effect of any axis
13523    permutation can be un-done before values are written out, as output
13524    values are written by this function in un-permuted order. */
13525    invperm = astMalloc( sizeof( int ) * (size_t) naxes );
13526    if ( astOK ) {
13527       for ( axis = 0; axis < naxes; axis++ ) invperm[ perm[ axis ] ] = axis;
13528 
13529 /* Write out values representing the instance variables for the Frame
13530    class.  Accompany these with appropriate comment strings, possibly
13531    depending on the values being written.*/
13532 
13533 /* In the case of attributes, we first use the appropriate (private)
13534    Test...  member function to see if they are set. If so, we then use
13535    the (private) Get... function to obtain the value to be written
13536    out.
13537 
13538    For attributes which are not set, we use the astGet... method to
13539    obtain the value instead. This will supply a default value
13540    (possibly provided by a derived class which over-rides this method)
13541    which is more useful to a human reader as it corresponds to the
13542    actual default attribute value.  Since "set" will be zero, these
13543    values are for information only and will not be read back. */
13544 
13545 /* Title. */
13546 /* ------ */
13547       set = TestTitle( this, status );
13548       sval = set ? GetTitle( this, status ) : astGetTitle( this );
13549       astWriteString( channel, "Title", set, 1, sval,
13550                       "Title of coordinate system" );
13551 
13552 /* Naxes. */
13553 /* ------ */
13554       set = ( this->naxes != 0 );
13555       ival = set ? this->naxes : naxes;
13556       astWriteInt( channel, "Naxes", set, 1, ival,
13557                    "Number of coordinate axes" );
13558 
13559 /* Domain. */
13560 /* ------- */
13561       set = TestDomain( this, status );
13562       sval = set ? GetDomain( this, status ) : astGetDomain( this );
13563 
13564 /* Don't show an un-set Domain value if it is blank. */
13565       helpful = ( sval && *sval );
13566       astWriteString( channel, "Domain", set, helpful, sval,
13567                       "Coordinate system domain" );
13568 
13569 /* Epoch. */
13570 /* ------ */
13571       set = TestEpoch( this, status );
13572       dval = set ? GetEpoch( this, status ) : astGetEpoch( this );
13573 
13574 /* Convert MJD to Besselian or Julian years, depending on the value. */
13575       bessyr = ( dval < palEpj2d( 1984.0 ) );
13576       dval = bessyr ? palEpb( dval ) : palEpj( dval );
13577       astWriteDouble( channel, "Epoch", set, !isFrame, dval,
13578                       bessyr ? "Besselian epoch of observation" :
13579                                "Julian epoch of observation" );
13580 
13581 /* Label. */
13582 /* ------ */
13583 /* This, and some other, attributes are stored internally by the
13584    Frame's Axis objects, but are "re-packaged" by the Frame class to
13585    appear as Frame attributes. We treat them here like Frame
13586    attributes that are "un-set". There is a Label value for each Frame
13587    axis. */
13588       for ( axis = 0; axis < naxes; axis++ ) {
13589 
13590 /* The inverse axis permutation array is used to obtain the axis index
13591    for astGetLabel. This reverses the effect of the Frame's axis
13592    permutation array and yields a default value appropriate to the
13593    axis with internal index "axis". */
13594          sval = astGetLabel( this, invperm[ axis ] );
13595 
13596 /* Create keyword and comment strings appropriate to each axis
13597    (converting to 1-based axis numbering) and write out the Label
13598    values. */
13599          (void) sprintf( key, "Lbl%d", axis + 1 );
13600          (void) sprintf( comment, "Label for axis %d", axis + 1 );
13601          astWriteString( channel, key, 0, 1, sval, comment );
13602       }
13603 
13604 /* Symbol. */
13605 /* ------- */
13606 /* There is a Symbol value for each Frame axis. These are handled in
13607    the same way as the Label values. */
13608       for ( axis = 0; axis < naxes; axis++ ) {
13609          sval = astGetSymbol( this, invperm[ axis ] );
13610          (void) sprintf( key, "Sym%d", axis + 1 );
13611          (void) sprintf( comment, "Symbol for axis %d", axis + 1 );
13612          astWriteString( channel, key, 0, 0, sval, comment );
13613       }
13614 
13615 /* System. */
13616 /* ------- */
13617       set = TestSystem( this, status );
13618       system = set ? GetSystem( this, status ) : astGetSystem( this );
13619 
13620 /* If set, convert explicitly to a string for the external representation. */
13621       if ( set ) {
13622          if ( astOK ) {
13623             sval = astSystemString( this, system );
13624 
13625 /* Report an error if the System value was not recognised. */
13626             if ( !sval ) {
13627                astError( AST__SCSIN,
13628                         "astWrite(%s): Corrupt %s contains invalid "
13629                         "System identification code (%d).", status,
13630                         astGetClass( channel ), astGetClass( this ),
13631                         (int) system );
13632             }
13633          }
13634 
13635 /* If not set, use astGetAttrib which returns a string value using
13636    (possibly over-ridden) methods. */
13637       } else {
13638          sval = astGetAttrib( this_object, "system" );
13639       }
13640 
13641 /* Write out the value. */
13642       astWriteString( channel, "System", set, !isFrame, sval,
13643                       "Coordinate system type" );
13644 
13645 /* AlignSystem. */
13646 /* ------------ */
13647       set = TestAlignSystem( this, status );
13648       system = set ? GetAlignSystem( this, status ) : astGetAlignSystem( this );
13649 
13650 /* If set, convert explicitly to a string for the external representation. */
13651       if ( set ) {
13652          if ( astOK ) {
13653             sval = astSystemString( this, system );
13654 
13655 /* Report an error if the AlignSystem value was not recognised. */
13656             if ( !sval ) {
13657                astError( AST__SCSIN,
13658                         "astWrite(%s): Corrupt %s contains invalid "
13659                         "AlignSystem identification code (%d).", status,
13660                         astGetClass( channel ), astGetClass( this ),
13661                         (int) system );
13662             }
13663          }
13664 
13665 /* If not set, use astGetAttrib which returns a string value using
13666    (possibly over-ridden) methods. */
13667       } else {
13668          sval = astGetAttrib( this_object, "alignsystem" );
13669       }
13670 
13671 /* Write out the value. */
13672       astWriteString( channel, "AlSys", set, 0, sval,
13673                       "Alignment coordinate system" );
13674 
13675 /* Unit. */
13676 /* ----- */
13677 /* There is a Unit value for each axis. */
13678       for ( axis = 0; axis < naxes; axis++ ) {
13679          sval = astGetUnit( this, invperm[ axis ] );
13680 
13681 /* Get any label associated with the unit string. */
13682          lab = astUnitLabel( sval );
13683 
13684 /* Construct a comment including the above label (but only if it is not
13685    the same as the unit string) . */
13686          if( lab && strcmp( lab, sval ) ) {
13687             (void) sprintf( comment, "Units for axis %d (%s)", axis + 1, lab );
13688          } else {
13689             (void) sprintf( comment, "Units for axis %d", axis + 1 );
13690          }
13691 
13692 /* Show the Unit value if it is not blank. */
13693          helpful = ( sval && *sval );
13694          (void) sprintf( key, "Uni%d", axis + 1 );
13695          astWriteString( channel, key, 0, helpful, sval, comment );
13696       }
13697 
13698 /* Digits. */
13699 /* ------- */
13700 /* There is a Digits value for each axis... */
13701       digits_set = 0;
13702       for ( axis = 0; axis < naxes; axis++ ) {
13703 
13704 /* Obtain the axis Digits value, using the Frame's Digits value as a
13705    default. */
13706          ax = astGetAxis( this, invperm[ axis ] );
13707          set = astTestAxisDigits( ax );
13708          ival = set ? astGetAxisDigits( ax ) : astGetDigits( this );
13709          ax = astAnnul( ax );
13710 
13711 /* Show the value if it is set for the axis (i.e. if it differs from
13712    the default for the whole Frame) and note if any such value is
13713    set. */
13714          helpful = set;
13715          if ( set ) digits_set = 1;
13716          (void) sprintf( key, "Dig%d", axis + 1 );
13717          (void) sprintf( comment, "Individual precision for axis %d",
13718                          axis + 1 );
13719          astWriteInt( channel, key, 0, helpful, ival, comment );
13720       }
13721 
13722 /* There is also a Digits value for the Frame as a whole... */
13723       set = TestDigits( this, status );
13724 
13725 /* Show the value (even if not set) if an explicit Digits value has
13726    been set for any axis (above). */
13727       helpful = digits_set;
13728       ival = set ? GetDigits( this, status ) : astGetDigits( this );
13729       astWriteInt( channel, "Digits", set, helpful, ival,
13730                    "Default formatting precision" );
13731 
13732 /* Format. */
13733 /* ------- */
13734 /* There is a Format value for each axis. */
13735       for ( axis = 0; axis < naxes; axis++ ) {
13736          sval = astGetFormat( this, invperm[ axis ] );
13737 
13738 /* Show the Format value if the Digits value is set for an individual
13739    axis. */
13740          ax = astGetAxis( this, invperm[ axis ] );
13741          helpful = astTestAxisDigits( ax );
13742          ax = astAnnul( ax );
13743          (void) sprintf( key, "Fmt%d", axis + 1 );
13744          (void) sprintf( comment, "Format specifier for axis %d", axis + 1 );
13745          astWriteString( channel, key, 0, helpful, sval, comment );
13746       }
13747 
13748 /* Direction. */
13749 /* ---------- */
13750 /* There is a Direction value for each axis. */
13751       for ( axis = 0; axis < naxes; axis++ ) {
13752          ival = astGetDirection( this, invperm[ axis ] );
13753 
13754 /* Show the value if it is zero. */
13755          helpful = ( ival == 0 );
13756          (void) sprintf( key, "Dir%d", axis + 1 );
13757          (void) sprintf( comment,
13758                          ival ? "Plot axis %d in conventional direction" :
13759                                 "Plot axis %d in reverse direction",
13760                          axis + 1 );
13761          astWriteInt( channel, key, 0, helpful, ival, comment );
13762       }
13763 
13764 /* Bottom. */
13765 /* ------- */
13766 /* There is a Bottom value for each axis. */
13767       for ( axis = 0; axis < naxes; axis++ ) {
13768          dval = astGetBottom( this, invperm[ axis ] );
13769 
13770 /* Show the value if it is zero. */
13771          helpful = ( dval != -DBL_MAX );
13772          (void) sprintf( key, "Bot%d", axis + 1 );
13773          astWriteDouble( channel, key, 0, helpful, dval, "Lowest legal axis value");
13774       }
13775 
13776 /* Top. */
13777 /* ------- */
13778 /* There is a Top value for each axis. */
13779       for ( axis = 0; axis < naxes; axis++ ) {
13780          dval = astGetTop( this, invperm[ axis ] );
13781 
13782 /* Show the value if it is zero. */
13783          helpful = ( dval != DBL_MAX );
13784          (void) sprintf( key, "Top%d", axis + 1 );
13785          astWriteDouble( channel, key, 0, helpful, dval, "Highest legal axis value");
13786       }
13787 
13788 /* PreserveAxes. */
13789 /* ------------- */
13790       set = TestPreserveAxes( this, status );
13791       ival = set ? GetPreserveAxes( this, status ) : astGetPreserveAxes( this );
13792       astWriteInt( channel, "Presrv", set, 0, ival,
13793                    ival ? "Preserve target axes" :
13794                           "Don't preserve target axes" );
13795 
13796 /* Permute. */
13797 /* -------- */
13798       set = TestPermute( this, status );
13799       ival = set ? GetPermute( this, status ) : astGetPermute( this );
13800       astWriteInt( channel, "Permut", set, 0, ival,
13801                    ival ? "Axes may be permuted to match" :
13802                           "Axes may not be permuted match" );
13803 
13804 /* MinAxes. */
13805 /* -------- */
13806       set = TestMinAxes( this, status );
13807       ival = set ? GetMinAxes( this, status ) : astGetMinAxes( this );
13808       astWriteInt( channel, "MinAx", set, 0, ival,
13809                    "Minimum number of axes to match" );
13810 
13811 /* MaxAxes. */
13812 /* -------- */
13813       set = TestMaxAxes( this, status );
13814       ival = set ? GetMaxAxes( this, status ) : astGetMaxAxes( this );
13815       astWriteInt( channel, "MaxAx", set, 0, ival,
13816                    "Maximum number of axes to match" );
13817 
13818 /* MatchEnd. */
13819 /* --------- */
13820       set = TestMatchEnd( this, status );
13821       ival = set ? GetMatchEnd( this, status ) : astGetMatchEnd( this );
13822       astWriteInt( channel, "MchEnd", set, 0, ival,
13823                    ival ? "Match final target axes" :
13824                           "Match initial target axes" );
13825 
13826 /* ObsLat. */
13827 /* ------- */
13828    set = TestObsLat( this, status );
13829    dval = set ? GetObsLat( this, status ) : astGetObsLat( this );
13830    astWriteDouble( channel, "ObsLat", set, 0, dval, "Observers geodetic latitude (rads)" );
13831 
13832 /* ObsLon. */
13833 /* ------- */
13834    set = TestObsLon( this, status );
13835    dval = set ? GetObsLon( this, status ) : astGetObsLon( this );
13836    astWriteDouble( channel, "ObsLon", set, 0, dval, "Observers geodetic longitude (rads)" );
13837 
13838 /* ObsAlt. */
13839 /* ------- */
13840    set = TestObsAlt( this, status );
13841    dval = set ? GetObsAlt( this, status ) : astGetObsAlt( this );
13842    astWriteDouble( channel, "ObsAlt", set, 0, dval, "Observers geodetic altitude (metres)" );
13843 
13844 /* Dut1*/
13845 /* ---- */
13846    set = TestDut1( this, status );
13847    dval = set ? GetDut1( this, status ) : astGetDut1( this );
13848    astWriteDouble( channel, "Dut1", set, 0, dval, "UT1-UTC in seconds" );
13849 
13850 
13851 /* ActiveUnit. */
13852 /* ----------- */
13853       if( astTestActiveUnit( this ) ) {
13854          ival = astGetActiveUnit( this );
13855          astWriteInt( channel, "ActUnt", 1, 0, ival,
13856                       ival ? "Unit strings affects alignment" :
13857                              "Unit strings do not affect alignment" );
13858       }
13859 
13860 /* Axis permutation array. */
13861 /* ----------------------- */
13862 /* Write out the axis permutation array value for each axis,
13863    converting to 1-based axis numbering. */
13864       for ( axis = 0; axis < this->naxes; axis++ ) {
13865          set = ( this->perm[ axis ] != axis );
13866          ival = this->perm[ axis ] + 1;
13867 
13868 /* Create a keyword and comment appropriate to the axis. */
13869          (void) sprintf( key, "Prm%d", axis + 1 );
13870          if ( set ) {
13871             (void) sprintf( comment,
13872                             "Axis %d permuted to use internal axis %d",
13873                             axis + 1, ival );
13874          } else {
13875             (void) sprintf( comment, "Axis %d not permuted", axis + 1 );
13876          }
13877          astWriteInt( channel, key, set, 0, ival, comment );
13878       }
13879 
13880 /* Axis Objects. */
13881 /* ------------- */
13882 /* Temporarily set the Channel's Full attribute to -1 (unless it is +1
13883    to start with), remembering the original setting. This prevents any
13884    unnecessary "un-set" Axis values being output that would otherwise
13885    simply duplicate the Frame's attributes which have already been
13886    written. "Set" Axis values are still written, however (and all
13887    values are written if Full is set to 1). */
13888       full_set = astTestFull( channel );
13889       full = astGetFull( channel );
13890       if ( full <= 0 ) astSetFull( channel, -1 );
13891 
13892 /* Handle each axis in turn. */
13893       for ( axis = 0; axis < this->naxes; axis++ ) {
13894 
13895 /* Create a keyword and comment appropriate to the axis (converting to
13896    1-based axis numbering). */
13897          (void) sprintf( key, "Ax%d", axis + 1 );
13898          (void) sprintf( comment, "Axis number %d", axis + 1 );
13899 
13900 /* Write out the axis Object description. */
13901          astWriteObject( channel, key, 1, 0, this->axis[ axis ], comment );
13902       }
13903 
13904 /* Restore the Channel's original Full attribute setting. */
13905       if ( full_set ) {
13906          astSetFull( channel, full );
13907       } else {
13908          astClearFull( channel );
13909       }
13910 
13911 /* Free the inverse axis permutation array. */
13912       invperm = astFree( invperm );
13913 
13914 /* Variants */
13915 /* ------- */
13916       if( this->variants ) astWriteObject( channel, "Vrnts", 1, 0,
13917                                            this->variants, "Variant Frames" );
13918    }
13919 
13920 /* Undefine macros local to this function. */
13921 #undef COMMENT_LEN
13922 #undef KEY_LEN
13923 }
13924 
13925 /* Standard class functions. */
13926 /* ========================= */
13927 /* Implement the astIsAFrame and astCheckFrame functions using the macros
13928    defined for this purpose in the "object.h" header file. */
astMAKE_ISA(Frame,Mapping)13929 astMAKE_ISA(Frame,Mapping)
13930 astMAKE_CHECK(Frame)
13931 
13932 AstFrame *astFrame_( int naxes, const char *options, int *status, ...) {
13933 /*
13934 *+
13935 *  Name:
13936 *     astFrame
13937 
13938 *  Purpose:
13939 *     Create a Frame.
13940 
13941 *  Type:
13942 *     Protected function.
13943 
13944 *  Synopsis:
13945 *     #include "frame.h"
13946 *     AstFrame *astFrame( int naxes, const char *options, int *status, ... )
13947 
13948 *  Class Membership:
13949 *     Frame constructor.
13950 
13951 *  Description:
13952 *     This function creates a new Frame and optionally initialises its
13953 *     attributes.
13954 
13955 *  Parameters:
13956 *     naxes
13957 *        The number of Frame axes.
13958 *     options
13959 *        Pointer to a null terminated string containing an optional
13960 *        comma-separated list of attribute assignments to be used for
13961 *        initialising the new Frame. The syntax used is the same as
13962 *        for the astSet method and may include "printf" format
13963 *        specifiers identified by "%" symbols in the normal way.
13964 *     status
13965 *        Pointer to the inherited status variable.
13966 *     ...
13967 *        If the "options" string contains "%" format specifiers, then
13968 *        an optional list of arguments may follow it in order to
13969 *        supply values to be substituted for these specifiers. The
13970 *        rules for supplying these are identical to those for the
13971 *        astSet method (and for the C "printf" function).
13972 
13973 *  Returned Value:
13974 *     A pointer to the new Frame.
13975 
13976 *  Notes:
13977 *     - A NULL pointer will be returned if this function is invoked
13978 *     with the global error status set, or if it should fail for any
13979 *     reason.
13980 *-
13981 
13982 *  Implementation Notes:
13983 *     - This function implements the basic Frame constructor which is
13984 *     available via the protected interface to the Frame class.  A
13985 *     public interface is provided by the astFrameId_ function.
13986 */
13987 
13988 /* Local Variables: */
13989    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
13990    AstFrame *new;                /* Pointer to new Frame */
13991    va_list args;                 /* Variable argument list */
13992 
13993 /* Get a pointer to the thread specific global data structure. */
13994    astGET_GLOBALS(NULL);
13995 
13996 /* Check the global error status. */
13997    if ( !astOK ) return NULL;
13998 
13999 /* Initialise the Frame, allocating memory and initialising the virtual
14000    function table as well if necessary. */
14001    new = astInitFrame( NULL, sizeof( AstFrame ), !class_init, &class_vtab,
14002                        "Frame", naxes );
14003 
14004 /* If successful, note that the virtual function table has been initialised. */
14005    if ( astOK ) {
14006       class_init = 1;
14007 
14008 /* Obtain the variable argument list and pass it along with the options string
14009    to the astVSet method to initialise the new Frame's attributes. */
14010       va_start( args, status );
14011       astVSet( new, options, NULL, args );
14012       va_end( args );
14013 
14014 /* If an error occurred, clean up by deleting the new object. */
14015       if ( !astOK ) new = astDelete( new );
14016    }
14017 
14018 /* Return a pointer to the new Frame. */
14019    return new;
14020 }
14021 
astInitFrame_(void * mem,size_t size,int init,AstFrameVtab * vtab,const char * name,int naxes,int * status)14022 AstFrame *astInitFrame_( void *mem, size_t size, int init,
14023                          AstFrameVtab *vtab, const char *name,
14024                          int naxes, int *status ) {
14025 /*
14026 *+
14027 *  Name:
14028 *     astInitFrame
14029 
14030 *  Purpose:
14031 *     Initialise a Frame.
14032 
14033 *  Type:
14034 *     Protected function.
14035 
14036 *  Synopsis:
14037 *     #include "frame.h"
14038 *     AstFrame *astInitFrame( void *mem, size_t size, int init,
14039 *                             AstFrameVtab *vtab, const char *name,
14040 *                             int naxes )
14041 
14042 *  Class Membership:
14043 *     Frame initialiser.
14044 
14045 *  Description:
14046 *     This function is provided for use by class implementations to initialise
14047 *     a new Frame object. It allocates memory (if necessary) to accommodate
14048 *     the Frame plus any additional data associated with the derived class.
14049 *     It then initialises a Frame structure at the start of this memory. If
14050 *     the "init" flag is set, it also initialises the contents of a virtual
14051 *     function table for a Frame at the start of the memory passed via the
14052 *     "vtab" parameter.
14053 
14054 *  Parameters:
14055 *     mem
14056 *        A pointer to the memory in which the Frame is to be created. This
14057 *        must be of sufficient size to accommodate the Frame data
14058 *        (sizeof(Frame)) plus any data used by the derived class. If a value
14059 *        of NULL is given, this function will allocate the memory itself using
14060 *        the "size" parameter to determine its size.
14061 *     size
14062 *        The amount of memory used by the Frame (plus derived class data).
14063 *        This will be used to allocate memory if a value of NULL is given for
14064 *        the "mem" parameter. This value is also stored in the Frame
14065 *        structure, so a valid value must be supplied even if not required for
14066 *        allocating memory.
14067 *     init
14068 *        A logical flag indicating if the Frame's virtual function table is
14069 *        to be initialised. If this value is non-zero, the virtual function
14070 *        table will be initialised by this function.
14071 *     vtab
14072 *        Pointer to the start of the virtual function table to be associated
14073 *        with the new Frame.
14074 *     name
14075 *        Pointer to a constant null-terminated character string which contains
14076 *        the name of the class to which the new object belongs (it is this
14077 *        pointer value that will subsequently be returned by the astGetClass
14078 *        method).
14079 *     naxes
14080 *        The number of Frame axes.
14081 
14082 *  Returned Value:
14083 *     A pointer to the new Frame.
14084 
14085 *  Notes:
14086 *     -  A null pointer will be returned if this function is invoked with the
14087 *     global error status set, or if it should fail for any reason.
14088 *-
14089 */
14090 
14091 /* Local Variables: */
14092    AstFrame *new;                /* Pointer to new Frame */
14093    int axis;                     /* Loop counter for Frame axes */
14094 
14095 /* Check the global status. */
14096    if ( !astOK ) return NULL;
14097 
14098 /* If necessary, initialise the virtual function table. */
14099    if ( init ) astInitFrameVtab( vtab, name );
14100 
14101 /* Initialise. */
14102    new = NULL;
14103 
14104 /* Check the number of axes for validity, reporting an error if necessary. */
14105    if ( naxes < 0 ) {
14106       astError( AST__NAXIN, "astInitFrame(%s): Number of axes (%d) is "
14107                 "invalid - this number should not be negative.", status, name, naxes );
14108 
14109 /* Initialise a Mapping structure (the parent class) as the first
14110    component within the Frame structure, allocating memory if
14111    necessary. Set the number of input/output coordinates to zero (the
14112    astGetNin and astGetNout methods are over-ridden by the Frame class
14113    to provide values for these that are equal to the number of Frame
14114    axes). */
14115    } else {
14116       new = (AstFrame *) astInitMapping( mem, size, 0,
14117                                          (AstMappingVtab *) vtab, name,
14118                                          0, 0, 1, 1 );
14119 
14120       if ( astOK ) {
14121 
14122 /* Initialise the Frame data. */
14123 /* ----------------------------- */
14124 /* Set the number of Frame axes. */
14125          new->naxes = naxes;
14126 
14127 /* Initialise all attributes to their "undefined" values. */
14128          new->digits = -INT_MAX;
14129          new->domain = NULL;
14130          new->epoch = AST__BAD;
14131          new->match_end = -INT_MAX;
14132          new->max_axes = -INT_MAX;
14133          new->min_axes = -INT_MAX;
14134          new->permute = -INT_MAX;
14135          new->preserve_axes = -INT_MAX;
14136          new->title = NULL;
14137          new->system = AST__BADSYSTEM;
14138          new->alignsystem = AST__BADSYSTEM;
14139          new->active_unit = -INT_MAX;
14140          new->obsalt = AST__BAD;
14141          new->obslat = AST__BAD;
14142          new->obslon = AST__BAD;
14143          new->dut1 = AST__BAD;
14144          new->flags = 0;
14145          new->variants = NULL;
14146 
14147 /* Allocate memory to store pointers to the Frame's Axis objects and to store
14148    its axis permutation array. */
14149          new->axis = astMalloc( sizeof( AstAxis * ) * (size_t) naxes );
14150          new->perm = astMalloc( sizeof( int ) * (size_t) naxes );
14151 
14152 /* Create a new Axis object to describe each axis of the Frame and store the
14153    resulting pointers in the memory allocated above. Also initialise the
14154    axis permutation array so that the axes appear in their natural order. */
14155          if ( astOK ) {
14156             for ( axis = 0; axis < naxes; axis++ ) {
14157                new->axis[ axis ] = astAxis( "", status );
14158                new->perm[ axis ] = axis;
14159 	    }
14160 
14161 /* If an error occurred while creating the Axis objects, scan through the array
14162    of pointers to them again to ensure that they are all correctly annulled. */
14163             if ( !astOK ) {
14164                for ( axis = 0; axis < naxes; axis++ ) {
14165                   new->axis[ axis ] = astAnnul( new->axis[ axis ] );
14166    	       }
14167 	    }
14168 	 }
14169 
14170 /* If an error occurred, clean up by deleting the new object. */
14171          if ( !astOK ) new = astDelete( new );
14172       }
14173    }
14174 
14175 /* Return a pointer to the new object. */
14176    return new;
14177 }
14178 
astLoadFrame_(void * mem,size_t size,AstFrameVtab * vtab,const char * name,AstChannel * channel,int * status)14179 AstFrame *astLoadFrame_( void *mem, size_t size,
14180                          AstFrameVtab *vtab, const char *name,
14181                          AstChannel *channel, int *status ) {
14182 /*
14183 *+
14184 *  Name:
14185 *     astLoadFrame
14186 
14187 *  Purpose:
14188 *     Load a Frame.
14189 
14190 *  Type:
14191 *     Protected function.
14192 
14193 *  Synopsis:
14194 *     #include "frame.h"
14195 *     AstFrame *astLoadFrame( void *mem, size_t size,
14196 *                              AstFrameVtab *vtab, const char *name,
14197 *                              AstChannel *channel )
14198 
14199 *  Class Membership:
14200 *     Frame loader.
14201 
14202 *  Description:
14203 *     This function is provided to load a new Frame using data read
14204 *     from a Channel. It first loads the data used by the parent class
14205 *     (which allocates memory if necessary) and then initialises a
14206 *     Frame structure in this memory, using data read from the input
14207 *     Channel.
14208 *
14209 *     If the "init" flag is set, it also initialises the contents of a
14210 *     virtual function table for a Frame at the start of the memory
14211 *     passed via the "vtab" parameter.
14212 
14213 
14214 *  Parameters:
14215 *     mem
14216 *        A pointer to the memory into which the Frame is to be loaded.
14217 *        This must be of sufficient size to accommodate the Frame data
14218 *        (sizeof(Frame)) plus any data used by derived classes. If a
14219 *        value of NULL is given, this function will allocate the
14220 *        memory itself using the "size" parameter to determine its
14221 *        size.
14222 *     size
14223 *        The amount of memory used by the Frame (plus derived class
14224 *        data).  This will be used to allocate memory if a value of
14225 *        NULL is given for the "mem" parameter. This value is also
14226 *        stored in the Frame structure, so a valid value must be
14227 *        supplied even if not required for allocating memory.
14228 *
14229 *        If the "vtab" parameter is NULL, the "size" value is ignored
14230 *        and sizeof(AstFrame) is used instead.
14231 *     vtab
14232 *        Pointer to the start of the virtual function table to be
14233 *        associated with the new Frame. If this is NULL, a pointer to
14234 *        the (static) virtual function table for the Frame class is
14235 *        used instead.
14236 *     name
14237 *        Pointer to a constant null-terminated character string which
14238 *        contains the name of the class to which the new object
14239 *        belongs (it is this pointer value that will subsequently be
14240 *        returned by the astGetClass method).
14241 *
14242 *        If the "vtab" parameter is NULL, the "name" value is ignored
14243 *        and a pointer to the string "Frame" is used instead.
14244 
14245 *  Returned Value:
14246 *     A pointer to the new Frame.
14247 
14248 *  Notes:
14249 *     - A null pointer will be returned if this function is invoked
14250 *     with the global error status set, or if it should fail for any
14251 *     reason.
14252 *-
14253 */
14254 
14255 /* Local Constants: */
14256    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
14257 #define KEY_LEN 50               /* Maximum length of a keyword */
14258 
14259 /* Local Variables: */
14260    AstFrame *new;                /* Pointer to the new Frame */
14261    char *sval;                   /* Pointer to string value */
14262    char key[ KEY_LEN + 1 ];      /* Buffer for keywords */
14263    double dval;                  /* DOuble attribute value */
14264    int axis;                     /* Loop counter for axes */
14265    int ival;                     /* Integer value */
14266 
14267 /* Get a pointer to the thread specific global data structure. */
14268    astGET_GLOBALS(channel);
14269 
14270 /* Initialise. */
14271    new = NULL;
14272 
14273 /* Check the global error status. */
14274    if ( !astOK ) return new;
14275 
14276 /* If a NULL virtual function table has been supplied, then this is
14277    the first loader to be invoked for this Frame. In this case the
14278    Frame belongs to this class, so supply appropriate values to be
14279    passed to the parent class loader (and its parent, etc.). */
14280    if ( !vtab ) {
14281       size = sizeof( AstFrame );
14282       vtab = &class_vtab;
14283       name = "Frame";
14284 
14285 /* If required, initialise the virtual function table for this class. */
14286       if ( !class_init ) {
14287          astInitFrameVtab( vtab, name );
14288          class_init = 1;
14289       }
14290    }
14291 
14292 /* Invoke the parent class loader to load data for all the ancestral
14293    classes of the current one, returning a pointer to the resulting
14294    partly-built Frame. */
14295    new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name,
14296                          channel );
14297 
14298    if ( astOK ) {
14299 
14300 /* Assign values for transient components that are not included in the
14301    Frame dump */
14302    new->flags = 0;
14303 
14304 /* Read input data. */
14305 /* ================ */
14306 /* Request the input Channel to read all the input data appropriate to
14307    this class into the internal "values list". */
14308       astReadClassData( channel, "Frame" );
14309 
14310 /* Now read each individual data item from this list and use it to
14311    initialise the appropriate instance variable(s) for this class. */
14312 
14313 /* In the case of attributes, we first read the "raw" input value,
14314    supplying the "unset" value as the default. If a "set" value is
14315    obtained, we then use the appropriate (private) Set... member
14316    function to validate and set the value properly. */
14317 
14318 /* Naxes. */
14319 /* ------ */
14320 /* Obtain the number of Frame axes and allocate memory for the arrays
14321    which hold axis information. */
14322       new->naxes = astReadInt( channel, "naxes", 0 );
14323       if ( new->naxes < 0 ) new->naxes = 0;
14324       new->perm = astMalloc( sizeof( int ) * (size_t) new->naxes );
14325       new->axis = astMalloc( sizeof( AstAxis * ) * (size_t) new->naxes );
14326 
14327 /* If an error occurred, ensure that any allocated memory is freed. */
14328       if ( !astOK ) {
14329          new->perm = astFree( new->perm );
14330          new->axis = astFree( new->axis );
14331 
14332 /* Otherwise, initialise the array of Axis pointers. */
14333       } else {
14334          for ( axis = 0; axis < new->naxes; axis++ ) new->axis[ axis ] = NULL;
14335 
14336 /* Now obtain those input values which are required for each axis... */
14337          for ( axis = 0; axis < new->naxes; axis++ ) {
14338 
14339 /* Axis object. */
14340 /* ------------ */
14341 /* This must be read first, so that it can hold the other axis values
14342    obtained below. */
14343 
14344 /* Create a keyword appropriate to this axis. */
14345             (void) sprintf( key, "ax%d", axis + 1 );
14346 
14347 /* Read the Axis object. If none was read, provide a default Axis
14348    instead. */
14349             new->axis[ axis ] = astReadObject( channel, key, NULL );
14350             if ( !new->axis[ axis ] ) new->axis[ axis ] = astAxis( "", status );
14351 
14352 /* Label. */
14353 /* ------ */
14354 /* Read the Label string for each axis. If a value is obtained, use
14355    it to set the Label attribute for the axis. Free the memory holding
14356    the string when no longer needed. */
14357             (void) sprintf( key, "lbl%d", axis + 1 );
14358             sval = astReadString( channel, key, NULL );
14359             if ( sval ) {
14360                astSetAxisLabel( new->axis[ axis ], sval );
14361                sval = astFree( sval );
14362             }
14363 
14364 /* Symbol. */
14365 /* ------- */
14366             (void) sprintf( key, "sym%d", axis + 1 );
14367             sval = astReadString( channel, key, NULL );
14368             if ( sval ) {
14369                astSetAxisSymbol( new->axis[ axis ], sval );
14370                sval = astFree( sval );
14371             }
14372 
14373 /* Format. */
14374 /* ------- */
14375             (void) sprintf( key, "fmt%d", axis + 1 );
14376             sval = astReadString( channel, key, NULL );
14377             if ( sval ) {
14378                astSetAxisFormat( new->axis[ axis ], sval );
14379                sval = astFree( sval );
14380             }
14381 
14382 /* Unit. */
14383 /* ----- */
14384             (void) sprintf( key, "uni%d", axis + 1 );
14385             sval = astReadString( channel, key, NULL );
14386             if ( sval ) {
14387                astSetAxisUnit( new->axis[ axis ], sval );
14388                sval = astFree( sval );
14389             }
14390 
14391 /* Direction. */
14392 /* ---------- */
14393             (void) sprintf( key, "dir%d", axis + 1 );
14394             ival = astReadInt( channel, key, -INT_MAX );
14395             if ( ival != -INT_MAX ) {
14396                astSetAxisDirection( new->axis[ axis ], ival );
14397             }
14398 
14399 /* Top. */
14400 /*----- */
14401             (void) sprintf( key, "top%d", axis + 1 );
14402             dval = astReadDouble( channel, key, AST__BAD );
14403             if ( dval != AST__BAD ) {
14404                astSetAxisTop( new->axis[ axis ], dval );
14405             }
14406 
14407 /* Bottom. */
14408 /*----- -- */
14409             (void) sprintf( key, "bot%d", axis + 1 );
14410             dval = astReadDouble( channel, key, AST__BAD );
14411             if ( dval != AST__BAD ) {
14412                astSetAxisBottom( new->axis[ axis ], dval );
14413             }
14414 
14415 /* Digits. */
14416 /* ------- */
14417             (void) sprintf( key, "dig%d", axis + 1 );
14418             ival = astReadInt( channel, key, -INT_MAX );
14419             if ( ival != -INT_MAX ) {
14420                astSetAxisDigits( new->axis[ axis ], ival );
14421             }
14422 
14423 /* Axis permutation array. */
14424 /* ----------------------- */
14425 /* Convert from 1-based to zero-based axis numbering at this
14426    point. The default is the "un-permuted" value. */
14427             sprintf( key, "prm%d", axis + 1 );
14428             new->perm[ axis ] = astReadInt( channel, key, axis + 1 ) - 1;
14429 
14430 /* Quit looping if an error occurs. */
14431             if ( !astOK ) break;
14432          }
14433 
14434 /* The remaining values are not associated with particular axes... */
14435 
14436 /* Title. */
14437 /* ------ */
14438          new->title = astReadString( channel, "title", NULL );
14439 
14440 /* Domain. */
14441 /* ------- */
14442          new->domain = astReadString( channel, "domain", NULL );
14443 
14444 /* Epoch. */
14445 /* ------ */
14446 /* Interpret this as Besselian or Julian depending on its value. */
14447          new->epoch = astReadDouble( channel, "epoch", AST__BAD );
14448          if ( TestEpoch( new, status ) ) {
14449             SetEpoch( new, ( new->epoch < 1984.0 ) ? palEpb2d( new->epoch ) :
14450                                                      palEpj2d( new->epoch ), status );
14451          }
14452 
14453 /* Digits. */
14454 /* ------- */
14455 /* This is the value that applies to the Frame as a whole. */
14456          new->digits = astReadInt( channel, "digits", -INT_MAX );
14457          if ( TestDigits( new, status ) ) SetDigits( new, new->digits, status );
14458 
14459 /* PreserveAxes. */
14460 /* ------------- */
14461          new->preserve_axes = astReadInt( channel, "presrv", -INT_MAX );
14462          if ( TestPreserveAxes( new, status ) ) {
14463             SetPreserveAxes( new, new->preserve_axes, status );
14464          }
14465 
14466 /* Permute. */
14467 /* -------- */
14468          new->permute = astReadInt( channel, "permut", -INT_MAX );
14469          if ( TestPermute( new, status ) ) SetPermute( new, new->permute, status );
14470 
14471 /* MinAxes. */
14472 /* -------- */
14473          new->min_axes = astReadInt( channel, "minax", -INT_MAX );
14474          if ( TestMinAxes( new, status ) ) SetMinAxes( new, new->min_axes, status );
14475 
14476 /* MaxAxes. */
14477 /* -------- */
14478          new->max_axes = astReadInt( channel, "maxax", -INT_MAX );
14479          if ( TestMaxAxes( new, status ) ) SetMaxAxes( new, new->max_axes, status );
14480 
14481 /* MatchEnd. */
14482 /* --------- */
14483          new->match_end = astReadInt( channel, "mchend", -INT_MAX );
14484          if ( TestMatchEnd( new, status ) ) SetMatchEnd( new, new->match_end, status );
14485 
14486 /* ObsLat. */
14487 /* ------- */
14488          new->obslat = astReadDouble( channel, "obslat", AST__BAD );
14489          if ( TestObsLat( new, status ) ) SetObsLat( new, new->obslat, status );
14490 
14491 /* ObsLon. */
14492 /* ------- */
14493          new->obslon = astReadDouble( channel, "obslon", AST__BAD );
14494          if ( TestObsLon( new, status ) ) SetObsLon( new, new->obslon, status );
14495 
14496 /* ObsAlt. */
14497 /* ------- */
14498          new->obsalt = astReadDouble( channel, "obsalt", AST__BAD );
14499          if ( TestObsAlt( new, status ) ) SetObsAlt( new, new->obsalt, status );
14500 
14501 /* Dut1. */
14502 /* ---- */
14503          new->dut1 = astReadDouble( channel, "dut1", AST__BAD );
14504          if ( TestDut1( new, status ) ) SetDut1( new, new->dut1, status );
14505 
14506 /* ActiveUnit. */
14507 /* ----------- */
14508          new->active_unit = astReadInt( channel, "actunt", -INT_MAX );
14509          if ( TestActiveUnit( new, status ) ) SetActiveUnit( new, new->active_unit, status );
14510 
14511 /* System. */
14512 /* ------- */
14513 /* Set the default and read the external representation as a string. */
14514          new->system = AST__BADSYSTEM;
14515          sval = astReadString( channel, "system", NULL );
14516 
14517 /* If a value was read, convert from a string to a System code. */
14518          if ( sval ) {
14519             if ( astOK ) {
14520                new->system = astSystemCode( new, sval );
14521 
14522 /* Report an error if the value wasn't recognised. */
14523                if ( new->system == AST__BADSYSTEM ) {
14524                   astError( AST__ATTIN,
14525                             "astRead(%s): Invalid System description "
14526                             "\"%s\".", status, astGetClass( channel ), sval );
14527                }
14528             }
14529 
14530 /* Free the string value. */
14531             sval = astFree( sval );
14532          }
14533 
14534 /* AlignSystem. */
14535 /* ------------ */
14536 /* Set the default and read the external representation as a string. */
14537          new->alignsystem = AST__BADSYSTEM;
14538          sval = astReadString( channel, "alsys", NULL );
14539 
14540 /* If a value was read, convert from a string to a System code. */
14541          if ( sval ) {
14542             if ( astOK ) {
14543                new->alignsystem = astSystemCode( new, sval );
14544 
14545 /* Report an error if the value wasn't recognised. */
14546                if ( new->alignsystem == AST__BADSYSTEM ) {
14547                   astError( AST__ATTIN,
14548                             "astRead(%s): Invalid AlignSystem description "
14549                             "\"%s\".", status, astGetClass( channel ), sval );
14550                }
14551             }
14552 
14553 /* Free the string value. */
14554             sval = astFree( sval );
14555          }
14556 
14557 /* Variants. */
14558 /* -------- */
14559          new->variants = astReadObject( channel, "vrnts", NULL );
14560       }
14561 
14562 /* If an error occurred, clean up by deleting the new Frame. */
14563       if ( !astOK ) new = astDelete( new );
14564    }
14565 
14566 /* Return the new Frame pointer. */
14567    return new;
14568 
14569 /* Undefine macros local to this function. */
14570 #undef KEY_LEN
14571 }
14572 
14573 /* Virtual function interfaces. */
14574 /* ============================ */
14575 /* These provide the external interface to the virtual functions defined by
14576    this class. Each simply checks the global error status and then locates and
14577    executes the appropriate member function, using the function pointer stored
14578    in the object's virtual function table (this pointer is located using the
14579    astMEMBER macro defined in "object.h").
14580 
14581    Note that the member function may not be the one defined here, as it may
14582    have been over-ridden by a derived class. However, it should still have the
14583    same interface. */
astAbbrev_(AstFrame * this,int axis,const char * fmt,const char * str1,const char * str2,int * status)14584 const char *astAbbrev_( AstFrame *this, int axis, const char *fmt,
14585                         const char *str1, const char *str2, int *status ) {
14586    if ( !astOK ) return str2;
14587    return (**astMEMBER(this,Frame,Abbrev))( this, axis, fmt, str1, str2, status );
14588 }
astFields_(AstFrame * this,int axis,const char * fmt,const char * str,int maxfld,char ** fields,int * nc,double * val,int * status)14589 int astFields_( AstFrame *this, int axis, const char *fmt,
14590                 const char *str, int maxfld, char **fields,
14591                 int *nc, double *val, int *status ) {
14592    if ( !astOK ) return 0;
14593    return (**astMEMBER(this,Frame,Fields))( this, axis, fmt, str, maxfld, fields, nc, val, status );
14594 }
astCheckPerm_(AstFrame * this,const int * perm,const char * method,int * status)14595 void astCheckPerm_( AstFrame *this, const int *perm, const char *method, int *status ) {
14596    if ( !astOK ) return;
14597    (**astMEMBER(this,Frame,CheckPerm))( this, perm, method, status );
14598 }
14599 
astResolvePoints_(AstFrame * this,const double point1[],const double point2[],AstPointSet * in,AstPointSet * out,int * status)14600 AstPointSet *astResolvePoints_( AstFrame *this, const double point1[],
14601                                 const double point2[], AstPointSet *in,
14602                                 AstPointSet *out, int *status ) {
14603    if ( !astOK ) return NULL;
14604    return (**astMEMBER(this,Frame,ResolvePoints))( this, point1, point2, in, out, status );
14605 }
astLineDef_(AstFrame * this,const double start[2],const double end[2],int * status)14606 AstLineDef *astLineDef_( AstFrame *this, const double start[2],
14607                              const double end[2], int *status ) {
14608    if ( !astOK ) return NULL;
14609    return (**astMEMBER(this,Frame,LineDef))( this, start, end, status );
14610 }
astLineCrossing_(AstFrame * this,AstLineDef * l1,AstLineDef * l2,double ** cross,int * status)14611 int astLineCrossing_( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
14612                       double **cross, int *status ) {
14613    if ( !astOK ) return 0;
14614    return (**astMEMBER(this,Frame,LineCrossing))( this, l1, l2, cross, status );
14615 }
astLineOffset_(AstFrame * this,AstLineDef * line,double par,double prp,double point[2],int * status)14616 void astLineOffset_( AstFrame *this, AstLineDef *line, double par, double prp,
14617                      double point[2], int *status ){
14618    if ( !astOK ) return;
14619    (**astMEMBER(this,Frame,LineOffset))( this, line, par, prp, point, status );
14620 }
astLineContains_(AstFrame * this,AstLineDef * l,int def,double * point,int * status)14621 int astLineContains_( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) {
14622    if ( !astOK ) return 0;
14623    return (**astMEMBER(this,Frame,LineContains))( this, l, def, point, status );
14624 }
astConvert_(AstFrame * from,AstFrame * to,const char * domainlist,int * status)14625 AstFrameSet *astConvert_( AstFrame *from, AstFrame *to,
14626                           const char *domainlist, int *status ) {
14627    if ( !astOK ) return NULL;
14628    return (**astMEMBER(from,Frame,Convert))( from, to, domainlist, status );
14629 }
astConvertX_(AstFrame * to,AstFrame * from,const char * domainlist,int * status)14630 AstFrameSet *astConvertX_( AstFrame *to, AstFrame *from,
14631                            const char *domainlist, int *status ) {
14632    if ( !astOK ) return NULL;
14633    return (**astMEMBER(to,Frame,ConvertX))( to, from, domainlist, status );
14634 }
astAngle_(AstFrame * this,const double a[],const double b[],const double c[],int * status)14635 double astAngle_( AstFrame *this, const double a[], const double b[],
14636                   const double c[], int *status ) {
14637    if ( !astOK ) return AST__BAD;
14638    return (**astMEMBER(this,Frame,Angle))( this, a, b, c, status );
14639 }
astGetActiveUnit_(AstFrame * this,int * status)14640 int astGetActiveUnit_( AstFrame *this, int *status ) {
14641    if ( !astOK ) return 0;
14642    return (**astMEMBER(this,Frame,GetActiveUnit))( this, status );
14643 }
astTestActiveUnit_(AstFrame * this,int * status)14644 int astTestActiveUnit_( AstFrame *this, int *status ) {
14645    if ( !astOK ) return 0;
14646    return (**astMEMBER(this,Frame,TestActiveUnit))( this, status );
14647 }
astSetActiveUnit_(AstFrame * this,int value,int * status)14648 void astSetActiveUnit_( AstFrame *this, int value, int *status ) {
14649    if ( !astOK ) return;
14650    (**astMEMBER(this,Frame,SetActiveUnit))( this, value, status );
14651 }
astDistance_(AstFrame * this,const double point1[],const double point2[],int * status)14652 double astDistance_( AstFrame *this,
14653                      const double point1[], const double point2[], int *status ) {
14654    if ( !astOK ) return AST__BAD;
14655    return (**astMEMBER(this,Frame,Distance))( this, point1, point2, status );
14656 }
astFindFrame_(AstFrame * target,AstFrame * template,const char * domainlist,int * status)14657 AstFrameSet *astFindFrame_( AstFrame *target, AstFrame *template,
14658                             const char *domainlist, int *status ) {
14659    if ( !astOK ) return NULL;
14660    return (**astMEMBER(target,Frame,FindFrame))( target, template, domainlist, status );
14661 }
astMatchAxes_(AstFrame * frm1,AstFrame * frm2,int * axes,int * status)14662 void astMatchAxes_( AstFrame *frm1, AstFrame *frm2, int *axes, int *status ) {
14663    if ( !astOK ) return;
14664    (**astMEMBER(frm1,Frame,MatchAxes))( frm1, frm2, axes, status );
14665 }
astMatchAxesX_(AstFrame * frm2,AstFrame * frm1,int * axes,int * status)14666 void astMatchAxesX_( AstFrame *frm2, AstFrame *frm1, int *axes, int *status ) {
14667    if ( !astOK ) return;
14668    (**astMEMBER(frm2,Frame,MatchAxesX))( frm2, frm1, axes, status );
14669 }
astFormat_(AstFrame * this,int axis,double value,int * status)14670 const char *astFormat_( AstFrame *this, int axis, double value, int *status ) {
14671    if ( !astOK ) return NULL;
14672    return (**astMEMBER(this,Frame,Format))( this, axis, value, status );
14673 }
astGap_(AstFrame * this,int axis,double gap,int * ntick,int * status)14674 double astGap_( AstFrame *this, int axis, double gap, int *ntick, int *status ) {
14675    if ( !astOK ) return 0.0;
14676    return (**astMEMBER(this,Frame,Gap))( this, axis, gap, ntick, status );
14677 }
astGetAxis_(AstFrame * this,int axis,int * status)14678 AstAxis *astGetAxis_( AstFrame *this, int axis, int *status ) {
14679    if ( !astOK ) return NULL;
14680    return (**astMEMBER(this,Frame,GetAxis))( this, axis, status );
14681 }
astGetNaxes_(AstFrame * this,int * status)14682 int astGetNaxes_( AstFrame *this, int *status ) {
14683    if ( !astOK ) return 0;
14684    return (**astMEMBER(this,Frame,GetNaxes))( this, status );
14685 }
astGetPerm_(AstFrame * this,int * status)14686 const int *astGetPerm_( AstFrame *this, int *status ) {
14687    if ( !astOK ) return NULL;
14688    return (**astMEMBER(this,Frame,GetPerm))( this, status );
14689 }
astGetFrameVariants_(AstFrame * this,int * status)14690 AstFrameSet *astGetFrameVariants_( AstFrame *this, int *status ) {
14691    if ( !astOK ) return NULL;
14692    return (**astMEMBER(this,Frame,GetFrameVariants))( this, status );
14693 }
astSetFrameVariants_(AstFrame * this,AstFrameSet * variants,int * status)14694 void astSetFrameVariants_( AstFrame *this, AstFrameSet *variants, int *status ) {
14695    if ( !astOK ) return;
14696    (**astMEMBER(this,Frame,SetFrameVariants))( this, variants, status );
14697 }
14698 
14699 
astMatch_(AstFrame * this,AstFrame * target,int matchsub,int ** template_axes,int ** target_axes,AstMapping ** map,AstFrame ** result,int * status)14700 int astMatch_( AstFrame *this, AstFrame *target, int matchsub,
14701                int **template_axes, int **target_axes,
14702                AstMapping **map, AstFrame **result, int *status ) {
14703 
14704    AstFrame *super_this;
14705    const char *dom;
14706    int match;
14707 
14708    if ( !astOK ) return 0;
14709 
14710    match = (**astMEMBER(this,Frame,Match))( this, target, matchsub,
14711                                             template_axes, target_axes,
14712                                             map, result, status );
14713 
14714 /* If the template ("this") could not be used to probe the target, it may
14715    be because the template class is a more specialised form of the target
14716    class. E.g. a SkyFrame cannot directly be used to probe a Frame, but a
14717    Frame *can* be used to probe a SkyFrame. This means (for instance),
14718    that a basic Frame with Domain FRED cannot be aligned (using astConvert)
14719    with a CmpFrame with Domain FRED. This sort of alignment is often
14720    useful, so we try now to use the supplied template to probe a modified
14721    form of the target that has been cast into the same class as the
14722    template. This is only possible if the template class is a sub-class of
14723    the target class. Attempt to do the cast. */
14724    if( ! match && matchsub ) {
14725       super_this = (AstFrame *) astCast( this, target );
14726 
14727 /* If the cast was  possible, fix the template Domain since the parent
14728    class may provide a different default Domain, and then invoke the Match
14729    method appropriate to the new template class (i.e. the target class). */
14730       if( super_this ) {
14731          if( astTestDomain( target ) ) {
14732             dom = astGetDomain( this );
14733             if( astChrLen( dom ) > 0 ) astSetDomain( super_this, dom );
14734          }
14735          match = (**astMEMBER(super_this,Frame,Match))( super_this, target,
14736                                                         matchsub, template_axes,
14737                                                         target_axes, map,
14738                                                         result, status );
14739          super_this = astAnnul( super_this );
14740       }
14741    }
14742 
14743    return match;
14744 }
14745 
14746 
astIsUnitFrame_(AstFrame * this,int * status)14747 int astIsUnitFrame_( AstFrame *this, int *status ){
14748    if ( !astOK ) return 0;
14749    return (**astMEMBER(this,Frame,IsUnitFrame))( this, status );
14750 }
astNorm_(AstFrame * this,double value[],int * status)14751 void astNorm_( AstFrame *this, double value[], int *status ) {
14752    if ( !astOK ) return;
14753    (**astMEMBER(this,Frame,Norm))( this, value, status );
14754 }
astNormBox_(AstFrame * this,double lbnd[],double ubnd[],AstMapping * reg,int * status)14755 void astNormBox_( AstFrame *this, double lbnd[], double ubnd[], AstMapping *reg, int *status ) {
14756    if ( !astOK ) return;
14757    (**astMEMBER(this,Frame,NormBox))( this, lbnd, ubnd, reg, status );
14758 }
astAxDistance_(AstFrame * this,int axis,double v1,double v2,int * status)14759 double astAxDistance_( AstFrame *this, int axis, double v1, double v2, int *status ) {
14760    if ( !astOK ) return AST__BAD;
14761    return (**astMEMBER(this,Frame,AxDistance))( this, axis, v1, v2, status );
14762 }
astAxOffset_(AstFrame * this,int axis,double v1,double dist,int * status)14763 double astAxOffset_( AstFrame *this, int axis, double v1, double dist, int *status ) {
14764    if ( !astOK ) return AST__BAD;
14765    return (**astMEMBER(this,Frame,AxOffset))( this, axis, v1, dist, status );
14766 }
14767 
14768 
astFrameGrid_(AstFrame * this,int size,const double * lbnd,const double * ubnd,int * status)14769 AstPointSet *astFrameGrid_( AstFrame *this, int size, const double *lbnd,
14770                             const double *ubnd, int *status ){
14771    if ( !astOK ) return NULL;
14772    return (**astMEMBER(this,Frame,FrameGrid))( this, size, lbnd, ubnd, status );
14773 }
14774 
14775 
astOffset_(AstFrame * this,const double point1[],const double point2[],double offset,double point3[],int * status)14776 void astOffset_( AstFrame *this, const double point1[], const double point2[],
14777                  double offset, double point3[], int *status ) {
14778    if ( !astOK ) return;
14779    (**astMEMBER(this,Frame,Offset))( this, point1, point2, offset, point3, status );
14780 }
astAxAngle_(AstFrame * this,const double a[2],const double b[2],int axis,int * status)14781 double astAxAngle_( AstFrame *this, const double a[2], const double b[2],
14782                     int axis, int *status ) {
14783    if ( !astOK ) return AST__BAD;
14784    return (**astMEMBER(this,Frame,AxAngle))( this, a, b, axis, status );
14785 }
astOffset2_(AstFrame * this,const double point1[2],double angle,double offset,double point2[2],int * status)14786 double astOffset2_( AstFrame *this, const double point1[2], double angle,
14787                  double offset, double point2[2], int *status ) {
14788    if ( !astOK ) return AST__BAD;
14789    return (**astMEMBER(this,Frame,Offset2))( this, point1, angle, offset, point2, status );
14790 }
astIntersect_(AstFrame * this,const double a1[2],const double a2[2],const double b1[2],const double b2[2],double cross[2],int * status)14791 void astIntersect_( AstFrame *this, const double a1[2],
14792                     const double a2[2], const double b1[2],
14793                     const double b2[2], double cross[2],
14794                     int *status ) {
14795    if ( !astOK ) return;
14796    (**astMEMBER(this,Frame,Intersect))( this, a1, a2, b1, b2, cross, status );
14797 }
astOverlay_(AstFrame * template,const int * template_axes,AstFrame * result,int * status)14798 void astOverlay_( AstFrame *template, const int *template_axes,
14799                   AstFrame *result, int *status ) {
14800    if ( !astOK ) return;
14801    (**astMEMBER(template,Frame,Overlay))( template, template_axes, result, status );
14802 }
astPermAxes_(AstFrame * this,const int perm[],int * status)14803 void astPermAxes_( AstFrame *this, const int perm[], int *status ) {
14804    if ( !astOK ) return;
14805    (**astMEMBER(this,Frame,PermAxes))( this, perm, status );
14806 }
astPickAxes_(AstFrame * this,int naxes,const int axes[],AstMapping ** map,int * status)14807 AstFrame *astPickAxes_( AstFrame *this, int naxes, const int axes[],
14808                         AstMapping **map, int *status ) {
14809    if ( !astOK ) return NULL;
14810    return (**astMEMBER(this,Frame,PickAxes))( this, naxes, axes, map, status );
14811 }
astPrimaryFrame_(AstFrame * this,int axis1,AstFrame ** frame,int * axis2,int * status)14812 void astPrimaryFrame_( AstFrame *this, int axis1,
14813                       AstFrame **frame, int *axis2, int *status ) {
14814    if ( !astOK ) return;
14815    (**astMEMBER(this,Frame,PrimaryFrame))( this, axis1, frame, axis2, status );
14816 }
astResolve_(AstFrame * this,const double point1[],const double point2[],const double point3[],double point4[],double * d1,double * d2,int * status)14817 void astResolve_( AstFrame *this, const double point1[], const double point2[],
14818                  const double point3[], double point4[], double *d1,
14819                  double *d2, int *status ) {
14820    if ( !astOK ) return;
14821    (**astMEMBER(this,Frame,Resolve))( this, point1, point2, point3, point4, d1, d2, status );
14822 }
astSetAxis_(AstFrame * this,int axis,AstAxis * newaxis,int * status)14823 void astSetAxis_( AstFrame *this, int axis, AstAxis *newaxis, int *status ) {
14824    if ( !astOK ) return;
14825    (**astMEMBER(this,Frame,SetAxis))( this, axis, newaxis, status );
14826 }
astSetUnit_(AstFrame * this,int axis,const char * value,int * status)14827 void astSetUnit_( AstFrame *this, int axis, const char *value, int *status ) {
14828    if ( !astOK ) return;
14829    (**astMEMBER(this,Frame,SetUnit))( this, axis, value, status );
14830 }
astClearUnit_(AstFrame * this,int axis,int * status)14831 void astClearUnit_( AstFrame *this, int axis, int *status ) {
14832    if ( !astOK ) return;
14833    (**astMEMBER(this,Frame,ClearUnit))( this, axis, status );
14834 }
astSubFrame_(AstFrame * target,AstFrame * template,int result_naxes,const int * target_axes,const int * template_axes,AstMapping ** map,AstFrame ** result,int * status)14835 int astSubFrame_( AstFrame *target, AstFrame *template, int result_naxes,
14836                   const int *target_axes, const int *template_axes,
14837                   AstMapping **map, AstFrame **result, int *status ) {
14838    if ( !astOK ) return 0;
14839    return (**astMEMBER(target,Frame,SubFrame))( target, template, result_naxes,
14840                                                 target_axes, template_axes,
14841                                                 map, result, status );
14842 }
astUnformat_(AstFrame * this,int axis,const char * string,double * value,int * status)14843 int astUnformat_( AstFrame *this, int axis, const char *string,
14844                   double *value, int *status ) {
14845    if ( !astOK ) return 0;
14846    return (**astMEMBER(this,Frame,Unformat))( this, axis, string, value, status );
14847 }
astValidateAxis_(AstFrame * this,int axis,int fwd,const char * method,int * status)14848 int astValidateAxis_( AstFrame *this, int axis, int fwd, const char *method, int *status ) {
14849    if ( !astOK ) return 0;
14850    return (**astMEMBER(this,Frame,ValidateAxis))( this, axis, fwd, method, status );
14851 }
astValidateAxisSelection_(AstFrame * this,int naxes,const int * axes,const char * method,int * status)14852 void astValidateAxisSelection_( AstFrame *this, int naxes, const int *axes,
14853                                 const char *method, int *status ) {
14854    if ( !astOK ) return;
14855    (**astMEMBER(this,Frame,ValidateAxisSelection))( this, naxes, axes,
14856                                                     method, status );
14857 }
astValidateSystem_(AstFrame * this,AstSystemType system,const char * method,int * status)14858 AstSystemType astValidateSystem_( AstFrame *this, AstSystemType system, const char *method, int *status ) {
14859    if ( !astOK ) return AST__BADSYSTEM;
14860    return (**astMEMBER(this,Frame,ValidateSystem))( this, system, method, status );
14861 }
astSystemCode_(AstFrame * this,const char * system,int * status)14862 AstSystemType astSystemCode_( AstFrame *this, const char *system, int *status ) {
14863    if ( !astOK ) return AST__BADSYSTEM;
14864    return (**astMEMBER(this,Frame,SystemCode))( this, system, status );
14865 }
astSystemString_(AstFrame * this,AstSystemType system,int * status)14866 const char *astSystemString_( AstFrame *this, AstSystemType system, int *status ) {
14867    if ( !astOK ) return NULL;
14868    return (**astMEMBER(this,Frame,SystemString))( this, system, status );
14869 }
astAxIn_(AstFrame * this,int axis,double lo,double hi,double val,int closed,int * status)14870 int astAxIn_( AstFrame *this, int axis, double lo, double hi, double val,
14871               int closed, int *status ) {
14872    if ( !astOK ) return 0;
14873    return (**astMEMBER(this,Frame,AxIn))( this, axis, lo, hi, val, closed, status );
14874 }
astGetFrameFlags_(AstFrame * this,int * status)14875 int astGetFrameFlags_( AstFrame *this, int *status ) {
14876    if ( !astOK ) return 0;
14877    return (**astMEMBER(this,Frame,GetFrameFlags))( this, status );
14878 }
astSetFrameFlags_(AstFrame * this,int value,int * status)14879 void astSetFrameFlags_( AstFrame *this, int value, int *status ) {
14880    if ( !astOK ) return;
14881    (**astMEMBER(this,Frame,SetFrameFlags))( this, value, status );
14882 }
14883 
14884 
14885 /* Special public interface functions. */
14886 /* =================================== */
14887 /* These provide the public interface to certain special functions
14888    whose public interface cannot be handled using macros (such as
14889    astINVOKE) alone. In general, they are named after the
14890    corresponding protected version of the function, but with "Id"
14891    appended to the name. */
14892 
14893 /* Public Interface Function Prototypes. */
14894 /* ------------------------------------- */
14895 /* The following functions have public prototypes only (i.e. no
14896    protected prototypes), so we must provide local prototypes for use
14897    within this module. */
14898 AstFrame *PickAxesId_( AstFrame *, int, const int[], AstMapping **, int * );
14899 AstFrame *astFrameId_( int, const char *, ... );
14900 const char *astFormatId_( AstFrame *, int, double, int * );
14901 int astUnformatId_( AstFrame *, int, const char *, double *, int * );
14902 void astPermAxesId_( AstFrame *, const int[], int * );
14903 
14904 /* Special interface function implementations. */
14905 /* ------------------------------------------- */
astFormatId_(AstFrame * this,int axis,double value,int * status)14906 const char *astFormatId_( AstFrame *this, int axis, double value, int *status ) {
14907 /*
14908 *++
14909 *  Name:
14910 c     astFormat
14911 f     AST_FORMAT
14912 
14913 *  Purpose:
14914 *     Format a coordinate value for a Frame axis.
14915 
14916 *  Type:
14917 *     Public virtual function.
14918 
14919 *  Synopsis:
14920 c     #include "frame.h"
14921 c     const char *astFormat( AstFrame *this, int axis, double value )
14922 f     RESULT = AST_FORMAT( THIS, AXIS, VALUE, STATUS )
14923 
14924 *  Class Membership:
14925 *     Frame method.
14926 
14927 *  Description:
14928 c     This function returns a pointer to a string containing the
14929 f     This function returns a character string containing the
14930 *     formatted (character) version of a coordinate value for a Frame
14931 *     axis. The formatting applied is determined by the Frame's
14932 *     attributes and, in particular, by any Format attribute string
14933 *     that has been set for the axis. A suitable default format (based
14934 *     on the Digits attribute value) will be applied if necessary.
14935 
14936 *  Parameters:
14937 c     this
14938 f     THIS = INTEGER (given)
14939 *        Pointer to the Frame.
14940 c     axis
14941 f     AXIS = INTEGER (Given)
14942 *        The number of the Frame axis for which formatting is to be
14943 *        performed (axis numbering starts at 1 for the first axis).
14944 c     value
14945 f     VALUE = DOUBLE PRECISION (Given)
14946 *        The coordinate value to be formatted.
14947 f     STATUS = INTEGER (Given and Returned)
14948 f        The global status.
14949 
14950 *  Returned Value:
14951 c     astFormat()
14952 c        A pointer to a null-terminated string containing the formatted
14953 c        value.
14954 f     AST_FORMAT = CHARACTER * ( AST__SZCHR )
14955 f        The formatted value.
14956 
14957 *  Notes:
14958 c     - The returned pointer is guaranteed to remain valid and the
14959 c     string to which it points will not be over-written for a total
14960 c     of 50 successive invocations of this function. After this, the
14961 c     memory containing the string may be re-used, so a copy of the
14962 c     string should be made if it is needed for longer than this.
14963 c     - A formatted value may be converted back into a numerical (double)
14964 c     value using astUnformat.
14965 f     - A formatted value may be converted back into a numerical
14966 f     (double precision) value using AST_UNFORMAT.
14967 c     - A NULL pointer will be returned if this function is invoked
14968 c     with the AST error status set, or if it should fail for any
14969 c     reason.
14970 f     - A blank string will be returned if this function is invoked
14971 f     with STATUS set to an error value, or if it should fail for any
14972 f     reason.
14973 *--
14974 
14975 *  Implementation Notes:
14976 *     This function implements the public interface for the astFormat
14977 *     method. It is identical to astFormat_ except that:
14978 *
14979 *     - The axis index is decremented by 1 before use. This allows the
14980 *     public interface to use 1-based axis numbers (whereas internally
14981 *     axis numbers are zero-based).
14982 *
14983 *     - The returned string value is buffered in dynamically allocated
14984 *     memory so that it will remain valid for a guaranteed number of
14985 *     function invocations.
14986 */
14987 
14988 /* Local Variables: */
14989    astDECLARE_GLOBALS            /* Thread-specific global data */
14990    const char *fvalue;           /* Pointer to formatted value */
14991    const char *result;           /* Pointer value to return */
14992    int i;                        /* Loop counter for initialisation */
14993 
14994 /* Initialise. */
14995    result = NULL;
14996 
14997 /* Check the global error status. */
14998    if ( !astOK ) return result;
14999 
15000 /* Get a pointer to Thread-specific global data. */
15001    astGET_GLOBALS(this);
15002 
15003 /* If the "astformatid_strings" array has not been initialised, fill it with NULL
15004    pointers. */
15005    if ( !astformatid_init ) {
15006       astformatid_init = 1;
15007       for ( i = 0; i < ASTFORMATID_MAX_STRINGS; i++ ) astformatid_strings[ i ] = NULL;
15008    }
15009 
15010 /* Invoke the normal astFormat_ function to obtain a pointer to the
15011    required formatted value, adjusting the axis index to become
15012    zero-based. */
15013    fvalue = astFormat( this, axis - 1, value );
15014 
15015 /* If OK, store a copy of the resulting string in dynamically allocated memory,
15016    putting a pointer to the copy into the next element of the "astformatid_strings"
15017    array.  (This process also de-allocates any previously allocated memory pointed
15018    at by this "astformatid_strings" element, so the earlier string is effectively
15019    replaced by the new one.) */
15020    if ( astOK ) {
15021       astBeginPM;
15022       astformatid_strings[ astformatid_istr ] = astStore( astformatid_strings[ astformatid_istr ], fvalue,
15023                                   strlen( fvalue ) + (size_t) 1 );
15024       astEndPM;
15025 
15026 /* If OK, return a pointer to the copy and increment "astformatid_istr" to use
15027    the next element of "astformatid_strings" on the next invocation. Recycle
15028    "astformatid_istr" to zero when all elements have been used. */
15029       if ( astOK ) {
15030          result = astformatid_strings[ astformatid_istr++ ];
15031          if ( astformatid_istr == ( ASTFORMATID_MAX_STRINGS - 1 ) ) astformatid_istr = 0;
15032       }
15033    }
15034 
15035 /* Return the result. */
15036    return result;
15037 
15038 }
15039 
astFrameId_(int naxes,const char * options,...)15040 AstFrame *astFrameId_( int naxes, const char *options, ... ) {
15041 /*
15042 *++
15043 *  Name:
15044 c     astFrame
15045 f     AST_FRAME
15046 
15047 *  Purpose:
15048 *     Create a Frame.
15049 
15050 *  Type:
15051 *     Public function.
15052 
15053 *  Synopsis:
15054 c     #include "frame.h"
15055 c     AstFrame *astFrame( int naxes, const char *options, ... )
15056 f     RESULT = AST_FRAME( NAXES, OPTIONS, STATUS )
15057 
15058 *  Class Membership:
15059 *     Frame constructor.
15060 
15061 *  Description:
15062 *     This function creates a new Frame and optionally initialises its
15063 *     attributes.
15064 *
15065 *     A Frame is used to represent a coordinate system. It does this
15066 *     in rather the same way that a frame around a graph describes the
15067 *     coordinate space in which data are plotted. Consequently, a
15068 *     Frame has a Title (string) attribute, which describes the
15069 *     coordinate space, and contains axes which in turn hold
15070 *     information such as Label and Units strings which are used for
15071 *     labelling (e.g.) graphical output. In general, however, the
15072 *     number of axes is not restricted to two.
15073 *
15074 *     Functions are available for converting Frame coordinate values
15075 *     into a form suitable for display, and also for calculating
15076 *     distances and offsets between positions within the Frame.
15077 *
15078 *     Frames may also contain knowledge of how to transform to and
15079 *     from related coordinate systems.
15080 
15081 *  Parameters:
15082 c     naxes
15083 f     NAXES = INTEGER (Given)
15084 *        The number of Frame axes (i.e. the number of dimensions of
15085 *        the coordinate space which the Frame describes).
15086 c     options
15087 f     OPTIONS = CHARACTER * ( * ) (Given)
15088 c        Pointer to a null-terminated string containing an optional
15089 c        comma-separated list of attribute assignments to be used for
15090 c        initialising the new Frame. The syntax used is identical to
15091 c        that for the astSet function and may include "printf" format
15092 c        specifiers identified by "%" symbols in the normal way.
15093 c        If no initialisation is required, a zero-length string may be
15094 c        supplied.
15095 f        A character string containing an optional comma-separated
15096 f        list of attribute assignments to be used for initialising the
15097 f        new Frame. The syntax used is identical to that for the
15098 f        AST_SET routine. If no initialisation is required, a blank
15099 f        value may be supplied.
15100 c     ...
15101 c        If the "options" string contains "%" format specifiers, then
15102 c        an optional list of additional arguments may follow it in
15103 c        order to supply values to be substituted for these
15104 c        specifiers. The rules for supplying these are identical to
15105 c        those for the astSet function (and for the C "printf"
15106 c        function).
15107 f     STATUS = INTEGER (Given and Returned)
15108 f        The global status.
15109 
15110 *  Returned Value:
15111 c     astFrame()
15112 f     AST_FRAME = INTEGER
15113 *        A pointer to the new Frame.
15114 
15115 *  Examples:
15116 c     frame = astFrame( 2, "Title=Energy Spectrum: Plot %d", n );
15117 c        Creates a new 2-dimensional Frame and initialises its Title
15118 c        attribute to the string "Energy Spectrum: Plot <n>", where
15119 c        <n> takes the value of the int variable "n".
15120 c     frame = astFrame( 2, "Label(1)=Energy, Label(2)=Response" );
15121 c        Creates a new 2-dimensional Frame and initialises its axis
15122 c        Label attributes to suitable string values.
15123 f     FRAME = AST_FRAME( 2, 'Title=Energy Spectrum', STATUS );
15124 f        Creates a new 2-dimensional Frame and initialises its Title
15125 f        attribute to the string "Energy Spectrum".
15126 f     FRAME = AST_FRAME( 2, 'Label(1)=Energy, Label(2)=Response', STATUS );
15127 f        Creates a new 2-dimensional Frame and initialises its axis
15128 f        Label attributes to suitable string values.
15129 
15130 *  Notes:
15131 *     - A null Object pointer (AST__NULL) will be returned if this
15132 c     function is invoked with the AST error status set, or if it
15133 f     function is invoked with STATUS set to an error value, or if it
15134 *     should fail for any reason.
15135 *--
15136 
15137 *  Implementation Notes:
15138 *     - This function implements the external (public) interface to
15139 *     the astFrame constructor function. It returns an ID value
15140 *     (instead of a true C pointer) to external users, and must be
15141 *     provided because astFrame_ has a variable argument list which
15142 *     cannot be encapsulated in a macro (where this conversion would
15143 *     otherwise occur).
15144 *     - The variable argument list also prevents this function from
15145 *     invoking astFrame_ directly, so it must be a re-implementation
15146 *     of it in all respects, except for the final conversion of the
15147 *     result to an ID value.
15148 */
15149 
15150 /* Local Variables: */
15151    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
15152    AstFrame *new;                /* Pointer to new Frame */
15153    va_list args;                 /* Variable argument list */
15154 
15155    int *status;                  /* Pointer to inherited status value */
15156 
15157 /* Get a pointer to the inherited status value. */
15158    status = astGetStatusPtr;
15159 
15160 /* Get a pointer to the thread specific global data structure. */
15161    astGET_GLOBALS(NULL);
15162 
15163 /* Check the global error status. */
15164    if ( !astOK ) return NULL;
15165 
15166 /* Initialise the Frame, allocating memory and initialising the virtual
15167    function table as well if necessary. */
15168    new = astInitFrame( NULL, sizeof( AstFrame ), !class_init, &class_vtab,
15169                        "Frame", naxes );
15170 
15171 /* If successful, note that the virtual function table has been initialised. */
15172    if ( astOK ) {
15173       class_init = 1;
15174 
15175 /* Obtain the variable argument list and pass it along with the options string
15176    to the astVSet method to initialise the new Frame's attributes. */
15177       va_start( args, options );
15178       astVSet( new, options, NULL, args );
15179       va_end( args );
15180 
15181 /* If an error occurred, clean up by deleting the new object. */
15182       if ( !astOK ) new = astDelete( new );
15183    }
15184 
15185 /* Return an ID value for the new Frame. */
15186    return astMakeId( new );
15187 }
15188 
astPermAxesId_(AstFrame * this,const int perm[],int * status)15189 void astPermAxesId_( AstFrame *this, const int perm[], int *status ) {
15190 /*
15191 *++
15192 *  Name:
15193 c     astPermAxes
15194 f     AST_PERMAXES
15195 
15196 *  Purpose:
15197 *     Permute the axis order in a Frame.
15198 
15199 *  Type:
15200 *     Public virtual function.
15201 
15202 *  Synopsis:
15203 c     #include "frame.h"
15204 c     void astPermAxes( AstFrame *this, const int perm[] )
15205 f     CALL AST_PERMAXES( THIS, PERM, STATUS )
15206 
15207 *  Class Membership:
15208 *     Frame method.
15209 
15210 *  Description:
15211 c     This function permutes the order in which a Frame's axes occur.
15212 f     This routine permutes the order in which a Frame's axes occur.
15213 
15214 *  Parameters:
15215 c     this
15216 f     THIS = INTEGER (Given)
15217 *        Pointer to the Frame.
15218 c     perm
15219 f     PERM( * ) = INTEGER (Given)
15220 *        An array with one element for each axis of the Frame (Naxes
15221 *        attribute). This should list the axes in their new order,
15222 *        using the original axis numbering (which starts at 1 for the
15223 *        first axis).
15224 f     STATUS = INTEGER (Given and Returned)
15225 f        The global status.
15226 
15227 *  Notes:
15228 *     - Only genuine permutations of the axis order are permitted, so
15229 c     each axis must be referenced exactly once in the "perm" array.
15230 f     each axis must be referenced exactly once in the PERM array.
15231 *     - If successive axis permutations are applied to a Frame, then
15232 *     the effects are cumulative.
15233 *--
15234 
15235 *  Implementation Notes:
15236 *     This function implements the public interface for the
15237 *     astPermAxes method. It is identical to astPermAxes_ except that
15238 *     the axis numbers in the "perm" array are decremented by 1 before
15239 *     use. This is to allow the public interface to use one-based axis
15240 *     numbering (internally, zero-based axis numbering is used).
15241 */
15242 
15243 /* Local Variables: */
15244    int *perm1;                   /* Pointer to modified perm array */
15245    int axis;                     /* Loop counter for Frame axes */
15246    int naxes;                    /* Number of Frame axes */
15247 
15248 /* Check the global error status. */
15249    if ( !astOK ) return;
15250 
15251 /* Obtain the number of Frame axes. */
15252    naxes = astGetNaxes( this );
15253 
15254 /* Allocate an array to hold a modified version of the "perm"
15255    array. */
15256    perm1 = astMalloc( sizeof( int ) * (size_t) naxes );
15257    if ( astOK ) {
15258 
15259 /* Make a modified copy of the "perm" array by subtracting one from
15260    each element. This allows the public interface to use one-based
15261    axis numbering, whereas all internal code is zero-based. */
15262       for ( axis = 0; axis < naxes; axis++ ) perm1[ axis ] = perm[ axis ] - 1;
15263 
15264 /* Invoke the normal astPermAxes_ function to permute the Frame's axes. */
15265       astPermAxes( this, perm1 );
15266    }
15267 
15268 /* Free the temporary array. */
15269    perm1 = astFree( perm1 );
15270 }
15271 
astPickAxesId_(AstFrame * this,int naxes,const int axes[],AstMapping ** map,int * status)15272 AstFrame *astPickAxesId_( AstFrame *this, int naxes, const int axes[],
15273                           AstMapping **map, int *status ) {
15274 /*
15275 *++
15276 *  Name:
15277 c     astPickAxes
15278 f     AST_PICKAXES
15279 
15280 *  Purpose:
15281 *     Create a new Frame by picking axes from an existing one.
15282 
15283 *  Type:
15284 *     Public virtual function.
15285 
15286 *  Synopsis:
15287 c     #include "frame.h"
15288 c     AstFrame *astPickAxes( AstFrame *this, int naxes, const int axes[],
15289 c                            AstMapping **map )
15290 f     RESULT = AST_PICKAXES( THIS, NAXES, AXES, MAP, STATUS )
15291 
15292 *  Class Membership:
15293 *     Frame method.
15294 
15295 *  Description:
15296 *     This function creates a new Frame whose axes are copied from an
15297 *     existing Frame along with other Frame attributes, such as its
15298 *     Title. Any number (zero or more) of the original Frame's axes
15299 *     may be copied, in any order, and additional axes with default
15300 *     attributes may also be included in the new Frame.
15301 *
15302 c     Optionally, a Mapping that converts between the coordinate
15303 f     A Mapping that converts between the coordinate
15304 *     systems described by the two Frames will also be returned.
15305 
15306 *  Parameters:
15307 c     this
15308 f     THIS = INTEGER (Given)
15309 *        Pointer to the original Frame.
15310 c     naxes
15311 f     NAXES = INTEGER (Given)
15312 *        The number of axes required in the new Frame.
15313 c     axes
15314 f     AXES( NAXES ) = INTEGER (Given)
15315 c        An array, with "naxes" elements, which lists the axes to be
15316 f        An array which lists the axes to be
15317 *        copied. These should be given in the order required in the
15318 *        new Frame, using the axis numbering in the original Frame
15319 *        (which starts at 1 for the first axis). Axes may be selected
15320 *        in any order, but each may only be used once.  If additional
15321 *        (default) axes are also to be included, the corresponding
15322 *        elements of this array should be set to zero.
15323 c     map
15324 f     MAP = INTEGER (Returned)
15325 c        Address of a location in which to return a pointer to a new
15326 f        A pointer to a new
15327 *        Mapping. This will be a PermMap (or a UnitMap as a special
15328 *        case) that describes the axis permutation that has taken
15329 *        place between the original and new Frames. The Mapping's
15330 *        forward transformation will convert coordinates from the
15331 *        original Frame into the new one, and vice versa.
15332 c
15333 c        If this Mapping is not required, a NULL value may be supplied
15334 c        for this parameter.
15335 f     STATUS = INTEGER (Given and Returned)
15336 f        The global status.
15337 
15338 *  Returned Value:
15339 c     astPickAxes()
15340 f     AST_PICKAXES = INTEGER
15341 *        A pointer to the new Frame.
15342 
15343 *  Applicability:
15344 *     Frame
15345 *        This function applies to all Frames. The class of Frame returned
15346 *        may differ from that of the original Frame, depending on which
15347 *        axes are selected. For example, if a single axis is picked from a
15348 *        SkyFrame (which must always have two axes) then the resulting
15349 *        Frame cannot be a valid SkyFrame, so will revert to the parent
15350 *        class (Frame) instead.
15351 *     FrameSet
15352 *        Using this function on a FrameSet is identical to using it on
15353 *        the current Frame in the FrameSet. The returned Frame will not
15354 *        be a FrameSet.
15355 *     Region
15356 *        If this function is used on a Region, an attempt is made to
15357 *        retain the bounds information on the selected axes. If
15358 *        succesful, the returned Frame will be a Region of some class.
15359 *        Otherwise, the returned Frame is obtained by calling this
15360 *        function on the Frame represented by the supplied Region (the
15361 *        returned Frame will then not be a Region). In order to be
15362 *        succesful, the selected axes in the Region must be independent
15363 *        of the others. For instance, a Box can be split in this way but
15364 *        a Circle cannot. Another requirement for success is that no
15365 *        default axes are added (that is, the
15366 c        "axes"
15367 f        AXES
15368 *        array must not contain any zero values.
15369 
15370 *  Notes:
15371 c     - The new Frame will contain a "deep" copy (c.f. astCopy) of all
15372 f     - The new Frame will contain a "deep" copy (c.f. AST_COPY) of all
15373 *     the data selected from the original Frame. Modifying any aspect
15374 *     of the new Frame will therefore not affect the original one.
15375 *     - A null Object pointer (AST__NULL) will be returned if this
15376 c     function is invoked with the AST error status set, or if it
15377 f     function is invoked with STATUS set to an error value, or if it
15378 *     should fail for any reason.
15379 *--
15380 
15381 *  Implementation Notes:
15382 *     This function implements the public interface for the
15383 *     astPickAxes method. It is identical to astPickAxes_ except for
15384 *     the following:
15385 *
15386 *     - The axis numbers in the "axes" array are decremented by 1 before
15387 *     use. This is to allow the public interface to use one-based axis
15388 *     numbering (internally, zero-based axis numbering is used).
15389 *
15390 *     - An ID value is returned via the "map" parameter (if used)
15391 *     instead of a true C pointer. This is required because this
15392 *     conversion cannot be performed by the macro that invokes the
15393 *     function.
15394 */
15395 
15396 /* Local Variables: */
15397    AstFrame *result;             /* Pointer to result Frame */
15398    int *axes1;                   /* Pointer to modified axes array */
15399    int axis;                     /* Loop counter for axes */
15400 
15401 /* Initialise. */
15402    result = NULL;
15403 
15404 /* Check the global error status. */
15405    if ( !astOK ) return result;
15406 
15407 /* Allocate an array to hold a modified version of the "axes" array
15408    (check that "naxes" is valid first - if not, this error will be
15409    reported by astPickAxes_ below). */
15410    axes1 = ( naxes >= 0 ) ? astMalloc( sizeof( int ) * (size_t) naxes ) :
15411                             NULL;
15412    if ( astOK ) {
15413 
15414 /* Make a modified copy of the "axes" array by subtracting one from
15415    each element. This allows the public interface to use one-based
15416    axis numbering, whereas all internal code is zero-based. */
15417       for ( axis = 0; axis < naxes; axis++ ) axes1[ axis ] = axes[ axis ] - 1;
15418 
15419 /* Invoke the normal astPickAxes_ function to select the required axes. */
15420       result = astPickAxes( this, naxes, axes1, map );
15421    }
15422 
15423 /* Free the temporary array. */
15424    axes1 = astFree( axes1 );
15425 
15426 /* If required, return an ID value for the Mapping. */
15427    if ( map ) *map = astMakeId( *map );
15428 
15429 /* Return the result. */
15430    return result;
15431 }
15432 
astUnformatId_(AstFrame * this,int axis,const char * string,double * value,int * status)15433 int astUnformatId_( AstFrame *this, int axis, const char *string,
15434                     double *value, int *status ) {
15435 /*
15436 *++
15437 *  Name:
15438 c     astUnformat
15439 f     AST_UNFORMAT
15440 
15441 *  Purpose:
15442 *     Read a formatted coordinate value for a Frame axis.
15443 
15444 *  Type:
15445 *     Public virtual function.
15446 
15447 *  Synopsis:
15448 c     #include "frame.h"
15449 c     int astUnformat( AstFrame *this, int axis, const char *string,
15450 c                      double *value )
15451 f     RESULT = AST_UNFORMAT( THIS, AXIS, STRING, VALUE, STATUS )
15452 
15453 *  Class Membership:
15454 *     Frame method.
15455 
15456 *  Description:
15457 c     This function reads a formatted coordinate value (given as a
15458 c     character string) for a Frame axis and returns the equivalent
15459 c     numerical (double) value. It also returns the number of
15460 c     characters read from the string.
15461 f     This function reads a formatted coordinate value (given as a
15462 f     character string) for a Frame axis and returns the equivalent
15463 f     numerical (double precision) value. It also returns the number
15464 f     of characters read from the string.
15465 *
15466 c     The principle use of this function is in decoding user-supplied
15467 c     input which contains formatted coordinate values. Free-format
15468 c     input is supported as far as possible. If input is ambiguous, it
15469 c     is interpreted with reference to the Frame's attributes (in
15470 c     particular, the Format string associated with the Frame's
15471 c     axis). This function is, in essence, the inverse of astFormat.
15472 f     The principle use of this function is in decoding user-supplied
15473 f     input which contains formatted coordinate values. Free-format
15474 f     input is supported as far as possible. If input is ambiguous, it
15475 f     is interpreted with reference to the Frame's attributes (in
15476 f     particular, the Format string associated with the Frame's
15477 f     axis). This function is, in essence, the inverse of AST_FORMAT.
15478 
15479 *  Parameters:
15480 c     this
15481 f     THIS = INTEGER (Given)
15482 *        Pointer to the Frame.
15483 c     axis
15484 f     AXIS = INTEGER (Given)
15485 *        The number of the Frame axis for which a coordinate value is to
15486 *        be read (axis numbering starts at 1 for the first axis).
15487 c     string
15488 f     STRING = CHARACTER * ( * ) (Given)
15489 c        Pointer to a null-terminated character string containing the
15490 c        formatted coordinate value.
15491 f        A character string containing the formatted coordinate value.
15492 *        This string may contain additional information following the
15493 *        value to be read, in which case reading stops at the first
15494 *        character which cannot be interpreted as part of the value.
15495 *        Any white space before or after the value is discarded.
15496 c     value
15497 f     VALUE = DOUBLE PRECISION (Returned)
15498 c        Pointer to a double in which the coordinate value read will be
15499 c        returned.
15500 f        The coordinate value read.
15501 f     STATUS = INTEGER (Given and Returned)
15502 f        The global status.
15503 
15504 *  Returned Value:
15505 c     astUnformat()
15506 f     AST_UNFORMAT = INTEGER
15507 *        The number of characters read from the string in order to
15508 *        obtain the coordinate value. This will include any white
15509 *        space which occurs before or after the value.
15510 
15511 *  Applicability:
15512 *     Frame
15513 *        This function applies to all Frames. See the "Frame Input
15514 *        Format" section below for details of the input formats
15515 *        accepted by a basic Frame.
15516 *     SkyFrame
15517 *        The SkyFrame class re-defines the input format to be suitable
15518 *        for representing angles and times, with the resulting
15519 *        coordinate value returned in radians.  See the "SkyFrame
15520 *        Input Format" section below for details of the formats
15521 *        accepted.
15522 *     FrameSet
15523 *        The input formats accepted by a FrameSet are determined by
15524 *        its current Frame (as specified by the Current attribute).
15525 
15526 *  Frame Input Format
15527 *     The input format accepted for a basic Frame axis is as follows:
15528 *     - An optional sign, followed by:
15529 *     - A sequence of one or more digits possibly containing a decimal point,
15530 *     followed by:
15531 *     - An optional exponent field.
15532 *     - The exponent field, if present, consists of "E" or "e"
15533 *     followed by a possibly signed integer.
15534 *
15535 *     Examples of acceptable Frame input formats include:
15536 *     - 99
15537 *     - 1.25
15538 *     - -1.6
15539 *     - 1E8
15540 *     - -.99e-17
15541 *     - <bad>
15542 
15543 *  SkyFrame Input Format
15544 *     The input format accepted for a SkyFrame axis is as follows:
15545 *     - An optional sign, followed by between one and three fields
15546 *     representing either degrees, arc-minutes, arc-seconds or hours,
15547 *     minutes, seconds (e.g. "-12 42 03").
15548 *     - Each field should consist of a sequence of one or more digits,
15549 *     which may include leading zeros. At most one field may contain a
15550 *     decimal point, in which case it is taken to be the final field
15551 *     (e.g. decimal degrees might be given as "124.707", while degrees
15552 *     and decimal arc-minutes might be given as "-13 33.8").
15553 *     - The first field given may take any value, allowing angles and
15554 *     times outside the conventional ranges to be
15555 *     represented. However, subsequent fields must have values of less
15556 *     than 60 (e.g. "720 45 31" is valid, whereas "11 45 61" is not).
15557 *     - Fields may be separated by white space or by ":" (colon), but
15558 *     the choice of separator must be used consistently throughout the
15559 *     value. Additional white space may be present around fields and
15560 *     separators (e.g. "- 2: 04 : 7.1").
15561 *     - The following field identification characters may be used as
15562 *     separators to replace either of those above (or may be appended
15563 *     to the final field), in order to identify the field to which
15564 *     they are appended: "d"---degrees; "h"---hours; "m"---minutes of
15565 *     arc or time; "s"---seconds of arc or time; "'" (single
15566 *     quote)---minutes of arc; """ (double quote)---seconds of arc.
15567 *     Either lower or upper case may be used.  Fields must be given in
15568 *     order of decreasing significance (e.g. "-11D 3' 14.4"" or
15569 *     "22h14m11.2s").
15570 *     - The presence of any of the field identification characters
15571 *     "d", "'" (single quote) or """ (double quote) indicates that the
15572 *     value is to be interpreted as an angle. Conversely, the presence
15573 *     of "h" indicates that it is to be interpreted as a time (with 24
15574 *     hours corresponding to 360 degrees). Incompatible angle/time
15575 *     identification characters may not be mixed (e.g. "10h14'3"" is
15576 *     not valid).  The remaining field identification characters and
15577 *     separators do not specify a preference for an angle or a time
15578 *     and may be used with either.
15579 c     - If no preference for an angle or a time is expressed anywhere
15580 c     within the value, it is interpreted as an angle if the Format
15581 c     attribute string associated with the SkyFrame axis generates an
15582 c     angle and as a time otherwise. This ensures that values produced
15583 c     by astFormat are correctly interpreted by astUnformat.
15584 f     - If no preference for an angle or a time is expressed anywhere
15585 f     within the value, it is interpreted as an angle if the Format
15586 f     attribute string associated with the SkyFrame axis generates an
15587 f     angle and as a time otherwise. This ensures that values produced
15588 f     by AST_FORMAT are correctly interpreted by AST_UNFORMAT.
15589 *     - Fields may be omitted, in which case they default to zero. The
15590 *     remaining fields may be identified by using appropriate field
15591 *     identification characters (see above) and/or by adding extra
15592 *     colon separators (e.g. "-05m13s" is equivalent to "-:05:13"). If
15593 *     a field is not identified explicitly, it is assumed that
15594 *     adjacent fields have been given, after taking account of any
15595 *     extra separator characters (e.g. "14:25.4s" specifies minutes
15596 *     and seconds, while "14::25.4s" specifies degrees and seconds).
15597 c     - If fields are omitted in such a way that the remaining ones
15598 c     cannot be identified uniquely (e.g. "01:02"), then the first
15599 c     field (either given explicitly or implied by an extra leading
15600 c     colon separator) is taken to be the most significant field that
15601 c     astFormat would produce when formatting a value (using the
15602 c     Format attribute associated with the SkyFrame axis).  By
15603 c     default, this means that the first field will normally be
15604 c     interpreted as degrees or hours. However, if this does not
15605 c     result in consistent field identification, then the last field
15606 c     (either given explicitly or implied by an extra trailing colon
15607 c     separator) is taken to to be the least significant field that
15608 c     astFormat would produce.
15609 f     - If fields are omitted in such a way that the remaining ones
15610 f     cannot be identified uniquely (e.g. "01:02"), then the first
15611 f     field (either given explicitly or implied by an extra leading
15612 f     colon separator) is taken to be the most significant field that
15613 f     AST_FORMAT would produce when formatting a value (using the
15614 f     Format attribute associated with the SkyFrame axis).  By
15615 f     default, this means that the first field will normally be
15616 f     interpreted as degrees or hours. However, if this does not
15617 f     result in consistent field identification, then the last field
15618 f     (either given explicitly or implied by an extra trailing colon
15619 f     separator) is taken to to be the least significant field that
15620 f     AST_FORMAT would produce.
15621 *
15622 c     This final convention is intended to ensure that values formatted
15623 c     by astFormat which contain less than three fields will be
15624 c     correctly interpreted if read back using astUnformat, even if
15625 c     they do not contain field identification characters.
15626 f     This final convention is intended to ensure that values formatted
15627 f     by AST_FORMAT which contain less than three fields will be
15628 f     correctly interpreted if read back using AST_UNFORMAT, even if
15629 f     they do not contain field identification characters.
15630 *
15631 *     Examples of acceptable SkyFrame input formats (with
15632 *     interpretation in parentheses) include:
15633 *     - -14d 13m 22.2s (-14d 13' 22.2")
15634 *     - + 12:34:56.7 (12d 34' 56.7" or 12h 34m 56.7s)
15635 *     - 001 : 02 : 03.4 (1d 02' 03.4" or 1h 02m 03.4s)
15636 *     - 22h 30 (22h 30m 00s)
15637 *     - 136::10" (136d 00' 10" or 136h 00m 10s)
15638 *     - -14M 27S (-0d 14' 27" or -0h 14m 27s)
15639 *     - -:14: (-0d 14' 00" or -0h 14m 00s)
15640 *     - -::4.1 (-0d 00' 04.1" or -0h 00m 04.1s)
15641 *     - .9" (0d 00' 00.9")
15642 *     - d12m (0d 12' 00")
15643 *     - H 12:22.3s (0h 12m 22.3s)
15644 *     - <bad> (AST__BAD)
15645 *
15646 *     Where alternative interpretations are shown, the choice of angle or
15647 *     time depends on the associated Format(axis) attribute.
15648 
15649 *  Notes:
15650 *     - A function value of zero (and no coordinate value) will be
15651 *     returned, without error, if the string supplied does not contain
15652 *     a suitably formatted value.
15653 c     - Beware that it is possible for a formatting error part-way
15654 c     through an input string to terminate input before it has been
15655 c     completely read, but to yield a coordinate value that appears
15656 c     valid. For example, if a user types "1.5r6" instead of "1.5e6",
15657 c     the "r" will terminate input, giving an incorrect coordinate
15658 c     value of 1.5. It is therefore most important to check the return
15659 c     value of this function to ensure that the correct number of
15660 c     characters have been read.
15661 f     - Beware that it is possible for a formatting error part-way
15662 f     through an input string to terminate input before it has been
15663 f     completely read, but to yield a coordinate value that appears
15664 f     valid. For example, if a user types "1.5R6" instead of "1.5E6",
15665 f     the "R" will terminate input, giving an incorrect coordinate
15666 f     value of 1.5. It is therefore most important to check the return
15667 f     value of this function to ensure that the correct number of
15668 f     characters have been read.
15669 *     - An error will result if a value is read which appears to have
15670 *     the correct format, but which cannot be converted into a valid
15671 *     coordinate value (for instance, because the value of one or more
15672 *     of its fields is invalid).
15673 *     - The string "<bad>" is recognised as a special case and will
15674 *     yield the coordinate value AST__BAD without error. The test for
15675 *     this string is case-insensitive and also permits embedded white
15676 *     space.
15677 c     - A function result of zero will be returned and no coordinate
15678 c     value will be returned via the "value" pointer if this function
15679 c     is invoked with the AST error status set, or if it should fail
15680 c     for any reason.
15681 f     - A function result of zero will be returned and no coordinate
15682 f     value will be returned via the VALUE argument if this function
15683 f     is invoked with the AST error status set, or if it should fail
15684 f     for any reason.
15685 *--
15686 
15687 *  Implementation Notes:
15688 *     This function implements the public interface for the
15689 *     astUnformat method. It is identical to astUnformat_ except that:
15690 *
15691 *     - The axis index is decremented by 1 before use. This allows the
15692 *     public interface to use 1-based axis numbers (whereas internally
15693 *     axis numbers are zero-based).
15694 */
15695 
15696 /* Invoke the normal astUnformat_ function, adjusting the axis index
15697    to become zero-based. */
15698    return astUnformat( this, axis - 1, string, value );
15699 }
15700 
15701 
15702 
15703 
15704 
15705 
15706 
15707 
15708 
15709 
15710 
15711 
15712 
15713