1 /*
2 *class++
3 * Name:
4 * SkyFrame
5
6 * Purpose:
7 * Celestial coordinate system description.
8
9 * Constructor Function:
10 c astSkyFrame
11 f AST_SKYFRAME
12
13 * Description:
14 * A SkyFrame is a specialised form of Frame which describes
15 * celestial longitude/latitude coordinate systems. The particular
16 * celestial coordinate system to be represented is specified by
17 * setting the SkyFrame's System attribute (currently, the default
18 * is ICRS) qualified, as necessary, by a mean Equinox value and/or
19 * an Epoch.
20 *
21 * For each of the supported celestial coordinate systems, a SkyFrame
22 * can apply an optional shift of origin to create a coordinate system
23 * representing offsets within the celestial coordinate system from some
24 * specified reference point. This offset coordinate system can also be
25 * rotated to define new longitude and latitude axes. See attributes
26 * SkyRef, SkyRefIs, SkyRefP and AlignOffset.
27 *
28 * All the coordinate values used by a SkyFrame are in
29 * radians. These may be formatted in more conventional ways for
30 c display by using astFormat.
31 f display by using AST_FORMAT.
32
33 * Inheritance:
34 * The SkyFrame class inherits from the Frame class.
35
36 * Attributes:
37 * In addition to those attributes common to all Frames, every
38 * SkyFrame also has the following attributes:
39 *
40 * - AlignOffset: Align SkyFrames using the offset coordinate system?
41 * - AsTime(axis): Format celestial coordinates as times?
42 * - Equinox: Epoch of the mean equinox
43 * - IsLatAxis: Is the specified axis the latitude axis?
44 * - IsLonAxis: Is the specified axis the longitude axis?
45 * - LatAxis: Index of the latitude axis
46 * - LonAxis: Index of the longitude axis
47 * - NegLon: Display longitude values in the range [-pi,pi]?
48 * - Projection: Sky projection description.
49 * - SkyRef: Position defining location of the offset coordinate system
50 * - SkyRefIs: Selects the nature of the offset coordinate system
51 * - SkyRefP: Position defining orientation of the offset coordinate system
52
53 * Functions:
54 * In addition to those
55 c functions
56 f routines
57 * applicable to all Frames, the following
58 c functions
59 f routines
60 * may also be applied to all SkyFrames:
61 *
62 c - astSkyOffsetMap: Obtain a Mapping from absolute to offset coordinates
63 f - AST_SKYOFFSETMAP: Obtain a Mapping from absolute to offset coordinates
64
65 * Copyright:
66 * Copyright (C) 1997-2006 Council for the Central Laboratory of the
67 * Research Councils
68 * Copyright (C) 2010 Science & Technology Facilities Council.
69 * All Rights Reserved.
70
71 * Licence:
72 * This program is free software: you can redistribute it and/or
73 * modify it under the terms of the GNU Lesser General Public
74 * License as published by the Free Software Foundation, either
75 * version 3 of the License, or (at your option) any later
76 * version.
77 *
78 * This program is distributed in the hope that it will be useful,
79 * but WITHOUT ANY WARRANTY; without even the implied warranty of
80 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81 * GNU Lesser General Public License for more details.
82 *
83 * You should have received a copy of the GNU Lesser General
84 * License along with this program. If not, see
85 * <http://www.gnu.org/licenses/>.
86
87 * Authors:
88 * RFWS: R.F. Warren-Smith (Starlink)
89 * DSB: David S. Berry (Starlink)
90 * BEC: Brad Cavanagh (JAC, Hawaii)
91
92 * History:
93 * 4-MAR-1996 (RFWS):
94 * Original version.
95 * 17-MAY-1996 (RFWS):
96 * Tidied up, etc.
97 * 31-JUL-1996 (RFWS):
98 * Added support for attributes and a public interface.
99 * 11-SEP-1996 (RFWS):
100 * Added Gap (written by DSB).
101 * 24-SEP-1996 (RFWS):
102 * Added I/O facilities.
103 * 27-FEB-1997 (RFWS):
104 * Improved the public prologues.
105 * 27-MAY-1997 (RFWS):
106 * Modified to use a new public interface to the SlaMap class
107 * and to use the astSimplify method to remove redundant
108 * conversions.
109 * 16-JUN-1997 (RFWS):
110 * Fixed bug in axis associations returned by astMatch if axes
111 * were swapped.
112 * 16-JUL-1997 (RFWS):
113 * Added Projection attribute.
114 * 14-NOV-1997 (RFWS):
115 * Corrected the omission of axis permutations from astNorm.
116 * 21-JAN-1998 (RFWS):
117 * Ensure that Title and Domain values appropriate to a SkyFrame
118 * are preserved if a Frame result is generated by SubFrame.
119 * 26-FEB-1998 (RFWS):
120 * Over-ride the astUnformat method.
121 * 3-APR-2001 (DSB):
122 * Added "Unknown" option for the System attribute. Added read-only
123 * attributes LatAxis and LonAxis.
124 * 21-JUN-2001 (DSB):
125 * Added astAngle and astOffset2.
126 * 4-SEP-2001 (DSB):
127 * Added NegLon attribute, and astResolve method.
128 * 9-SEP-2001 (DSB):
129 * Added astBear method.
130 * 21-SEP-2001 (DSB):
131 * Removed astBear method.
132 * 10-OCT-2002 (DSB):
133 * Moved definitions of macros for SkyFrame system values from
134 * this file into skyframe.h.
135 * 24-OCT-2002 (DSB):
136 * Modified MakeSkyMapping so that any two SkyFrames with system=unknown
137 * are assumed to be related by a UnitMap. previously, they were
138 * considered to be unrelated, resulting in no ability to convert from
139 * one to the other. This could result for instance in astConvert
140 * being unable to find a maping from a SkyFrame to itself.
141 * 15-NOV-2002 (DSB):
142 * Moved System and Epoch attributes to the Frame class.
143 * 8-JAN-2003 (DSB):
144 * Changed private InitVtab method to protected astInitSkyFrameVtab
145 * method.
146 * 11-JUN-2003 (DSB):
147 * Added ICRS option for System attribute, and made it the default
148 * in place of FK5.
149 * 27-SEP-2003 (DSB):
150 * Added HELIOECLIPTIC option for System attribute.
151 * 19-APR-2004 (DSB):
152 * Added SkyRef, SkyRefIs, SkyRefP and AlignOffset attributes.
153 * 8-SEP-2004 (DSB):
154 * Added astResolvePoints method.
155 * 2-DEC-2004 (DSB):
156 * Added System "J2000"
157 * 27-JAN-2005 (DSB):
158 * Fix memory leaks in astLoadSkyFrame_ and Match.
159 * 7-APR-2005 (DSB):
160 * Allow SkyRefIs to be set to "Ignored".
161 * 12-MAY-2005 (DSB):
162 * Override astNormBox method.
163 * 15-AUG-2005 (DSB):
164 * Added AZEL system.
165 * 13-SEP-2005 (DSB):
166 * Override astClearSystem so that SkyRef/SkyRefPcan be converted
167 * from the original System to the default System.
168 * 19-SEP-2005 (DSB):
169 * Changed default for SkyRefIs from ORIGIN to IGNORED.
170 * 14-FEB-2006 (DSB):
171 * Override astGetObjSize.
172 * 22-FEB-2006 (DSB):
173 * Store the Local Apparent Sidereal Time in the SkyFrame structure
174 * in order to avoid expensive re-computations.
175 * 22-AUG-2006 (DSB):
176 * Ensure the cached Local Apparent Siderial Time is initialised
177 * when initialising or loading a SkyFrame.
178 * 22-SEP-2006 (DSB):
179 * Report an error in SetSystem if it is not possible to convert
180 * from old to new systems.
181 * 3-OCT-2006 (DSB):
182 * Added Equation of Equinoxes to the SkyFrame structure.
183 * 6-OCT-2006 (DSB):
184 * - Guard against annulling null pointers in subFrame.
185 * - Add Dut1 attribute
186 * - Use linear approximation for LAST over short periods (less
187 * than 0.001 of a day)
188 * - Remove Equation of Equinoxes from the SkyFrame structure.
189 * 10-OCT-2006 (DSB):
190 * Use "AlOff" instead of "AlignOffset" as the external channel name
191 * for the AlignOffset attribute. The longer form exceeded the
192 * limit that can be used by the Channel class.
193 * 14-OCT-2006 (DSB):
194 * - Move Dut1 attribute to the Frame class.
195 * - Use the TimeFrame class to do the TDB->LAST conversions.
196 * 17-JAN-2007 (DSB):
197 * - Use a UnitMap to align offset coordinate systems in two
198 * SkyFrames, regardless of other attribute values.
199 * - Only align in offset coordinates if both target and template
200 * have a non-zero value for AlignOffset.
201 * 23-JAN-2007 (DSB):
202 * Modified so that a SkyFrame can be used as a template to find a
203 * SkyFrame contained within a CmpFrame. This involves changes in
204 * Match and the removal of the local versions of SetMaxAxes and
205 * SetMinAxes.
206 * 4-JUL-2007 (DSB):
207 * Modified GetLast to use the correct solar to sidereal conversion
208 * factor. As a consequence the largest acceptable epoch gap before
209 * the LAST needs to be recalculated has been increased.
210 * 11-JUL-2007 (DSB):
211 * Override astSetEpoch and astClearEpoch by implementations which
212 * update the LAST value stored in the SkyFrame.
213 * 7-AUG-2007 (DSB):
214 * - Set a value for the CentreZero attribute when extracting a
215 * SkyAxis from a SkyFrame in function SubFrame.
216 * - In SubFrame, clear extended attributes such as System after
217 * all axis attributes have been "fixated.
218 * 30-AUG-2007 (DSB):
219 * Override astSetDut1 and astClearDut1 by implementations which
220 * update the LAST value stored in the SkyFrame.
221 * 31-AUG-2007 (DSB):
222 * - Cache the magnitude of the diurnal aberration vector in the
223 * SkyFrame structure for use when correcting for diurnal aberration.
224 * - Modify the azel conversions to include correction for diurnal
225 * aberration.
226 * - Override astClearObsLat and astSetObsLat by implementations which
227 * reset the magnitude of the diurnal aberration vector.
228 * 3-SEP-2007 (DSB):
229 * In SubFrame, since AlignSystem is extended by the SkyFrame class
230 * it needs to be cleared before invoking the parent SubFrame
231 * method in cases where the result Frame is not a SkyFrame.
232 * 2-OCT-2007 (DSB):
233 * In Overlay, clear AlignSystem as well as System before calling
234 * the parent overlay method.
235 * 10-OCT-2007 (DSB):
236 * In MakeSkyMapping, correct the usage of variables "system" and
237 * "align_sys" when aligning in AZEL.
238 * 18-OCT-2007 (DSB):
239 * Compare target and template AlignSystem values in Match, rather
240 * than comparing target and result AlignSystem values in MakeSkyMapping
241 * (since result is basically a copy of target).
242 * 27-NOV-2007 (DSB):
243 * - Modify SetSystem to ensure that SkyRef and SkyRefP position are
244 * always transformed as absolute values, rather than as offset
245 * values.
246 * - Modify SubMatch so that a value of zero is assumed for
247 * AlignOffset when restoring thre integrity of a FrameSet.
248 * 15-DEC-2008 (DSB):
249 * Improve calculation of approximate Local Apparent Sidereal time
250 * by finding and using the ratio of solar to sidereal time
251 * independently for each approximation period.
252 * 14-JAN-2009 (DSB):
253 * Override the astIntersect method.
254 * 21-JAN-2009 (DSB):
255 * Fix mis-use of results buffers for GetFormat and GetAttrib.
256 * 16-JUN-2009 (DSB):
257 * All sky coordinate systems currently supported by SkyFrame are
258 * left handed. So fix GetDirection method to return zero for all
259 * longitude axes and 1 for all latitude axes.
260 * 18-JUN-2009 (DSB):
261 * Incorporate the new ObsAlt attribute.
262 * 23-SEP-2009 (DSB):
263 * Allow some rounding error when checking for changes in SetObsLon
264 * and SetDut1. This reduces the number of times the expensive
265 * calculation of LAST is performed.
266 * 24-SEP-2009 (DSB);
267 * Create a static cache of LAST values stored in the class virtual
268 * function table. These are used in preference to calculating a new
269 * value from scratch.
270 * 25-SEP-2009 (DSB);
271 * Do not calculate LAST until it is needed.
272 * 12-OCT-2009 (DSB);
273 * - Handle 2.PI->0 discontinuity in cached LAST values.
274 * 12-OCT-2009 (BEC);
275 * - Fix bug in caching LAST value.
276 * 31-OCT-2009 (DSB);
277 * Correct SetCachedLAST to handle cases where the epoch to be
278 * stored is smaller than any epoch already in the table.
279 * 24-NOV-2009 (DSB):
280 * - In CalcLast, only use end values form the table of stored
281 * LAST values if the corresponding epochs are within 0.001 of
282 * a second of the required epoch (this tolerance used to be
283 * 0.1 seconds).
284 * - Do not clear the cached LAST value in SetEpoch and ClearEpoch.
285 * 8-MAR-2010 (DSB):
286 * Add astSkyOffsetMap method.
287 * 7-APR-2010 (DSB):
288 * Add IsLatAxis and IsLonAxis attributes.
289 * 11-MAY-2010 (DSB):
290 * In SetSystem, clear SkyRefP as well as SkyRef.
291 * 22-MAR-2011 (DSB):
292 * Override astFrameGrid method.
293 * 29-APR-2011 (DSB):
294 * Prevent astFindFrame from matching a subclass template against a
295 * superclass target.
296 * 23-MAY-2011 (DSB):
297 * Truncate returned PointSet in function FrameGrid to exclude unused points.
298 * 24-MAY-2011 (DSB):
299 * When clearing or setting the System attribute, clear SkyRef rather
300 * than reporting an error if the Mapping from the old System to the
301 * new System is unknown.
302 * 30-NOV-2011 (DSB):
303 * When aligning two SkyFrames in the system specified by AlignSystem,
304 * do not assume inappropriate default equinox values for systems
305 * that are not referred to the equinox specified by the Equinox attribute.
306 * 26-APR-2012 (DSB):
307 * - Correct Dump function so that any axis permutation is taken into
308 * account when dumping SkyFrame attributes that have a separate value
309 * for each axis (e.g. SkyRef and SkyRefP).
310 * - Take axis permutation into account when setting a new value
311 * for attributes that have a separate value for each axis (e.g.
312 * SkyRef and SkyRefP).
313 * - Remove the code that overrides ClearEpoch and SetEpoch (these
314 * overrides have not been needed since the changes made on
315 * 24/11/2009).
316 * 27-APR-2012 (DSB):
317 * - Correct astLoadSkyFrame function so that any axis permutation is
318 * taken into account when loading SkyFrame attributes that have a
319 * separate value for each axis.
320 * 25-JUL-2013 (DSB):
321 * Use a single table of cached LAST values for all threads, rather
322 * than a separate table for each thread. The problem with a table per
323 * thread is that if you have N threads, each table contains only
324 * one N'th of the total number of cached values, resulting in
325 * poorer accuracy, and small variations in interpolated LAST value
326 * depending on the way the cached values are distributed amongst the
327 * N threads.
328 * 6-AST-2013 (DSB):
329 * Fix the use of the read-write lock that is used to serialise
330 * access to the table of cached LAST values. This bug could
331 * cause occasional problems where an AST pointer would became
332 * invalid for no apparent reason.
333 * 21-FEB-2014 (DSB):
334 * Rounding errors in the SkyLineDef constructor could result in the line
335 * between coincident points being given a non-zero length.
336 *class--
337 */
338
339 /* Module Macros. */
340 /* ============== */
341 /* Set the name of the class we are implementing. This indicates to
342 the header files that define class interfaces that they should make
343 "protected" symbols available. */
344 #define astCLASS SkyFrame
345
346 /* Define the first and last acceptable System values. */
347 #define FIRST_SYSTEM AST__FK4
348 #define LAST_SYSTEM AST__AZEL
349
350 /* Speed of light (AU per day) (from SLA_AOPPA) */
351 #define C 173.14463331
352
353 /* Ratio between solar and sidereal time (from SLA_AOPPA) */
354 #define SOLSID 1.00273790935
355
356 /* Define values for the different values of the SkyRefIs attribute. */
357 #define POLE_STRING "Pole"
358 #define ORIGIN_STRING "Origin"
359 #define IGNORED_STRING "Ignored"
360
361 /* Define other numerical constants for use in this module. */
362 #define GETATTRIB_BUFF_LEN 200
363 #define GETFORMAT_BUFF_LEN 50
364 #define GETLABEL_BUFF_LEN 40
365 #define GETSYMBOL_BUFF_LEN 20
366 #define GETTITLE_BUFF_LEN 200
367
368 /* A macro which returns a flag indicating if the supplied system is
369 references to the equinox specified by the Equinox attribute. */
370 #define EQREF(system) \
371 ((system==AST__FK4||system==AST__FK4_NO_E||system==AST__FK5||system==AST__ECLIPTIC)?1:0)
372
373 /*
374 *
375 * Name:
376 * MAKE_CLEAR
377
378 * Purpose:
379 * Implement a method to clear a single value in a multi-valued attribute.
380
381 * Type:
382 * Private macro.
383
384 * Synopsis:
385 * #include "skyframe.h"
386 * MAKE_CLEAR(attr,component,assign,nval)
387
388 * Class Membership:
389 * Defined by the SkyFrame class.
390
391 * Description:
392 * This macro expands to an implementation of a private member function of
393 * the form:
394 *
395 * static void Clear<Attribute>( AstSkyFrame *this, int axis )
396 *
397 * and an external interface function of the form:
398 *
399 * void astClear<Attribute>_( AstSkyFrame *this, int axis )
400 *
401 * which implement a method for clearing a single value in a specified
402 * multi-valued attribute for an axis of a SkyFrame.
403
404 * Parameters:
405 * attr
406 * The name of the attribute to be cleared, as it appears in the function
407 * name (e.g. Label in "astClearLabelAt").
408 * component
409 * The name of the class structure component that holds the attribute
410 * value.
411 * assign
412 * An expression that evaluates to the value to assign to the component
413 * to clear its value.
414 * nval
415 * Specifies the number of values in the multi-valued attribute. The
416 * "axis" values supplied to the created function should be in the
417 * range zero to (nval - 1).
418
419 * Notes:
420 * - To avoid problems with some compilers, you should not leave any white
421 * space around the macro arguments.
422 *
423 */
424
425 /* Define the macro. */
426 #define MAKE_CLEAR(attr,component,assign,nval) \
427 \
428 /* Private member function. */ \
429 /* ------------------------ */ \
430 static void Clear##attr( AstSkyFrame *this, int axis, int *status ) { \
431 \
432 int axis_p; \
433 \
434 /* Check the global error status. */ \
435 if ( !astOK ) return; \
436 \
437 /* Validate and permute the axis index. */ \
438 axis_p = astValidateAxis( this, axis, 1, "astClear" #attr ); \
439 \
440 /* Assign the "clear" value. */ \
441 if( astOK ) { \
442 this->component[ axis_p ] = (assign); \
443 } \
444 } \
445 \
446 /* External interface. */ \
447 /* ------------------- */ \
448 void astClear##attr##_( AstSkyFrame *this, int axis, int *status ) { \
449 \
450 /* Check the global error status. */ \
451 if ( !astOK ) return; \
452 \
453 /* Invoke the required method via the virtual function table. */ \
454 (**astMEMBER(this,SkyFrame,Clear##attr))( this, axis, status ); \
455 }
456
457
458 /*
459 *
460 * Name:
461 * MAKE_GET
462
463 * Purpose:
464 * Implement a method to get a single value in a multi-valued attribute.
465
466 * Type:
467 * Private macro.
468
469 * Synopsis:
470 * #include "skyframe.h"
471 * MAKE_GET(attr,type,bad_value,assign,nval)
472
473 * Class Membership:
474 * Defined by the SkyFrame class.
475
476 * Description:
477 * This macro expands to an implementation of a private member function of
478 * the form:
479 *
480 * static <Type> Get<Attribute>( AstSkyFrame *this, int axis )
481 *
482 * and an external interface function of the form:
483 *
484 * <Type> astGet<Attribute>_( AstSkyFrame *this, int axis )
485 *
486 * which implement a method for getting a single value from a specified
487 * multi-valued attribute for an axis of a SkyFrame.
488
489 * Parameters:
490 * attr
491 * The name of the attribute whose value is to be obtained, as it
492 * appears in the function name (e.g. Label in "astGetLabel").
493 * type
494 * The C type of the attribute.
495 * bad_value
496 * A constant value to return if the global error status is set, or if
497 * the function fails.
498 * assign
499 * An expression that evaluates to the value to be returned. This can
500 * use the string "axis" to represent the zero-based value index.
501 * nval
502 * Specifies the number of values in the multi-valued attribute. The
503 * "axis" values supplied to the created function should be in the
504 * range zero to (nval - 1).
505
506 * Notes:
507 * - To avoid problems with some compilers, you should not leave any white
508 * space around the macro arguments.
509 *
510 */
511
512 /* Define the macro. */
513 #define MAKE_GET(attr,type,bad_value,assign,nval) \
514 \
515 /* Private member function. */ \
516 /* ------------------------ */ \
517 static type Get##attr( AstSkyFrame *this, int axis, int *status ) { \
518 int axis_p; /* Permuted axis index */ \
519 type result; /* Result to be returned */ \
520 \
521 /* Initialise */\
522 result = (bad_value); \
523 \
524 /* Check the global error status. */ \
525 if ( !astOK ) return result; \
526 \
527 /* Validate and permute the axis index. */ \
528 axis_p = astValidateAxis( this, axis, 1, "astGet" #attr ); \
529 \
530 /* Assign the result value. */ \
531 if( astOK ) { \
532 result = (assign); \
533 } \
534 \
535 /* Check for errors and clear the result if necessary. */ \
536 if ( !astOK ) result = (bad_value); \
537 \
538 /* Return the result. */ \
539 return result; \
540 } \
541 /* External interface. */ \
542 /* ------------------- */ \
543 type astGet##attr##_( AstSkyFrame *this, int axis, int *status ) { \
544 \
545 /* Check the global error status. */ \
546 if ( !astOK ) return (bad_value); \
547 \
548 /* Invoke the required method via the virtual function table. */ \
549 return (**astMEMBER(this,SkyFrame,Get##attr))( this, axis, status ); \
550 }
551
552 /*
553 *
554 * Name:
555 * MAKE_SET
556
557 * Purpose:
558 * Implement a method to set a single value in a multi-valued attribute
559 * for a SkyFrame.
560
561 * Type:
562 * Private macro.
563
564 * Synopsis:
565 * #include "skyframe.h"
566 * MAKE_SET(attr,type,component,assign,nval)
567
568 * Class Membership:
569 * Defined by the SkyFrame class.
570
571 * Description:
572 * This macro expands to an implementation of a private member function of
573 * the form:
574 *
575 * static void Set<Attribute>( AstSkyFrame *this, int axis, <Type> value )
576 *
577 * and an external interface function of the form:
578 *
579 * void astSet<Attribute>_( AstSkyFrame *this, int axis, <Type> value )
580 *
581 * which implement a method for setting a single value in a specified
582 * multi-valued attribute for a SkyFrame.
583
584 * Parameters:
585 * attr
586 * The name of the attribute to be set, as it appears in the function
587 * name (e.g. Label in "astSetLabelAt").
588 * type
589 * The C type of the attribute.
590 * component
591 * The name of the class structure component that holds the attribute
592 * value.
593 * assign
594 * An expression that evaluates to the value to be assigned to the
595 * component.
596 * nval
597 * Specifies the number of values in the multi-valued attribute. The
598 * "axis" values supplied to the created function should be in the
599 * range zero to (nval - 1).
600
601 * Notes:
602 * - To avoid problems with some compilers, you should not leave any white
603 * space around the macro arguments.
604 *-
605 */
606
607 /* Define the macro. */
608 #define MAKE_SET(attr,type,component,assign,nval) \
609 \
610 /* Private member function. */ \
611 /* ------------------------ */ \
612 static void Set##attr( AstSkyFrame *this, int axis, type value, int *status ) { \
613 \
614 int axis_p; \
615 \
616 /* Check the global error status. */ \
617 if ( !astOK ) return; \
618 \
619 /* Validate and permute the axis index. */ \
620 axis_p = astValidateAxis( this, axis, 1, "astSet" #attr ); \
621 \
622 /* Store the new value in the structure component. */ \
623 if( astOK ) { \
624 this->component[ axis_p ] = (assign); \
625 } \
626 } \
627 \
628 /* External interface. */ \
629 /* ------------------- */ \
630 void astSet##attr##_( AstSkyFrame *this, int axis, type value, int *status ) { \
631 \
632 /* Check the global error status. */ \
633 if ( !astOK ) return; \
634 \
635 /* Invoke the required method via the virtual function table. */ \
636 (**astMEMBER(this,SkyFrame,Set##attr))( this, axis, value, status ); \
637 }
638
639 /*
640 *
641 * Name:
642 * MAKE_TEST
643
644 * Purpose:
645 * Implement a method to test if a single value has been set in a
646 * multi-valued attribute for a class.
647
648 * Type:
649 * Private macro.
650
651 * Synopsis:
652 * #include "skyframe.h"
653 * MAKE_TEST(attr,assign,nval)
654
655 * Class Membership:
656 * Defined by the SkyFrame class.
657
658 * Description:
659 * This macro expands to an implementation of a private member function of
660 * the form:
661 *
662 * static int Test<Attribute>( AstSkyFrame *this, int axis )
663 *
664 * and an external interface function of the form:
665 *
666 * int astTest<Attribute>_( AstSkyFrame *this, int axis )
667 *
668 * which implement a method for testing if a single value in a specified
669 * multi-valued attribute has been set for a class.
670
671 * Parameters:
672 * attr
673 * The name of the attribute to be tested, as it appears in the function
674 * name (e.g. Label in "astTestLabelAt").
675 * assign
676 * An expression that evaluates to 0 or 1, to be used as the returned
677 * value. This can use the string "axis" to represent the zero-based
678 * index of the value within the attribute.
679 * nval
680 * Specifies the number of values in the multi-valued attribute. The
681 * "axis" values supplied to the created function should be in the
682 * range zero to (nval - 1).
683
684 * Notes:
685 * - To avoid problems with some compilers, you should not leave any white
686 * space around the macro arguments.
687 *-
688 */
689
690 /* Define the macro. */
691 #define MAKE_TEST(attr,assign,nval) \
692 \
693 /* Private member function. */ \
694 /* ------------------------ */ \
695 static int Test##attr( AstSkyFrame *this, int axis, int *status ) { \
696 int result; /* Value to return */ \
697 int axis_p; /* Permuted axis index */ \
698 \
699 /* Initialise */ \
700 result =0; \
701 \
702 /* Check the global error status. */ \
703 if ( !astOK ) return result; \
704 \
705 /* Validate and permute the axis index. */ \
706 axis_p = astValidateAxis( this, axis, 1, "astTest" #attr ); \
707 \
708 /* Assign the result value. */ \
709 if( astOK ) { \
710 result = (assign); \
711 } \
712 \
713 /* Check for errors and clear the result if necessary. */ \
714 if ( !astOK ) result = 0; \
715 \
716 /* Return the result. */ \
717 return result; \
718 } \
719 /* External interface. */ \
720 /* ------------------- */ \
721 int astTest##attr##_( AstSkyFrame *this, int axis, int *status ) { \
722 \
723 /* Check the global error status. */ \
724 if ( !astOK ) return 0; \
725 \
726 /* Invoke the required method via the virtual function table. */ \
727 return (**astMEMBER(this,SkyFrame,Test##attr))( this, axis, status ); \
728 }
729
730
731 /* Header files. */
732 /* ============= */
733 /* Interface definitions. */
734 /* ---------------------- */
735
736 #include "globals.h" /* Thread-safe global data access */
737 #include "error.h" /* Error reporting facilities */
738 #include "memory.h" /* Memory allocation facilities */
739 #include "globals.h" /* Thread-safe global data access */
740 #include "object.h" /* Base Object class */
741 #include "pointset.h" /* Sets of points (for AST__BAD) */
742 #include "unitmap.h" /* Unit Mappings */
743 #include "permmap.h" /* Coordinate permutations */
744 #include "cmpmap.h" /* Compound Mappings */
745 #include "slamap.h" /* SLALIB sky coordinate Mappings */
746 #include "timemap.h" /* Time conversions */
747 #include "skyaxis.h" /* Sky axes */
748 #include "frame.h" /* Parent Frame class */
749 #include "matrixmap.h" /* Matrix multiplication */
750 #include "sphmap.h" /* Cartesian<->Spherical transformations */
751 #include "skyframe.h" /* Interface definition for this class */
752 #include "pal.h" /* SLALIB library interface */
753 #include "wcsmap.h" /* Factors of PI */
754 #include "timeframe.h" /* Time system transformations */
755
756 /* Error code definitions. */
757 /* ----------------------- */
758 #include "ast_err.h" /* AST error codes */
759
760 /* C header files. */
761 /* --------------- */
762 #include <ctype.h>
763 #include <float.h>
764 #include <limits.h>
765 #include <math.h>
766 #include <stdarg.h>
767 #include <stddef.h>
768 #include <stdio.h>
769 #include <string.h>
770
771 /* Type Definitions. */
772 /* ================= */
773
774 /* Cached Line structure. */
775 /* ---------------------- */
776 /* This structure contains information describing a line segment within a
777 SkyFrame. It differs from the AstLineDef defined in frame.h because
778 positions are represented by 3D (x,y,z) cartesian coords rather than
779 2D (long,lat) coords. */
780
781 typedef struct SkyLineDef {
782 AstFrame *frame; /* Pointer to Frame in which the line is defined */
783 double length; /* Line length */
784 int infinite; /* Disregard the start and end of the line? */
785 double start[3]; /* Unit vector defining start of line */
786 double end[3]; /* Unit vector defining end of line */
787 double dir[3]; /* Unit vector defining line direction */
788 double q[3]; /* Unit vector perpendicular to line */
789 double start_2d[2];
790 double end_2d[2];
791 } SkyLineDef;
792
793 /* Module Variables. */
794 /* ================= */
795
796 /* Address of this static variable is used as a unique identifier for
797 member of this class. */
798 static int class_check;
799
800 /* Pointers to parent class methods which are used or extended by this
801 class. */
802 static AstSystemType (* parent_getalignsystem)( AstFrame *, int * );
803 static AstSystemType (* parent_getsystem)( AstFrame *, int * );
804 static const char *(* parent_format)( AstFrame *, int, double, int * );
805 static const char *(* parent_getattrib)( AstObject *, const char *, int * );
806 static const char *(* parent_getdomain)( AstFrame *, int * );
807 static const char *(* parent_getformat)( AstFrame *, int, int * );
808 static const char *(* parent_getlabel)( AstFrame *, int, int * );
809 static const char *(* parent_getsymbol)( AstFrame *, int, int * );
810 static const char *(* parent_gettitle)( AstFrame *, int * );
811 static const char *(* parent_getunit)( AstFrame *, int, int * );
812 static double (* parent_gap)( AstFrame *, int, double, int *, int * );
813 static double (* parent_getbottom)( AstFrame *, int, int * );
814 static double (* parent_getepoch)( AstFrame *, int * );
815 static double (* parent_gettop)( AstFrame *, int, int * );
816 static int (* parent_getdirection)( AstFrame *, int, int * );
817 static int (* parent_getobjsize)( AstObject *, int * );
818 static int (* parent_match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
819 static int (* parent_subframe)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
820 static int (* parent_testattrib)( AstObject *, const char *, int * );
821 static int (* parent_testformat)( AstFrame *, int, int * );
822 static int (* parent_unformat)( AstFrame *, int, const char *, double *, int * );
823 static void (* parent_clearattrib)( AstObject *, const char *, int * );
824 static void (* parent_cleardut1)( AstFrame *, int * );
825 static void (* parent_clearformat)( AstFrame *, int, int * );
826 static void (* parent_clearobsalt)( AstFrame *, int * );
827 static void (* parent_clearobslat)( AstFrame *, int * );
828 static void (* parent_clearobslon)( AstFrame *, int * );
829 static void (* parent_clearsystem)( AstFrame *, int * );
830 static void (* parent_overlay)( AstFrame *, const int *, AstFrame *, int * );
831 static void (* parent_setattrib)( AstObject *, const char *, int * );
832 static void (* parent_setdut1)( AstFrame *, double, int * );
833 static void (* parent_setformat)( AstFrame *, int, const char *, int * );
834 static void (* parent_setobsalt)( AstFrame *, double, int * );
835 static void (* parent_setobslat)( AstFrame *, double, int * );
836 static void (* parent_setobslon)( AstFrame *, double, int * );
837 static void (* parent_setsystem)( AstFrame *, AstSystemType, int * );
838
839 /* Factors for converting between hours, degrees and radians. */
840 static double hr2rad;
841 static double deg2rad;
842 static double pi;
843 static double piby2;
844
845 /* Table of cached Local Apparent Sidereal Time values and corresponding
846 epochs. */
847 static int nlast_tables = 0;
848 static AstSkyLastTable **last_tables = NULL;
849
850
851 /* Define macros for accessing each item of thread specific global data. */
852 #ifdef THREAD_SAFE
853
854 /* Define how to initialise thread-specific globals. */
855 #define GLOBAL_inits \
856 globals->Class_Init = 0; \
857 globals->GetAttrib_Buff[ 0 ] = 0; \
858 globals->GetFormat_Buff[ 0 ] = 0; \
859 globals->GetLabel_Buff[ 0 ] = 0; \
860 globals->GetSymbol_Buff[ 0 ] = 0; \
861 globals->GetTitle_Buff[ 0 ] = 0; \
862 globals->GetTitle_Buff2[ 0 ] = 0; \
863 globals->TDBFrame = NULL; \
864 globals->LASTFrame = NULL; \
865
866 /* Create the function that initialises global data for this module. */
867 astMAKE_INITGLOBALS(SkyFrame)
868
869 /* Define macros for accessing each item of thread specific global data. */
870 #define class_init astGLOBAL(SkyFrame,Class_Init)
871 #define class_vtab astGLOBAL(SkyFrame,Class_Vtab)
872 #define getattrib_buff astGLOBAL(SkyFrame,GetAttrib_Buff)
873 #define getformat_buff astGLOBAL(SkyFrame,GetFormat_Buff)
874 #define getlabel_buff astGLOBAL(SkyFrame,GetLabel_Buff)
875 #define getsymbol_buff astGLOBAL(SkyFrame,GetSymbol_Buff)
876 #define gettitle_buff astGLOBAL(SkyFrame,GetTitle_Buff)
877 #define gettitle_buff2 astGLOBAL(SkyFrame,GetTitle_Buff2)
878 #define tdbframe astGLOBAL(SkyFrame,TDBFrame)
879 #define lastframe astGLOBAL(SkyFrame,LASTFrame)
880
881
882
883 static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
884 #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 );
885 #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 );
886
887 /* A read-write lock used to protect the table of cached LAST values so
888 that multiple threads can read simultaneously so long as no threads are
889 writing to the table. */
890 static pthread_rwlock_t rwlock1=PTHREAD_RWLOCK_INITIALIZER;
891 #define LOCK_WLOCK1 pthread_rwlock_wrlock( &rwlock1 );
892 #define LOCK_RLOCK1 pthread_rwlock_rdlock( &rwlock1 );
893 #define UNLOCK_RWLOCK1 pthread_rwlock_unlock( &rwlock1 );
894
895 /* If thread safety is not needed, declare and initialise globals at static
896 variables. */
897 #else
898
899 /* Buffer returned by GetAttrib. */
900 static char getattrib_buff[ GETATTRIB_BUFF_LEN + 1 ];
901
902 /* Buffer returned by GetFormat. */
903 static char getformat_buff[ GETFORMAT_BUFF_LEN + 1 ];
904
905 /* Default GetLabel string buffer */
906 static char getlabel_buff[ GETLABEL_BUFF_LEN + 1 ];
907
908 /* Default GetSymbol buffer */
909 static char getsymbol_buff[ GETSYMBOL_BUFF_LEN + 1 ];
910
911 /* Default Title string buffer */
912 static char gettitle_buff[ AST__SKYFRAME_GETTITLE_BUFF_LEN + 1 ];
913 static char gettitle_buff2[ AST__SKYFRAME_GETTITLE_BUFF_LEN + 1 ];
914
915 /* TimeFrames for doing TDB<->LAST conversions. */
916 static AstTimeFrame *tdbframe = NULL;
917 static AstTimeFrame *lastframe = NULL;
918
919
920 /* Define the class virtual function table and its initialisation flag
921 as static variables. */
922 static AstSkyFrameVtab class_vtab; /* Virtual function table */
923 static int class_init = 0; /* Virtual function table initialised? */
924
925 #define LOCK_MUTEX2
926 #define UNLOCK_MUTEX2
927
928 #define LOCK_WLOCK1
929 #define LOCK_RLOCK1
930 #define UNLOCK_RWLOCK1
931
932 #endif
933
934
935 /* Prototypes for Private Member Functions. */
936 /* ======================================== */
937 static AstLineDef *LineDef( AstFrame *, const double[2], const double[2], int * );
938 static AstMapping *SkyOffsetMap( AstSkyFrame *, int * );
939 static AstPointSet *FrameGrid( AstFrame *, int, const double *, const double *, int * );
940 static AstPointSet *ResolvePoints( AstFrame *, const double [], const double [], AstPointSet *, AstPointSet *, int * );
941 static AstSystemType GetAlignSystem( AstFrame *, int * );
942 static AstSystemType GetSystem( AstFrame *, int * );
943 static AstSystemType SystemCode( AstFrame *, const char *, int * );
944 static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * );
945 static const char *Format( AstFrame *, int, double, int * );
946 static const char *GetAttrib( AstObject *, const char *, int * );
947 static const char *GetDomain( AstFrame *, int * );
948 static const char *GetFormat( AstFrame *, int, int * );
949 static const char *GetLabel( AstFrame *, int, int * );
950 static const char *GetProjection( AstSkyFrame *, int * );
951 static const char *GetSymbol( AstFrame *, int, int * );
952 static const char *GetTitle( AstFrame *, int * );
953 static const char *GetUnit( AstFrame *, int, int * );
954 static const char *SystemString( AstFrame *, AstSystemType, int * );
955 static double Angle( AstFrame *, const double[], const double[], const double[], int * );
956 static double CalcLAST( AstSkyFrame *, double, double, double, double, double, int * );
957 static double Distance( AstFrame *, const double[], const double[], int * );
958 static double Gap( AstFrame *, int, double, int *, int * );
959 static double GetBottom( AstFrame *, int, int * );
960 static double GetCachedLAST( AstSkyFrame *, double, double, double, double, double, int * );
961 static double GetEpoch( AstFrame *, int * );
962 static double GetEquinox( AstSkyFrame *, int * );
963 static void SetCachedLAST( AstSkyFrame *, double, double, double, double, double, double, int * );
964 static void SetLast( AstSkyFrame *, int * );
965 static double GetTop( AstFrame *, int, int * );
966 static double Offset2( AstFrame *, const double[2], double, double, double[2], int * );
967 static double GetDiurab( AstSkyFrame *, int * );
968 static double GetLAST( AstSkyFrame *, int * );
969 static int GetActiveUnit( AstFrame *, int * );
970 static int GetAsTime( AstSkyFrame *, int, int * );
971 static int GetDirection( AstFrame *, int, int * );
972 static int GetIsLatAxis( AstSkyFrame *, int, int * );
973 static int GetIsLonAxis( AstSkyFrame *, int, int * );
974 static int GetLatAxis( AstSkyFrame *, int * );
975 static int GetLonAxis( AstSkyFrame *, int * );
976 static int GetNegLon( AstSkyFrame *, int * );
977 static int GetObjSize( AstObject *, int * );
978 static int IsEquatorial( AstSystemType, int * );
979 static int LineContains( AstFrame *, AstLineDef *, int, double *, int * );
980 static int LineCrossing( AstFrame *, AstLineDef *, AstLineDef *, double **, int * );
981 static int LineIncludes( SkyLineDef *, double[3], int * );
982 static int MakeSkyMapping( AstSkyFrame *, AstSkyFrame *, AstSystemType, AstMapping **, int * );
983 static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
984 static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
985 static int TestActiveUnit( AstFrame *, int * );
986 static int TestAsTime( AstSkyFrame *, int, int * );
987 static int TestAttrib( AstObject *, const char *, int * );
988 static int TestEquinox( AstSkyFrame *, int * );
989 static int TestNegLon( AstSkyFrame *, int * );
990 static int TestProjection( AstSkyFrame *, int * );
991 static int Unformat( AstFrame *, int, const char *, double *, int * );
992 static void ClearAsTime( AstSkyFrame *, int, int * );
993 static void ClearAttrib( AstObject *, const char *, int * );
994 static void ClearDut1( AstFrame *, int * );
995 static void ClearEquinox( AstSkyFrame *, int * );
996 static void ClearNegLon( AstSkyFrame *, int * );
997 static void ClearObsAlt( AstFrame *, int * );
998 static void ClearObsLat( AstFrame *, int * );
999 static void ClearObsLon( AstFrame *, int * );
1000 static void ClearProjection( AstSkyFrame *, int * );
1001 static void ClearSystem( AstFrame *, int * );
1002 static void Copy( const AstObject *, AstObject *, int * );
1003 static void Delete( AstObject *, int * );
1004 static void Dump( AstObject *, AstChannel *, int * );
1005 static void Intersect( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * );
1006 static void LineOffset( AstFrame *, AstLineDef *, double, double, double[2], int * );
1007 static void MatchAxesX( AstFrame *, AstFrame *, int *, int * );
1008 static void Norm( AstFrame *, double[], int * );
1009 static void NormBox( AstFrame *, double[], double[], AstMapping *, int * );
1010 static void Offset( AstFrame *, const double[], const double[], double, double[], int * );
1011 static void Overlay( AstFrame *, const int *, AstFrame *, int * );
1012 static void Resolve( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * );
1013 static void SetAsTime( AstSkyFrame *, int, int, int * );
1014 static void SetAttrib( AstObject *, const char *, int * );
1015 static void SetDut1( AstFrame *, double, int * );
1016 static void SetEquinox( AstSkyFrame *, double, int * );
1017 static void SetNegLon( AstSkyFrame *, int, int * );
1018 static void SetObsAlt( AstFrame *, double, int * );
1019 static void SetObsLat( AstFrame *, double, int * );
1020 static void SetObsLon( AstFrame *, double, int * );
1021 static void SetProjection( AstSkyFrame *, const char *, int * );
1022 static void SetSystem( AstFrame *, AstSystemType, int * );
1023 static void Shapp( double, double *, double *, double, double *, int * );
1024 static void Shcal( double, double, double, double *, double *, int * );
1025 static void VerifyMSMAttrs( AstSkyFrame *, AstSkyFrame *, int, const char *, const char *, int * );
1026
1027 static double GetSkyRef( AstSkyFrame *, int, int * );
1028 static int TestSkyRef( AstSkyFrame *, int, int * );
1029 static void SetSkyRef( AstSkyFrame *, int, double, int * );
1030 static void ClearSkyRef( AstSkyFrame *, int, int * );
1031
1032 static double GetSkyRefP( AstSkyFrame *, int, int * );
1033 static int TestSkyRefP( AstSkyFrame *, int, int * );
1034 static void SetSkyRefP( AstSkyFrame *, int, double, int * );
1035 static void ClearSkyRefP( AstSkyFrame *, int, int * );
1036
1037 static int GetSkyRefIs( AstSkyFrame *, int * );
1038 static int TestSkyRefIs( AstSkyFrame *, int * );
1039 static void SetSkyRefIs( AstSkyFrame *, int, int * );
1040 static void ClearSkyRefIs( AstSkyFrame *, int * );
1041
1042 static int GetAlignOffset( AstSkyFrame *, int * );
1043 static int TestAlignOffset( AstSkyFrame *, int * );
1044 static void SetAlignOffset( AstSkyFrame *, int, int * );
1045 static void ClearAlignOffset( AstSkyFrame *, int * );
1046
1047 /* Member functions. */
1048 /* ================= */
Angle(AstFrame * this_frame,const double a[],const double b[],const double c[],int * status)1049 static double Angle( AstFrame *this_frame, const double a[],
1050 const double b[], const double c[], int *status ) {
1051 /*
1052 * Name:
1053 * Angle
1054
1055 * Purpose:
1056 * Calculate the angle subtended by two points at a third point.
1057
1058 * Type:
1059 * Private function.
1060
1061 * Synopsis:
1062 * #include "skyframe.h"
1063 * double Angle( AstFrame *this_frame, const double a[],
1064 * const double b[], const double c[], int *status )
1065
1066 * Class Membership:
1067 * SkyFrame member function (over-rides the astAngle method
1068 * inherited from the Frame class).
1069
1070 * Description:
1071 * This function finds the angle at point B between the line
1072 * joining points A and B, and the line joining points C
1073 * and B. These lines will in fact be geodesic curves (great circles).
1074
1075 * Parameters:
1076 * this
1077 * Pointer to the SkyFrame.
1078 * a
1079 * An array of double, with one element for each SkyFrame axis,
1080 * containing the coordinates of the first point.
1081 * b
1082 * An array of double, with one element for each SkyFrame axis,
1083 * containing the coordinates of the second point.
1084 * c
1085 * An array of double, with one element for each SkyFrame axis,
1086 * containing the coordinates of the third point.
1087 * status
1088 * Pointer to the inherited status variable.
1089
1090 * Returned Value:
1091 * The angle in radians, from the line AB to the line CB, in
1092 * the range $\pm \pi$ with positive rotation is in the same sense
1093 * as rotation from axis 2 to axis 1.
1094
1095 * Notes:
1096 * - This function will return a "bad" result value (AST__BAD) if
1097 * any of the input coordinates has this value.
1098 * - A "bad" value will also be returned if points A and B are
1099 * co-incident, or if points B and C are co-incident.
1100 * - A "bad" value will also be returned if this function is
1101 * invoked with the AST error status set, or if it should fail for
1102 * any reason.
1103 */
1104
1105 AstSkyFrame *this; /* Pointer to SkyFrame structure */
1106 const int *perm; /* Axis permutation array */
1107 double aa[ 2 ]; /* Permuted a coordinates */
1108 double anga; /* Angle from north to the line BA */
1109 double angc; /* Angle from north to the line BC */
1110 double bb[ 2 ]; /* Permuted b coordinates */
1111 double cc[ 2 ]; /* Permuted c coordinates */
1112 double result; /* Value to return */
1113
1114 /* Initialise. */
1115 result = AST__BAD;
1116
1117 /* Check the global error status. */
1118 if ( !astOK ) return result;
1119
1120 /* Obtain a pointer to the SkyFrame structure. */
1121 this = (AstSkyFrame *) this_frame;
1122
1123 /* Obtain a pointer to the SkyFrame's axis permutation array. */
1124 perm = astGetPerm( this );
1125 if ( astOK ) {
1126
1127 /* Check that all supplied coordinates are OK. */
1128 if ( ( a[ 0 ] != AST__BAD ) && ( a[ 1 ] != AST__BAD ) &&
1129 ( b[ 0 ] != AST__BAD ) && ( b[ 1 ] != AST__BAD ) &&
1130 ( c[ 0 ] != AST__BAD ) && ( c[ 1 ] != AST__BAD ) ) {
1131
1132 /* Apply the axis permutation array to obtain the coordinates of the
1133 three points in the required (longitude,latitude) order. */
1134 aa[ perm[ 0 ] ] = a[ 0 ];
1135 aa[ perm[ 1 ] ] = a[ 1 ];
1136 bb[ perm[ 0 ] ] = b[ 0 ];
1137 bb[ perm[ 1 ] ] = b[ 1 ];
1138 cc[ perm[ 0 ] ] = c[ 0 ];
1139 cc[ perm[ 1 ] ] = c[ 1 ];
1140
1141 /* Check that A and B are not co-incident. */
1142 if( aa[ 0 ] != bb[ 0 ] || aa[ 1 ] != bb[ 1 ] ) {
1143
1144 /* Check that C and B are not co-incident. */
1145 if( cc[ 0 ] != bb[ 0 ] || cc[ 1 ] != bb[ 1 ] ) {
1146
1147 /* Find the angle from north to the line BA. */
1148 anga = palDbear( bb[ 0 ], bb[ 1 ], aa[ 0 ], aa[ 1 ] );
1149
1150 /* Find the angle from north to the line BC. */
1151 angc = palDbear( bb[ 0 ], bb[ 1 ], cc[ 0 ], cc[ 1 ] );
1152
1153 /* Find the difference. */
1154 result = angc - anga;
1155
1156 /* This value is the angle from north, but we want the angle from axis 2.
1157 If the axes have been swapped so that axis 2 is actually the longitude
1158 axis, then we need to correct this result. */
1159 if( perm[ 0 ] != 0 ) result = piby2 - result;
1160
1161 /* Fold the result into the range +/- PI. */
1162 result = palDrange( result );
1163 }
1164 }
1165 }
1166 }
1167
1168 /* Return the result. */
1169 return result;
1170 }
1171
CalcLAST(AstSkyFrame * this,double epoch,double obslon,double obslat,double obsalt,double dut1,int * status)1172 static double CalcLAST( AstSkyFrame *this, double epoch, double obslon,
1173 double obslat, double obsalt, double dut1,
1174 int *status ) {
1175 /*
1176 * Name:
1177 * CalcLAST
1178
1179 * Purpose:
1180 * Calculate the Local Appearent Sidereal Time for a SkyFrame.
1181
1182 * Type:
1183 * Private function.
1184
1185 * Synopsis:
1186 * #include "skyframe.h"
1187 * double CalcLAST( AstSkyFrame *this, double epoch, double obslon,
1188 * double obslat, double obsalt, double dut1,
1189 * int *status )
1190
1191 * Class Membership:
1192 * SkyFrame member function.
1193
1194 * Description:
1195 * This function calculates and returns the Local Apparent Sidereal Time
1196 * at the given epoch, etc.
1197
1198 * Parameters:
1199 * this
1200 * Pointer to the SkyFrame.
1201 * epoch
1202 * The epoch (MJD).
1203 * obslon
1204 * Observatory geodetic longitude (radians)
1205 * obslat
1206 * Observatory geodetic latitude (radians)
1207 * obsalt
1208 * Observatory geodetic altitude (metres)
1209 * dut1
1210 * The UT1-UTC correction, in seconds.
1211 * status
1212 * Pointer to the inherited status variable.
1213
1214 * Returned Value:
1215 * The Local Apparent Sidereal Time, in radians.
1216
1217 * Notes:
1218 * - A value of AST__BAD will be returned if this function is invoked
1219 * with the global error status set, or if it should fail for any reason.
1220 */
1221
1222 /* Local Variables: */
1223 astDECLARE_GLOBALS /* Declare the thread specific global data */
1224 AstFrameSet *fs; /* Mapping from TDB offset to LAST offset */
1225 double epoch0; /* Supplied epoch value */
1226 double result; /* Returned LAST value */
1227
1228 /* Get a pointer to the structure holding thread-specific global data. */
1229 astGET_GLOBALS(this);
1230
1231 /* Check the global error status. */
1232 if ( !astOK ) return AST__BAD;
1233
1234 /* See if the required LAST value can be determined from the cached LAST
1235 values in the SkyFrame virtual function table. */
1236 result = GetCachedLAST( this, epoch, obslon, obslat, obsalt, dut1,
1237 status );
1238
1239 /* If not, we do an exact calculation from scratch. */
1240 if( result == AST__BAD ) {
1241
1242 /* If not yet done, create two TimeFrames. Note, this is done here
1243 rather than in astInitSkyFrameVtab in order to avoid infinite vtab
1244 initialisation loops (caused by the TimeFrame class containing a
1245 static SkyFrame). */
1246 if( ! tdbframe ) {
1247 astBeginPM;
1248 tdbframe = astTimeFrame( "system=mjd,timescale=tdb", status );
1249 lastframe = astTimeFrame( "system=mjd,timescale=last", status );
1250 astEndPM;
1251 }
1252
1253 /* For better accuracy, use this integer part of the epoch as the origin of
1254 the two TimeFrames. */
1255 astSetTimeOrigin( tdbframe, (int) epoch );
1256 astSetTimeOrigin( lastframe, (int) epoch );
1257
1258 /* Convert the absolute Epoch value to an offset from the above origin. */
1259 epoch0 = epoch;
1260 epoch -= (int) epoch;
1261
1262 /* Store the observers position in the two TimeFrames. */
1263 astSetObsLon( tdbframe, obslon );
1264 astSetObsLon( lastframe, obslon );
1265
1266 astSetObsLat( tdbframe, obslat );
1267 astSetObsLat( lastframe, obslat );
1268
1269 astSetObsAlt( tdbframe, obsalt );
1270 astSetObsAlt( lastframe, obsalt );
1271
1272 /* Store the DUT1 value. */
1273 astSetDut1( tdbframe, dut1 );
1274 astSetDut1( lastframe, dut1 );
1275
1276 /* Get the conversion from tdb mjd offset to last mjd offset. */
1277 fs = astConvert( tdbframe, lastframe, "" );
1278
1279 /* Use it to transform the SkyFrame Epoch from TDB offset to LAST offset. */
1280 astTran1( fs, 1, &epoch, 1, &epoch );
1281 fs = astAnnul( fs );
1282
1283 /* Convert the LAST offset from days to radians. */
1284 result = ( epoch - (int) epoch )*2*AST__DPI;
1285
1286 /* Cache the new LAST value in the SkyFrame virtual function table. */
1287 SetCachedLAST( this, result, epoch0, obslon, obslat, obsalt, dut1,
1288 status );
1289 }
1290
1291 /* Return the required LAST value. */
1292 return result;
1293 }
1294
ClearAsTime(AstSkyFrame * this,int axis,int * status)1295 static void ClearAsTime( AstSkyFrame *this, int axis, int *status ) {
1296 /*
1297 * Name:
1298 * ClearAsTime
1299
1300 * Purpose:
1301 * Clear the value of the AsTime attribute for a SkyFrame's axis.
1302
1303 * Type:
1304 * Private function.
1305
1306 * Synopsis:
1307 * #include "skyframe.h"
1308 * void ClearAsTime( AstSkyFrame *this, int axis, int *status )
1309
1310 * Class Membership:
1311 * SkyFrame member function.
1312
1313 * Description:
1314 * This function clears any value that has been set for the AsTime
1315 * attribute for a specified axis of a SkyFrame. This attribute indicates
1316 * whether axis values should be formatted as times (as opposed to angles)
1317 * by default.
1318
1319 * Parameters:
1320 * this
1321 * Pointer to the SkyFrame.
1322 * axis
1323 * Index of the axis for which the value is to be cleared (zero based).
1324 * status
1325 * Pointer to the inherited status variable.
1326
1327 * Returned Value:
1328 * void.
1329 */
1330
1331 /* Local Variables: */
1332 AstAxis *ax; /* Pointer to Axis object */
1333
1334 /* Check the global error status. */
1335 if ( !astOK ) return;
1336
1337 /* Validate the axis index. */
1338 (void) astValidateAxis( this, axis, 1, "astClearAsTime" );
1339
1340 /* Obtain a pointer to the Axis object. */
1341 ax = astGetAxis( this, axis );
1342
1343 /* If the Axis is a SkyAxis, clear the AsTime attribute (if it is not a
1344 SkyAxis, it will not have this attribute anyway). */
1345 if ( astIsASkyAxis( ax ) ) astClearAxisAsTime( ax );
1346
1347 /* Annul the Axis pointer. */
1348 ax = astAnnul( ax );
1349 }
1350
ClearAttrib(AstObject * this_object,const char * attrib,int * status)1351 static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
1352 /*
1353 * Name:
1354 * ClearAttrib
1355
1356 * Purpose:
1357 * Clear an attribute value for a SkyFrame.
1358
1359 * Type:
1360 * Private function.
1361
1362 * Synopsis:
1363 * #include "skyframe.h"
1364 * void ClearAttrib( AstObject *this, const char *attrib, int *status )
1365
1366 * Class Membership:
1367 * SkyFrame member function (over-rides the astClearAttrib protected
1368 * method inherited from the Frame class).
1369
1370 * Description:
1371 * This function clears the value of a specified attribute for a
1372 * SkyFrame, so that the default value will subsequently be used.
1373
1374 * Parameters:
1375 * this
1376 * Pointer to the SkyFrame.
1377 * attrib
1378 * Pointer to a null terminated string specifying the attribute
1379 * name. This should be in lower case with no surrounding white
1380 * space.
1381 * status
1382 * Pointer to the inherited status variable.
1383
1384 * Notes:
1385 * - This function uses one-based axis numbering so that it is
1386 * suitable for external (public) use.
1387 */
1388
1389 /* Local Variables: */
1390 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
1391 int axis; /* SkyFrame axis number */
1392 int len; /* Length of attrib string */
1393 int nc; /* No. characters read by astSscanf */
1394
1395 /* Check the global error status. */
1396 if ( !astOK ) return;
1397
1398 /* Obtain a pointer to the SkyFrame structure. */
1399 this = (AstSkyFrame *) this_object;
1400
1401 /* Obtain the length of the "attrib" string. */
1402 len = strlen( attrib );
1403
1404 /* Check the attribute name and clear the appropriate attribute. */
1405
1406 /* AsTime(axis). */
1407 /* ------------- */
1408 if ( nc = 0,
1409 ( 1 == astSscanf( attrib, "astime(%d)%n", &axis, &nc ) )
1410 && ( nc >= len ) ) {
1411 astClearAsTime( this, axis - 1 );
1412
1413 /* Equinox. */
1414 /* -------- */
1415 } else if ( !strcmp( attrib, "equinox" ) ) {
1416 astClearEquinox( this );
1417
1418 /* NegLon. */
1419 /* ------- */
1420 } else if ( !strcmp( attrib, "neglon" ) ) {
1421 astClearNegLon( this );
1422
1423 /* Projection. */
1424 /* ----------- */
1425 } else if ( !strcmp( attrib, "projection" ) ) {
1426 astClearProjection( this );
1427
1428 /* SkyRef. */
1429 /* ------- */
1430 } else if ( !strcmp( attrib, "skyref" ) ) {
1431 astClearSkyRef( this, 0 );
1432 astClearSkyRef( this, 1 );
1433
1434 /* SkyRef(axis). */
1435 /* ------------- */
1436 } else if ( nc = 0,
1437 ( 1 == astSscanf( attrib, "skyref(%d)%n", &axis, &nc ) )
1438 && ( nc >= len ) ) {
1439 astClearSkyRef( this, axis - 1 );
1440
1441 /* SkyRefP. */
1442 /* -------- */
1443 } else if ( !strcmp( attrib, "skyrefp" ) ) {
1444 astClearSkyRefP( this, 0 );
1445 astClearSkyRefP( this, 1 );
1446
1447 /* SkyRefP(axis). */
1448 /* ------------- */
1449 } else if ( nc = 0,
1450 ( 1 == astSscanf( attrib, "skyrefp(%d)%n", &axis, &nc ) )
1451 && ( nc >= len ) ) {
1452 astClearSkyRefP( this, axis - 1 );
1453
1454 /* SkyRefIs. */
1455 /* --------- */
1456 } else if ( !strcmp( attrib, "skyrefis" ) ) {
1457 astClearSkyRefIs( this );
1458
1459 /* AlignOffset. */
1460 /* ------------ */
1461 } else if ( !strcmp( attrib, "alignoffset" ) ) {
1462 astClearAlignOffset( this );
1463
1464 /* If the name was not recognised, test if it matches any of the
1465 read-only attributes of this class. If it does, then report an
1466 error. */
1467 } else if ( !strncmp( attrib, "islataxis", 9 ) ||
1468 !strncmp( attrib, "islonaxis", 9 ) ||
1469 !strcmp( attrib, "lataxis" ) ||
1470 !strcmp( attrib, "lonaxis" ) ) {
1471 astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" "
1472 "value for a %s.", status, attrib, astGetClass( this ) );
1473 astError( AST__NOWRT, "This is a read-only attribute." , status);
1474
1475 /* If the attribute is not recognised, pass it on to the parent method
1476 for further interpretation. */
1477 } else {
1478 (*parent_clearattrib)( this_object, attrib, status );
1479 }
1480 }
1481
ClearDut1(AstFrame * this,int * status)1482 static void ClearDut1( AstFrame *this, int *status ) {
1483 /*
1484 * Name:
1485 * ClearDut1
1486
1487 * Purpose:
1488 * Clear the value of the Dut1 attribute for a SkyFrame.
1489
1490 * Type:
1491 * Private function.
1492
1493 * Synopsis:
1494 * #include "skyframe.h"
1495 * void ClearDut1( AstFrame *this, int *status )
1496
1497 * Class Membership:
1498 * SkyFrame member function (over-rides the astClearDut1 method
1499 * inherited from the Frame class).
1500
1501 * Description:
1502 * This function clears the Dut1 value and updates the LAST value
1503 * stored in the SkyFrame.
1504
1505 * Parameters:
1506 * this
1507 * Pointer to the SkyFrame.
1508 * status
1509 * Pointer to the inherited status variable.
1510
1511 */
1512
1513 /* Local Variables: */
1514 double orig;
1515
1516 /* Check the global error status. */
1517 if ( !astOK ) return;
1518
1519 /* Note the original value */
1520 orig = astGetDut1( this );
1521
1522 /* Invoke the parent method to clear the Frame Dut1 */
1523 (*parent_cleardut1)( this, status );
1524
1525 /* If the DUT1 value has changed significantly, indicate that the LAST value
1526 will need to be re-calculated when it is next needed. */
1527 if( fabs( orig - astGetDut1( this ) ) > 1.0E-6 ) {
1528 ( (AstSkyFrame *) this )->last = AST__BAD;
1529 ( (AstSkyFrame *) this )->eplast = AST__BAD;
1530 ( (AstSkyFrame *) this )->klast = AST__BAD;
1531 }
1532 }
1533
ClearObsAlt(AstFrame * this,int * status)1534 static void ClearObsAlt( AstFrame *this, int *status ) {
1535 /*
1536 * Name:
1537 * ClearObsAlt
1538
1539 * Purpose:
1540 * Clear the value of the ObsAlt attribute for a SkyFrame.
1541
1542 * Type:
1543 * Private function.
1544
1545 * Synopsis:
1546 * #include "skyframe.h"
1547 * void ClearObsAlt( AstFrame *this, int *status )
1548
1549 * Class Membership:
1550 * SkyFrame member function (over-rides the astClearObsAlt method
1551 * inherited from the Frame class).
1552
1553 * Description:
1554 * This function clears the ObsAlt value.
1555
1556 * Parameters:
1557 * this
1558 * Pointer to the SkyFrame.
1559 * status
1560 * Pointer to the inherited status variable.
1561
1562 */
1563
1564 /* Local Variables: */
1565 double orig;
1566
1567 /* Check the global error status. */
1568 if ( !astOK ) return;
1569
1570 /* Note the original value */
1571 orig = astGetObsAlt( this );
1572
1573 /* Invoke the parent method to clear the Frame ObsAlt. */
1574 (*parent_clearobsalt)( this, status );
1575
1576 /* If the altitude has changed significantly, indicate that the LAST value
1577 and magnitude of the diurnal aberration vector will need to be
1578 re-calculated when next needed. */
1579 if( fabs( orig - astGetObsAlt( this ) ) > 0.001 ) {
1580 ( (AstSkyFrame *) this )->last = AST__BAD;
1581 ( (AstSkyFrame *) this )->eplast = AST__BAD;
1582 ( (AstSkyFrame *) this )->klast = AST__BAD;
1583 ( (AstSkyFrame *) this )->diurab = AST__BAD;
1584 }
1585 }
1586
ClearObsLat(AstFrame * this,int * status)1587 static void ClearObsLat( AstFrame *this, int *status ) {
1588 /*
1589 * Name:
1590 * ClearObsLat
1591
1592 * Purpose:
1593 * Clear the value of the ObsLat attribute for a SkyFrame.
1594
1595 * Type:
1596 * Private function.
1597
1598 * Synopsis:
1599 * #include "skyframe.h"
1600 * void ClearObsLat( AstFrame *this, int *status )
1601
1602 * Class Membership:
1603 * SkyFrame member function (over-rides the astClearObsLat method
1604 * inherited from the Frame class).
1605
1606 * Description:
1607 * This function clears the ObsLat value.
1608
1609 * Parameters:
1610 * this
1611 * Pointer to the SkyFrame.
1612 * status
1613 * Pointer to the inherited status variable.
1614
1615 */
1616
1617 /* Local Variables: */
1618 double orig;
1619
1620 /* Check the global error status. */
1621 if ( !astOK ) return;
1622
1623 /* Note the original value */
1624 orig = astGetObsLat( this );
1625
1626 /* Invoke the parent method to clear the Frame ObsLat. */
1627 (*parent_clearobslat)( this, status );
1628
1629 /* If the altitude has changed significantly, indicate that the LAST value
1630 and magnitude of the diurnal aberration vector will need to be
1631 re-calculated when next needed. */
1632 if( fabs( orig - astGetObsLat( this ) ) > 1.0E-8 ) {
1633 ( (AstSkyFrame *) this )->last = AST__BAD;
1634 ( (AstSkyFrame *) this )->eplast = AST__BAD;
1635 ( (AstSkyFrame *) this )->klast = AST__BAD;
1636 ( (AstSkyFrame *) this )->diurab = AST__BAD;
1637 }
1638 }
1639
ClearObsLon(AstFrame * this,int * status)1640 static void ClearObsLon( AstFrame *this, int *status ) {
1641 /*
1642 * Name:
1643 * ClearObsLon
1644
1645 * Purpose:
1646 * Clear the value of the ObsLon attribute for a SkyFrame.
1647
1648 * Type:
1649 * Private function.
1650
1651 * Synopsis:
1652 * #include "skyframe.h"
1653 * void ClearObsLon( AstFrame *this, int *status )
1654
1655 * Class Membership:
1656 * SkyFrame member function (over-rides the astClearObsLon method
1657 * inherited from the Frame class).
1658
1659 * Description:
1660 * This function clears the ObsLon value.
1661
1662 * Parameters:
1663 * this
1664 * Pointer to the SkyFrame.
1665 * status
1666 * Pointer to the inherited status variable.
1667
1668 */
1669
1670 /* Local Variables: */
1671 double orig;
1672
1673 /* Check the global error status. */
1674 if ( !astOK ) return;
1675
1676 /* Note the original value */
1677 orig = astGetObsLon( this );
1678
1679 /* Invoke the parent method to clear the Frame ObsLon. */
1680 (*parent_clearobslon)( this, status );
1681
1682 /* If the longitude has changed significantly, indicate that the LAST value
1683 will need to be re-calculated when it is next needed. */
1684 if( fabs( orig - astGetObsLon( this ) ) > 1.0E-8 ) {
1685 ( (AstSkyFrame *) this )->last = AST__BAD;
1686 ( (AstSkyFrame *) this )->eplast = AST__BAD;
1687 ( (AstSkyFrame *) this )->klast = AST__BAD;
1688 }
1689 }
1690
ClearSystem(AstFrame * this_frame,int * status)1691 static void ClearSystem( AstFrame *this_frame, int *status ) {
1692 /*
1693 * Name:
1694 * ClearSystem
1695
1696 * Purpose:
1697 * Clear the System attribute for a SkyFrame.
1698
1699 * Type:
1700 * Private function.
1701
1702 * Synopsis:
1703 * #include "skyframe.h"
1704 * void ClearSystem( AstFrame *this_frame, int *status )
1705
1706 * Class Membership:
1707 * SkyFrame member function (over-rides the astClearSystem protected
1708 * method inherited from the Frame class).
1709
1710 * Description:
1711 * This function clears the System attribute for a SkyFrame.
1712
1713 * Parameters:
1714 * this
1715 * Pointer to the SkyFrame.
1716 * status
1717 * Pointer to the inherited status variable.
1718
1719 */
1720
1721 /* Local Variables: */
1722 AstFrameSet *fs; /* FrameSet to be used as the Mapping */
1723 AstSkyFrame *sfrm; /* Copy of original SkyFrame */
1724 AstSkyFrame *this; /* Pointer to SkyFrame structure */
1725 double xin[ 2 ]; /* Axis 0 values */
1726 double yin[ 2 ]; /* Axis 1 values */
1727 double xout[ 2 ]; /* Axis 0 values */
1728 double yout[ 2 ]; /* Axis 1 values */
1729 int skyref_set; /* Is either SkyRef attribute set? */
1730 int skyrefp_set; /* Is either SkyRefP attribute set? */
1731
1732 /* Check the global error status. */
1733 if ( !astOK ) return;
1734
1735 /* Obtain a pointer to the SkyFrame structure. */
1736 this = (AstSkyFrame *) this_frame;
1737
1738 /* See if either the SkyRef or SkyRefP attribute is set. */
1739 skyref_set = astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 );
1740 skyrefp_set = astTestSkyRefP( this, 0 ) || astTestSkyRefP( this, 1 );
1741
1742 /* If so, we will need to transform their values into the new coordinate
1743 system. Save a copy of the SkyFrame with its original System value. */
1744 sfrm = ( skyref_set || skyrefp_set )?astCopy( this ):NULL;
1745
1746 /* Use the parent method to clear the System value. */
1747 (*parent_clearsystem)( this_frame, status );
1748
1749 /* Now modify the SkyRef and SkyRefP attributes if necessary. */
1750 if( sfrm ) {
1751
1752 /* Save the SkyRef and SkyRefP values. */
1753 xin[ 0 ] = astGetSkyRef( sfrm, 0 );
1754 xin[ 1 ] = astGetSkyRefP( sfrm, 0 );
1755 yin[ 0 ] = astGetSkyRef( sfrm, 1 );
1756 yin[ 1 ] = astGetSkyRefP( sfrm, 1 );
1757
1758 /* Clear the SkyRef values to avoid infinite recursion in the following
1759 call to astConvert. */
1760 if( skyref_set ) {
1761 astClearSkyRef( sfrm, 0 );
1762 astClearSkyRef( sfrm, 1 );
1763 astClearSkyRef( this, 0 );
1764 astClearSkyRef( this, 1 );
1765 }
1766
1767 /* Get the Mapping from the original System to the default System. Invoking
1768 astConvert will recursively invoke ClearSystem again. This is why we need
1769 to be careful to ensure that SkyRef is cleared above - doing so ensure
1770 we do not end up with infinite recursion. */
1771 fs = astConvert( sfrm, this, "" );
1772
1773 /* Check the Mapping was found. */
1774 if( fs ) {
1775
1776 /* Use the Mapping to find the SkyRef and SkyRefP positions in the default
1777 coordinate system. */
1778 astTran2( fs, 2, xin, yin, 1, xout, yout );
1779
1780 /* Store the values as required. */
1781 if( skyref_set ) {
1782 astSetSkyRef( this, 0, xout[ 0 ] );
1783 astSetSkyRef( this, 1, yout[ 0 ] );
1784 }
1785
1786 if( skyrefp_set ) {
1787 astSetSkyRefP( this, 0, xout[ 1 ] );
1788 astSetSkyRefP( this, 1, yout[ 1 ] );
1789 }
1790
1791 /* Free resources. */
1792 fs = astAnnul( fs );
1793
1794 /* If the Mapping is not defined, we cannot convert the SkyRef or SkyRefP
1795 positions in the new Frame so clear them. */
1796 } else {
1797 if( skyref_set ) {
1798 astClearSkyRef( this, 0 );
1799 astClearSkyRef( this, 1 );
1800 }
1801 if( skyrefp_set ) {
1802 astClearSkyRefP( this, 0 );
1803 astClearSkyRefP( this, 1 );
1804 }
1805 }
1806
1807 /* Free resources. */
1808 sfrm = astAnnul( sfrm );
1809 }
1810 }
1811
Distance(AstFrame * this_frame,const double point1[],const double point2[],int * status)1812 static double Distance( AstFrame *this_frame,
1813 const double point1[], const double point2[], int *status ) {
1814 /*
1815 * Name:
1816 * Distance
1817
1818 * Purpose:
1819 * Calculate the distance between two points.
1820
1821 * Type:
1822 * Private function.
1823
1824 * Synopsis:
1825 * #include "skyframe.h"
1826 * double Distance( AstFrame *this,
1827 * const double point1[], const double point2[], int *status )
1828
1829 * Class Membership:
1830 * SkyFrame member function (over-rides the astDistance method
1831 * inherited from the Frame class).
1832
1833 * Description:
1834 * This function finds the distance between two points whose
1835 * SkyFrame coordinates are given. The distance calculated is that
1836 * along the geodesic curve (i.e. great circle) that joins the two
1837 * points.
1838
1839 * Parameters:
1840 * this
1841 * Pointer to the SkyFrame.
1842 * point1
1843 * An array of double, with one element for each SkyFrame axis,
1844 * containing the coordinates of the first point.
1845 * point2
1846 * An array of double, with one element for each SkyFrame axis,
1847 * containing the coordinates of the second point.
1848 * status
1849 * Pointer to the inherited status variable.
1850
1851 * Returned Value:
1852 * The distance between the two points, in radians.
1853
1854 * Notes:
1855 * - This function will return a "bad" result value (AST__BAD) if
1856 * any of the input coordinates has this value.
1857 * - A "bad" value will also be returned if this function is
1858 * invoked with the AST error status set or if it should fail for
1859 * any reason.
1860 */
1861
1862 /* Local Variables: */
1863 AstSkyFrame *this; /* Pointer to SkyFrame structure */
1864 const int *perm; /* Axis permutation array */
1865 double p1[ 2 ]; /* Permuted point1 coordinates */
1866 double p2[ 2 ]; /* Permuted point2 coordinates */
1867 double result; /* Value to return */
1868
1869 /* Initialise. */
1870 result = AST__BAD;
1871
1872 /* Check the global error status. */
1873 if ( !astOK ) return result;
1874
1875 /* Obtain a pointer to the SkyFrame structure. */
1876 this = (AstSkyFrame *) this_frame;
1877
1878 /* Obtain a pointer to the SkyFrame's axis permutation array. */
1879 perm = astGetPerm( this );
1880 if ( astOK ) {
1881
1882 /* Check that all supplied coordinates are OK. */
1883 if ( ( point1[ 0 ] != AST__BAD ) && ( point1[ 1 ] != AST__BAD ) &&
1884 ( point2[ 0 ] != AST__BAD ) && ( point2[ 1 ] != AST__BAD ) ) {
1885
1886 /* Apply the axis permutation array to obtain the coordinates of the
1887 two points in the required (longitude,latitude) order. */
1888 p1[ perm[ 0 ] ] = point1[ 0 ];
1889 p1[ perm[ 1 ] ] = point1[ 1 ];
1890 p2[ perm[ 0 ] ] = point2[ 0 ];
1891 p2[ perm[ 1 ] ] = point2[ 1 ];
1892
1893 /* Calculate the great circle distance between the points in radians. */
1894 result = palDsep( p1[ 0 ], p1[ 1 ], p2[ 0 ], p2[ 1 ] );
1895 }
1896 }
1897
1898 /* Return the result. */
1899 return result;
1900 }
1901
Format(AstFrame * this_frame,int axis,double value,int * status)1902 static const char *Format( AstFrame *this_frame, int axis, double value, int *status ) {
1903 /*
1904 * Name:
1905 * Format
1906
1907 * Purpose:
1908 * Format a coordinate value for a SkyFrame axis.
1909
1910 * Type:
1911 * Private function.
1912
1913 * Synopsis:
1914 * #include "skyframe.h"
1915 * const char *Format( AstFrame *this, int axis, double value, int *status )
1916
1917 * Class Membership:
1918 * SkyFrame member function (over-rides the astFormat method inherited
1919 * from the Frame class).
1920
1921 * Description:
1922 * This function returns a pointer to a string containing the formatted
1923 * (character) version of a coordinate value for a SkyFrame axis. The
1924 * formatting applied is that specified by a previous invocation of the
1925 * astSetFormat method. A suitable default format is applied if necessary,
1926 * and this may depend on which sky coordinate system the SkyFrame
1927 * describes.
1928
1929 * Parameters:
1930 * this
1931 * Pointer to the SkyFrame.
1932 * axis
1933 * The number of the axis (zero-based) for which formatting is to be
1934 * performed.
1935 * value
1936 * The coordinate value to be formatted, in radians.
1937 * status
1938 * Pointer to the inherited status variable.
1939
1940 * Returned Value:
1941 * A pointer to a null-terminated string containing the formatted value.
1942
1943 * Notes:
1944 * - A NULL pointer will be returned if this function is invoked with the
1945 * global error status set, or if it should fail for any reason.
1946 */
1947
1948 /* Local Variables: */
1949 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
1950 const char *result; /* Pointer value to return */
1951 int format_set; /* Format attribute set? */
1952
1953 /* Check the global error status. */
1954 if ( !astOK ) return NULL;
1955
1956 /* Obtain a pointer to the SkyFrame structure. */
1957 this = (AstSkyFrame *) this_frame;
1958
1959 /* Validate the axis index. */
1960 (void) astValidateAxis( this, axis, 1, "astFormat" );
1961
1962 /* Determine if a Format value has been set for the axis and set a temporary
1963 value if it has not. Use the GetFormat member function for this class
1964 together with member functions inherited from the parent class (rather than
1965 using the object's methods directly) because if any of these methods have
1966 been over-ridden by a derived class the Format string syntax may no longer
1967 be compatible with this class. */
1968 format_set = (*parent_testformat)( this_frame, axis, status );
1969 if ( !format_set ) {
1970 (*parent_setformat)( this_frame, axis, GetFormat( this_frame, axis, status ), status );
1971 }
1972
1973 /* Use the Format member function inherited from the parent class to format the
1974 value and return a pointer to the resulting string. */
1975 result = (*parent_format)( this_frame, axis, value, status );
1976
1977 /* If necessary, clear any temporary Format value that was set above. */
1978 if ( !format_set ) (*parent_clearformat)( this_frame, axis, status );
1979
1980 /* If an error occurred, clear the returned value. */
1981 if ( !astOK ) result = NULL;
1982
1983 /* Return the result. */
1984 return result;
1985 }
1986
FrameGrid(AstFrame * this_object,int size,const double * lbnd,const double * ubnd,int * status)1987 static AstPointSet *FrameGrid( AstFrame *this_object, int size, const double *lbnd,
1988 const double *ubnd, int *status ){
1989 /*
1990 * Name:
1991 * FrameGrid
1992
1993 * Purpose:
1994 * Return a grid of points covering a rectangular area of a Frame.
1995
1996 * Type:
1997 * Private function.
1998
1999 * Synopsis:
2000 * #include "skyframe.h"
2001 * AstPointSet *FrameGrid( AstFrame *this_frame, int size,
2002 * const double *lbnd, const double *ubnd,
2003 * int *status )
2004
2005 * Class Membership:
2006 * SkyFrame member function (over-rides the protected astFrameGrid
2007 * method inherited from the Frame class).
2008
2009 * Description:
2010 * This function returns a PointSet containing positions spread
2011 * approximately evenly throughtout a specified rectangular area of
2012 * the Frame.
2013
2014 * Parameters:
2015 * this
2016 * Pointer to the Frame.
2017 * size
2018 * The preferred number of points in the returned PointSet. The
2019 * actual number of points in the returned PointSet may be
2020 * different, but an attempt is made to stick reasonably closely to
2021 * the supplied value.
2022 * lbnd
2023 * Pointer to an array holding the lower bound of the rectangular
2024 * area on each Frame axis. The array should have one element for
2025 * each Frame axis.
2026 * ubnd
2027 * Pointer to an array holding the upper bound of the rectangular
2028 * area on each Frame axis. The array should have one element for
2029 * each Frame axis.
2030
2031 * Returned Value:
2032 * A pointer to a new PointSet holding the grid of points.
2033
2034 * Notes:
2035 * - A NULL pointer is returned if an error occurs.
2036 */
2037
2038 /* Local Variables: */
2039 AstPointSet *result;
2040 AstSkyFrame *this;
2041 double **ptr;
2042 double box_area;
2043 double cl;
2044 double dlon;
2045 double hilat;
2046 double hilon;
2047 double inclon;
2048 double lat_size;
2049 double lat;
2050 double lon;
2051 double lolon;
2052 double lon_size;
2053 double lolat;
2054 double totlen;
2055 int ilat;
2056 int ilon;
2057 int imer;
2058 int ip;
2059 int ipar;
2060 int ipmax;
2061 int nmer;
2062 int npar;
2063
2064 /* Initialise. */
2065 result = NULL;
2066
2067 /* Check the global error status. */
2068 if ( !astOK ) return result;
2069
2070 /* Obtain a pointer to the SkyFrame structure. */
2071 this = (AstSkyFrame *) this_object;
2072
2073 /* Get the zero-based indices of the longitude and latitude axes. */
2074 ilon = astGetLonAxis( this );
2075 ilat = 1 - ilon;
2076
2077 /* The latitude bounds may not be the right way round so check for it. */
2078 if( lbnd[ ilat ] <= ubnd[ ilat ] ) {
2079 lolat = lbnd[ ilat ];
2080 hilat = ubnd[ ilat ];
2081 } else {
2082 lolat = ubnd[ ilat ];
2083 hilat = lbnd[ ilat ];
2084 }
2085
2086 /* Check all bounds are good. Also check the size is positive. */
2087 lolon = lbnd[ ilon ];
2088 hilon = ubnd[ ilon ];
2089 if( size > 0 && lolat != AST__BAD && hilat != AST__BAD &&
2090 lolon != AST__BAD && hilon != AST__BAD ) {
2091
2092 /* Ensure the longitude bounds are in the range 0-2PI. */
2093 lolon = palDranrm( lolon );
2094 hilon = palDranrm( hilon );
2095
2096 /* If the upper longitude limit is less than the lower limit, add 2.PI */
2097 if( hilon <= lolon &&
2098 ubnd[ ilon ] != lbnd[ ilon ] ) hilon += 2*AST__DPI;
2099
2100 /* Get the total area of the box in steradians. */
2101 dlon = hilon - lolon;
2102 box_area = fabs( dlon*( sin( hilat ) - sin( lolat ) ) );
2103
2104 /* Get the nominal size of a square grid cell, in radians. */
2105 lat_size = sqrt( box_area/size );
2106
2107 /* How many parallels should we use to cover the box? Ensure we use at
2108 least two. These parallels pass through the centre of the grid cells. */
2109 npar = (int)( 0.5 + ( hilat - lolat )/lat_size );
2110 if( npar < 2 ) npar = 2;
2111
2112 /* Find the actual sample size implied by this number of parallels. */
2113 lat_size = ( hilat - lolat )/npar;
2114
2115 /* Find the total arc length of the parallels. */
2116 totlen = 0.0;
2117 lat = lolat + 0.5*lat_size;
2118 for( ipar = 0; ipar < npar; ipar++ ) {
2119 totlen += dlon*cos( lat );
2120 lat += lat_size;
2121 }
2122
2123 /* If we space "size" samples evenly over this total arc-length, what is
2124 the arc-distance between samples? */
2125 lon_size = totlen/size;
2126
2127 /* Create a PointSet in which to store the grid. Make it bigger than
2128 necessary in order to leave room for extra samples caused by integer
2129 truncation. */
2130 ipmax = 2*size;
2131 result = astPointSet( ipmax, 2, " ", status );
2132 ptr = astGetPoints( result );
2133 if( astOK ) {
2134
2135 /* Loop over all the parallels. */
2136 ip = 0;
2137 lat = lolat + 0.5*lat_size;
2138 for( ipar = 0; ipar < npar; ipar++ ) {
2139
2140 /* Get the longitude increment between samples on this parallel. */
2141 cl = cos( lat );
2142 inclon = ( cl != 0.0 ) ? lon_size/cl : 0.0;
2143
2144 /* Get the number of longitude samples for this parallel. Reduce it if
2145 it would extend beyond the end of the PointSet. */
2146 nmer = dlon/inclon;
2147 if( ip + nmer >= ipmax ) nmer = ipmax - ip;
2148
2149 /* Adjust the longitude increment to take up any slack caused by the
2150 above integer division. */
2151 inclon = dlon/nmer;
2152
2153 /* Produce the samples for the current parallel. */
2154 lon = lolon + 0.5*inclon;
2155 for( imer = 0; imer < nmer; imer++ ) {
2156 ptr[ ilon ][ ip ] = lon;
2157 ptr[ ilat ][ ip ] = lat;
2158
2159 lon += inclon;
2160 ip++;
2161 }
2162
2163 /* Get the latitude on the next parallel. */
2164 lat += lat_size;
2165 }
2166
2167 /* Truncate the PointSet to exclude unused elements at the end. */
2168 astSetNpoint( result, ip );
2169 }
2170
2171 /* Report error if supplied values were bad. */
2172 } else if( astOK ) {
2173 if( size < 1 ) {
2174 astError( AST__ATTIN, "astFrameGrid(%s): The supplied grid "
2175 "size (%d) is invalid (programming error).",
2176 status, astGetClass( this ), size );
2177 } else {
2178 astError( AST__ATTIN, "astFrameGrid(%s): One of more of the "
2179 "supplied bounds is AST__BAD (programming error).",
2180 status, astGetClass( this ) );
2181 }
2182 }
2183
2184 /* Annul the returned PointSet if an error has occurred. */
2185 if( !astOK ) result = astAnnul( result );
2186
2187 /* Return the PointSet holding the grid. */
2188 return result;
2189 }
2190
Gap(AstFrame * this_frame,int axis,double gap,int * ntick,int * status)2191 static double Gap( AstFrame *this_frame, int axis, double gap, int *ntick, int *status ) {
2192 /*
2193 * Name:
2194 * Gap
2195
2196 * Purpose:
2197 * Find a "nice" gap for tabulating SkyFrame axis values.
2198
2199 * Type:
2200 * Private function.
2201
2202 * Synopsis:
2203 * #include "skyframe.h"
2204 * double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status )
2205
2206 * Class Membership:
2207 * SkyFrame member function (over-rides the protected astGap method
2208 * inherited from the Frame class).
2209
2210 * Description:
2211 * This function returns a gap size which produces a nicely spaced
2212 * series of formatted values for a SkyFrame axis, the returned gap
2213 * size being as close as possible to the supplied target gap
2214 * size. It also returns a convenient number of divisions into
2215 * which the gap can be divided.
2216
2217 * Parameters:
2218 * this
2219 * Pointer to the SkyFrame.
2220 * axis
2221 * The number of the axis (zero-based) for which a gap is to be found.
2222 * gap
2223 * The target gap size.
2224 * ntick
2225 * Address of an int in which to return a convenient number of
2226 * divisions into which the gap can be divided.
2227 * status
2228 * Pointer to the inherited status variable.
2229
2230 * Returned Value:
2231 * The nice gap size.
2232
2233 * Notes:
2234 * - A value of zero is returned if the target gap size is zero.
2235 * - A negative gap size is returned if the supplied gap size is negative.
2236 * - A value of zero will be returned if this function is invoked
2237 * with the global error status set, or if it should fail for any
2238 * reason.
2239 */
2240
2241 /* Local Variables: */
2242 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
2243 double result; /* Gap value to return */
2244 int format_set; /* Format attribute set? */
2245
2246 /* Check the global error status. */
2247 if ( !astOK ) return 0.0;
2248
2249 /* Obtain a pointer to the SkyFrame structure. */
2250 this = (AstSkyFrame *) this_frame;
2251
2252 /* Validate the axis index. */
2253 (void) astValidateAxis( this, axis, 1, "astGap" );
2254
2255 /* Determine if a Format value has been set for the axis and set a
2256 temporary value if it has not. Use the GetFormat member function
2257 for this class together with member functions inherited from the
2258 parent class (rather than using the object's methods directly)
2259 because if any of these methods have been over-ridden by a derived
2260 class the Format string syntax may no longer be compatible with
2261 this class. */
2262 format_set = (*parent_testformat)( this_frame, axis, status );
2263 if ( !format_set ) {
2264 (*parent_setformat)( this_frame, axis, GetFormat( this_frame, axis, status ), status );
2265 }
2266
2267 /* Use the Gap member function inherited from the parent class to find
2268 the gap size. */
2269 result = (*parent_gap)( this_frame, axis, gap, ntick, status );
2270
2271 /* If necessary, clear any temporary Format value that was set above. */
2272 if ( !format_set ) (*parent_clearformat)( this_frame, axis, status );
2273
2274 /* If an error occurred, clear the returned value. */
2275 if ( !astOK ) result = 0.0;
2276
2277 /* Return the result. */
2278 return result;
2279 }
2280
GetObjSize(AstObject * this_object,int * status)2281 static int GetObjSize( AstObject *this_object, int *status ) {
2282 /*
2283 * Name:
2284 * GetObjSize
2285
2286 * Purpose:
2287 * Return the in-memory size of an Object.
2288
2289 * Type:
2290 * Private function.
2291
2292 * Synopsis:
2293 * #include "skyframe.h"
2294 * int GetObjSize( AstObject *this, int *status )
2295
2296 * Class Membership:
2297 * SkyFrame member function (over-rides the astGetObjSize protected
2298 * method inherited from the parent class).
2299
2300 * Description:
2301 * This function returns the in-memory size of the supplied SkyFrame,
2302 * in bytes.
2303
2304 * Parameters:
2305 * this
2306 * Pointer to the SkyFrame.
2307 * status
2308 * Pointer to the inherited status variable.
2309
2310 * Returned Value:
2311 * The Object size, in bytes.
2312
2313 * Notes:
2314 * - A value of zero will be returned if this function is invoked
2315 * with the global status set, or if it should fail for any reason.
2316 */
2317
2318 /* Local Variables: */
2319 AstSkyFrame *this; /* Pointer to SkyFrame structure */
2320 int result; /* Result value to return */
2321
2322 /* Initialise. */
2323 result = 0;
2324
2325 /* Check the global error status. */
2326 if ( !astOK ) return result;
2327
2328 /* Obtain a pointers to the SkyFrame structure. */
2329 this = (AstSkyFrame *) this_object;
2330
2331 /* Invoke the GetObjSize method inherited from the parent class, and then
2332 add on any components of the class structure defined by thsi class
2333 which are stored in dynamically allocated memory. */
2334 result = (*parent_getobjsize)( this_object, status );
2335 result += astTSizeOf( this->projection );
2336
2337 /* If an error occurred, clear the result value. */
2338 if ( !astOK ) result = 0;
2339
2340 /* Return the result, */
2341 return result;
2342 }
2343
GetActiveUnit(AstFrame * this_frame,int * status)2344 static int GetActiveUnit( AstFrame *this_frame, int *status ) {
2345 /*
2346 * Name:
2347 * GetActiveUnit
2348
2349 * Purpose:
2350 * Obtain the value of the ActiveUnit flag for a SkyFrame.
2351
2352 * Type:
2353 * Private function.
2354
2355 * Synopsis:
2356 * #include "skyframe.h"
2357 * int GetActiveUnit( AstFrame *this_frame, int *status )
2358
2359 * Class Membership:
2360 * SkyFrame member function (over-rides the astGetActiveUnit protected
2361 * method inherited from the Frame class).
2362
2363 * Description:
2364 * This function returns the value of the ActiveUnit flag for a
2365 * SkyFrame, which is always 0.
2366
2367 * Parameters:
2368 * this
2369 * Pointer to the SkyFrame.
2370 * status
2371 * Pointer to the inherited status variable.
2372
2373 * Returned Value:
2374 * The value to use for the ActiveUnit flag (0).
2375
2376 */
2377 return 0;
2378 }
2379
GetAsTime(AstSkyFrame * this,int axis,int * status)2380 static int GetAsTime( AstSkyFrame *this, int axis, int *status ) {
2381 /*
2382 * Name:
2383 * GetAsTime
2384
2385 * Purpose:
2386 * Obtain the value of the AsTime attribute for a SkyFrame's axis.
2387
2388 * Type:
2389 * Private function.
2390
2391 * Synopsis:
2392 * #include "skyframe.h"
2393 * int GetAsTime( AstSkyFrame *this, int axis, int *status )
2394
2395 * Class Membership:
2396 * SkyFrame member function.
2397
2398 * Description:
2399 * This function returns the boolean value of the AsTime attribute for a
2400 * specified axis of a SkyFrame. This value indicates whether axis values
2401 * should be formatted as times (as opposed to angles) by default.
2402
2403 * Parameters:
2404 * this
2405 * Pointer to the SkyFrame.
2406 * axis
2407 * Index of the axis for which information is required (zero based).
2408 * status
2409 * Pointer to the inherited status variable.
2410
2411 * Returned Value:
2412 * Zero or one, according to the setting of the AsTime attribute (if no
2413 * value has previously been set, a suitable default is returned).
2414
2415 * Notes:
2416 * - A value of zero will be returned if this function is invoked with the
2417 * global error status set, or if it should fail for any reason.
2418 */
2419
2420 /* Local Variables: */
2421 AstAxis *ax; /* Pointer to Axis object */
2422 int axis_p; /* Permuted axis index */
2423 int result; /* Result to be returned */
2424
2425 /* Check the global error status. */
2426 if ( !astOK ) return 0;
2427
2428 /* Initialise. */
2429 result = 0;
2430
2431 /* Validate and permute the axis index. */
2432 axis_p = astValidateAxis( this, axis, 1, "astGetAsTime" );
2433
2434 /* Obtain a pointer to the required Axis object. */
2435 ax = astGetAxis( this, axis );
2436
2437 /* Determine if the AsTime attribute has been set for the axis (this can only
2438 be the case if the object is a SkyAxis). If the attribute is set, obtain its
2439 value. */
2440 if ( astIsASkyAxis( ax ) && astTestAxisAsTime( ax ) ) {
2441 result = astGetAxisAsTime( ax );
2442
2443 /* Otherwise, check which (permuted) axis is involved. Only the first
2444 (longitude) axis may be displayed as a time by default. */
2445 } else if ( axis_p == 0 ) {
2446
2447 /* Test for those coordinate systems which normally have their longitude axes
2448 displayed as times (basically, those that involve the Earth's equator) and
2449 set the returned value appropriately. */
2450 result = IsEquatorial( astGetSystem( this ), status );
2451 }
2452
2453 /* Annul the Axis object pointer. */
2454 ax = astAnnul( ax );
2455
2456 /* Return the result. */
2457 return result;
2458 }
2459
GetAttrib(AstObject * this_object,const char * attrib,int * status)2460 static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
2461 /*
2462 * Name:
2463 * GetAttrib
2464
2465 * Purpose:
2466 * Get the value of a specified attribute for a SkyFrame.
2467
2468 * Type:
2469 * Private function.
2470
2471 * Synopsis:
2472 * #include "skyframe.h"
2473 * const char *GetAttrib( AstObject *this, const char *attrib, int *status )
2474
2475 * Class Membership:
2476 * SkyFrame member function (over-rides the protected astGetAttrib
2477 * method inherited from the Frame class).
2478
2479 * Description:
2480 * This function returns a pointer to the value of a specified
2481 * attribute for a SkyFrame, formatted as a character string.
2482
2483 * Parameters:
2484 * this
2485 * Pointer to the SkyFrame.
2486 * attrib
2487 * Pointer to a null-terminated string containing the name of
2488 * the attribute whose value is required. This name should be in
2489 * lower case, with all white space removed.
2490 * status
2491 * Pointer to the inherited status variable.
2492
2493 * Returned Value:
2494 * - Pointer to a null-terminated string containing the attribute
2495 * value.
2496
2497 * Notes:
2498 * - This function uses one-based axis numbering so that it is
2499 * suitable for external (public) use.
2500 * - The returned string pointer may point at memory allocated
2501 * within the SkyFrame, or at static memory. The contents of the
2502 * string may be over-written or the pointer may become invalid
2503 * following a further invocation of the same function or any
2504 * modification of the SkyFrame. A copy of the string should
2505 * therefore be made if necessary.
2506 * - A NULL pointer will be returned if this function is invoked
2507 * with the global error status set, or if it should fail for any
2508 * reason.
2509 */
2510
2511 /* Local Variables: */
2512 astDECLARE_GLOBALS /* Declare the thread specific global data */
2513 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
2514 const char *cval; /* Pointer to character attribute value */
2515 const char *result; /* Pointer value to return */
2516 double dval; /* Floating point attribute value */
2517 double equinox; /* Equinox attribute value (as MJD) */
2518 int as_time; /* AsTime attribute value */
2519 int axis; /* SkyFrame axis number */
2520 int ival; /* Integer attribute value */
2521 int len; /* Length of attrib string */
2522 int nc; /* No. characters read by astSscanf */
2523 int neglon; /* Display long. values as [-pi,pi]? */
2524
2525 /* Initialise. */
2526 result = NULL;
2527
2528 /* Check the global error status. */
2529 if ( !astOK ) return result;
2530
2531 /* Get a pointer to the structure holding thread-specific global data. */
2532 astGET_GLOBALS(this_object);
2533
2534 /* Obtain a pointer to the SkyFrame structure. */
2535 this = (AstSkyFrame *) this_object;
2536
2537 /* Obtain the length of the attrib string. */
2538 len = strlen( attrib );
2539
2540 /* Compare "attrib" with each recognised attribute name in turn,
2541 obtaining the value of the required attribute. If necessary, write
2542 the value into "getattrib_buff" as a null-terminated string in an appropriate
2543 format. Set "result" to point at the result string. */
2544
2545 /* AsTime(axis). */
2546 /* ------------- */
2547 if ( nc = 0,
2548 ( 1 == astSscanf( attrib, "astime(%d)%n", &axis, &nc ) )
2549 && ( nc >= len ) ) {
2550 as_time = astGetAsTime( this, axis - 1 );
2551 if ( astOK ) {
2552 (void) sprintf( getattrib_buff, "%d", as_time );
2553 result = getattrib_buff;
2554 }
2555
2556 /* Equinox. */
2557 /* -------- */
2558 } else if ( !strcmp( attrib, "equinox" ) ) {
2559 equinox = astGetEquinox( this );
2560 if ( astOK ) {
2561
2562 /* Format the Equinox as decimal years. Use a Besselian epoch if it
2563 will be less than 1984.0, otherwise use a Julian epoch. */
2564 result = astFmtDecimalYr( ( equinox < palEpj2d( 1984.0 ) ) ?
2565 palEpb( equinox ) : palEpj( equinox ),
2566 DBL_DIG );
2567 }
2568
2569 /* IsLatAxis(axis) */
2570 /* --------------- */
2571 } else if ( nc = 0,
2572 ( 1 == astSscanf( attrib, "islataxis(%d)%n", &axis, &nc ) )
2573 && ( nc >= len ) ) {
2574 ival = astGetIsLatAxis( this, axis - 1 );
2575 if ( astOK ) {
2576 (void) sprintf( getattrib_buff, "%d", ival );
2577 result = getattrib_buff;
2578 }
2579
2580 /* IsLonAxis(axis) */
2581 /* --------------- */
2582 } else if ( nc = 0,
2583 ( 1 == astSscanf( attrib, "islonaxis(%d)%n", &axis, &nc ) )
2584 && ( nc >= len ) ) {
2585 ival = astGetIsLonAxis( this, axis - 1 );
2586 if ( astOK ) {
2587 (void) sprintf( getattrib_buff, "%d", ival );
2588 result = getattrib_buff;
2589 }
2590
2591 /* LatAxis */
2592 /* -------- */
2593 } else if ( !strcmp( attrib, "lataxis" ) ) {
2594 axis = astGetLatAxis( this );
2595 if ( astOK ) {
2596 (void) sprintf( getattrib_buff, "%d", axis + 1 );
2597 result = getattrib_buff;
2598 }
2599
2600 /* LonAxis */
2601 /* -------- */
2602 } else if ( !strcmp( attrib, "lonaxis" ) ) {
2603 axis = astGetLonAxis( this );
2604 if ( astOK ) {
2605 (void) sprintf( getattrib_buff, "%d", axis + 1 );
2606 result = getattrib_buff;
2607 }
2608
2609 /* NegLon */
2610 /* ------ */
2611 } else if ( !strcmp( attrib, "neglon" ) ) {
2612 neglon = astGetNegLon( this );
2613 if ( astOK ) {
2614 (void) sprintf( getattrib_buff, "%d", neglon );
2615 result = getattrib_buff;
2616 }
2617
2618 /* Projection. */
2619 /* ----------- */
2620 } else if ( !strcmp( attrib, "projection" ) ) {
2621 result = astGetProjection( this );
2622
2623 /* SkyRef. */
2624 /* ------- */
2625 } else if ( !strcmp( attrib, "skyref" ) ) {
2626 cval = astFormat( this, 0, astGetSkyRef( this, 0 ) );
2627 if ( astOK ) {
2628 nc = sprintf( getattrib_buff, "%s, ", cval );
2629 cval = astFormat( this, 1, astGetSkyRef( this, 1 ) );
2630 if ( astOK ) {
2631 (void) sprintf( getattrib_buff + nc, "%s", cval );
2632 result = getattrib_buff;
2633 }
2634 }
2635
2636 /* SkyRef(axis). */
2637 /* ------------- */
2638 } else if ( nc = 0,
2639 ( 1 == astSscanf( attrib, "skyref(%d)%n", &axis, &nc ) )
2640 && ( nc >= len ) ) {
2641 dval = astGetSkyRef( this, axis - 1 );
2642 if ( astOK ) {
2643 (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
2644 result = getattrib_buff;
2645 }
2646
2647 /* SkyRefP. */
2648 /* -------- */
2649 } else if ( !strcmp( attrib, "skyrefp" ) ) {
2650 cval = astFormat( this, 0, astGetSkyRefP( this, 0 ) );
2651 if ( astOK ) {
2652 nc = sprintf( getattrib_buff, "%s, ", cval );
2653 cval = astFormat( this, 1, astGetSkyRefP( this, 1 ) );
2654 if ( astOK ) {
2655 (void) sprintf( getattrib_buff + nc, "%s", cval );
2656 result = getattrib_buff;
2657 }
2658 }
2659
2660 /* SkyRefP(axis). */
2661 /* -------------- */
2662 } else if ( nc = 0,
2663 ( 1 == astSscanf( attrib, "skyrefp(%d)%n", &axis, &nc ) )
2664 && ( nc >= len ) ) {
2665 dval = astGetSkyRefP( this, axis - 1 );
2666 if ( astOK ) {
2667 (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
2668 result = getattrib_buff;
2669 }
2670
2671 /* SkyRefIs. */
2672 /* --------- */
2673 } else if ( !strcmp( attrib, "skyrefis" ) ) {
2674 ival = astGetSkyRefIs( this );
2675 if ( astOK ) {
2676 if( ival == AST__POLE_REF ){
2677 result = POLE_STRING;
2678 } else if( ival == AST__IGNORED_REF ){
2679 result = IGNORED_STRING;
2680 } else {
2681 result = ORIGIN_STRING;
2682 }
2683 }
2684
2685 /* AlignOffset */
2686 /* ----------- */
2687 } else if ( !strcmp( attrib, "alignoffset" ) ) {
2688 ival = astGetAlignOffset( this );
2689 if ( astOK ) {
2690 (void) sprintf( getattrib_buff, "%d", ival );
2691 result = getattrib_buff;
2692 }
2693
2694 /* If the attribute name was not recognised, pass it on to the parent
2695 method for further interpretation. */
2696 } else {
2697 result = (*parent_getattrib)( this_object, attrib, status );
2698 }
2699
2700 /* Return the result. */
2701 return result;
2702 }
2703
GetDirection(AstFrame * this_frame,int axis,int * status)2704 static int GetDirection( AstFrame *this_frame, int axis, int *status ) {
2705 /*
2706 * Name:
2707 * GetDirection
2708
2709 * Purpose:
2710 * Obtain the value of the Direction attribute for a SkyFrame axis.
2711
2712 * Type:
2713 * Private function.
2714
2715 * Synopsis:
2716 * #include "skyframe.h"
2717 * int GetDirection( AstFrame *this_frame, int axis, int *status )
2718
2719 * Class Membership:
2720 * SkyFrame member function (over-rides the astGetDirection method inherited
2721 * from the Frame class).
2722
2723 * Description:
2724 * This function returns the value of the Direction attribute for a
2725 * specified axis of a SkyFrame. A suitable default value is returned if no
2726 * Direction value has previously been set.
2727
2728 * Parameters:
2729 * this
2730 * Pointer to the SkyFrame.
2731 * axis
2732 * Axis index (zero-based) identifying the axis for which information is
2733 * required.
2734 * status
2735 * Pointer to the inherited status variable.
2736
2737 * Returned Value:
2738 * Zero or one, depending on the Direction attribute value.
2739
2740 * Notes:
2741 * - A value of zero will be returned if this function is invoked with the
2742 * global error status set, or if it should fail for any reason.
2743 */
2744
2745 /* Local Variables: */
2746 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
2747 int axis_p; /* Permuted axis index */
2748 int result; /* Result to be returned */
2749
2750 /* Check the global error status. */
2751 if ( !astOK ) return 0;
2752
2753 /* Initialise. */
2754 result = 0;
2755
2756 /* Obtain a pointer to the SkyFrame structure. */
2757 this = (AstSkyFrame *) this_frame;
2758
2759 /* Validate and permute the axis index. */
2760 axis_p = astValidateAxis( this, axis, 1, "astGetDirection" );
2761
2762 /* Check if a value has been set for the axis Direction attribute. If so,
2763 obtain its value. */
2764 if ( astTestDirection( this, axis ) ) {
2765 result = (*parent_getdirection)( this_frame, axis, status );
2766
2767 /* Otherwise, we will generate a default Direction value. Currently all
2768 systems supported by SkyFrame are left handed, so all longitude axes
2769 are reversed and all latitude axes are not reversed. */
2770 } else if( axis_p == 0 ) {
2771 result = 0;
2772 } else {
2773 result = 1;
2774 }
2775
2776 /* If an error occurred, clear the result value. */
2777 if ( !astOK ) result = 0;
2778
2779 /* Return the result. */
2780 return result;
2781 }
2782
GetBottom(AstFrame * this_frame,int axis,int * status)2783 static double GetBottom( AstFrame *this_frame, int axis, int *status ) {
2784 /*
2785 * Name:
2786 * GetBottom
2787
2788 * Purpose:
2789 * Obtain the value of the Bottom attribute for a SkyFrame axis.
2790
2791 * Type:
2792 * Private function.
2793
2794 * Synopsis:
2795 * #include "skyframe.h"
2796 * double GetBottom( AstFrame *this_frame, int axis, int *status )
2797
2798 * Class Membership:
2799 * SkyFrame member function (over-rides the astGetBottom method inherited
2800 * from the Frame class).
2801
2802 * Description:
2803 * This function returns the value of the Bottom attribute for a
2804 * specified axis of a SkyFrame. A suitable default value is returned if no
2805 * value has previously been set.
2806
2807 * Parameters:
2808 * this
2809 * Pointer to the SkyFrame.
2810 * axis
2811 * Axis index (zero-based) identifying the axis for which information is
2812 * required.
2813 * status
2814 * Pointer to the inherited status variable.
2815
2816 * Returned Value:
2817 * The Bottom value to use.
2818
2819 * Notes:
2820 * - A value of -DBL_MAX will be returned if this function is invoked
2821 * with the global error status set, or if it should fail for any reason.
2822 */
2823
2824 /* Local Variables: */
2825 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
2826 int axis_p; /* Permuted axis index */
2827 double result; /* Result to be returned */
2828
2829 /* Check the global error status. */
2830 if ( !astOK ) return -DBL_MAX;
2831
2832 /* Initialise. */
2833 result = -DBL_MAX;
2834
2835 /* Obtain a pointer to the SkyFrame structure. */
2836 this = (AstSkyFrame *) this_frame;
2837
2838 /* Validate and permute the axis index. */
2839 axis_p = astValidateAxis( this, axis, 1, "astGetBottom" );
2840
2841 /* Check if a value has been set for the axis Bottom attribute. If so,
2842 obtain its value. */
2843 if ( astTestBottom( this, axis ) ) {
2844 result = (*parent_getbottom)( this_frame, axis, status );
2845
2846 /* Otherwise, we will return a default Bottom value appropriate to the
2847 SkyFrame class. */
2848 } else {
2849
2850 /* If it is a latitude axis return -pi/2. */
2851 if( axis_p == 1 ) {
2852 result = -piby2;
2853
2854 /* If it is a longitude value return -DBL_MAX (i.e. no lower limit). */
2855 } else {
2856 result = -DBL_MAX;
2857 }
2858 }
2859
2860 /* If an error occurred, clear the result value. */
2861 if ( !astOK ) result = -DBL_MAX;
2862
2863 /* Return the result. */
2864 return result;
2865 }
2866
GetCachedLAST(AstSkyFrame * this,double epoch,double obslon,double obslat,double obsalt,double dut1,int * status)2867 static double GetCachedLAST( AstSkyFrame *this, double epoch, double obslon,
2868 double obslat, double obsalt, double dut1,
2869 int *status ) {
2870 /*
2871 * Name:
2872 * GetCachedLAST
2873
2874 * Purpose:
2875 * Attempt to get a LAST value from the cache in the SkyFrame vtab.
2876
2877 * Type:
2878 * Private function.
2879
2880 * Synopsis:
2881 * #include "skyframe.h"
2882 * double GetCachedLAST( AstSkyFrame *this, double epoch, double obslon,
2883 * double obslat, double obsalt, double dut1,
2884 * int *status )
2885
2886 * Class Membership:
2887 * SkyFrame member function.
2888
2889 * Description:
2890 * This function searches the static cache of LAST values held in the
2891 * SkyFrame virtual function table for a value that corresponds to the
2892 * supplied parameter values. If one is found, it is returned.
2893 * Otherwise AST__BAD is found.
2894
2895 * Parameters:
2896 * this
2897 * Pointer to the SkyFrame.
2898 * epoch
2899 * The epoch (MJD).
2900 * obslon
2901 * Observatory geodetic longitude (radians)
2902 * obslat
2903 * Observatory geodetic latitude (radians)
2904 * obsalt
2905 * Observatory geodetic altitude (metres)
2906 * dut1
2907 * The UT1-UTC correction, in seconds.
2908 * status
2909 * Pointer to the inherited status variable.
2910
2911 * Returned Value:
2912 * The Local Apparent Sidereal Time, in radians.
2913
2914 * Notes:
2915 * - A value of AST__BAD will be returned if this function is invoked
2916 * with the global error status set, or if it should fail for any reason.
2917 */
2918
2919 /* Local Variables: */
2920 astDECLARE_GLOBALS
2921 AstSkyLastTable *table;
2922 double *ep;
2923 double *lp;
2924 double dep;
2925 double result;
2926 int ihi;
2927 int ilo;
2928 int itable;
2929 int itest;
2930
2931 /* Get a pointer to the structure holding thread-specific global data. */
2932 astGET_GLOBALS(this);
2933
2934 /* Initialise */
2935 result = AST__BAD;
2936
2937 /* Check the global error status. */
2938 if ( !astOK ) return result;
2939
2940 /* Wait until the table is not being written to by any thread. This also
2941 prevents a thread from writing to the table whilst we are reading it. */
2942 LOCK_RLOCK1
2943
2944 /* Loop round every LAST table held in the vtab. Each table refers to a
2945 different observatory position and/or DUT1 value. */
2946 for( itable = 0; itable < nlast_tables; itable++ ) {
2947 table = last_tables[ itable ];
2948
2949 /* See if the table refers to the given position and dut1 value, allowing
2950 some small tolerance. */
2951 if( fabs( table->obslat - obslat ) < 2.0E-7 &&
2952 fabs( table->obslon - obslon ) < 2.0E-7 &&
2953 fabs( table->obsalt - obsalt ) < 1.0 &&
2954 fabs( table->dut1 - dut1 ) < 1.0E-5 ) {
2955
2956 /* Get pointers to the array of epoch and corresponding LAST values in
2957 the table. */
2958 ep = table->epoch;
2959 lp = table->last;
2960
2961 /* The values in the epoch array are monotonic increasing. Do a binary chop
2962 within the table's epoch array to find the earliest entry that has a
2963 value equal to or greater than the supplied epoch value. */
2964 ilo = 0;
2965 ihi = table->nentry - 1;
2966 while( ihi > ilo ) {
2967 itest = ( ilo + ihi )/2;
2968 if( ep[ itest ] >= epoch ) {
2969 ihi = itest;
2970 } else {
2971 ilo = itest + 1;
2972 }
2973 }
2974
2975 /* Get the difference between the epoch at the entry selected above and
2976 the requested epoch. */
2977 dep = ep[ ilo ] - epoch;
2978
2979 /* If the entry selected above is the first entry in the table, it can
2980 only be used if it is within 0.001 second of the requested epoch. */
2981 if( ilo == 0 ) {
2982 if( fabs( dep ) < 0.001/86400.0 ) {
2983 result = lp[ 0 ];
2984 }
2985
2986 /* If the list of epoch values contained no value that was greater than
2987 the supplied epoch value, then we can use the last entry if
2988 it is no more than 0.001 second away from the requested epoch. */
2989 } else if( dep <= 0.0 ) {
2990 if( fabs( dep ) < 0.001/86400.0 ) {
2991 result = lp[ ilo ];
2992 }
2993
2994
2995 /* Otherwise, see if the entry selected above is sufficiently close to
2996 its lower neighbour (i.e. closer than 0.4 days) to allow a reasonably
2997 accurate LAST value to be determined by interpolation. */
2998 } else if( ep[ ilo ] - ep[ ilo - 1 ] < 0.4 ) {
2999 ep += ilo - 1;
3000 lp += ilo - 1;
3001 result = *lp + ( epoch - *ep )*( lp[ 1 ] - *lp )/( ep[ 1 ] - *ep );
3002
3003 /* If the neighbouring point is too far away for interpolation to be
3004 reliable, then we can only use the point if it is within 0.001 seconds of
3005 the requested epoch. */
3006 } else if( fabs( dep ) < 0.001/86400.0 ) {
3007 result = lp[ ilo ];
3008 }
3009
3010 /* If we have found the right table, we do not need to look at any other
3011 tables, so leave the table loop. */
3012 break;
3013 }
3014 }
3015
3016 /* Indicate that threads may now write to the table. */
3017 UNLOCK_RWLOCK1
3018
3019 /* Ensure the returned value is within the range 0 - 2.PI. */
3020 if( result != AST__BAD ) {
3021 while( result > 2*AST__DPI ) result -= 2*AST__DPI;
3022 while( result < 0.0 ) result += 2*AST__DPI;
3023 }
3024
3025 /* Return the required LAST value. */
3026 return result;
3027 }
3028
GetEpoch(AstFrame * this_frame,int * status)3029 static double GetEpoch( AstFrame *this_frame, int *status ) {
3030 /*
3031 * Name:
3032 * GetEpoch
3033
3034 * Purpose:
3035 * Obtain the value of the Epoch attribute for a SkyFrame axis.
3036
3037 * Type:
3038 * Private function.
3039
3040 * Synopsis:
3041 * #include "skyframe.h"
3042 * double GetEpoch( AstFrame *this_frame, int *status )
3043
3044 * Class Membership:
3045 * SkyFrame member function (over-rides the astGetEpoch method inherited
3046 * from the Frame class).
3047
3048 * Description:
3049 * This function returns the value of the Epoch attribute for a
3050 * SkyFrame. A suitable default value is returned if no value has
3051 * previously been set.
3052
3053 * Parameters:
3054 * this
3055 * Pointer to the SkyFrame.
3056 * status
3057 * Pointer to the inherited status variable.
3058
3059 * Returned Value:
3060 * The Epoch value to use.
3061
3062 * Notes:
3063 * - A value of AST__BAD will be returned if this function is invoked
3064 * with the global error status set, or if it should fail for any reason.
3065 */
3066
3067 /* Local Variables: */
3068 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
3069 AstSystemType system; /* System attribute */
3070 double result; /* Result to be returned */
3071
3072 /* Check the global error status. */
3073 if ( !astOK ) return AST__BAD;
3074
3075 /* Initialise. */
3076 result = AST__BAD;
3077
3078 /* Obtain a pointer to the SkyFrame structure. */
3079 this = (AstSkyFrame *) this_frame;
3080
3081 /* Check if a value has been set for the Epoch attribute. If so, obtain its
3082 value. */
3083 if ( astTestEpoch( this ) ) {
3084 result = (*parent_getepoch)( this_frame, status );
3085
3086 /* Otherwise, we will return a default Epoch value appropriate to the
3087 SkyFrame class. */
3088 } else {
3089
3090 /* Provide a default value of B1950.0 or J2000.0 depending on the System
3091 setting. */
3092 system = astGetSystem( this );
3093 if( system == AST__FK4 || system == AST__FK4_NO_E ) {
3094 result = palEpb2d( 1950.0 );
3095 } else {
3096 result = palEpj2d( 2000.0 );
3097 }
3098 }
3099
3100 /* If an error occurred, clear the result value. */
3101 if ( !astOK ) result = AST__BAD;
3102
3103 /* Return the result. */
3104 return result;
3105 }
3106
GetTop(AstFrame * this_frame,int axis,int * status)3107 static double GetTop( AstFrame *this_frame, int axis, int *status ) {
3108 /*
3109 * Name:
3110 * GetTop
3111
3112 * Purpose:
3113 * Obtain the value of the Top attribute for a SkyFrame axis.
3114
3115 * Type:
3116 * Private function.
3117
3118 * Synopsis:
3119 * #include "skyframe.h"
3120 * double GetTop( AstFrame *this_frame, int axis, int *status )
3121
3122 * Class Membership:
3123 * SkyFrame member function (over-rides the astGetTop method inherited
3124 * from the Frame class).
3125
3126 * Description:
3127 * This function returns the value of the Top attribute for a
3128 * specified axis of a SkyFrame. A suitable default value is returned if no
3129 * value has previously been set.
3130
3131 * Parameters:
3132 * this
3133 * Pointer to the SkyFrame.
3134 * axis
3135 * Axis index (zero-based) identifying the axis for which information is
3136 * required.
3137 * status
3138 * Pointer to the inherited status variable.
3139
3140 * Returned Value:
3141 * The Top value to use.
3142
3143 * Notes:
3144 * - A value of DBL_MAX will be returned if this function is invoked
3145 * with the global error status set, or if it should fail for any reason.
3146 */
3147
3148 /* Local Variables: */
3149 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
3150 int axis_p; /* Permuted axis index */
3151 double result; /* Result to be returned */
3152
3153 /* Check the global error status. */
3154 if ( !astOK ) return DBL_MAX;
3155
3156 /* Initialise. */
3157 result = DBL_MAX;
3158
3159 /* Obtain a pointer to the SkyFrame structure. */
3160 this = (AstSkyFrame *) this_frame;
3161
3162 /* Validate and permute the axis index. */
3163 axis_p = astValidateAxis( this, axis, 1, "astGetTop" );
3164
3165 /* Check if a value has been set for the axis Top attribute. If so,
3166 obtain its value. */
3167 if ( astTestTop( this, axis ) ) {
3168 result = (*parent_gettop)( this_frame, axis, status );
3169
3170 /* Otherwise, we will return a default Top value appropriate to the
3171 SkyFrame class. */
3172 } else {
3173
3174 /* If this is a latitude axis return pi/2. */
3175 if( axis_p == 1 ) {
3176 result = piby2;
3177
3178 /* If it is a longitude value return DBL_MAX (i.e. no upper limit). */
3179 } else {
3180 result = DBL_MAX;
3181 }
3182 }
3183
3184 /* If an error occurred, clear the result value. */
3185 if ( !astOK ) result = DBL_MAX;
3186
3187 /* Return the result. */
3188 return result;
3189 }
3190
GetDomain(AstFrame * this_frame,int * status)3191 static const char *GetDomain( AstFrame *this_frame, int *status ) {
3192 /*
3193 * Name:
3194 * GetDomain
3195
3196 * Purpose:
3197 * Obtain a pointer to the Domain attribute string for a SkyFrame.
3198
3199 * Type:
3200 * Private function.
3201
3202 * Synopsis:
3203 * #include "skyframe.h"
3204 * const char *GetDomain( AstFrame *this, int *status )
3205
3206 * Class Membership:
3207 * SkyFrame member function (over-rides the astGetDomain protected
3208 * method inherited from the Frame class).
3209
3210 * Description:
3211 * This function returns a pointer to the Domain attribute string
3212 * for a SkyFrame.
3213
3214 * Parameters:
3215 * this
3216 * Pointer to the SkyFrame.
3217 * status
3218 * Pointer to the inherited status variable.
3219
3220 * Returned Value:
3221 * A pointer to a constant null-terminated string containing the
3222 * Domain value.
3223
3224 * Notes:
3225 * - The returned pointer or the string it refers to may become
3226 * invalid following further invocation of this function or
3227 * modification of the SkyFrame.
3228 * - A NULL pointer is returned if this function is invoked with
3229 * the global error status set or if it should fail for any reason.
3230 */
3231
3232 /* Local Variables: */
3233 AstSkyFrame *this; /* Pointer to SkyFrame structure */
3234 const char *result; /* Pointer value to return */
3235
3236 /* Initialise. */
3237 result = NULL;
3238
3239 /* Check the global error status. */
3240 if ( !astOK ) return result;
3241
3242 /* Obtain a pointer to the SkyFrame structure. */
3243 this = (AstSkyFrame *) this_frame;
3244
3245 /* If a Domain attribute string has been set, invoke the parent method
3246 to obtain a pointer to it. */
3247 if ( astTestDomain( this ) ) {
3248 result = (*parent_getdomain)( this_frame, status );
3249
3250 /* Otherwise, provide a pointer to a suitable default string. */
3251 } else {
3252 result = "SKY";
3253 }
3254
3255 /* Return the result. */
3256 return result;
3257 }
3258
GetFormat(AstFrame * this_frame,int axis,int * status)3259 static const char *GetFormat( AstFrame *this_frame, int axis, int *status ) {
3260 /*
3261 * Name:
3262 * GetFormat
3263
3264 * Purpose:
3265 * Access the Format string for a SkyFrame axis.
3266
3267 * Type:
3268 * Private function.
3269
3270 * Synopsis:
3271 * #include "skyframe.h"
3272 * const char *GetFormat( AstFrame *this, int axis )
3273
3274 * Class Membership:
3275 * SkyFrame member function (over-rides the astGetFormat method inherited
3276 * from the Frame class).
3277
3278 * Description:
3279 * This function returns a pointer to the Format string for a specified axis
3280 * of a SkyFrame. A pointer to a suitable default string is returned if no
3281 * Format value has previously been set.
3282
3283 * Parameters:
3284 * this
3285 * Pointer to the SkyFrame.
3286 * axis
3287 * Axis index (zero-based) identifying the axis for which information is
3288 * required.
3289
3290 * Returned Value:
3291 * Pointer to a null-terminated character string containing the requested
3292 * information.
3293
3294 * Notes:
3295 * - A NULL pointer will be returned if this function is invoked with the
3296 * global error status set, or if it should fail for any reason.
3297 */
3298
3299 /* Local Variables: */
3300 astDECLARE_GLOBALS /* Declare the thread specific global data */
3301 AstAxis *ax; /* Pointer to Axis object */
3302 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
3303 const char *result; /* Pointer value to return */
3304 int as_time; /* Value of AsTime attribute */
3305 int as_time_set; /* AsTime attribute set? */
3306 int axis_p; /* Permuted axis index */
3307 int digits; /* Number of digits of precision */
3308 int is_latitude; /* Value of IsLatitude attribute */
3309 int is_latitude_set; /* IsLatitude attribute set? */
3310 int parent; /* Use parent method? */
3311 int skyaxis; /* Is the Axis a SkyAxis? */
3312
3313 /* Check the global error status. */
3314 if ( !astOK ) return NULL;
3315
3316 /* Get a pointer to the structure holding thread-specific global data. */
3317 astGET_GLOBALS(this_frame);
3318
3319 /* Initialise. */
3320 result = NULL;
3321 as_time_set = 0;
3322 is_latitude = 0;
3323 is_latitude_set = 0;
3324
3325 /* Obtain a pointer to the SkyFrame structure. */
3326 this = (AstSkyFrame *) this_frame;
3327
3328 /* Validate and permute the axis index. */
3329 axis_p = astValidateAxis( this, axis, 1, "astGetFormat" );
3330
3331 /* Obtain a pointer to the Axis structure. */
3332 ax = astGetAxis( this, axis );
3333
3334 /* Decide whether the parent astGetFormat method is able to provide the format
3335 string we require. We must use the parent method if the Axis is not a
3336 SkyAxis, because the syntax of the Format string would become unsuitable
3337 for use with the Axis astFormat method if it was over-ridden here. We also
3338 use the parent method to return a Format pointer if an explicit Format
3339 string has already been set. */
3340 skyaxis = astIsASkyAxis( ax );
3341 parent = ( !skyaxis || (*parent_testformat)( this_frame, axis, status ) );
3342
3343 /* If neither of the above conditions apply, we may still be able to use the
3344 parent method if the Axis (actually a SkyAxis) is required to behave as a
3345 normal RA or DEC axis, as this is the standard behaviour provided by the
3346 SkyAxis class. Examine the SkyFrame's System attribute to determine if its
3347 axes should behave in this way. */
3348 if ( !parent ) parent = IsEquatorial( astGetSystem( this ), status );
3349
3350 /* If using the parent method and dealing with a SkyAxis, determine the
3351 settings of any attributes that may affect the Format string. */
3352 if ( astOK ) {
3353 if ( parent ) {
3354 if ( skyaxis ) {
3355 as_time_set = astTestAsTime( this, axis );
3356 is_latitude_set = astTestAxisIsLatitude( ax );
3357 is_latitude = astGetAxisIsLatitude( ax );
3358
3359 /* If no AsTime value is set for the axis, set a temporary value as determined
3360 by the astGetAsTime method, which supplies suitable defaults for the axes of
3361 a SkyFrame. */
3362 if ( !as_time_set ) {
3363 astSetAsTime( this, axis, astGetAsTime( this, axis ) );
3364 }
3365
3366 /* Temporarly over-ride the SkyAxis IsLatitude attribute, regardless of its
3367 setting, as the second axis of a SkyFrame is always the latitude axis. */
3368 astSetAxisIsLatitude( ax, axis_p == 1 );
3369 }
3370
3371 /* Invoke the parent method to obtain a pointer to the Format string. */
3372 result = (*parent_getformat)( this_frame, axis, status );
3373
3374 /* Now restore the attributes that were temporarily over-ridden above to their
3375 previous states. */
3376 if ( skyaxis ) {
3377 if ( !as_time_set ) astClearAsTime( this, axis );
3378 if ( !is_latitude_set ) {
3379 astClearAxisIsLatitude( ax );
3380 } else {
3381 astSetAxisIsLatitude( ax, is_latitude );
3382 }
3383 }
3384
3385 /* If the parent method is unsuitable, we must construct a new Format string
3386 here. This affects only those coordinate systems whose axes do not behave
3387 like standard RA/DEC axes (e.g. typically ecliptic, galactic and
3388 supergalactic coordinates). For these, we format values as decimal degrees
3389 (or decimal hours if the AsTime attribute is set). Obtain the AsTime
3390 value. */
3391 } else {
3392 as_time = astGetAsTime( this, axis );
3393
3394 /* Determine how many digits of precision to use. This is obtained from the
3395 SkyAxis Digits attribute (if set), otherwise from the Digits attribute of
3396 the enclosing SkyFrame. */
3397 if ( astTestAxisDigits( ax ) ) {
3398 digits = astGetAxisDigits( ax );
3399 } else {
3400 digits = astGetDigits( this );
3401 }
3402
3403 /* If a time format is required, generate a Format string using decimal
3404 hours. */
3405 if ( astOK ) {
3406 if ( as_time ) {
3407 if ( digits <= 2 ) {
3408 result = "h";
3409 } else {
3410 (void) sprintf( getformat_buff, "h.%d", digits - 2 );
3411 result = getformat_buff;
3412 }
3413
3414 /* Otherwise use decimal degrees. */
3415 } else {
3416 if ( digits <= 3 ) {
3417 result = "d";
3418 } else {
3419 (void) sprintf( getformat_buff, "d.%d", digits - 3 );
3420 result = getformat_buff;
3421 }
3422 }
3423 }
3424 }
3425 }
3426
3427 /* Annul the Axis pointer. */
3428 ax = astAnnul( ax );
3429
3430 /* If an error occurred, clear the returned value. */
3431 if ( !astOK ) result = NULL;
3432
3433 /* Return the result. */
3434 return result;
3435 }
3436
GetLabel(AstFrame * this,int axis,int * status)3437 static const char *GetLabel( AstFrame *this, int axis, int *status ) {
3438 /*
3439 * Name:
3440 * GetLabel
3441
3442 * Purpose:
3443 * Access the Label string for a SkyFrame axis.
3444
3445 * Type:
3446 * Private function.
3447
3448 * Synopsis:
3449 * #include "skyframe.h"
3450 * const char *GetLabel( AstFrame *this, int axis, int *status )
3451
3452 * Class Membership:
3453 * SkyFrame member function (over-rides the astGetLabel method inherited
3454 * from the Frame class).
3455
3456 * Description:
3457 * This function returns a pointer to the Label string for a specified axis
3458 * of a SkyFrame.
3459
3460 * Parameters:
3461 * this
3462 * Pointer to the SkyFrame.
3463 * axis
3464 * Axis index (zero-based) identifying the axis for which information is
3465 * required.
3466 * status
3467 * Pointer to the inherited status variable.
3468
3469 * Returned Value:
3470 * Pointer to a constant null-terminated character string containing the
3471 * requested information.
3472
3473 * Notes:
3474 * - A NULL pointer will be returned if this function is invoked with the
3475 * global error status set, or if it should fail for any reason.
3476 */
3477
3478 /* Local Variables: */
3479 astDECLARE_GLOBALS /* Declare the thread specific global data */
3480 AstSystemType system; /* Code identifying type of sky coordinates */
3481 const char *result; /* Pointer to label string */
3482 int axis_p; /* Permuted axis index */
3483
3484 /* Check the global error status. */
3485 if ( !astOK ) return NULL;
3486
3487 /* Get a pointer to the structure holding thread-specific global data. */
3488 astGET_GLOBALS(this);
3489
3490 /* Initialise. */
3491 result = NULL;
3492
3493 /* Validate and permute the axis index. */
3494 axis_p = astValidateAxis( this, axis, 1, "astGetLabel" );
3495
3496 /* Check if a value has been set for the required axis label string. If so,
3497 invoke the parent astGetLabel method to obtain a pointer to it. */
3498 if ( astTestLabel( this, axis ) ) {
3499 result = (*parent_getlabel)( this, axis, status );
3500
3501 /* Otherwise, identify the sky coordinate system described by the SkyFrame. */
3502 } else {
3503 system = astGetSystem( this );
3504
3505 /* If OK, supply a pointer to a suitable default label string. */
3506 if ( astOK ) {
3507
3508 /* Equatorial coordinate systems. */
3509 if ( IsEquatorial( system, status ) ) {
3510 result = ( axis_p == 0 ) ? "Right ascension" :
3511 "Declination";
3512
3513 /* Ecliptic coordinates. */
3514 } else if ( system == AST__ECLIPTIC ) {
3515 result = ( axis_p == 0 ) ? "Ecliptic longitude" :
3516 "Ecliptic latitude";
3517
3518 /* Helio-ecliptic coordinates. */
3519 } else if ( system == AST__HELIOECLIPTIC ) {
3520 result = ( axis_p == 0 ) ? "Helio-ecliptic longitude" :
3521 "Helio-ecliptic latitude";
3522
3523 /* AzEl coordinates. */
3524 } else if ( system == AST__AZEL ) {
3525 result = ( axis_p == 0 ) ? "Azimuth" :
3526 "Elevation";
3527
3528 /* Galactic coordinates. */
3529 } else if ( system == AST__GALACTIC ) {
3530 result = ( axis_p == 0 ) ? "Galactic longitude" :
3531 "Galactic latitude";
3532
3533 /* Supergalactic coordinates. */
3534 } else if ( system == AST__SUPERGALACTIC ) {
3535 result = ( axis_p == 0 ) ? "Supergalactic longitude" :
3536 "Supergalactic latitude";
3537
3538 /* Unknown spherical coordinates. */
3539 } else if ( system == AST__UNKNOWN ) {
3540 result = ( axis_p == 0 ) ? "Longitude" :
3541 "Latitude";
3542
3543 /* Report an error if the coordinate system was not recognised. */
3544 } else {
3545 astError( AST__SCSIN, "astGetLabel(%s): Corrupt %s contains "
3546 "invalid sky coordinate system identification code "
3547 "(%d).", status, astGetClass( this ), astGetClass( this ),
3548 (int) system );
3549 }
3550
3551 /* If the SkyRef attribute has a set value, append " offset" to the label. */
3552 if( astGetSkyRefIs( this ) != AST__IGNORED_REF &&
3553 ( astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ) ) ) {
3554 sprintf( getlabel_buff, "%s offset", result );
3555 result = getlabel_buff;
3556 }
3557 }
3558 }
3559
3560 /* Return the result. */
3561 return result;
3562 }
3563
GetDiurab(AstSkyFrame * this,int * status)3564 static double GetDiurab( AstSkyFrame *this, int *status ) {
3565 /*
3566 * Name:
3567 * GetDiurab
3568
3569 * Purpose:
3570 * Return the magnitude of the diurnal aberration vector.
3571
3572 * Type:
3573 * Private function.
3574
3575 * Synopsis:
3576 * #include "skyframe.h"
3577 * double GetDiurab( AstSkyFrame *this, int *status )
3578
3579 * Class Membership:
3580 * SkyFrame member function
3581
3582 * Description:
3583 * This function returns the magnitude of the diurnal aberration
3584 * vector.
3585
3586 * Parameters:
3587 * this
3588 * Pointer to the SkyFrame.
3589 * status
3590 * Pointer to the inherited status variable.
3591
3592 * Returned Value:
3593 * The magnitude of the diurnal aberration vector.
3594
3595 */
3596
3597 /* Local Variables: */
3598 double uau;
3599 double vau;
3600
3601 /* Check the global error status. */
3602 if ( !astOK ) return AST__BAD;
3603
3604 /* If the magnitude of the diurnal aberration vector has not yet been
3605 found, find it now, and cache it in the SkyFrame structure. The cached
3606 value will be reset to AST__BAD if the ObsLat attribute value is
3607 changed. This code is transliterated from SLA_AOPPA. */
3608 if( this->diurab == AST__BAD ) {
3609 palGeoc( astGetObsLat( this ), astGetObsAlt( this ), &uau, &vau );
3610 this->diurab = 2*AST__DPI*uau*SOLSID/C;
3611 }
3612
3613 /* Return the result, */
3614 return this->diurab;
3615 }
3616
GetLAST(AstSkyFrame * this,int * status)3617 static double GetLAST( AstSkyFrame *this, int *status ) {
3618 /*
3619 * Name:
3620 * GetLAST
3621
3622 * Purpose:
3623 * Return the Local Apparent Sidereal Time for the SkyFrame.
3624
3625 * Type:
3626 * Private function.
3627
3628 * Synopsis:
3629 * #include "skyframe.h"
3630 * double GetLAST( AstSkyFrame *this, int *status )
3631
3632 * Class Membership:
3633 * SkyFrame member function
3634
3635 * Description:
3636 * This function returns the Local Apparent Sidereal Time (LAST)
3637 * at the moment intime given by the Epoch attribute of the SkyFrame.
3638
3639 * Parameters:
3640 * this
3641 * Pointer to the SkyFrame.
3642 * status
3643 * Pointer to the inherited status variable.
3644
3645 * Returned Value:
3646 * The LAST value.
3647
3648 */
3649
3650 /* Local Variables: */
3651 double dlast; /* Change in LAST */
3652 double epoch; /* Epoch (TDB MJD) */
3653 double last1; /* LAST at end of current interval */
3654 double result; /* Result value to return */
3655 double delta_epoch; /* Change in Epoch */
3656
3657 /* Initialise. */
3658 result = 0;
3659
3660 /* Check the global error status. */
3661 if ( !astOK ) return result;
3662
3663 /* The "last" component of the SkyFrame structure holds the accurate
3664 LAST at the moment in time given by the "eplast" (a TDB MJD) component
3665 of the SkyFrame structure. If the current value of the SkyFrame's
3666 Epoch attribute is not much different to "eplast" (within 0.4 of a day),
3667 then the returned LAST value is the "last" value plus the difference
3668 between Epoch and "eplast", converted from solar to sidereal time,
3669 then converted to radians. This approximation seems to be good to less
3670 than a tenth of an arcsecond. If this approximation cannot be used,
3671 invoke SetLast to recalculate the accurate LAST and update the "eplast"
3672 and "last" values. */
3673 if( this->eplast != AST__BAD ) {
3674 epoch = astGetEpoch( this );
3675 delta_epoch = epoch - this->eplast;
3676
3677 /* Return the current LAST value if the epoch has not changed. */
3678 if( delta_epoch == 0.0 ) {
3679 result = this->last;
3680
3681 /* If the previous full calculation of LAST was less than 0.4 days ago,
3682 use a linear approximation to LAST. */
3683 } else if( fabs( delta_epoch ) < 0.4 ) {
3684
3685 /* If we do not know the ratio of sidereal to solar time at the current
3686 epoch, calculate it now. This involves a full calculation of LAST at
3687 the end of the current linear approximation period. */
3688 if( this->klast == AST__BAD ) {
3689 last1 = CalcLAST( this, this->eplast + 0.4, astGetObsLon( this ),
3690 astGetObsLat( this ), astGetObsAlt( this ),
3691 astGetDut1( this ), status );
3692
3693 /* Ensure the change in LAST is positive so that we get a positive ratio. */
3694 dlast = last1 - this->last;
3695 if( dlast < 0.0 ) dlast += 2*AST__DPI;
3696 this->klast = 2*AST__DPI*0.4/dlast;
3697 }
3698
3699 /* Now use the ratio of solar to sidereal time to calculate the linear
3700 approximation to LAST. */
3701 result = this->last + 2*AST__DPI*delta_epoch/this->klast;
3702
3703 /* If the last accurate calculation of LAST was more than 0.4 days ago,
3704 do a full accurate calculation. */
3705 } else {
3706 SetLast( this, status );
3707 result = this->last;
3708 }
3709
3710 /* If we have not yet done an accurate calculation of LAST, do one now. */
3711 } else {
3712 SetLast( this, status );
3713 result = this->last;
3714 }
3715
3716 /* Return the result, */
3717 return result;
3718 }
3719
GetIsLatAxis(AstSkyFrame * this,int axis,int * status)3720 static int GetIsLatAxis( AstSkyFrame *this, int axis, int *status ) {
3721 /*
3722 * Name:
3723 * GetIsLatAxis
3724
3725 * Purpose:
3726 * Test an axis to see if it is a latitude axis.
3727
3728 * Type:
3729 * Private function.
3730
3731 * Synopsis:
3732 * #include "skyframe.h"
3733 * int GetIsLatAxis( AstSkyFrame *this, int axis, int *status )
3734
3735 * Class Membership:
3736 * SkyFrame member function.
3737
3738 * Description:
3739 * This function tests if a SkyFrame axis is a celestial latitude axis.
3740
3741 * Parameters:
3742 * this
3743 * Pointer to the SkyFrame.
3744 * axis
3745 * Zero based axis index.
3746 * status
3747 * Pointer to the inherited status variable.
3748
3749 * Returned Value:
3750 * One if the supplied axis is a celestial latitude axis, and zero
3751 * otherwise.
3752
3753 * Notes:
3754 * - A value of zero will be returned if this function is invoked with the
3755 * global error status set, or if it should fail for any reason.
3756 */
3757
3758 /* Local Variables: */
3759 int result; /* Result to be returned */
3760
3761 /* Check the global error status. */
3762 if ( !astOK ) return 0;
3763
3764 /* Get the index of the latitude axis and compare to the supplied axis
3765 index. */
3766 result = ( axis == astGetLatAxis( this ) );
3767
3768 /* Return the result. */
3769 return astOK ? result : 0;
3770
3771 }
3772
GetIsLonAxis(AstSkyFrame * this,int axis,int * status)3773 static int GetIsLonAxis( AstSkyFrame *this, int axis, int *status ) {
3774 /*
3775 * Name:
3776 * GetIsLonAxis
3777
3778 * Purpose:
3779 * Test an axis to see if it is a longitude axis.
3780
3781 * Type:
3782 * Private function.
3783
3784 * Synopsis:
3785 * #include "skyframe.h"
3786 * int GetIsLonAxis( AstSkyFrame *this, int axis, int *status )
3787
3788 * Class Membership:
3789 * SkyFrame member function.
3790
3791 * Description:
3792 * This function tests if a SkyFrame axis is a celestial longitude axis.
3793
3794 * Parameters:
3795 * this
3796 * Pointer to the SkyFrame.
3797 * axis
3798 * Zero based axis index.
3799 * status
3800 * Pointer to the inherited status variable.
3801
3802 * Returned Value:
3803 * One if the supplied axis is a celestial longitude axis, and zero
3804 * otherwise.
3805
3806 * Notes:
3807 * - A value of zero will be returned if this function is invoked with the
3808 * global error status set, or if it should fail for any reason.
3809 */
3810
3811 /* Local Variables: */
3812 int result; /* Result to be returned */
3813
3814 /* Check the global error status. */
3815 if ( !astOK ) return 0;
3816
3817 /* Get the index of the longitude axis and compare to the supplied axis
3818 index. */
3819 result = ( axis == astGetLonAxis( this ) );
3820
3821 /* Return the result. */
3822 return astOK ? result : 0;
3823
3824 }
3825
GetLatAxis(AstSkyFrame * this,int * status)3826 static int GetLatAxis( AstSkyFrame *this, int *status ) {
3827 /*
3828 * Name:
3829 * GetLatAxis
3830
3831 * Purpose:
3832 * Obtain the index of the latitude axis of a SkyFrame.
3833
3834 * Type:
3835 * Private function.
3836
3837 * Synopsis:
3838 * #include "skyframe.h"
3839 * int GetLatAxis( AstSkyFrame *this, int *status )
3840
3841 * Class Membership:
3842 * SkyFrame member function.
3843
3844 * Description:
3845 * This function returns the zero-based index of the latitude axis of
3846 * a SkyFrame, taking into account any current axis permutation.
3847
3848 * Parameters:
3849 * this
3850 * Pointer to the SkyFrame.
3851 * status
3852 * Pointer to the inherited status variable.
3853
3854 * Returned Value:
3855 * The zero based axis index (0 or 1) of the latitude axis.
3856
3857 * Notes:
3858 * - A value of one will be returned if this function is invoked with the
3859 * global error status set, or if it should fail for any reason.
3860 */
3861
3862 /* Local Variables: */
3863 int result; /* Result to be returned */
3864 const int *perm; /* Axis permutation array */
3865
3866 /* Check the global error status. */
3867 if ( !astOK ) return 1;
3868
3869 /* Initialise. */
3870 result = 1;
3871
3872 /* Obtain a pointer to the SkyFrame's axis permutation array. */
3873 perm = astGetPerm( this );
3874 if ( astOK ) {
3875
3876 /* Identify the latitude axis. */
3877 if( perm[ 0 ] == 1 ) {
3878 result = 0;
3879 } else {
3880 result = 1;
3881 }
3882
3883 }
3884
3885 /* Return the result. */
3886 return result;
3887
3888 }
3889
GetLonAxis(AstSkyFrame * this,int * status)3890 static int GetLonAxis( AstSkyFrame *this, int *status ) {
3891 /*
3892 * Name:
3893 * GetLonAxis
3894
3895 * Purpose:
3896 * Obtain the index of the longitude axis of a SkyFrame.
3897
3898 * Type:
3899 * Private function.
3900
3901 * Synopsis:
3902 * #include "skyframe.h"
3903 * int GetLonAxis( AstSkyFrame *this, int *status )
3904
3905 * Class Membership:
3906 * SkyFrame member function.
3907
3908 * Description:
3909 * This function returns the zero-based index of the longitude axis of
3910 * a SkyFrame, taking into account any current axis permutation.
3911
3912 * Parameters:
3913 * this
3914 * Pointer to the SkyFrame.
3915 * status
3916 * Pointer to the inherited status variable.
3917
3918 * Returned Value:
3919 * The zero based axis index (0 or 1) of the longitude axis.
3920
3921 * Notes:
3922 * - A value of zero will be returned if this function is invoked with the
3923 * global error status set, or if it should fail for any reason.
3924 */
3925
3926 /* Local Variables: */
3927 int result; /* Result to be returned */
3928 const int *perm; /* Axis permutation array */
3929
3930 /* Check the global error status. */
3931 if ( !astOK ) return 0;
3932
3933 /* Initialise. */
3934 result = 0;
3935
3936 /* Obtain a pointer to the SkyFrame's axis permutation array. */
3937 perm = astGetPerm( this );
3938 if ( astOK ) {
3939
3940 /* Identify the longitude axis. */
3941 if( perm[ 0 ] == 0 ) {
3942 result = 0;
3943 } else {
3944 result = 1;
3945 }
3946
3947 }
3948
3949 /* Return the result. */
3950 return result;
3951
3952 }
3953
GetSkyRefP(AstSkyFrame * this,int axis,int * status)3954 static double GetSkyRefP( AstSkyFrame *this, int axis, int *status ) {
3955 /*
3956 * Name:
3957 * GetSkyRefP
3958
3959 * Purpose:
3960 * Obtain the value of the SkyRefP attribute for a SkyFrame axis.
3961
3962 * Type:
3963 * Private function.
3964
3965 * Synopsis:
3966 * #include "skyframe.h"
3967 * double GetSkyRefP( AstSkyFrame *this, int axis, int *status )
3968
3969 * Class Membership:
3970 * SkyFrame member function.
3971
3972 * Description:
3973 * This function returns the value of the SkyRefP attribute for a
3974 * SkyFrame axis, providing suitable defaults.
3975
3976 * Parameters:
3977 * this
3978 * Pointer to the SkyFrame.
3979 * axis
3980 * Axis index (zero-based) identifying the axis for which information is
3981 * required.
3982 * status
3983 * Pointer to the inherited status variable.
3984
3985 * Returned Value:
3986 * The SkyRefP value to be used.
3987
3988 * Notes:
3989 * - A value of zero will be returned if this function is invoked with the
3990 * global error status set, or if it should fail for any reason.
3991 */
3992
3993 /* Local Variables: */
3994 double result; /* Returned value */
3995 int axis_p; /* Permuted axis index */
3996
3997 /* Initialise. */
3998 result = 0.0;
3999
4000 /* Check the global error status. */
4001 if ( !astOK ) return result;
4002
4003 /* Validate and permute the axis index. */
4004 axis_p = astValidateAxis( this, axis, 1, "astGetSkyRefP" );
4005
4006 /* Check if a value has been set for the required axis. If so, return it. */
4007 if( this->skyrefp[ axis_p ] != AST__BAD ) {
4008 result = this->skyrefp[ axis_p ];
4009
4010 /* Otherwise, return the default value */
4011 } else {
4012
4013 /* The default longitude value is always zero. */
4014 if( axis_p == 0 ) {
4015 result= 0.0;
4016
4017 /* The default latitude value depends on SkyRef. The usual default is the
4018 north pole. The exception to this is if the SkyRef attribute identifies
4019 either the north or the south pole, in which case the origin is used as
4020 the default. Allow some tolerance. */
4021 } else if( fabs( cos( this->skyref[ 1 ] ) ) > 1.0E-10 ) {
4022 result = pi/2;
4023
4024 } else {
4025 result = 0.0;
4026 }
4027 }
4028
4029 /* Return the result. */
4030 return result;
4031 }
4032
GetSymbol(AstFrame * this,int axis,int * status)4033 static const char *GetSymbol( AstFrame *this, int axis, int *status ) {
4034 /*
4035 * Name:
4036 * GetSymbol
4037
4038 * Purpose:
4039 * Obtain a pointer to the Symbol string for a SkyFrame axis.
4040
4041 * Type:
4042 * Private function.
4043
4044 * Synopsis:
4045 * #include "skyframe.h"
4046 * const char *GetSymbol( AstFrame *this, int axis, int *status )
4047
4048 * Class Membership:
4049 * SkyFrame member function (over-rides the astGetSymbol method inherited
4050 * from the Frame class).
4051
4052 * Description:
4053 * This function returns a pointer to the Symbol string for a specified axis
4054 * of a SkyFrame.
4055
4056 * Parameters:
4057 * this
4058 * Pointer to the SkyFrame.
4059 * axis
4060 * Axis index (zero-based) identifying the axis for which information is
4061 * required.
4062 * status
4063 * Pointer to the inherited status variable.
4064
4065 * Returned Value:
4066 * Pointer to a constant null-terminated character string containing the
4067 * requested information.
4068
4069 * Notes:
4070 * - A NULL pointer will be returned if this function is invoked with the
4071 * global error status set, or if it should fail for any reason.
4072 */
4073
4074 /* Local Variables: */
4075 astDECLARE_GLOBALS /* Declare the thread specific global data */
4076 AstSystemType system; /* Code identifying type of sky coordinates */
4077 const char *result; /* Pointer to symbol string */
4078 int axis_p; /* Permuted axis index */
4079
4080 /* Check the global error status. */
4081 if ( !astOK ) return NULL;
4082
4083 /* Get a pointer to the structure holding thread-specific global data. */
4084 astGET_GLOBALS(this);
4085
4086 /* Initialise. */
4087 result = NULL;
4088
4089 /* Validate and permute the axis index. */
4090 axis_p = astValidateAxis( this, axis, 1, "astGetSymbol" );
4091
4092 /* Check if a value has been set for the required axis symbol string. If so,
4093 invoke the parent astGetSymbol method to obtain a pointer to it. */
4094 if ( astTestSymbol( this, axis ) ) {
4095 result = (*parent_getsymbol)( this, axis, status );
4096
4097 /* Otherwise, identify the sky coordinate system described by the SkyFrame. */
4098 } else {
4099 system = astGetSystem( this );
4100
4101 /* If OK, supply a pointer to a suitable default Symbol string. */
4102 if ( astOK ) {
4103
4104 /* Equatorial coordinate systems. */
4105 if ( IsEquatorial( system, status ) ) {
4106 result = ( axis_p == 0 ) ? "RA" : "Dec";
4107
4108 /* Ecliptic coordinates. */
4109 } else if ( system == AST__ECLIPTIC ) {
4110 result = ( axis_p == 0 ) ? "Lambda" : "Beta";
4111
4112 /* Helio-ecliptic coordinates. */
4113 } else if ( system == AST__HELIOECLIPTIC ) {
4114 result = ( axis_p == 0 ) ? "Lambda" : "Beta";
4115
4116 /* AzEl coordinates. */
4117 } else if ( system == AST__AZEL ) {
4118 result = ( axis_p == 0 ) ? "Az" : "El";
4119
4120 /* Galactic coordinates. */
4121 } else if ( system == AST__GALACTIC ) {
4122 result = ( axis_p == 0 ) ? "l" : "b";
4123
4124 /* Supergalactic coordinates. */
4125 } else if ( system == AST__SUPERGALACTIC ) {
4126 result = ( axis_p == 0 ) ? "SGL" : "SGB";
4127
4128 /* Unknown spherical coordinates. */
4129 } else if ( system == AST__UNKNOWN ) {
4130 result = ( axis_p == 0 ) ? "Lon" : "Lat";
4131
4132 /* Report an error if the coordinate system was not recognised. */
4133 } else {
4134 astError( AST__SCSIN, "astGetSymbol(%s): Corrupt %s contains "
4135 "invalid sky coordinate system identification code "
4136 "(%d).", status, astGetClass( this ), astGetClass( this ),
4137 (int) system );
4138 }
4139
4140 /* If the SkyRef attribute had a set value, prepend "D" (for "delta") to the
4141 Symbol. */
4142 if( astGetSkyRefIs( this ) != AST__IGNORED_REF &&
4143 ( astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ) ) ) {
4144 sprintf( getsymbol_buff, "D%s", result );
4145 result = getsymbol_buff;
4146 }
4147 }
4148 }
4149
4150 /* Return the result. */
4151 return result;
4152 }
4153
GetAlignSystem(AstFrame * this_frame,int * status)4154 static AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) {
4155 /*
4156 * Name:
4157 * GetAlignSystem
4158
4159 * Purpose:
4160 * Obtain the AlignSystem attribute for a SkyFrame.
4161
4162 * Type:
4163 * Private function.
4164
4165 * Synopsis:
4166 * #include "skyframe.h"
4167 * AstSystemType GetAlignSystem( AstFrame *this_frame, int *status )
4168
4169 * Class Membership:
4170 * SkyFrame member function (over-rides the astGetAlignSystem protected
4171 * method inherited from the Frame class).
4172
4173 * Description:
4174 * This function returns the AlignSystem attribute for a SkyFrame.
4175
4176 * Parameters:
4177 * this
4178 * Pointer to the SkyFrame.
4179 * status
4180 * Pointer to the inherited status variable.
4181
4182 * Returned Value:
4183 * The AlignSystem value.
4184
4185 */
4186
4187 /* Local Variables: */
4188 AstSkyFrame *this; /* Pointer to SkyFrame structure */
4189 AstSystemType result; /* Value to return */
4190
4191 /* Initialise. */
4192 result = AST__BADSYSTEM;
4193
4194 /* Check the global error status. */
4195 if ( !astOK ) return result;
4196
4197 /* Obtain a pointer to the SkyFrame structure. */
4198 this = (AstSkyFrame *) this_frame;
4199
4200 /* If a AlignSystem attribute has been set, invoke the parent method to obtain
4201 it. */
4202 if ( astTestAlignSystem( this ) ) {
4203 result = (*parent_getalignsystem)( this_frame, status );
4204
4205 /* Otherwise, provide a suitable default. */
4206 } else {
4207 result = AST__ICRS;
4208 }
4209
4210 /* Return the result. */
4211 return result;
4212 }
4213
GetSystem(AstFrame * this_frame,int * status)4214 static AstSystemType GetSystem( AstFrame *this_frame, int *status ) {
4215 /*
4216 * Name:
4217 * GetSystem
4218
4219 * Purpose:
4220 * Obtain the System attribute for a SkyFrame.
4221
4222 * Type:
4223 * Private function.
4224
4225 * Synopsis:
4226 * #include "skyframe.h"
4227 * AstSystemType GetSystem( AstFrame *this_frame, int *status )
4228
4229 * Class Membership:
4230 * SkyFrame member function (over-rides the astGetSystem protected
4231 * method inherited from the Frame class).
4232
4233 * Description:
4234 * This function returns the System attribute for a SkyFrame.
4235
4236 * Parameters:
4237 * this
4238 * Pointer to the SkyFrame.
4239 * status
4240 * Pointer to the inherited status variable.
4241
4242 * Returned Value:
4243 * The System value.
4244
4245 * Notes:
4246 * - AST__BADSYSTEM is returned if this function is invoked with
4247 * the global error status set or if it should fail for any reason.
4248 */
4249
4250 /* Local Variables: */
4251 AstSkyFrame *this; /* Pointer to SkyFrame structure */
4252 AstSystemType result; /* Value to return */
4253
4254 /* Initialise. */
4255 result = AST__BADSYSTEM;
4256
4257 /* Check the global error status. */
4258 if ( !astOK ) return result;
4259
4260 /* Obtain a pointer to the SkyFrame structure. */
4261 this = (AstSkyFrame *) this_frame;
4262
4263 /* If a System attribute has been set, invoke the parent method to obtain
4264 it. */
4265 if ( astTestSystem( this ) ) {
4266 result = (*parent_getsystem)( this_frame, status );
4267
4268 /* Otherwise, provide a suitable default. */
4269 } else {
4270 result = AST__ICRS;
4271 }
4272
4273 /* Return the result. */
4274 return result;
4275 }
4276
GetTitle(AstFrame * this_frame,int * status)4277 static const char *GetTitle( AstFrame *this_frame, int *status ) {
4278 /*
4279 * Name:
4280 * GetTitle
4281
4282 * Purpose:
4283 * Obtain a pointer to the Title string for a SkyFrame.
4284
4285 * Type:
4286 * Private function.
4287
4288 * Synopsis:
4289 * #include "skyframe.h"
4290 * const char *GetTitle( AstFrame *this_frame, int *status )
4291
4292 * Class Membership:
4293 * SkyFrame member function (over-rides the astGetTitle method inherited
4294 * from the Frame class).
4295
4296 * Description:
4297 * This function returns a pointer to the Title string for a SkyFrame.
4298 * A pointer to a suitable default string is returned if no Title value has
4299 * previously been set.
4300
4301 * Parameters:
4302 * this
4303 * Pointer to the SkyFrame.
4304 * status
4305 * Pointer to the inherited status variable.
4306
4307 * Returned Value:
4308 * Pointer to a null-terminated character string containing the requested
4309 * information.
4310
4311 * Notes:
4312 * - A NULL pointer will be returned if this function is invoked with the
4313 * global error status set, or if it should fail for any reason.
4314 */
4315
4316 /* Local Variables: */
4317 astDECLARE_GLOBALS /* Declare the thread specific global data */
4318 AstSkyFrame *this; /* Pointer to SkyFrame structure */
4319 AstSystemType system; /* Code identifying type of sky coordinates */
4320 const char *extra; /* Pointer to extra information */
4321 const char *p; /* Character pointer */
4322 const char *projection; /* Pointer to sky projection description */
4323 const char *result; /* Pointer to result string */
4324 const char *word; /* Pointer to critical word */
4325 double epoch; /* Value of Epoch attribute */
4326 double equinox; /* Value of Equinox attribute */
4327 int lextra; /* Length of extra information */
4328 int offset; /* Using offset coordinate system? */
4329 int pos; /* Buffer position to enter text */
4330
4331 /* Check the global error status. */
4332 if ( !astOK ) return NULL;
4333
4334 /* Get a pointer to the structure holding thread-specific global data. */
4335 astGET_GLOBALS(this_frame);
4336
4337 /* Initialise. */
4338 result = NULL;
4339 pos = 0;
4340
4341 /* Obtain a pointer to the SkyFrame structure. */
4342 this = (AstSkyFrame *) this_frame;
4343
4344 /* See if a Title string has been set. If so, use the parent astGetTitle
4345 method to obtain a pointer to it. */
4346 if ( astTestTitle( this ) ) {
4347 result = (*parent_gettitle)( this_frame, status );
4348
4349 /* Otherwise, we will generate a default Title string. Obtain the values of the
4350 SkyFrame's attributes that determine what this string will be. */
4351 } else {
4352 epoch = astGetEpoch( this );
4353 equinox = astGetEquinox( this );
4354 projection = astGetProjection( this );
4355 system = astGetSystem( this );
4356
4357 /* See if an offset coordinate system is being used.*/
4358 offset = ( astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ) )
4359 && ( astGetSkyRefIs( this ) != AST__IGNORED_REF );
4360
4361 /* Use this to determine if the word "coordinates" or "offsets" should be
4362 used.*/
4363 word = offset ? "offsets" : "coordinates";
4364
4365 /* Classify the coordinate system type and create an appropriate Title
4366 string. (Note that when invoking the astFmtDecimalYr function we must
4367 use a separate sprintf on each occasion so as not to over-write its
4368 internal buffer before the result string has been used.) */
4369 if ( astOK ) {
4370 result = gettitle_buff;
4371 switch ( system ) {
4372
4373 /* FK4 equatorial coordinates. */
4374 /* --------------------------- */
4375 /* Display the Equinox and Epoch values. */
4376 case AST__FK4:
4377 pos = sprintf( gettitle_buff, "FK4 equatorial %s", word );
4378 if( astTestEquinox( this ) || astGetUseDefs( this ) ) {
4379 pos += sprintf( gettitle_buff + pos, "; mean equinox B%s",
4380 astFmtDecimalYr( palEpb( equinox ), 9 ) );
4381 }
4382 if( astTestEpoch( this ) || astGetUseDefs( this ) ) {
4383 pos += sprintf( gettitle_buff + pos,
4384 "; epoch B%s", astFmtDecimalYr( palEpb( epoch ), 9 ) );
4385 }
4386 break;
4387
4388 /* FK4 coordinates with no E-terms of aberration. */
4389 /* ---------------------------------------------- */
4390 /* Display the Equinox and Epoch values. */
4391 case AST__FK4_NO_E:
4392 pos = sprintf( gettitle_buff, "FK4 equatorial %s; no E-terms", word );
4393 if( astTestEquinox( this ) || astGetUseDefs( this ) ) {
4394 pos += sprintf( gettitle_buff + pos, "; mean equinox B%s",
4395 astFmtDecimalYr( palEpb( equinox ), 9 ) );
4396 }
4397 if( astTestEpoch( this ) || astGetUseDefs( this ) ) {
4398 pos += sprintf( gettitle_buff + pos,
4399 "; epoch B%s", astFmtDecimalYr( palEpb( epoch ), 9 ) );
4400 }
4401 break;
4402
4403 /* FK5 equatorial coordinates. */
4404 /* --------------------------- */
4405 /* Display only the Equinox value. */
4406 case AST__FK5:
4407 pos = sprintf( gettitle_buff, "FK5 equatorial %s", word );
4408 if( astTestEquinox( this ) || astGetUseDefs( this ) ) {
4409 pos += sprintf( gettitle_buff + pos, "; mean equinox J%s",
4410 astFmtDecimalYr( palEpj( equinox ), 9 ) );
4411 }
4412 break;
4413
4414 /* J2000 equatorial coordinates. */
4415 /* ----------------------------- */
4416 /* Based on the dynamically determined mean equator and equinox of J2000,
4417 rather than on a model such as FK4 or FK5 */
4418 case AST__J2000:
4419 pos = sprintf( gettitle_buff, "J2000 equatorial %s", word );
4420 break;
4421
4422 /* ICRS coordinates. */
4423 /* ----------------- */
4424 /* ICRS is only like RA/Dec by co-incidence, it is not really an
4425 equatorial system by definition. */
4426 case AST__ICRS:
4427 pos = sprintf( gettitle_buff, "ICRS %s", word );
4428 break;
4429
4430 /* AzEl coordinates. */
4431 /* ----------------- */
4432 case AST__AZEL:
4433 pos = sprintf( gettitle_buff, "Horizon (Azimuth/Elevation) %s", word );
4434 break;
4435
4436 /* Geocentric apparent equatorial coordinates. */
4437 /* ------------------------------------------ */
4438 /* Display only the Epoch value. */
4439 case AST__GAPPT:
4440 pos = sprintf( gettitle_buff,
4441 "Geocentric apparent equatorial %s; "
4442 "; epoch J%s", word, astFmtDecimalYr( palEpj( epoch ), 9 ) );
4443 break;
4444
4445 /* Ecliptic coordinates. */
4446 /* --------------------- */
4447 /* Display only the Equinox value. */
4448 case AST__ECLIPTIC:
4449 pos = sprintf( gettitle_buff, "Ecliptic %s", word );
4450 if( astTestEquinox( this ) || astGetUseDefs( this ) ) {
4451 pos += sprintf( gettitle_buff + pos, "; mean equinox J%s",
4452 astFmtDecimalYr( palEpj( equinox ), 9 ) );
4453 }
4454 break;
4455
4456 /* Helio-ecliptic coordinates. */
4457 /* --------------------------- */
4458 /* Display only the Epoch value (equinox is fixed). */
4459 case AST__HELIOECLIPTIC:
4460 pos = sprintf( gettitle_buff, "Helio-ecliptic %s; mean equinox J2000", word );
4461 if( astTestEpoch( this ) || astGetUseDefs( this ) ) {
4462 pos += sprintf( gettitle_buff + pos, "; epoch J%s",
4463 astFmtDecimalYr( palEpj( epoch ), 9 ) );
4464 }
4465 break;
4466
4467 /* Galactic coordinates. */
4468 /* --------------------- */
4469 /* Do not display an Equinox or Epoch value. */
4470 case AST__GALACTIC:
4471 pos = sprintf( gettitle_buff, "IAU (1958) galactic %s", word );
4472 break;
4473
4474 /* Supergalactic coordinates. */
4475 /* -------------------------- */
4476 /* Do not display an Equinox or Epoch value. */
4477 case AST__SUPERGALACTIC:
4478 pos = sprintf( gettitle_buff,
4479 "De Vaucouleurs supergalactic %s", word );
4480 break;
4481
4482 /* Unknown coordinates. */
4483 /* -------------------------- */
4484 case AST__UNKNOWN:
4485 pos = sprintf( gettitle_buff,
4486 "Spherical %s", word );
4487 break;
4488
4489 /* Report an error if the coordinate system was not recognised. */
4490 default:
4491 astError( AST__SCSIN, "astGetTitle(%s): Corrupt %s contains "
4492 "invalid sky coordinate system identification code "
4493 "(%d).", status, astGetClass( this ), astGetClass( this ),
4494 (int) system );
4495 break;
4496 }
4497
4498 /* If OK, we add either a description of the sky projection, or (if used)
4499 a description of the origin or pole of the offset coordinate system.
4500 We include only one of these two strings in order to keep the length
4501 of the title down to a reasonable value.*/
4502 if ( astOK ) {
4503
4504 /* If the SkyRef attribute has set values, create a description of the offset
4505 coordinate system. */
4506 if( offset ){
4507 word = ( astGetSkyRefIs( this ) == AST__POLE_REF )?"pole":"origin";
4508 lextra = sprintf( gettitle_buff2, "%s at %s ", word,
4509 astFormat( this, 0, astGetSkyRef( this, 0 ) ) );
4510 lextra += sprintf( gettitle_buff2 + lextra, "%s",
4511 astFormat( this, 1, astGetSkyRef( this, 1 ) ) );
4512 extra = gettitle_buff2;
4513
4514 /* Otherwise, get the sky projection description. */
4515 } else {
4516 extra = projection;
4517
4518 /* Determine the length of the extra information, after removing trailing
4519 white space. */
4520 for ( lextra = (int) strlen( extra ); lextra > 0; lextra-- ) {
4521 if ( !isspace( extra[ lextra - 1 ] ) ) break;
4522 }
4523 }
4524
4525 /* If non-blank extra information is available, append it to the title string,
4526 checking that the end of the buffer is not over-run. */
4527 if ( lextra ) {
4528 p = "; ";
4529 while ( ( pos < AST__SKYFRAME_GETTITLE_BUFF_LEN ) && *p ) gettitle_buff[ pos++ ] = *p++;
4530 p = extra;
4531 while ( ( pos < AST__SKYFRAME_GETTITLE_BUFF_LEN ) &&
4532 ( p < ( extra + lextra ) ) ) gettitle_buff[ pos++ ] = *p++;
4533 if( extra == projection ) {
4534 p = " projection";
4535 while ( ( pos < AST__SKYFRAME_GETTITLE_BUFF_LEN ) && *p ) gettitle_buff[ pos++ ] = *p++;
4536 }
4537 gettitle_buff[ pos ] = '\0';
4538 }
4539 }
4540 }
4541 }
4542
4543 /* If an error occurred, clear the returned pointer value. */
4544 if ( !astOK ) result = NULL;
4545
4546 /* Return the result. */
4547 return result;
4548 }
4549
GetUnit(AstFrame * this_frame,int axis,int * status)4550 static const char *GetUnit( AstFrame *this_frame, int axis, int *status ) {
4551 /*
4552 * Name:
4553 * GetUnit
4554
4555 * Purpose:
4556 * Obtain a pointer to the Unit string for a SkyFrame's axis.
4557
4558 * Type:
4559 * Private function.
4560
4561 * Synopsis:
4562 * #include "skyframe.h"
4563 * const char *GetUnit( AstFrame *this_frame, int axis )
4564
4565 * Class Membership:
4566 * SkyFrame member function (over-rides the astGetUnit method inherited
4567 * from the Frame class).
4568
4569 * Description:
4570 * This function returns a pointer to the Unit string for a specified axis
4571 * of a SkyFrame. If the Unit attribute has not been set for the axis, a
4572 * pointer to a suitable default string is returned instead. This string may
4573 * depend on the value of the Format attribute for the axis and, in turn, on
4574 * the type of sky coordinate system that the SkyFrame describes.
4575
4576 * Parameters:
4577 * this
4578 * Pointer to the SkyFrame.
4579 * axis
4580 * The number of the axis (zero-based) for which information is required.
4581
4582 * Returned Value:
4583 * A pointer to a null-terminated string containing the Unit value.
4584
4585 * Notes:
4586 * - A NULL pointer will be returned if this function is invoked with the
4587 * global error status set, or if it should fail for any reason.
4588 */
4589
4590 /* Local Variables: */
4591 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
4592 const char *result; /* Pointer value to return */
4593 int format_set; /* Format attribute set? */
4594
4595 /* Check the global error status. */
4596 if ( !astOK ) return NULL;
4597
4598 /* Obtain a pointer to the SkyFrame structure. */
4599 this = (AstSkyFrame *) this_frame;
4600
4601 /* Validate the axis index. */
4602 (void) astValidateAxis( this, axis, 1, "astGetUnit" );
4603
4604 /* The Unit value may depend on the value of the Format attribute, so
4605 determine if a Format value has been set for the axis and set a
4606 temporary value if it has not. Use the GetFormat member function
4607 for this class together with member functions inherited from the
4608 parent class (rather than using the object's methods directly)
4609 because if any of these methods have been over-ridden by a derived
4610 class the Format string syntax may no longer be compatible with
4611 this class. */
4612 format_set = (*parent_testformat)( this_frame, axis, status );
4613 if ( !format_set ) {
4614 (*parent_setformat)( this_frame, axis, GetFormat( this_frame, axis, status ), status );
4615 }
4616
4617 /* Use the parent GetUnit method to return a pointer to the required Unit
4618 string. */
4619 result = (*parent_getunit)( this_frame, axis, status );
4620
4621 /* If necessary, clear any temporary Format value that was set above. */
4622 if ( !format_set ) (*parent_clearformat)( this_frame, axis, status );
4623
4624 /* If an error occurred, clear the returned value. */
4625 if ( !astOK ) result = NULL;
4626
4627 /* Return the result. */
4628 return result;
4629 }
4630
astInitSkyFrameVtab_(AstSkyFrameVtab * vtab,const char * name,int * status)4631 void astInitSkyFrameVtab_( AstSkyFrameVtab *vtab, const char *name, int *status ) {
4632 /*
4633 *+
4634 * Name:
4635 * astInitSkyFrameVtab
4636
4637 * Purpose:
4638 * Initialise a virtual function table for a SkyFrame.
4639
4640 * Type:
4641 * Protected function.
4642
4643 * Synopsis:
4644 * #include "skyframe.h"
4645 * void astInitSkyFrameVtab( AstSkyFrameVtab *vtab, const char *name )
4646
4647 * Class Membership:
4648 * SkyFrame vtab initialiser.
4649
4650 * Description:
4651 * This function initialises the component of a virtual function
4652 * table which is used by the SkyFrame class.
4653
4654 * Parameters:
4655 * vtab
4656 * Pointer to the virtual function table. The components used by
4657 * all ancestral classes will be initialised if they have not already
4658 * been initialised.
4659 * name
4660 * Pointer to a constant null-terminated character string which contains
4661 * the name of the class to which the virtual function table belongs (it
4662 * is this pointer value that will subsequently be returned by the Object
4663 * astClass function).
4664 *-
4665 */
4666
4667 /* Local Variables: */
4668 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
4669 AstFrameVtab *frame; /* Pointer to Frame component of Vtab */
4670 AstObjectVtab *object; /* Pointer to Object component of Vtab */
4671 int stat; /* SLALIB status */
4672
4673 /* Check the local error status. */
4674 if ( !astOK ) return;
4675
4676 /* Get a pointer to the thread specific global data structure. */
4677 astGET_GLOBALS(NULL);
4678
4679 /* Initialize the component of the virtual function table used by the
4680 parent class. */
4681 astInitFrameVtab( (AstFrameVtab *) vtab, name );
4682
4683 /* Store a unique "magic" value in the virtual function table. This
4684 will be used (by astIsASkyFrame) to determine if an object belongs
4685 to this class. We can conveniently use the address of the (static)
4686 class_check variable to generate this unique value. */
4687 vtab->id.check = &class_check;
4688 vtab->id.parent = &(((AstFrameVtab *) vtab)->id);
4689
4690 /* Initialise member function pointers. */
4691 /* ------------------------------------ */
4692 /* Store pointers to the member functions (implemented here) that
4693 provide virtual methods for this class. */
4694 vtab->ClearAsTime = ClearAsTime;
4695 vtab->ClearEquinox = ClearEquinox;
4696 vtab->ClearNegLon = ClearNegLon;
4697 vtab->ClearProjection = ClearProjection;
4698 vtab->GetAsTime = GetAsTime;
4699 vtab->GetEquinox = GetEquinox;
4700 vtab->GetNegLon = GetNegLon;
4701 vtab->GetIsLatAxis = GetIsLatAxis;
4702 vtab->GetIsLonAxis = GetIsLonAxis;
4703 vtab->GetLatAxis = GetLatAxis;
4704 vtab->GetLonAxis = GetLonAxis;
4705 vtab->GetProjection = GetProjection;
4706 vtab->SetAsTime = SetAsTime;
4707 vtab->SetEquinox = SetEquinox;
4708 vtab->SetNegLon = SetNegLon;
4709 vtab->SetProjection = SetProjection;
4710 vtab->SkyOffsetMap = SkyOffsetMap;
4711 vtab->TestAsTime = TestAsTime;
4712 vtab->TestEquinox = TestEquinox;
4713 vtab->TestNegLon = TestNegLon;
4714 vtab->TestProjection = TestProjection;
4715
4716 vtab->TestSkyRef = TestSkyRef;
4717 vtab->SetSkyRef = SetSkyRef;
4718 vtab->GetSkyRef = GetSkyRef;
4719 vtab->ClearSkyRef = ClearSkyRef;
4720
4721 vtab->TestSkyRefP = TestSkyRefP;
4722 vtab->SetSkyRefP = SetSkyRefP;
4723 vtab->GetSkyRefP = GetSkyRefP;
4724 vtab->ClearSkyRefP = ClearSkyRefP;
4725
4726 vtab->TestSkyRefIs = TestSkyRefIs;
4727 vtab->SetSkyRefIs = SetSkyRefIs;
4728 vtab->GetSkyRefIs = GetSkyRefIs;
4729 vtab->ClearSkyRefIs = ClearSkyRefIs;
4730
4731 vtab->TestAlignOffset = TestAlignOffset;
4732 vtab->SetAlignOffset = SetAlignOffset;
4733 vtab->GetAlignOffset = GetAlignOffset;
4734 vtab->ClearAlignOffset = ClearAlignOffset;
4735
4736 /* Save the inherited pointers to methods that will be extended, and
4737 replace them with pointers to the new member functions. */
4738 object = (AstObjectVtab *) vtab;
4739 frame = (AstFrameVtab *) vtab;
4740 parent_getobjsize = object->GetObjSize;
4741 object->GetObjSize = GetObjSize;
4742
4743 parent_clearattrib = object->ClearAttrib;
4744 object->ClearAttrib = ClearAttrib;
4745 parent_getattrib = object->GetAttrib;
4746 object->GetAttrib = GetAttrib;
4747 parent_setattrib = object->SetAttrib;
4748 object->SetAttrib = SetAttrib;
4749 parent_testattrib = object->TestAttrib;
4750 object->TestAttrib = TestAttrib;
4751
4752 parent_gettop = frame->GetTop;
4753 frame->GetTop = GetTop;
4754
4755 parent_setobsalt = frame->SetObsAlt;
4756 frame->SetObsAlt = SetObsAlt;
4757
4758 parent_setobslat = frame->SetObsLat;
4759 frame->SetObsLat = SetObsLat;
4760
4761 parent_setobslon = frame->SetObsLon;
4762 frame->SetObsLon = SetObsLon;
4763
4764 parent_clearobslon = frame->ClearObsLon;
4765 frame->ClearObsLon = ClearObsLon;
4766
4767 parent_clearobsalt = frame->ClearObsAlt;
4768 frame->ClearObsAlt = ClearObsAlt;
4769
4770 parent_clearobslat = frame->ClearObsLat;
4771 frame->ClearObsLat = ClearObsLat;
4772
4773 parent_getbottom = frame->GetBottom;
4774 frame->GetBottom = GetBottom;
4775
4776 parent_getepoch = frame->GetEpoch;
4777 frame->GetEpoch = GetEpoch;
4778
4779 parent_format = frame->Format;
4780 frame->Format = Format;
4781 parent_gap = frame->Gap;
4782 frame->Gap = Gap;
4783 parent_getdirection = frame->GetDirection;
4784 frame->GetDirection = GetDirection;
4785 parent_getdomain = frame->GetDomain;
4786 frame->GetDomain = GetDomain;
4787 parent_getsystem = frame->GetSystem;
4788 frame->GetSystem = GetSystem;
4789 parent_setsystem = frame->SetSystem;
4790 frame->SetSystem = SetSystem;
4791 parent_clearsystem = frame->ClearSystem;
4792 frame->ClearSystem = ClearSystem;
4793 parent_getalignsystem = frame->GetAlignSystem;
4794 frame->GetAlignSystem = GetAlignSystem;
4795 parent_getformat = frame->GetFormat;
4796 frame->GetFormat = GetFormat;
4797 parent_getlabel = frame->GetLabel;
4798 frame->GetLabel = GetLabel;
4799 parent_getsymbol = frame->GetSymbol;
4800 frame->GetSymbol = GetSymbol;
4801 parent_gettitle = frame->GetTitle;
4802 frame->GetTitle = GetTitle;
4803 parent_getunit = frame->GetUnit;
4804 frame->GetUnit = GetUnit;
4805 parent_match = frame->Match;
4806 frame->Match = Match;
4807 parent_overlay = frame->Overlay;
4808 frame->Overlay = Overlay;
4809 parent_subframe = frame->SubFrame;
4810 frame->SubFrame = SubFrame;
4811 parent_unformat = frame->Unformat;
4812 frame->Unformat = Unformat;
4813
4814 parent_setdut1 = frame->SetDut1;
4815 frame->SetDut1 = SetDut1;
4816
4817 parent_cleardut1 = frame->ClearDut1;
4818 frame->ClearDut1 = ClearDut1;
4819
4820 /* Store replacement pointers for methods which will be over-ridden by new
4821 member functions implemented here. */
4822 frame->Angle = Angle;
4823 frame->Distance = Distance;
4824 frame->FrameGrid = FrameGrid;
4825 frame->Intersect = Intersect;
4826 frame->Norm = Norm;
4827 frame->NormBox = NormBox;
4828 frame->Resolve = Resolve;
4829 frame->ResolvePoints = ResolvePoints;
4830 frame->Offset = Offset;
4831 frame->Offset2 = Offset2;
4832 frame->ValidateSystem = ValidateSystem;
4833 frame->SystemString = SystemString;
4834 frame->SystemCode = SystemCode;
4835 frame->LineDef = LineDef;
4836 frame->LineContains = LineContains;
4837 frame->LineCrossing = LineCrossing;
4838 frame->LineOffset = LineOffset;
4839 frame->GetActiveUnit = GetActiveUnit;
4840 frame->TestActiveUnit = TestActiveUnit;
4841 frame->MatchAxesX = MatchAxesX;
4842
4843 /* Store pointers to inherited methods that will be invoked explicitly
4844 by this class. */
4845 parent_clearformat = frame->ClearFormat;
4846 parent_setformat = frame->SetFormat;
4847 parent_testformat = frame->TestFormat;
4848
4849 /* Declare the copy constructor, destructor and class dump
4850 function. */
4851 astSetCopy( vtab, Copy );
4852 astSetDelete( vtab, Delete );
4853 astSetDump( vtab, Dump, "SkyFrame",
4854 "Description of celestial coordinate system" );
4855
4856 /* Initialize constants for converting between hours, degrees and
4857 radians, etc.. */
4858 LOCK_MUTEX2
4859 palDtf2r( 1, 0, 0.0, &hr2rad, &stat );
4860 palDaf2r( 1, 0, 0.0, °2rad, &stat );
4861 palDaf2r( 180, 0, 0.0, &pi, &stat );
4862 piby2 = 0.5*pi;
4863 UNLOCK_MUTEX2
4864
4865 /* If we have just initialised the vtab for the current class, indicate
4866 that the vtab is now initialised, and store a pointer to the class
4867 identifier in the base "object" level of the vtab. */
4868 if( vtab == &class_vtab ) {
4869 class_init = 1;
4870 astSetVtabClassIdentifier( vtab, &(vtab->id) );
4871 }
4872 }
4873
Intersect(AstFrame * this_frame,const double a1[2],const double a2[2],const double b1[2],const double b2[2],double cross[2],int * status)4874 static void Intersect( AstFrame *this_frame, const double a1[2],
4875 const double a2[2], const double b1[2],
4876 const double b2[2], double cross[2],
4877 int *status ) {
4878 /*
4879 * Name:
4880 * Intersect
4881
4882 * Purpose:
4883 * Find the point of intersection between two geodesic curves.
4884
4885 * Type:
4886 * Private function.
4887
4888 * Synopsis:
4889 * #include "skyframe.h"
4890 * void Intersect( AstFrame *this_frame, const double a1[2],
4891 * const double a2[2], const double b1[2],
4892 * const double b2[2], double cross[2],
4893 * int *status )
4894
4895 * Class Membership:
4896 * SkyFrame member function (over-rides the astIntersect method
4897 * inherited from the Frame class).
4898
4899 * Description:
4900 * This function finds the coordinate values at the point of
4901 * intersection between two geodesic curves. Each curve is specified
4902 * by two points on the curve.
4903
4904 * Parameters:
4905 * this
4906 * Pointer to the SkyFrame.
4907 * a1
4908 * An array of double, with one element for each Frame axis.
4909 * This should contain the coordinates of a point on the first
4910 * geodesic curve.
4911 * a2
4912 * An array of double, with one element for each Frame axis.
4913 * This should contain the coordinates of a second point on the
4914 * first geodesic curve.
4915 * b1
4916 * An array of double, with one element for each Frame axis.
4917 * This should contain the coordinates of a point on the second
4918 * geodesic curve.
4919 * b2
4920 * An array of double, with one element for each Frame axis.
4921 * This should contain the coordinates of a second point on
4922 * the second geodesic curve.
4923 * cross
4924 * An array of double, with one element for each Frame axis
4925 * in which the coordinates of the required intersection
4926 * point will be returned. These will be AST__BAD if the curves do
4927 * not intersect.
4928 * status
4929 * Pointer to the inherited status variable.
4930
4931 * Notes:
4932 * - The geodesic curve used by this function is the path of
4933 * shortest distance between two points, as defined by the
4934 * astDistance function.
4935 * - This function will return "bad" coordinate values (AST__BAD)
4936 * if any of the input coordinates has this value.
4937 * - For SkyFrames each curve will be a great circle, and in general
4938 * each pair of curves will intersect at two diametrically opposite
4939 * points on the sky. The returned position is the one which is
4940 * closest to point "a1".
4941 */
4942
4943 /* Local Variables: */
4944 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
4945 const int *perm; /* Pointer to axis permutation array */
4946 double aa1[ 2 ]; /* Permuted coordinates for a1 */
4947 double aa2[ 2 ]; /* Permuted coordinates for a2 */
4948 double bb1[ 2 ]; /* Permuted coordinates for b1 */
4949 double bb2[ 2 ]; /* Permuted coordinates for b2 */
4950 double cc[ 2 ]; /* Permuted coords at intersection */
4951 double d1; /* Cos(distance from a1 to vp) */
4952 double d2; /* Cos(distance from a1 to -vp) */
4953 double na[ 3 ]; /* Normal to the a1/a2 great circle */
4954 double nb[ 3 ]; /* Normal to the b1/b2 great circle */
4955 double va1[ 3 ]; /* Vector pointing at a1 */
4956 double va2[ 3 ]; /* Vector pointing at a2 */
4957 double vb1[ 3 ]; /* Vector pointing at b1 */
4958 double vb2[ 3 ]; /* Vector pointing at b2 */
4959 double vmod; /* Length of "vp" */
4960 double vp[ 3 ]; /* Vector pointing at the intersection */
4961 double vpn[ 3 ]; /* Normalised vp */
4962 int iaxis; /* Axis index */
4963
4964 /* Initialise. */
4965 cross[ 0 ] = AST__BAD;
4966 cross[ 1 ] = AST__BAD;
4967
4968 /* Check the global error status. */
4969 if ( !astOK ) return;
4970
4971 /* Obtain a pointer to the SkyFrame structure. */
4972 this = (AstSkyFrame *) this_frame;
4973
4974 /* Check that all supplied values are OK. */
4975 if ( ( a1[ 0 ] != AST__BAD ) && ( a1[ 1 ] != AST__BAD ) &&
4976 ( a2[ 0 ] != AST__BAD ) && ( a2[ 1 ] != AST__BAD ) &&
4977 ( b1[ 0 ] != AST__BAD ) && ( b1[ 1 ] != AST__BAD ) &&
4978 ( b2[ 0 ] != AST__BAD ) && ( b2[ 1 ] != AST__BAD ) ) {
4979
4980 /* Obtain a pointer to the SkyFrame's axis permutation array. */
4981 perm = astGetPerm( this );
4982 if ( astOK ) {
4983
4984 /* Apply the axis permutation array to obtain the coordinates of
4985 the points in the required (longitude,latitude) order. */
4986 for( iaxis = 0; iaxis < 2; iaxis++ ) {
4987 aa1[ perm[ iaxis ] ] = a1[ iaxis ];
4988 aa2[ perm[ iaxis ] ] = a2[ iaxis ];
4989 bb1[ perm[ iaxis ] ] = b1[ iaxis ];
4990 bb2[ perm[ iaxis ] ] = b2[ iaxis ];
4991 }
4992
4993 /* Convert each (lon,lat) pair into a unit length 3-vector. */
4994 palDcs2c( aa1[ 0 ], aa1[ 1 ], va1 );
4995 palDcs2c( aa2[ 0 ], aa2[ 1 ], va2 );
4996 palDcs2c( bb1[ 0 ], bb1[ 1 ], vb1 );
4997 palDcs2c( bb2[ 0 ], bb2[ 1 ], vb2 );
4998
4999 /* Find the normal vectors to the two great cicles. */
5000 palDvxv( va1, va2, na );
5001 palDvxv( vb1, vb2, nb );
5002
5003 /* The cross product of the two normal vectors points to one of the
5004 two diametrically opposite intersections. */
5005 palDvxv( na, nb, vp );
5006
5007 /* Normalise the "vp" vector, also obtaining its original modulus. */
5008 palDvn( vp, vpn, &vmod );
5009 if( vmod != 0.0 ) {
5010
5011 /* We want the intersection which is closest to "a1". The dot product
5012 gives the cos(distance) between two positions. So find the dot
5013 product between "a1" and "vpn", and then between "a1" and the point
5014 diametrically opposite "vpn". */
5015 d1 = palDvdv( vpn, va1 );
5016 vpn[ 0 ] = -vpn[ 0 ];
5017 vpn[ 1 ] = -vpn[ 1 ];
5018 vpn[ 2 ] = -vpn[ 2 ];
5019 d2 = palDvdv( vpn, va1 );
5020
5021 /* Revert to "vpn" if it is closer to "a1". */
5022 if( d1 > d2 ) {
5023 vpn[ 0 ] = -vpn[ 0 ];
5024 vpn[ 1 ] = -vpn[ 1 ];
5025 vpn[ 2 ] = -vpn[ 2 ];
5026 }
5027
5028 /* Convert the vector back into a (lon,lat) pair, and put the longitude
5029 into the range 0 to 2.pi. */
5030 palDcc2s( vpn, cc, cc + 1 );
5031 *cc = palDranrm( *cc );
5032
5033 /* Permute the result coordinates to undo the effect of the SkyFrame
5034 axis permutation array. */
5035 cross[ 0 ] = cc[ perm[ 0 ] ];
5036 cross[ 1 ] = cc[ perm[ 1 ] ];
5037 }
5038 }
5039 }
5040 }
5041
IsEquatorial(AstSystemType system,int * status)5042 static int IsEquatorial( AstSystemType system, int *status ) {
5043 /*
5044 * Name:
5045 * IsEquatorial
5046
5047 * Purpose:
5048 * Test for an equatorial sky coordinate system.
5049
5050 * Type:
5051 * Private function.
5052
5053 * Synopsis:
5054 * #include "skyframe.h"
5055 * int IsEquatorial( AstSystemType system, int *status )
5056
5057 * Class Membership:
5058 * SkyFrame member function.
5059
5060 * Description:
5061 * This function returns a boolean value to indicate if a sky coordinate
5062 * system is equatorial.
5063
5064 * Parameters:
5065 * system
5066 * Code to identify the sky coordinate system.
5067 * status
5068 * Pointer to the inherited status variable.
5069
5070 * Returned Value:
5071 * Non-zero if the sky coordinate system is equatorial, otherwise zero.
5072
5073 * Notes:
5074 * - A value of zero is returned if this function is invoked with the
5075 * global error status set or if it should fail for any reason.
5076 */
5077
5078 /* Local Variables: */
5079 int result; /* Result value to return */
5080
5081 /* Check the global error status. */
5082 if ( !astOK ) return 0;
5083
5084 /* Determine if the sky coordinate system is an equatorial one. Note,
5085 ICRS is not equatorial by definition, but is included here because it
5086 is normally treated as an equatorial system in terms of the axis
5087 labels, formats, etc. */
5088 result = ( ( system == AST__FK4 ) ||
5089 ( system == AST__FK4_NO_E ) ||
5090 ( system == AST__ICRS ) ||
5091 ( system == AST__FK5 ) ||
5092 ( system == AST__J2000 ) ||
5093 ( system == AST__GAPPT ) );
5094
5095 /* Return the result. */
5096 return result;
5097 }
5098
LineContains(AstFrame * this,AstLineDef * l,int def,double * point,int * status)5099 static int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) {
5100 /*
5101 * Name:
5102 * LineContains
5103
5104 * Purpose:
5105 * Determine if a line contains a point.
5106
5107 * Type:
5108 * Private function.
5109
5110 * Synopsis:
5111 * #include "skyframe.h"
5112 * int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status )
5113
5114 * Class Membership:
5115 * SkyFrame member function (over-rides the protected astLineContains
5116 * method inherited from the Frame class).
5117
5118 * Description:
5119 * This function determines if the supplied point is on the supplied
5120 * line within the supplied Frame. The start point of the line is
5121 * considered to be within the line, but the end point is not. The tests
5122 * are that the point of closest approach of the line to the point should
5123 * be between the start and end, and that the distance from the point to
5124 * the point of closest aproach should be less than 1.0E-7 of the length
5125 * of the line.
5126
5127 * Parameters:
5128 * this
5129 * Pointer to the Frame.
5130 * l
5131 * Pointer to the structure defining the line.
5132 * def
5133 * Should be set non-zero if the "point" array was created by a
5134 * call to astLineCrossing (in which case it may contain extra
5135 * information following the axis values),and zero otherwise.
5136 * point
5137 * Point to an array containing the axis values of the point to be
5138 * tested, possibly followed by extra cached information (see "def").
5139 * status
5140 * Pointer to the inherited status variable.
5141
5142 * Returned Value:
5143 * A non-zero value is returned if the line contains the point.
5144
5145 * Notes:
5146 * - The pointer supplied for "l" should have been created using the
5147 * astLineDef method. These structures contained cached information about
5148 * the lines which improve the efficiency of this method when many
5149 * repeated calls are made. An error will be reported if the structure
5150 * does not refer to the Frame specified by "this".
5151 * - Zero will be returned if this function is invoked with the global
5152 * error status set, or if it should fail for any reason.
5153 *-
5154 */
5155
5156 /* Local Variables: */
5157 SkyLineDef *sl; /* SkyLine information */
5158 const int *perm; /* Pointer to axis permutation array */
5159 double *b; /* Pointer to Cartesian coords array */
5160 double bb[3]; /* Buffer for Cartesian coords */
5161 double p1[2]; /* Buffer for Spherical coords */
5162 double t1, t2;
5163 int result; /* Returned value */
5164
5165 /* Initialise */
5166 result =0;
5167
5168 /* Check the global error status. */
5169 if ( !astOK ) return result;
5170
5171 /* Check that the line refers to the supplied Frame. */
5172 if( l->frame != this ) {
5173 astError( AST__INTER, "astLineContains(%s): The supplied line does "
5174 "not relate to the supplied %s (AST internal programming "
5175 "error).", status, astGetClass( this ), astGetClass( this ) );
5176
5177 /* Check the axis values are good */
5178 } else if( point[ 0 ] != AST__BAD && point[ 1 ] != AST__BAD ){
5179
5180 /* Get a pointer to an array holding the corresponding Cartesian coords. */
5181 if( def ) {
5182 b = point + 2;
5183
5184 } else {
5185 perm = astGetPerm( this );
5186 if ( perm ) {
5187 p1[ perm[ 0 ] ] = point[ 0 ];
5188 p1[ perm[ 1 ] ] = point[ 1 ];
5189 palDcs2c( p1[ 0 ], p1[ 1 ], bb );
5190 b = bb;
5191 } else {
5192 b = NULL;
5193 }
5194 }
5195
5196 /* Recast the supplied AstLineDef into a SkyLineDef to get the different
5197 structure (we know from the above check on the Frame that it is safe to
5198 do this). */
5199 sl = (SkyLineDef *) l;
5200
5201 /* Check that the point of closest approach of the line to the point is
5202 within the limits of the line. */
5203 if( LineIncludes( sl, b, status ) ){
5204
5205 /* Check that the point is 90 degrees away from the pole of the great
5206 circle containing the line. */
5207 t1 = palDvdv( sl->q, b );
5208 t2 = 1.0E-7*sl->length;
5209 if( t2 < 1.0E-10 ) t2 = 1.0E-10;
5210 if( fabs( t1 ) <= t2 ) result = 1;
5211 }
5212 }
5213
5214 /* Return the result. */
5215 return result;
5216 }
5217
LineCrossing(AstFrame * this,AstLineDef * l1,AstLineDef * l2,double ** cross,int * status)5218 static int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
5219 double **cross, int *status ) {
5220 /*
5221 * Name:
5222 * LineCrossing
5223
5224 * Purpose:
5225 * Determine if two lines cross.
5226
5227 * Type:
5228 * Private function.
5229
5230 * Synopsis:
5231 * #include "skyframe.h"
5232 * int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
5233 * double **cross, int *status )
5234
5235 * Class Membership:
5236 * SkyFrame member function (over-rides the protected astLineCrossing
5237 * method inherited from the Frame class).
5238
5239 * Description:
5240 * This function determines if the two suplied line segments cross,
5241 * and if so returns the axis values at the point where they cross.
5242 * A flag is also returned indicating if the crossing point occurs
5243 * within the length of both line segments, or outside one or both of
5244 * the line segments.
5245
5246 * Parameters:
5247 * this
5248 * Pointer to the Frame.
5249 * l1
5250 * Pointer to the structure defining the first line.
5251 * l2
5252 * Pointer to the structure defining the second line.
5253 * cross
5254 * Pointer to a location at which to put a pointer to a dynamically
5255 * alocated array containing the axis values at the crossing. If
5256 * NULL is supplied no such array is returned. Otherwise, the returned
5257 * array should be freed using astFree when no longer needed. If the
5258 * lines are parallel (i.e. do not cross) then AST__BAD is returned for
5259 * all axis values. Note usable axis values are returned even if the
5260 * lines cross outside the segment defined by the start and end points
5261 * of the lines. The order of axes in the returned array will take
5262 * account of the current axis permutation array if appropriate. Note,
5263 * sub-classes such as SkyFrame may append extra values to the end
5264 * of the basic frame axis values. A NULL pointer is returned if an
5265 * error occurs.
5266 * status
5267 * Pointer to the inherited status variable.
5268
5269 * Returned Value:
5270 * A non-zero value is returned if the lines cross at a point which is
5271 * within the [start,end) segment of both lines. If the crossing point
5272 * is outside this segment on either line, or if the lines are parallel,
5273 * zero is returned. Note, the start point is considered to be inside
5274 * the length of the segment, but the end point is outside.
5275
5276 * Notes:
5277 * - The pointers supplied for "l1" and "l2" should have been created
5278 * using the astLineDef method. These structures contained cached
5279 * information about the lines which improve the efficiency of this method
5280 * when many repeated calls are made. An error will be reported if
5281 * either structure does not refer to the Frame specified by "this".
5282 * - Zero will be returned if this function is invoked with the global
5283 * error status set, or if it should fail for any reason.
5284 */
5285
5286 /* Local Variables: */
5287 SkyLineDef *sl1; /* SkyLine information for line 1 */
5288 SkyLineDef *sl2; /* SkyLine information for line 2 */
5289 const int *perm; /* Pointer to axis permutation array */
5290 double *crossing; /* Pointer to returned array */
5291 double *b; /* Pointer to Cartesian coords */
5292 double len; /* Vector length */
5293 double p[ 2 ]; /* Temporary (lon,lat) pair */
5294 double temp[ 3 ]; /* Temporary vector */
5295 int result; /* Returned value */
5296
5297 /* Initialise */
5298 result = 0;
5299 if( cross ) *cross = NULL;
5300
5301 /* Check the global error status. */
5302 if ( !astOK ) return result;
5303
5304 /* Allocate returned array (2 elements for the lon and lat values, plus 3
5305 for the corresponding (x,y,z) coords). */
5306 crossing = astMalloc( sizeof(double)*5 );
5307
5308 /* Check that both lines refer to the supplied Frame. */
5309 if( l1->frame != this ) {
5310 astError( AST__INTER, "astLineCrossing(%s): First supplied line does "
5311 "not relate to the supplied %s (AST internal programming "
5312 "error).", status, astGetClass( this ), astGetClass( this ) );
5313
5314 } else if( l2->frame != this ) {
5315 astError( AST__INTER, "astLineCrossing(%s): Second supplied line does "
5316 "not relate to the supplied %s (AST internal programming "
5317 "error).", status, astGetClass( this ), astGetClass( this ) );
5318
5319 /* Recast the supplied AstLineDefs into a SkyLineDefs to get the different
5320 structure (we know from the above check on the Frame that it is safe to
5321 do this). */
5322 } else if( crossing ){
5323 sl1 = (SkyLineDef *) l1;
5324 sl2 = (SkyLineDef *) l2;
5325
5326 /* Point of intersection of the two great circles is perpendicular to the
5327 pole vectors of both great circles. Put the Cartesian coords in elements
5328 2 to 4 of the returned array. */
5329 palDvxv( sl1->q, sl2->q, temp );
5330 b = crossing + 2;
5331 palDvn( temp, b, &len );
5332
5333 /* See if this point is within the length of both arcs. If so return it. */
5334 if( LineIncludes( sl2, b, status ) && LineIncludes( sl1, b, status ) ) {
5335 result = 1;
5336
5337 /* If not, see if the negated b vector is within the length of both arcs.
5338 If so return it. Otherwise, we return zero. */
5339 } else {
5340 b[ 0 ] *= -1.0;
5341 b[ 1 ] *= -1.0;
5342 b[ 2 ] *= -1.0;
5343 if( LineIncludes( sl2, b, status ) && LineIncludes( sl1, b, status ) ) result = 1;
5344 }
5345
5346 /* Store the spherical coords in elements 0 and 1 of the returned array. */
5347 palDcc2s( b, p, p + 1 );
5348
5349 /* Permute the spherical axis value into the order used by the SkyFrame. */
5350 perm = astGetPerm( this );
5351 if( perm ){
5352 crossing[ 0 ] = p[ perm[ 0 ] ];
5353 crossing[ 1 ] = p[ perm[ 1 ] ];
5354 }
5355 }
5356
5357 /* If an error occurred, return 0. */
5358 if( !astOK ) {
5359 result = 0;
5360 crossing = astFree( crossing );
5361 }
5362
5363 /* Return the array */
5364 if( cross ) {
5365 *cross = crossing;
5366 } else {
5367 crossing = astFree( crossing );
5368 }
5369
5370 /* Return the result. */
5371 return result;
5372 }
5373
LineDef(AstFrame * this,const double start[2],const double end[2],int * status)5374 static AstLineDef *LineDef( AstFrame *this, const double start[2],
5375 const double end[2], int *status ) {
5376 /*
5377 * Name:
5378 * LineDef
5379
5380 * Purpose:
5381 * Creates a structure describing a line segment in a 2D Frame.
5382
5383 * Type:
5384 * Private function.
5385
5386 * Synopsis:
5387 * #include "skyframe.h"
5388 * AstLineDef *LineDef( AstFrame *this, const double start[2],
5389 * const double end[2], int *status )
5390
5391 * Class Membership:
5392 * SkyFrame member function (over-rides the protected astLineDef
5393 * method inherited from the Frame class).
5394
5395 * Description:
5396 * This function creates a structure containing information describing a
5397 * given line segment within the supplied 2D Frame. This may include
5398 * information which allows other methods such as astLineCrossing to
5399 * function more efficiently. Thus the returned structure acts as a
5400 * cache to store intermediate values used by these other methods.
5401
5402 * Parameters:
5403 * this
5404 * Pointer to the Frame. Must have 2 axes.
5405 * start
5406 * An array of 2 doubles marking the start of the line segment.
5407 * end
5408 * An array of 2 doubles marking the end of the line segment.
5409 * status
5410 * Pointer to the inherited status variable.
5411
5412 * Returned Value:
5413 * Pointer to the memory structure containing the description of the
5414 * line. This structure should be freed using astFree when no longer
5415 * needed. A NULL pointer is returned (without error) if any of the
5416 * supplied axis values are AST__BAD.
5417
5418 * Notes:
5419 * - A null pointer will be returned if this function is invoked
5420 * with the global error status set, or if it should fail for any
5421 * reason.
5422 */
5423
5424 /* Local Variables: */
5425 SkyLineDef *result; /* Returned value */
5426 const int *perm; /* Axis permutation array */
5427 double le; /* Length of end vector */
5428 double len; /* Permuted point1 coordinates */
5429 double ls; /* Length of start vector */
5430 double p1[ 2 ]; /* Permuted point1 coordinates */
5431 double p2[ 2 ]; /* Permuted point2 coordinates */
5432 double temp[3]; /* Cartesian coords at offset position */
5433
5434 /* Initialise */
5435 result = NULL;
5436
5437 /* Check the global error status. */
5438 if ( !astOK ) return NULL;
5439
5440 /* Check the axis values are good */
5441 if( start[ 0 ] != AST__BAD && start[ 1 ] != AST__BAD &&
5442 end[ 0 ] != AST__BAD && end[ 1 ] != AST__BAD ) {
5443
5444 /* Allocate memory for the returned structure. */
5445 result = astMalloc( sizeof( SkyLineDef ) );
5446
5447 /* Obtain a pointer to the SkyFrame's axis permutation array. */
5448 perm = astGetPerm( this );
5449 if ( perm ) {
5450
5451 /* Apply the axis permutation array to obtain the coordinates of the two
5452 input points in the required (longitude,latitude) order. */
5453 p1[ perm[ 0 ] ] = start[ 0 ];
5454 p1[ perm[ 1 ] ] = start[ 1 ];
5455 p2[ perm[ 0 ] ] = end[ 0 ];
5456 p2[ perm[ 1 ] ] = end[ 1 ];
5457
5458 /* Convert each point into a 3-vector of unit length and store in the
5459 returned structure. */
5460 palDcs2c( p1[ 0 ], p1[ 1 ], result->start );
5461 palDcs2c( p2[ 0 ], p2[ 1 ], result->end );
5462
5463 /* Calculate the great circle distance between the points in radians and
5464 store in the result structure. Correct for rounding errors in palDcs2c
5465 that can result in the vectors not having exactly unit length. */
5466 result->length = palDvdv( result->start, result->end );
5467 ls = result->start[0]*result->start[0] +
5468 result->start[1]*result->start[1] +
5469 result->start[2]*result->start[2];
5470 le = result->end[0]*result->end[0] +
5471 result->end[1]*result->end[1] +
5472 result->end[2]*result->end[2];
5473 result->length = acos( result->length/sqrt( ls*le ) );
5474
5475 /* Find a unit vector representing the pole of the system in which the
5476 equator is given by the great circle. This is such that going the
5477 short way from the start to the end, the pole is to the left of the
5478 line as seen by the observer (i.e. from the centre of the sphere).
5479 If the line has zero length, or 180 degrees length, the pole is
5480 undefined, so we use an arbitrary value. */
5481 if( result->length == 0.0 || result->length > pi - 5.0E-11 ) {
5482 palDcs2c( p1[ 0 ] + 0.01, p1[ 1 ] + 0.01, temp );
5483 palDvxv( temp, result->start, result->dir );
5484 } else {
5485 palDvxv( result->end, result->start, result->dir );
5486 }
5487 palDvn( result->dir, result->q, &len );
5488
5489 /* Also store a point which is 90 degrees along the great circle from the
5490 start. */
5491 palDvxv( result->start, result->q, result->dir );
5492
5493 /* Store a pointer to the defining SkyFrame. */
5494 result->frame = this;
5495
5496 /* Indicate that the line is considered to be terminated at the start and
5497 end points. */
5498 result->infinite = 0;
5499
5500 /* Normalise the spherical start and end positions stored in the returned
5501 structure. */
5502 result->start_2d[ 0 ] = start[ 0 ];
5503 result->start_2d[ 1 ] = start[ 1 ];
5504 result->end_2d[ 0 ] = end[ 0 ];
5505 result->end_2d[ 1 ] = end[ 1 ];
5506
5507 astNorm( this, result->start_2d );
5508 astNorm( this, result->end_2d );
5509 }
5510 }
5511
5512 /* Free the returned pointer if an error occurred. */
5513 if( !astOK ) result = astFree( result );
5514
5515 /* Return a pointer to the output structure. */
5516 return (AstLineDef *) result;
5517 }
5518
LineIncludes(SkyLineDef * l,double point[3],int * status)5519 static int LineIncludes( SkyLineDef *l, double point[3], int *status ) {
5520 /*
5521 * Name:
5522 * LineIncludes
5523
5524 * Purpose:
5525 * Determine if a line includes a point which is known to be in the
5526 * great circle.
5527
5528 * Type:
5529 * Private function.
5530
5531 * Synopsis:
5532 * #include "skyframe.h"
5533 * int LineIncludes( SkyLineDef *l, double point[3], int *status )
5534
5535 * Class Membership:
5536 * SkyFrame member function (over-rides the protected astLineIncludes
5537 * method inherited from the Frame class).
5538
5539 * Description:
5540 * The supplied point is assumed to be a point on the great circle of
5541 * which the supplied line is a segment. This function returns true if
5542 * "point" is within the bounds of the segment (the end point of the
5543 * line is assumed * not to be part of the segment).
5544
5545 * Parameters:
5546 * l
5547 * Pointer to the structure defining the line.
5548 * point
5549 * An array holding the Cartesian coords of the point to be tested.
5550 * status
5551 * Pointer to the inherited status variable.
5552
5553 * Returned Value:
5554 * A non-zero value is returned if the line includes the point.
5555
5556 * Notes:
5557 * - Zero will be returned if this function is invoked with the global
5558 * error status set, or if it should fail for any reason.
5559 */
5560
5561 /* Local Variables: */
5562 double t1, t2, t3;
5563
5564 /* Check the global error status. */
5565 if ( !astOK ) return 0;
5566
5567 /* If the line is of infite length, it is assumed to include the supplied
5568 point. */
5569 if( l->infinite ) return 1;
5570
5571 /* Otherwise, get the unsigned distance of the point from the start of the
5572 line in the range 0 - 180 degs. Check it is less than the line length.
5573 Then check that the point is not more than 90 degs away from the quarter
5574 point. */
5575 t1 = palDvdv( l->start, point );
5576 t2 = acos( t1 );
5577 t3 = palDvdv( l->dir, point );
5578 return ( ((l->length > 0) ? t2 < l->length : t2 == 0.0 ) && t3 >= -1.0E-8 );
5579 }
5580
LineOffset(AstFrame * this,AstLineDef * line,double par,double prp,double point[2],int * status)5581 static void LineOffset( AstFrame *this, AstLineDef *line, double par,
5582 double prp, double point[2], int *status ){
5583 /*
5584 * Name:
5585 * LineOffset
5586
5587 * Purpose:
5588 * Find a position close to a line.
5589
5590 * Type:
5591 * Private function.
5592
5593 * Synopsis:
5594 * #include "skyframe.h"
5595 * void LineOffset( AstFrame *this, AstLineDef *line, double par,
5596 * double prp, double point[2], int *status )
5597
5598 * Class Membership:
5599 * SkyFrame member function (over-rides the protected astLineOffset
5600 * method inherited from the Frame class).
5601
5602 * Description:
5603 * This function returns a position formed by moving a given distance along
5604 * the supplied line, and then a given distance away from the supplied line.
5605
5606 * Parameters:
5607 * this
5608 * Pointer to the Frame.
5609 * line
5610 * Pointer to the structure defining the line.
5611 * par
5612 * The distance to move along the line from the start towards the end.
5613 * prp
5614 * The distance to move at right angles to the line. Positive
5615 * values result in movement to the left of the line, as seen from
5616 * the observer, when moving from start towards the end.
5617 * status
5618 * Pointer to the inherited status variable.
5619
5620 * Notes:
5621 * - The pointer supplied for "line" should have been created using the
5622 * astLineDef method. This structure contains cached information about the
5623 * line which improves the efficiency of this method when many repeated
5624 * calls are made. An error will be reported if the structure does not
5625 * refer to the Frame specified by "this".
5626 *-
5627 */
5628
5629 /* Local Variables; */
5630 SkyLineDef *sl;
5631 const int *perm;
5632 double c;
5633 double nx;
5634 double ny;
5635 double nz;
5636 double p[2];
5637 double s;
5638 double v[3];
5639
5640 /* Check the global error status. */
5641 if ( !astOK ) return;
5642
5643 /* Check that the line refers to the supplied Frame. */
5644 if( line->frame != this ) {
5645 astError( AST__INTER, "astLineOffset(%s): The supplied line does "
5646 "not relate to the supplied %s (AST internal programming "
5647 "error).", status, astGetClass( this ), astGetClass( this ) );
5648
5649 /* This implementation uses spherical geometry. */
5650 } else {
5651
5652 /* Get a pointer to the SkyLineDef structure. */
5653 sl = (SkyLineDef *) line;
5654
5655 /* Move a distance par from start to end. */
5656 c = cos( par );
5657 s = sin( par );
5658 nx = c * sl->start[ 0 ] + s * sl->dir[ 0 ];
5659 ny = c * sl->start[ 1 ] + s * sl->dir[ 1 ];
5660 nz = c * sl->start[ 2 ] + s * sl->dir[ 2 ];
5661
5662 /* Move a distance prp from this point towards the pole point. */
5663 if( prp != 0.0 ) {
5664 c = cos( prp );
5665 s = sin( prp );
5666 v[ 0 ] = c * nx + s * sl->q[ 0 ];
5667 v[ 1 ] = c * ny + s * sl->q[ 1 ];
5668 v[ 2 ] = c * nz + s * sl->q[ 2 ];
5669 } else {
5670 v[ 0 ] = nx;
5671 v[ 1 ] = ny;
5672 v[ 2 ] = nz;
5673 }
5674
5675 /* Convert to lon/lat */
5676 palDcc2s( v, p, p + 1 );
5677
5678 /* Permute the spherical axis value into the order used by the SkyFrame. */
5679 perm = astGetPerm( this );
5680 if( perm ){
5681 point[ 0 ] = p[ perm[ 0 ] ];
5682 point[ 1 ] = p[ perm[ 1 ] ];
5683 }
5684 }
5685 }
5686
MakeSkyMapping(AstSkyFrame * target,AstSkyFrame * result,AstSystemType align_sys,AstMapping ** map,int * status)5687 static int MakeSkyMapping( AstSkyFrame *target, AstSkyFrame *result,
5688 AstSystemType align_sys, AstMapping **map, int *status ) {
5689 /*
5690 * Name:
5691 * MakeSkyMapping
5692
5693 * Purpose:
5694 * Generate a Mapping between two SkyFrames.
5695
5696 * Type:
5697 * Private function.
5698
5699 * Synopsis:
5700 * #include "skyframe.h"
5701 * int MakeSkyMapping( AstSkyFrame *target, AstSkyFrame *result,
5702 * AstSystemType align_sys, AstMapping **map, int *status )
5703
5704 * Class Membership:
5705 * SkyFrame member function.
5706
5707 * Description:
5708 * This function takes two SkyFrames and generates a Mapping that
5709 * converts between them, taking account of differences in their
5710 * coordinate systems, equinox value, epoch, etc. (but not allowing
5711 * for any axis permutations).
5712
5713 * Parameters:
5714 * target
5715 * Pointer to the first SkyFrame.
5716 * result
5717 * Pointer to the second SkyFrame.
5718 * align_sys
5719 * The system in which to align the two SkyFrames.
5720 * map
5721 * Pointer to a location which is to receive a pointer to the
5722 * returned Mapping. The forward transformation of this Mapping
5723 * will convert from "target" coordinates to "result"
5724 * coordinates, and the inverse transformation will convert in
5725 * the opposite direction (all coordinate values in radians).
5726 * status
5727 * Pointer to the inherited status variable.
5728
5729 * Returned Value:
5730 * Non-zero if the Mapping could be generated, or zero if the two
5731 * SkyFrames are sufficiently un-related that no meaningful Mapping
5732 * can be produced.
5733
5734 * Notes:
5735 * A value of zero is returned if this function is invoked with the
5736 * global error status set or if it should fail for any reason.
5737 */
5738
5739 /* Local Constants: */
5740 #define MAX_ARGS 4 /* Max arguments for an SlaMap conversion */
5741
5742 /* Local Variables: */
5743 AstMapping *omap; /* Mapping from coorinates to offsets */
5744 AstMapping *tmap2; /* Temporary Mapping */
5745 AstMapping *tmap; /* Temporary Mapping */
5746 AstSlaMap *slamap; /* Pointer to SlaMap */
5747 AstSystemType result_system; /* Code to identify result coordinate system */
5748 AstSystemType system; /* Code to identify coordinate system */
5749 AstSystemType target_system; /* Code to identify target coordinate system */
5750 double args[ MAX_ARGS ]; /* Conversion argument array */
5751 double epoch; /* Epoch as Modified Julian Date */
5752 double epoch_B; /* Besselian epoch as decimal years */
5753 double epoch_J; /* Julian epoch as decimal years */
5754 double equinox; /* Equinox as Modified Julian Date */
5755 double equinox_B; /* Besselian equinox as decimal years */
5756 double equinox_J; /* Julian equinox as decimal years */
5757 double diurab; /* Magnitude of diurnal aberration vector */
5758 double last; /* Local Apparent Sidereal Time */
5759 double lat; /* Observers latitude */
5760 double result_epoch; /* Result frame Epoch */
5761 double result_equinox; /* Result frame Epoch */
5762 double target_epoch; /* Target frame Epoch */
5763 double target_equinox; /* Target frame Epoch */
5764 int match; /* Mapping can be generated? */
5765 int step1; /* Convert target to FK5 J2000? */
5766 int step2; /* Convert FK5 J2000 to align sys? */
5767 int step3; /* Convert align sys to FK5 J2000? */
5768 int step4; /* Convert FK5 J2000 to result? */
5769
5770 /* Check the global error status. */
5771 if ( !astOK ) return 0;
5772
5773 /* Initialise the returned values. */
5774 match = 1;
5775 *map = NULL;
5776
5777 /* Initialise variables to avoid "used of uninitialised variable"
5778 messages from dumb compilers. */
5779 epoch_B = 0.0;
5780 epoch_J = 0.0;
5781 equinox_B = 0.0;
5782 equinox_J = 0.0;
5783
5784 /* Get the two epoch values. */
5785 result_epoch = astGetEpoch( result );
5786 target_epoch = astGetEpoch( target );
5787
5788 /* Get the two equinox values. */
5789 result_equinox = astGetEquinox( result );
5790 target_equinox = astGetEquinox( target );
5791
5792 /* Get the two system values. */
5793 result_system = astGetSystem( result );
5794 target_system = astGetSystem( target );
5795
5796 /* If either system is not references to the equinox given by the Equinox
5797 attribute, then use the equinox of the other system rather than
5798 adopting the arbitrary default of J2000. */
5799 if( !EQREF(result_system) ) result_equinox = target_equinox;
5800 if( !EQREF(target_system) ) target_equinox = result_equinox;
5801
5802 /* If both systems are unknown, assume they are the same. Return a UnitMap.
5803 We need to do this, otherwise a simple change of Title (for instance)
5804 will result in a FrameSet whose current Frame has System=AST__UNKNOWN
5805 loosing its integrity. */
5806 if( target_system == AST__UNKNOWN && result_system == AST__UNKNOWN ) {
5807 *map = (AstMapping *) astUnitMap( 2, "", status );
5808 return 1;
5809 }
5810
5811 /* The total Mapping is divided into two parts in series; the first part
5812 converts from the target SkyFrame to the alignment system, using the
5813 Epoch and Equinox of the target Frame, the second part converts from
5814 the alignment system to the result SkyFrame, using the Epoch and Equinox
5815 of the result Frame. Each of these parts has an arbitrary input and an
5816 output system, and therefore could be implemented using a collection
5817 of NxN conversions. To reduce the complexity, each part is implement
5818 by converting from the input system to FK5 J2000, and then from FK5
5819 J2000 to the output system. This scheme required only N conversions
5820 rather than NxN. Thus overall the total Mapping is made up of 4 steps
5821 in series. Some of these steps may be ommitted if they are effectively
5822 a UnitMap. Determine which steps need to be included. Assume all need
5823 to be done to begin with. */
5824 step1 = 1;
5825 step2 = 1;
5826 step3 = 1;
5827 step4 = 1;
5828
5829 /* If the target system is the same as the alignment system, neither of the
5830 first 2 steps need be done. */
5831 if( target_system == align_sys ) {
5832 step1 = 0;
5833 step2 = 0;
5834 }
5835
5836 /* If the result system is the same as the alignment system, neither of the
5837 last 2 steps need be done. */
5838 if( result_system == align_sys ) {
5839 step3 = 0;
5840 step4 = 0;
5841 }
5842
5843 /* If the two epochs are the same, or if the alignment system is FK5 J2000,
5844 steps 2 and 3 are not needed. */
5845 if( step2 && step3 ) {
5846 if( align_sys == AST__FK5 || result_epoch == target_epoch ) {
5847 step2 = 0;
5848 step3 = 0;
5849 }
5850 }
5851
5852 /* None are needed if the target and result SkyFrames have the same
5853 System, Epoch and Equinox. */
5854 if( result_system == target_system &&
5855 result_epoch == target_epoch &&
5856 result_equinox == target_equinox ) {
5857 step1 = 0;
5858 step2 = 0;
5859 step3 = 0;
5860 step4 = 0;
5861 }
5862
5863 /* Create an initial (null) SlaMap. */
5864 slamap = astSlaMap( 0, "", status );
5865
5866 /* Define local macros as shorthand for adding sky coordinate
5867 conversions to this SlaMap. Each macro simply stores details of
5868 the additional arguments in the "args" array and then calls
5869 astSlaAdd. The macros differ in the number of additional argument
5870 values. */
5871 #define TRANSFORM_0(cvt) \
5872 astSlaAdd( slamap, cvt, NULL );
5873
5874 #define TRANSFORM_1(cvt,arg0) \
5875 args[ 0 ] = arg0; \
5876 astSlaAdd( slamap, cvt, args );
5877
5878 #define TRANSFORM_2(cvt,arg0,arg1) \
5879 args[ 0 ] = arg0; \
5880 args[ 1 ] = arg1; \
5881 astSlaAdd( slamap, cvt, args );
5882
5883 #define TRANSFORM_3(cvt,arg0,arg1,arg2) \
5884 args[ 0 ] = arg0; \
5885 args[ 1 ] = arg1; \
5886 args[ 2 ] = arg2; \
5887 astSlaAdd( slamap, cvt, args );
5888
5889 #define TRANSFORM_4(cvt,arg0,arg1,arg2,arg3) \
5890 args[ 0 ] = arg0; \
5891 args[ 1 ] = arg1; \
5892 args[ 2 ] = arg2; \
5893 args[ 3 ] = arg3; \
5894 astSlaAdd( slamap, cvt, args );
5895
5896 /* Convert _to_ FK5 J2000.0 coordinates. */
5897 /* ===================================== */
5898 /* The overall conversion is formulated in four phases. In this first
5899 phase, we convert from the target coordinate system to intermediate sky
5900 coordinates expressed using the FK5 system, mean equinox J2000.0. */
5901
5902 /* Obtain the sky coordinate system, equinox, epoch, etc, of the target
5903 SkyFrame. */
5904 system = target_system;
5905 equinox = target_equinox;
5906 epoch = target_epoch;
5907 last = GetLAST( target, status );
5908 diurab = GetDiurab( target, status );
5909 lat = astGetObsLat( target );
5910 if( astOK && step1 ) {
5911
5912 /* Convert the equinox and epoch values (stored as Modified Julian
5913 Dates) into the equivalent Besselian and Julian epochs (as decimal
5914 years). */
5915 equinox_B = palEpb( equinox );
5916 equinox_J = palEpj( equinox );
5917 epoch_B = palEpb( epoch );
5918 epoch_J = palEpj( epoch );
5919
5920 /* Formulate the conversion... */
5921
5922 /* From FK4. */
5923 /* --------- */
5924 /* If necessary, apply the old-style FK4 precession model to bring the
5925 equinox to B1950.0, with rigorous handling of the E-terms of
5926 aberration. Then convert directly to FK5 J2000.0 coordinates. */
5927 if ( system == AST__FK4 ) {
5928 VerifyMSMAttrs( target, result, 1, "Equinox Epoch", "astMatch", status );
5929 if ( equinox_B != 1950.0 ) {
5930 TRANSFORM_1( "SUBET", equinox_B )
5931 TRANSFORM_2( "PREBN", equinox_B, 1950.0 )
5932 TRANSFORM_1( "ADDET", 1950.0 )
5933 }
5934 TRANSFORM_1( "FK45Z", epoch_B )
5935
5936 /* From FK4 with no E-terms. */
5937 /* ------------------------- */
5938 /* This is the same as above, except that we do not need to subtract
5939 the E-terms initially as they are already absent. */
5940 } else if ( system == AST__FK4_NO_E ) {
5941 VerifyMSMAttrs( target, result, 1, "Equinox Epoch", "astMatch", status );
5942 if ( equinox_B != 1950.0 ) {
5943 TRANSFORM_2( "PREBN", equinox_B, 1950.0 )
5944 }
5945 TRANSFORM_1( "ADDET", 1950.0 )
5946 TRANSFORM_1( "FK45Z", epoch_B )
5947
5948 /* From FK5. */
5949 /* --------- */
5950 /* We simply need to apply a precession correction for the change of
5951 equinox. Omit even this if the equinox is already J2000.0. */
5952 } else if ( system == AST__FK5 ) {
5953 VerifyMSMAttrs( target, result, 1, "Equinox", "astMatch", status );
5954 if ( equinox_J != 2000.0 ) {
5955 TRANSFORM_2( "PREC", equinox_J, 2000.0 );
5956 }
5957
5958 /* From J2000. */
5959 /* ----------- */
5960 /* Convert from J2000 to ICRS, then from ICRS to FK5. */
5961 } else if ( system == AST__J2000 ) {
5962 VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status );
5963 TRANSFORM_0( "J2000H" )
5964 TRANSFORM_1( "HFK5Z", epoch_J );
5965
5966 /* From geocentric apparent. */
5967 /* ------------------------- */
5968 /* This conversion is supported directly by SLALIB. */
5969 } else if ( system == AST__GAPPT ) {
5970 VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status );
5971 TRANSFORM_2( "AMP", epoch, 2000.0 )
5972
5973 /* From ecliptic coordinates. */
5974 /* -------------------------- */
5975 /* This conversion is supported directly by SLALIB. */
5976 } else if ( system == AST__ECLIPTIC ) {
5977 VerifyMSMAttrs( target, result, 1, "Equinox", "astMatch", status );
5978 TRANSFORM_1( "ECLEQ", equinox )
5979
5980 /* From helio-ecliptic coordinates. */
5981 /* -------------------------------- */
5982 } else if ( system == AST__HELIOECLIPTIC ) {
5983 VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status );
5984 TRANSFORM_1( "HEEQ", epoch )
5985
5986 /* From galactic coordinates. */
5987 /* -------------------------- */
5988 /* This conversion is supported directly by SLALIB. */
5989 } else if ( system == AST__GALACTIC ) {
5990 TRANSFORM_0( "GALEQ" )
5991
5992 /* From ICRS. */
5993 /* ---------- */
5994 /* This conversion is supported directly by SLALIB. */
5995 } else if ( system == AST__ICRS ) {
5996 VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status );
5997 TRANSFORM_1( "HFK5Z", epoch_J );
5998
5999 /* From supergalactic coordinates. */
6000 /* ------------------------------- */
6001 /* Convert to galactic coordinates and then to FK5 J2000.0
6002 equatorial. */
6003 } else if ( system == AST__SUPERGALACTIC ) {
6004 TRANSFORM_0( "SUPGAL" )
6005 TRANSFORM_0( "GALEQ" )
6006
6007 /* From AzEl. */
6008 /* ---------- */
6009 /* Rotate from horizon to equator (H2E), shift hour angle into RA (H2R),
6010 go from geocentric apparent to FK5 J2000. */
6011 } else if ( system == AST__AZEL ) {
6012 VerifyMSMAttrs( target, result, 1, "ObsLon ObsLat Epoch", "astMatch", status );
6013 TRANSFORM_2( "H2E", lat, diurab )
6014 TRANSFORM_1( "H2R", last )
6015 TRANSFORM_2( "AMP", epoch, 2000.0 )
6016
6017 /* From unknown coordinates. */
6018 /* ------------------------- */
6019 /* No conversion is possible. */
6020 } else if ( system == AST__UNKNOWN ) {
6021 match = 0;
6022 }
6023 }
6024
6025 /* Convert _from_ FK5 J2000.0 coordinates _to_ the alignment system. */
6026 /* ============================================================ */
6027 /* In this second phase, we convert to the system given by the align_sys
6028 argument (if required), still using the properties of the target Frame. */
6029 if ( astOK && match && step2 ) {
6030
6031 /* Align in FK4. */
6032 /* --------------- */
6033 /* Convert directly from FK5 J2000.0 to FK4 B1950.0 coordinates at the
6034 appropriate epoch. Then, if necessary, apply the old-style FK4
6035 precession model to bring the equinox to that required, with
6036 rigorous handling of the E-terms of aberration. */
6037 if ( align_sys == AST__FK4 ) {
6038 VerifyMSMAttrs( target, result, 1, "Equinox Epoch", "astMatch", status );
6039 TRANSFORM_1( "FK54Z", epoch_B )
6040 if ( equinox_B != 1950.0 ) {
6041 TRANSFORM_1( "SUBET", 1950.0 )
6042 TRANSFORM_2( "PREBN", 1950.0, equinox_B )
6043 TRANSFORM_1( "ADDET", equinox_B )
6044 }
6045
6046 /* Align in FK4 with no E-terms. */
6047 /* ------------------------------- */
6048 /* This is the same as above, except that we do not need to add the
6049 E-terms at the end. */
6050 } else if ( align_sys == AST__FK4_NO_E ) {
6051 VerifyMSMAttrs( target, result, 1, "Equinox Epoch", "astMatch", status );
6052 TRANSFORM_1( "FK54Z", epoch_B )
6053 TRANSFORM_1( "SUBET", 1950.0 )
6054 if ( equinox_B != 1950.0 ) {
6055 TRANSFORM_2( "PREBN", 1950.0, equinox_B )
6056 }
6057
6058 /* Align in FK5. */
6059 /* ------------- */
6060 /* We simply need to apply a precession correction for the change of
6061 equinox. Omit even this if the required equinox is J2000.0. */
6062 } else if ( align_sys == AST__FK5 ) {
6063 VerifyMSMAttrs( target, result, 1, "Equinox", "astMatch", status );
6064 if ( equinox_J != 2000.0 ) {
6065 TRANSFORM_2( "PREC", 2000.0, equinox_J )
6066 }
6067
6068 /* Align in J2000. */
6069 /* --------------- */
6070 /* Mov from FK5 to ICRS, and from ICRS to J2000. */
6071 } else if ( align_sys == AST__J2000 ) {
6072 VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status );
6073 TRANSFORM_1( "FK5HZ", epoch_J )
6074 TRANSFORM_0( "HJ2000" )
6075
6076 /* Align in geocentric apparent. */
6077 /* ------------------------------- */
6078 /* This conversion is supported directly by SLALIB. */
6079 } else if ( align_sys == AST__GAPPT ) {
6080 VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status );
6081 TRANSFORM_2( "MAP", 2000.0, epoch )
6082
6083 /* Align in ecliptic coordinates. */
6084 /* -------------------------------- */
6085 /* This conversion is supported directly by SLALIB. */
6086 } else if ( align_sys == AST__ECLIPTIC ) {
6087 VerifyMSMAttrs( target, result, 1, "Equinox", "astMatch", status );
6088 TRANSFORM_1( "EQECL", equinox )
6089
6090 /* Align in helio-ecliptic coordinates. */
6091 /* ------------------------------------ */
6092 } else if ( align_sys == AST__HELIOECLIPTIC ) {
6093 VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status );
6094 TRANSFORM_1( "EQHE", epoch )
6095
6096 /* Align in galactic coordinates. */
6097 /* -------------------------------- */
6098 /* This conversion is supported directly by SLALIB. */
6099 } else if ( align_sys == AST__GALACTIC ) {
6100 TRANSFORM_0( "EQGAL" )
6101
6102 /* Align in ICRS. */
6103 /* -------------- */
6104 /* This conversion is supported directly by SLALIB. */
6105 } else if ( align_sys == AST__ICRS ) {
6106 VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status );
6107 TRANSFORM_1( "FK5HZ", epoch_J )
6108
6109 /* Align in supergalactic coordinates. */
6110 /* ------------------------------------- */
6111 /* Convert to galactic coordinates and then to supergalactic. */
6112 } else if ( align_sys == AST__SUPERGALACTIC ) {
6113 TRANSFORM_0( "EQGAL" )
6114 TRANSFORM_0( "GALSUP" )
6115
6116 /* Align in AzEl coordinates. */
6117 /* -------------------------- */
6118 /* Go from FK5 J2000 to geocentric apparent (MAP), shift RA into hour angle
6119 (R2H), rotate from equator to horizon (E2H). */
6120 } else if ( align_sys == AST__AZEL ) {
6121 VerifyMSMAttrs( target, result, 1, "ObsLon ObsLat Epoch", "astMatch", status );
6122 TRANSFORM_2( "MAP", 2000.0, epoch )
6123 TRANSFORM_1( "R2H", last )
6124 TRANSFORM_2( "E2H", lat, diurab )
6125
6126 /* Align in unknown coordinates. */
6127 /* ------------------------------- */
6128 /* No conversion is possible. */
6129 } else if ( align_sys == AST__UNKNOWN ) {
6130 match = 0;
6131 }
6132 }
6133
6134 /* Convert _from_ the alignment system _to_ FK5 J2000.0 coordinates */
6135 /* =========================================================== */
6136 /* In this third phase, we convert from the alignment system (if required)
6137 to the intermediate FK5 J2000 system, using the properties of the
6138 result SkyFrame. */
6139
6140 /* Obtain the sky coordinate system, equinox, epoch, etc, of the result
6141 SkyFrame. */
6142 system = result_system;
6143 equinox = result_equinox;
6144 epoch = result_epoch;
6145 diurab = GetDiurab( result, status );
6146 last = GetLAST( result, status );
6147 lat = astGetObsLat( result );
6148
6149 /* Convert the equinox and epoch values (stored as Modified Julian
6150 Dates) into the equivalent Besselian and Julian epochs (as decimal
6151 years). */
6152 if( astOK ) {
6153 equinox_B = palEpb( equinox );
6154 equinox_J = palEpj( equinox );
6155 epoch_B = palEpb( epoch );
6156 epoch_J = palEpj( epoch );
6157 }
6158
6159 /* Check we need to do the conversion. */
6160 if ( astOK && match && step3 ) {
6161
6162 /* Formulate the conversion... */
6163
6164 /* From FK4. */
6165 /* --------- */
6166 /* If necessary, apply the old-style FK4 precession model to bring the
6167 equinox to B1950.0, with rigorous handling of the E-terms of
6168 aberration. Then convert directly to FK5 J2000.0 coordinates. */
6169 if ( align_sys == AST__FK4 ) {
6170 VerifyMSMAttrs( target, result, 3, "Equinox Epoch", "astMatch", status );
6171 if ( equinox_B != 1950.0 ) {
6172 TRANSFORM_1( "SUBET", equinox_B )
6173 TRANSFORM_2( "PREBN", equinox_B, 1950.0 )
6174 TRANSFORM_1( "ADDET", 1950.0 )
6175 }
6176 TRANSFORM_1( "FK45Z", epoch_B )
6177
6178 /* From FK4 with no E-terms. */
6179 /* ------------------------- */
6180 /* This is the same as above, except that we do not need to subtract
6181 the E-terms initially as they are already absent. */
6182 } else if ( align_sys == AST__FK4_NO_E ) {
6183 VerifyMSMAttrs( target, result, 3, "Equinox Epoch", "astMatch", status );
6184 if ( equinox_B != 1950.0 ) {
6185 TRANSFORM_2( "PREBN", equinox_B, 1950.0 )
6186 }
6187 TRANSFORM_1( "ADDET", 1950.0 )
6188 TRANSFORM_1( "FK45Z", epoch_B )
6189
6190 /* From FK5. */
6191 /* --------- */
6192 /* We simply need to apply a precession correction for the change of
6193 equinox. Omit even this if the equinox is already J2000.0. */
6194 } else if ( align_sys == AST__FK5 ) {
6195 VerifyMSMAttrs( target, result, 3, "Equinox", "astMatch", status );
6196 if ( equinox_J != 2000.0 ) {
6197 TRANSFORM_2( "PREC", equinox_J, 2000.0 );
6198 }
6199
6200 /* From geocentric apparent. */
6201 /* ------------------------- */
6202 /* This conversion is supported directly by SLALIB. */
6203 } else if ( align_sys == AST__GAPPT ) {
6204 VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status );
6205 TRANSFORM_2( "AMP", epoch, 2000.0 )
6206
6207 /* From ecliptic coordinates. */
6208 /* -------------------------- */
6209 /* This conversion is supported directly by SLALIB. */
6210 } else if ( align_sys == AST__ECLIPTIC ) {
6211 VerifyMSMAttrs( target, result, 3, "Equinox", "astMatch", status );
6212 TRANSFORM_1( "ECLEQ", equinox )
6213
6214 /* From helio-ecliptic coordinates. */
6215 /* -------------------------------- */
6216 } else if ( align_sys == AST__HELIOECLIPTIC ) {
6217 VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status );
6218 TRANSFORM_1( "HEEQ", epoch )
6219
6220 /* From galactic coordinates. */
6221 /* -------------------------- */
6222 /* This conversion is supported directly by SLALIB. */
6223 } else if ( align_sys == AST__GALACTIC ) {
6224 TRANSFORM_0( "GALEQ" )
6225
6226 /* From ICRS. */
6227 /* ---------- */
6228 /* This conversion is supported directly by SLALIB. */
6229 } else if ( align_sys == AST__ICRS ) {
6230 VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status );
6231 TRANSFORM_1( "HFK5Z", epoch_J )
6232
6233 /* From J2000. */
6234 /* ----------- */
6235 /* From J2000 to ICRS, and from ICRS to FK5. */
6236 } else if ( align_sys == AST__J2000 ) {
6237 VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status );
6238 TRANSFORM_0( "J2000H" )
6239 TRANSFORM_1( "HFK5Z", epoch_J )
6240
6241 /* From supergalactic coordinates. */
6242 /* ------------------------------- */
6243 /* Convert to galactic coordinates and then to FK5 J2000.0
6244 equatorial. */
6245 } else if ( align_sys == AST__SUPERGALACTIC ) {
6246 TRANSFORM_0( "SUPGAL" )
6247 TRANSFORM_0( "GALEQ" )
6248
6249 /* From AzEl. */
6250 /* ---------- */
6251 /* Rotate from horizon to equator (H2E), shift hour angle into RA (H2R),
6252 go from geocentric apparent to FK5 J2000. */
6253 } else if ( align_sys == AST__AZEL ) {
6254 VerifyMSMAttrs( target, result, 3, "ObsLon ObsLat Epoch", "astMatch", status );
6255 TRANSFORM_2( "H2E", lat, diurab )
6256 TRANSFORM_1( "H2R", last )
6257 TRANSFORM_2( "AMP", epoch, 2000.0 )
6258
6259 /* From unknown coordinates. */
6260 /* ------------------------------- */
6261 /* No conversion is possible. */
6262 } else if ( align_sys == AST__UNKNOWN ) {
6263 match = 0;
6264 }
6265 }
6266
6267 /* Convert _from_ FK5 J2000.0 coordinates. */
6268 /* ======================================= */
6269 /* In this fourth and final phase, we convert to the result coordinate
6270 system from the intermediate FK5 J2000 sky coordinates generated above. */
6271 if ( astOK && match && step4 ) {
6272
6273 /* To FK4. */
6274 /* ------- */
6275 /* Convert directly from FK5 J2000.0 to FK4 B1950.0 coordinates at the
6276 appropriate epoch. Then, if necessary, apply the old-style FK4
6277 precession model to bring the equinox to that required, with
6278 rigorous handling of the E-terms of aberration. */
6279 if ( system == AST__FK4 ) {
6280 VerifyMSMAttrs( target, result, 3, "Equinox Epoch", "astMatch", status );
6281 TRANSFORM_1( "FK54Z", epoch_B )
6282 if ( equinox_B != 1950.0 ) {
6283 TRANSFORM_1( "SUBET", 1950.0 )
6284 TRANSFORM_2( "PREBN", 1950.0, equinox_B )
6285 TRANSFORM_1( "ADDET", equinox_B )
6286 }
6287
6288 /* To FK4 with no E-terms. */
6289 /* ----------------------- */
6290 /* This is the same as above, except that we do not need to add the
6291 E-terms at the end. */
6292 } else if ( system == AST__FK4_NO_E ) {
6293 VerifyMSMAttrs( target, result, 3, "Equinox Epoch", "astMatch", status );
6294 TRANSFORM_1( "FK54Z", epoch_B )
6295 TRANSFORM_1( "SUBET", 1950.0 )
6296 if ( equinox_B != 1950.0 ) {
6297 TRANSFORM_2( "PREBN", 1950.0, equinox_B )
6298 }
6299
6300 /* To FK5. */
6301 /* ------- */
6302 /* We simply need to apply a precession correction for the change of
6303 equinox. Omit even this if the required equinox is J2000.0. */
6304 } else if ( system == AST__FK5 ) {
6305 VerifyMSMAttrs( target, result, 3, "Equinox", "astMatch", status );
6306 if ( equinox_J != 2000.0 ) {
6307 TRANSFORM_2( "PREC", 2000.0, equinox_J )
6308 }
6309
6310 /* To geocentric apparent. */
6311 /* ----------------------- */
6312 /* This conversion is supported directly by SLALIB. */
6313 } else if ( system == AST__GAPPT ) {
6314 VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status );
6315 TRANSFORM_2( "MAP", 2000.0, epoch )
6316
6317 /* To ecliptic coordinates. */
6318 /* ------------------------ */
6319 /* This conversion is supported directly by SLALIB. */
6320 } else if ( system == AST__ECLIPTIC ) {
6321 VerifyMSMAttrs( target, result, 3, "Equinox", "astMatch", status );
6322 TRANSFORM_1( "EQECL", equinox )
6323
6324 /* To helio-ecliptic coordinates. */
6325 /* ------------------------------ */
6326 } else if ( system == AST__HELIOECLIPTIC ) {
6327 VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status );
6328 TRANSFORM_1( "EQHE", epoch )
6329
6330 /* To galactic coordinates. */
6331 /* ------------------------ */
6332 /* This conversion is supported directly by SLALIB. */
6333 } else if ( system == AST__GALACTIC ) {
6334 TRANSFORM_0( "EQGAL" )
6335
6336 /* To ICRS. */
6337 /* -------- */
6338 /* This conversion is supported directly by SLALIB. */
6339 } else if ( system == AST__ICRS ) {
6340 VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status );
6341 TRANSFORM_1( "FK5HZ", epoch_J )
6342
6343 /* To J2000. */
6344 /* --------- */
6345 /* From FK5 to ICRS, then from ICRS to J2000. */
6346 } else if ( system == AST__J2000 ) {
6347 VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status );
6348 TRANSFORM_1( "FK5HZ", epoch_J )
6349 TRANSFORM_0( "HJ2000" )
6350
6351 /* To supergalactic coordinates. */
6352 /* ----------------------------- */
6353 /* Convert to galactic coordinates and then to supergalactic. */
6354 } else if ( system == AST__SUPERGALACTIC ) {
6355 TRANSFORM_0( "EQGAL" )
6356 TRANSFORM_0( "GALSUP" )
6357
6358 /* To AzEl */
6359 /* ------- */
6360 /* Go from FK5 J2000 to geocentric apparent (MAP), shift RA into hour angle
6361 (R2H), rotate from equator to horizon (E2H). */
6362 } else if ( system == AST__AZEL ) {
6363 VerifyMSMAttrs( target, result, 3, "ObsLon ObsLat Epoch", "astMatch", status );
6364 TRANSFORM_2( "MAP", 2000.0, epoch )
6365 TRANSFORM_1( "R2H", last )
6366 TRANSFORM_2( "E2H", lat, diurab )
6367
6368 /* To unknown coordinates. */
6369 /* ----------------------------- */
6370 /* No conversion is possible. */
6371 } else if ( system == AST__UNKNOWN ) {
6372 match = 0;
6373 }
6374 }
6375
6376 /* Now need to take account of the possibility that the input or output
6377 SkyFrame may represent an offset system rather than a coordinate system.
6378 Form the Mapping from the target coordinate system to the associated
6379 offset system. A UnitMap is returned if the target does not use an
6380 offset system. */
6381 omap = SkyOffsetMap( target, status );
6382
6383 /* Invert it to get the Mapping from the actual used system (whther
6384 offsets or coordinates) to the coordinate system. */
6385 astInvert( omap );
6386
6387 /* Combine it with the slamap created earlier, so that its coordinate
6388 outputs feed the inputs of the slamap. Annul redundant pointers
6389 afterwards. */
6390 tmap = (AstMapping *) astCmpMap( omap, slamap, 1, "", status );
6391 omap = astAnnul( omap );
6392 slamap =astAnnul( slamap );
6393
6394 /* Now form the Mapping from the result coordinate system to the associated
6395 offset system. A UnitMap is returned if the result does not use an
6396 offset system. */
6397 omap = SkyOffsetMap( result, status );
6398
6399 /* Combine it with the above CmpMap, so that the CmpMap outputs feed the
6400 new Mapping inputs. Annul redundant pointers afterwards. */
6401 tmap2 = (AstMapping *) astCmpMap( tmap, omap, 1, "", status );
6402 omap =astAnnul( omap );
6403 tmap =astAnnul( tmap );
6404
6405 /* Simplify the Mapping produced above (this eliminates any redundant
6406 conversions) and annul the original pointer. */
6407 *map = astSimplify( tmap2 );
6408 tmap2 = astAnnul( tmap2 );
6409
6410 /* If an error occurred, annul the returned Mapping and clear the
6411 returned values. */
6412 if ( !astOK ) {
6413 *map = astAnnul( *map );
6414 match = -1;
6415 }
6416
6417 /* Return the result. */
6418 return match;
6419
6420 /* Undefine macros local to this function. */
6421 #undef MAX_ARGS
6422 #undef TRANSFORM_0
6423 #undef TRANSFORM_1
6424 #undef TRANSFORM_2
6425 #undef TRANSFORM_3
6426 }
6427
Match(AstFrame * template_frame,AstFrame * target,int matchsub,int ** template_axes,int ** target_axes,AstMapping ** map,AstFrame ** result,int * status)6428 static int Match( AstFrame *template_frame, AstFrame *target, int matchsub,
6429 int **template_axes, int **target_axes, AstMapping **map,
6430 AstFrame **result, int *status ) {
6431 /*
6432 * Name:
6433 * Match
6434
6435 * Purpose:
6436 * Determine if conversion is possible between two coordinate systems.
6437
6438 * Type:
6439 * Private function.
6440
6441 * Synopsis:
6442 * #include "skyframe.h"
6443 * int Match( AstFrame *template, AstFrame *target, int matchsub,
6444 * int **template_axes, int **target_axes,
6445 * AstMapping **map, AstFrame **result, int *status )
6446
6447 * Class Membership:
6448 * SkyFrame member function (over-rides the protected astMatch method
6449 * inherited from the Frame class).
6450
6451 * Description:
6452 * This function matches a "template" SkyFrame to a "target" Frame and
6453 * determines whether it is possible to convert coordinates between them.
6454 * If it is, a mapping that performs the transformation is returned along
6455 * with a new Frame that describes the coordinate system that results when
6456 * this mapping is applied to the "target" coordinate system. In addition,
6457 * information is returned to allow the axes in this "result" Frame to be
6458 * associated with the corresponding axes in the "target" and "template"
6459 * Frames from which they are derived.
6460
6461 * Parameters:
6462 * template
6463 * Pointer to the template SkyFrame. This describes the coordinate system
6464 * (or set of possible coordinate systems) into which we wish to convert
6465 * our coordinates.
6466 * target
6467 * Pointer to the target Frame. This describes the coordinate system in
6468 * which we already have coordinates.
6469 * matchsub
6470 * If zero then a match only occurs if the template is of the same
6471 * class as the target, or of a more specialised class. If non-zero
6472 * then a match can occur even if this is not the case.
6473 * template_axes
6474 * Address of a location where a pointer to int will be returned if the
6475 * requested coordinate conversion is possible. This pointer will point
6476 * at a dynamically allocated array of integers with one element for each
6477 * axis of the "result" Frame (see below). It must be freed by the caller
6478 * (using astFree) when no longer required.
6479 *
6480 * For each axis in the result Frame, the corresponding element of this
6481 * array will return the index of the template SkyFrame axis from which
6482 * it is derived. If it is not derived from any template SkyFrame axis,
6483 * a value of -1 will be returned instead.
6484 * target_axes
6485 * Address of a location where a pointer to int will be returned if the
6486 * requested coordinate conversion is possible. This pointer will point
6487 * at a dynamically allocated array of integers with one element for each
6488 * axis of the "result" Frame (see below). It must be freed by the caller
6489 * (using astFree) when no longer required.
6490 *
6491 * For each axis in the result Frame, the corresponding element of this
6492 * array will return the index of the target Frame axis from which it
6493 * is derived. If it is not derived from any target Frame axis, a value
6494 * of -1 will be returned instead.
6495 * map
6496 * Address of a location where a pointer to a new Mapping will be
6497 * returned if the requested coordinate conversion is possible. If
6498 * returned, the forward transformation of this Mapping may be used to
6499 * convert coordinates between the "target" Frame and the "result"
6500 * Frame (see below) and the inverse transformation will convert in the
6501 * opposite direction.
6502 * result
6503 * Address of a location where a pointer to a new Frame will be returned
6504 * if the requested coordinate conversion is possible. If returned, this
6505 * Frame describes the coordinate system that results from applying the
6506 * returned Mapping (above) to the "target" coordinate system. In
6507 * general, this Frame will combine attributes from (and will therefore
6508 * be more specific than) both the target and the template Frames. In
6509 * particular, when the template allows the possibility of transformaing
6510 * to any one of a set of alternative coordinate systems, the "result"
6511 * Frame will indicate which of the alternatives was used.
6512 * status
6513 * Pointer to the inherited status variable.
6514
6515 * Returned Value:
6516 * A non-zero value is returned if the requested coordinate conversion is
6517 * possible. Otherwise zero is returned (this will not in itself result in
6518 * an error condition).
6519
6520 * Notes:
6521 * - A value of zero will be returned if this function is invoked with the
6522 * global error status set, or if it should fail for any reason.
6523
6524 * Implementation Notes:
6525 * This implementation addresses the matching of a SkyFrame class object to
6526 * any other class of Frame. A SkyFrame will match any class of SkyFrame
6527 * (i.e. possibly from a derived class) but will not match a less
6528 * specialised class of Frame.
6529 */
6530
6531 /* Local Variables: */
6532 AstFrame *frame0; /* Pointer to Frame underlying axis 0 */
6533 AstFrame *frame1; /* Pointer to Frame underlying axis 1 */
6534 AstSkyFrame *template; /* Pointer to template SkyFrame structure */
6535 int iaxis; /* Axis index */
6536 int iaxis0; /* Axis index underlying axis 0 */
6537 int iaxis1; /* Axis index underlying axis 1 */
6538 int match; /* Coordinate conversion possible? */
6539 int swap1; /* Template axes swapped? */
6540 int swap2; /* Target axes swapped? */
6541 int swap; /* Additional axis swap needed? */
6542 int target_axis0; /* Index of 1st SkyFrame axis in the target */
6543 int target_axis1; /* Index of 2nd SkyFrame axis in the target */
6544 int target_naxes; /* Number of target axes */
6545
6546 /* Initialise the returned values. */
6547 *template_axes = NULL;
6548 *target_axes = NULL;
6549 *map = NULL;
6550 *result = NULL;
6551 match = 0;
6552
6553 /* Check the global error status. */
6554 if ( !astOK ) return match;
6555
6556 /* Initialise variables to avoid "used of uninitialised variable"
6557 messages from dumb compilers. */
6558 swap = 0;
6559 target_axis0 = -1;
6560 target_axis1 = -1;
6561
6562 /* Obtain a pointer to the template SkyFrame structure. */
6563 template = (AstSkyFrame *) template_frame;
6564
6565 /* Obtain the number of axes in the target Frame. */
6566 target_naxes = astGetNaxes( target );
6567
6568 /* The first criterion for a match is that the template matches as a
6569 Frame class object. This ensures that the number of axes (2) and
6570 domain, etc. of the target Frame are suitable. Invoke the parent
6571 "astMatch" method to verify this. */
6572 match = (*parent_match)( template_frame, target, matchsub,
6573 template_axes, target_axes, map, result, status );
6574
6575 /* If a match was found, annul the returned objects, which are not
6576 needed, but keep the memory allocated for the axis association
6577 arrays, which we will re-use. */
6578 if ( astOK && match ) {
6579 *map = astAnnul( *map );
6580 *result = astAnnul( *result );
6581 }
6582
6583 /* If OK so far, obtain pointers to the primary Frames which underlie
6584 all target axes. Stop when a SkyFrame axis is found. */
6585 if ( match && astOK ) {
6586
6587 match = 0;
6588 for( iaxis = 0; iaxis < target_naxes; iaxis++ ) {
6589 astPrimaryFrame( target, iaxis, &frame0, &iaxis0 );
6590 if( astIsASkyFrame( frame0 ) ) {
6591 target_axis0 = iaxis;
6592 match = 1;
6593 break;
6594 } else {
6595 frame0 = astAnnul( frame0 );
6596 }
6597 }
6598
6599 /* Check at least one SkyFrame axis was found it the target. */
6600 if( match ) {
6601
6602 /* If so, search the remaining target axes for another axis that is
6603 derived from the same SkyFrame. */
6604 match = 0;
6605 for( iaxis++ ; iaxis < target_naxes; iaxis++ ) {
6606 astPrimaryFrame( target, iaxis, &frame1, &iaxis1 );
6607 if( frame1 == frame0 ) {
6608 target_axis1 = iaxis;
6609 frame1 = astAnnul( frame1 );
6610 match = 1;
6611 break;
6612 } else {
6613 frame1 = astAnnul( frame1 );
6614 }
6615 }
6616
6617 /* Annul the remaining Frame pointer used in the above tests. */
6618 frame0 = astAnnul( frame0 );
6619 }
6620
6621 /* If this test is passed, we can now test that the underlying axis indices
6622 are 0 and 1, in either order. This then ensures that we have a
6623 single SkyFrame (not a compound Frame) with both axes present. */
6624 if ( match && astOK ) {
6625 match = ( ( ( iaxis0 == 0 ) && ( iaxis1 == 1 ) ) ||
6626 ( ( iaxis1 == 0 ) && ( iaxis0 == 1 ) ) );
6627 }
6628
6629 }
6630
6631 /* If a possible match has been detected, we must now decide how the
6632 order of the axes in the result Frame relates to the order of axes
6633 in the target Frame. There are two factors involved. The first
6634 depends on whether the axis permutation array for the template
6635 SkyFrame (whose method we are executing) causes an axis
6636 reversal. Determine this by permuting axis index zero. */
6637 if ( astOK && match ) {
6638 swap1 = ( astValidateAxis( template, 0, 1, "astMatch" ) != 0 );
6639
6640 /* The second factor depends on whether the axes of the underlying
6641 primary SkyFrame are reversed when seen in the target Frame. */
6642 swap2 = ( iaxis0 != 0 );
6643
6644 /* Combine these to determine if an additional axis swap will be
6645 needed. */
6646 swap = ( swap1 != swap2 );
6647
6648 /* Now check to see if this additional swap is permitted by the
6649 template's Permute attribute. */
6650 match = ( !swap || astGetPermute( template ) );
6651 }
6652
6653 /* If the Frames still match, we next set up the axis association
6654 arrays. */
6655 if ( astOK && match ) {
6656
6657 /* If the target axis order is to be preserved, then the target axis
6658 association involves no permutation but the template axis
6659 association may involve an axis swap. */
6660 if ( astGetPreserveAxes( template ) ) {
6661 (*template_axes)[ 0 ] = swap;
6662 (*template_axes)[ 1 ] = !swap;
6663 (*target_axes)[ 0 ] = target_axis0;
6664 (*target_axes)[ 1 ] = target_axis1;
6665
6666 /* Otherwise, any swap applies to the target axis association
6667 instead. */
6668 } else {
6669 (*template_axes)[ 0 ] = 0;
6670 (*template_axes)[ 1 ] = 1;
6671 (*target_axes)[ 0 ] = swap ? target_axis1 : target_axis0;
6672 (*target_axes)[ 1 ] = swap ? target_axis0 : target_axis1;
6673 }
6674
6675 /* Use the target's "astSubFrame" method to create a new Frame (the
6676 result Frame) with copies of the target axes in the required
6677 order. This process also overlays the template attributes on to the
6678 target Frame and returns a Mapping between the target and result
6679 Frames which effects the required coordinate conversion. */
6680 match = astSubFrame( target, template, 2, *target_axes, *template_axes,
6681 map, result );
6682 }
6683
6684 /* If an error occurred, or conversion to the result Frame's
6685 coordinate system was not possible, then free all memory, annul the
6686 returned objects, and reset the returned value. */
6687 if ( !astOK || !match ) {
6688 *template_axes = astFree( *template_axes );
6689 *target_axes = astFree( *target_axes );
6690 if( *map ) *map = astAnnul( *map );
6691 if( *result ) *result = astAnnul( *result );
6692 match = 0;
6693 }
6694
6695 /* Return the result. */
6696 return match;
6697 }
6698
MatchAxesX(AstFrame * frm2_frame,AstFrame * frm1,int * axes,int * status)6699 static void MatchAxesX( AstFrame *frm2_frame, AstFrame *frm1, int *axes,
6700 int *status ) {
6701 /*
6702 * Name:
6703 * MatchAxesX
6704
6705 * Purpose:
6706 * Find any corresponding axes in two Frames.
6707
6708 * Type:
6709 * Private function.
6710
6711 * Synopsis:
6712 * #include "skyframe.h"
6713 * void MatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes )
6714 * int *status )
6715
6716 * Class Membership:
6717 * SkyFrame member function (over-rides the protected astMatchAxesX
6718 * method inherited from the Frame class).
6719
6720 * This function looks for corresponding axes within two supplied
6721 * Frames. An array of integers is returned that contains an element
6722 * for each axis in the second supplied Frame. An element in this array
6723 * will be set to zero if the associated axis within the second Frame
6724 * has no corresponding axis within the first Frame. Otherwise, it
6725 * will be set to the index (a non-zero positive integer) of the
6726 * corresponding axis within the first supplied Frame.
6727
6728 * Parameters:
6729 * frm2
6730 * Pointer to the second Frame.
6731 * frm1
6732 * Pointer to the first Frame.
6733 * axes
6734 * Pointer to an integer array in which to return the indices of
6735 * the axes (within the first Frame) that correspond to each axis
6736 * within the second Frame. Axis indices start at 1. A value of zero
6737 * will be stored in the returned array for each axis in the second
6738 * Frame that has no corresponding axis in the first Frame.
6739 *
6740 * The number of elements in this array must be greater than or
6741 * equal to the number of axes in the second Frame.
6742 * status
6743 * Pointer to inherited status value.
6744
6745 * Notes:
6746 * - Corresponding axes are identified by the fact that a Mapping
6747 * can be found between them using astFindFrame or astConvert. Thus,
6748 * "corresponding axes" are not necessarily identical. For instance,
6749 * SkyFrame axes in two Frames will match even if they describe
6750 * different celestial coordinate systems
6751 */
6752
6753 /* Local Variables: */
6754 AstFrame *resfrm;
6755 AstMapping *resmap;
6756 AstSkyFrame *frm2;
6757 int *frm2_axes;
6758 int *frm1_axes;
6759 int max_axes;
6760 int min_axes;
6761 int preserve_axes;
6762
6763 /* Check the global error status. */
6764 if ( !astOK ) return;
6765
6766 /* Get a pointer to the SkyFrame. */
6767 frm2 = (AstSkyFrame *) frm2_frame;
6768
6769 /* Temporarily ensure that the PreserveAxes attribute is non-zero in
6770 the first supplied Frame. This means thte result Frame returned by
6771 astMatch below will have the axis count and order of the target Frame
6772 (i.e. "pfrm"). */
6773 if( astTestPreserveAxes( frm1 ) ) {
6774 preserve_axes = astGetPreserveAxes( frm1 ) ? 1 : 0;
6775 } else {
6776 preserve_axes = -1;
6777 }
6778 astSetPreserveAxes( frm1, 1 );
6779
6780 /* Temporarily ensure that the MaxAxes and MinAxes attributes in the
6781 first supplied Frame are set so the Frame can be used as a template
6782 in astMatch for matching any number of axes. */
6783 if( astTestMaxAxes( frm1 ) ) {
6784 max_axes = astGetMaxAxes( frm1 );
6785 } else {
6786 max_axes = -1;
6787 }
6788 astSetMaxAxes( frm1, 10000 );
6789
6790 if( astTestMinAxes( frm1 ) ) {
6791 min_axes = astGetMinAxes( frm1 );
6792 } else {
6793 min_axes = -1;
6794 }
6795 astSetMinAxes( frm1, 1 );
6796
6797 /* Attempt to find a sub-frame within the first supplied Frame that
6798 corresponds to the supplied SkyFrame. */
6799 if( astMatch( frm1, frm2, 1, &frm1_axes, &frm2_axes, &resmap, &resfrm ) ) {
6800
6801 /* If successfull, Store the one-based index within "frm1" of the
6802 corresponding axes. */
6803 axes[ 0 ] = frm1_axes[ 0 ] + 1;
6804 axes[ 1 ] = frm1_axes[ 1 ] + 1;
6805
6806 /* Free resources */
6807 frm1_axes = astFree( frm1_axes );
6808 frm2_axes = astFree( frm2_axes );
6809 resmap = astAnnul( resmap );
6810 resfrm = astAnnul( resfrm );
6811
6812 /* If no corresponding SkyFrame was found store zeros in the returned array. */
6813 } else {
6814 axes[ 0 ] = 0;
6815 axes[ 1 ] = 0;
6816 }
6817
6818 /* Re-instate the original attribute values in the first supplied Frame. */
6819 if( preserve_axes == -1 ) {
6820 astClearPreserveAxes( frm1 );
6821 } else {
6822 astSetPreserveAxes( frm1, preserve_axes );
6823 }
6824
6825 if( max_axes == -1 ) {
6826 astClearMaxAxes( frm1 );
6827 } else {
6828 astSetMaxAxes( frm1, max_axes );
6829 }
6830
6831 if( min_axes == -1 ) {
6832 astClearMinAxes( frm1 );
6833 } else {
6834 astSetMinAxes( frm1, min_axes );
6835 }
6836 }
6837
Norm(AstFrame * this_frame,double value[],int * status)6838 static void Norm( AstFrame *this_frame, double value[], int *status ) {
6839 /*
6840 * Name:
6841 * Norm
6842
6843 * Purpose:
6844 * Normalise a set of SkyFrame coordinates.
6845
6846 * Type:
6847 * Private function.
6848
6849 * Synopsis:
6850 * #include "skyframe.h"
6851 * void Norm( AstAxis *this, double value[], int *status )
6852
6853 * Class Membership:
6854 * SkyFrame member function (over-rides the astNorm method inherited
6855 * from the Frame class).
6856
6857 * Description:
6858 * This function converts a set of SkyFrame coordinate values,
6859 * which might potentially be unsuitable for display to a user (for
6860 * instance, may lie outside the expected range of values) into a
6861 * set of acceptable alternative values suitable for display.
6862 *
6863 * This is done by wrapping coordinates so that the latitude lies
6864 * in the range (-pi/2.0) <= latitude <= (pi/2.0). If the NegLon
6865 * attribute is zero (the default), then the wrapped longitude value
6866 * lies in the range 0.0 <= longitude < (2.0*pi). Otherwise, it lies
6867 * in the range -pi <= longitude < pi.
6868
6869 * Parameters:
6870 * this
6871 * Pointer to the SkyFrame.
6872 * value
6873 * An array of double, with one element for each SkyFrame axis.
6874 * This should contain the initial set of coordinate values,
6875 * which will be modified in place.
6876 * status
6877 * Pointer to the inherited status variable.
6878 */
6879
6880 /* Local Variables: */
6881 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
6882 const int *perm; /* Axis permutation array */
6883 double sky_lat; /* Sky latitude value */
6884 double sky_long; /* Sky longitude value */
6885 double v[ 2 ]; /* Permuted value coordinates */
6886
6887 /* Check the global error status. */
6888 if ( !astOK ) return;
6889
6890 /* Obtain a pointer to the SkyFrame structure. */
6891 this = (AstSkyFrame *) this_frame;
6892
6893 /* Obtain a pointer to the SkyFrame's axis permutation array. */
6894 perm = astGetPerm( this );
6895 if ( astOK ) {
6896
6897 /* Obtain the sky longitude and latitude values, allowing for any axis
6898 permutation. */
6899 v[ perm[ 0 ] ] = value[ 0 ];
6900 v[ perm[ 1 ] ] = value[ 1 ];
6901 sky_long = v[ 0 ];
6902 sky_lat = v[ 1 ];
6903
6904 /* Test if both values are OK (i.e. not "bad"). */
6905 if ( ( sky_long != AST__BAD ) && ( sky_lat != AST__BAD ) ) {
6906
6907 /* Fold the longitude value into the range 0 to 2*pi and the latitude into
6908 the range -pi to +pi. */
6909 sky_long = palDranrm( sky_long );
6910 sky_lat = palDrange( sky_lat );
6911
6912 /* If the latitude now exceeds pi/2, shift the longitude by pi in whichever
6913 direction will keep it in the range 0 to 2*pi. */
6914 if ( sky_lat > ( pi / 2.0 ) ) {
6915 sky_long += ( sky_long < pi ) ? pi : -pi;
6916
6917 /* Reflect the latitude value through the pole, so it lies in the range 0 to
6918 pi/2. */
6919 sky_lat = pi - sky_lat;
6920
6921 /* If the latitude is less than -pi/2, shift the longitude in the same way
6922 as above. */
6923 } else if ( sky_lat < -( pi / 2.0 ) ) {
6924 sky_long += ( sky_long < pi ) ? pi : -pi;
6925
6926 /* But reflect the latitude through the other pole, so it lies in the range
6927 -pi/2 to 0. */
6928 sky_lat = -pi - sky_lat;
6929 }
6930
6931 /* If only the longitude value is valid, wrap it into the range 0 to 2*pi. */
6932 } else if ( sky_long != AST__BAD ) {
6933 sky_long = palDranrm( sky_long );
6934
6935 /* If only the latitude value is valid, wrap it into the range -pi to +pi. */
6936 } else if ( sky_lat != AST__BAD ) {
6937 sky_lat = palDrange( sky_lat );
6938
6939 /* Then refect through one of the poles (as above), if necessary, to move it
6940 into the range -pi/2 to +pi/2. */
6941 if ( sky_lat > ( pi / 2.0 ) ) {
6942 sky_lat = pi - sky_lat;
6943 } else if ( sky_lat < -( pi / 2.0 ) ) {
6944 sky_lat = -pi - sky_lat;
6945 }
6946 }
6947
6948 /* Convert 2*pi longitude into zero. Allow for a small error. */
6949 if ( fabs( sky_long - ( 2.0 * pi ) ) <=
6950 ( 2.0 * pi ) * ( DBL_EPSILON * (double) FLT_RADIX ) ) sky_long = 0.0;
6951
6952 /* If the NegLon attribute is set, and the longitude value is good,
6953 convert it into the range -pi to +pi. */
6954 if( sky_long != AST__BAD && astGetNegLon( this ) ) {
6955 sky_long = palDrange( sky_long );
6956 }
6957
6958 /* Return the new values, allowing for any axis permutation. */
6959 v[ 0 ] = sky_long;
6960 v[ 1 ] = sky_lat;
6961 value[ 0 ] = v[ perm[ 0 ] ];
6962 value[ 1 ] = v[ perm[ 1 ] ];
6963 }
6964 }
6965
NormBox(AstFrame * this_frame,double lbnd[],double ubnd[],AstMapping * reg,int * status)6966 static void NormBox( AstFrame *this_frame, double lbnd[], double ubnd[],
6967 AstMapping *reg, int *status ) {
6968 /*
6969 * Name:
6970 * NormBox
6971
6972 * Purpose:
6973 * Extend a box to include effect of any singularities in the Frame.
6974
6975 * Type:
6976 * Private function.
6977
6978 * Synopsis:
6979 * #include "skyframe.h"
6980 * void astNormBox( AstFrame *this, double lbnd[], double ubnd[],
6981 * AstMapping *reg, int *status )
6982
6983 * Class Membership:
6984 * SkyFrame member function (over-rides the astNormBox method inherited
6985 * from the Frame class).
6986
6987 * Description:
6988 * This function modifies a supplied box to include the effect of any
6989 * singularities in the co-ordinate system represented by the Frame.
6990 * For a normal Cartesian coordinate system, the box will be returned
6991 * unchanged. Other classes of Frame may do other things. For instance,
6992 * a SkyFrame will check to see if the box contains either the north
6993 * or south pole and extend the box appropriately.
6994
6995 * Parameters:
6996 * this
6997 * Pointer to the Frame.
6998 * lbnd
6999 * An array of double, with one element for each Frame axis
7000 * (Naxes attribute). Initially, this should contain a set of
7001 * lower axis bounds for the box. They will be modified on exit
7002 * to include the effect of any singularities within the box.
7003 * ubnd
7004 * An array of double, with one element for each Frame axis
7005 * (Naxes attribute). Initially, this should contain a set of
7006 * upper axis bounds for the box. They will be modified on exit
7007 * to include the effect of any singularities within the box.
7008 * reg
7009 * A Mapping which should be used to test if any singular points are
7010 * inside or outside the box. The Mapping should leave an input
7011 * position unchanged if the point is inside the box, and should
7012 * set all bad if the point is outside the box.
7013 * status
7014 * Pointer to the inherited status variable.
7015 */
7016
7017 /* Local Variables: */
7018 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
7019 const int *perm; /* Axis permutation array */
7020 double lb[ 2 ]; /* Permuted lower bounds */
7021 double t; /* Temporary storage */
7022 double t2; /* Temporary storage */
7023 double ub[ 2 ]; /* Permuted upper bounds */
7024 double x[2]; /* 1st axis values at poles */
7025 double xo[2]; /* Tested 1st axis values at poles */
7026 double y[2]; /* 2nd axis values at poles */
7027 double yo[2]; /* Tested 2nd axis values at poles */
7028
7029 /* Check the global error status. */
7030 if ( !astOK ) return;
7031
7032 /* Obtain a pointer to the SkyFrame structure. */
7033 this = (AstSkyFrame *) this_frame;
7034
7035 /* Obtain a pointer to the SkyFrame's axis permutation array. */
7036 perm = astGetPerm( this );
7037 if( perm ) {
7038
7039 /* Obtain the sky longitude and latitude limits, allowing for any axis
7040 permutation. */
7041 lb[ perm[ 0 ] ] = lbnd[ 0 ];
7042 lb[ perm[ 1 ] ] = lbnd[ 1 ];
7043 ub[ perm[ 0 ] ] = ubnd[ 0 ];
7044 ub[ perm[ 1 ] ] = ubnd[ 1 ];
7045
7046 /* Use the supplied Mapping to test if box includes either pole. */
7047 if( perm[ 0 ] == 0 ) {
7048 x[ 0 ] = 0.0;
7049 y[ 0 ] = AST__DPIBY2;
7050 x[ 1 ] = 0.0;
7051 y[ 1 ] = -AST__DPIBY2;
7052 } else {
7053 x[ 0 ] = AST__DPIBY2;
7054 y[ 0 ] = 0.0;
7055 x[ 1 ] = -AST__DPIBY2;
7056 y[ 1 ] = 0.0;
7057 }
7058 astTran2( reg, 2, x, y, 1, xo, yo );
7059
7060 /* If the box includes the north pole... */
7061 if( xo[ 0 ] != AST__BAD ) {
7062
7063 /* Find the lowest latitude after normalisation. */
7064 if( ub[ 1 ] != AST__BAD && lb[ 1 ] != AST__BAD ){
7065 t = palDrange( ub[ 1 ] );
7066 t2 = palDrange( lb[ 1 ] );
7067 if( t2 < t ) t = t2;
7068 } else {
7069 t = AST__BAD;
7070 }
7071
7072 /* Set the lower returned limit to this value and the upper returned limit
7073 to +90 degs */
7074 lb[ 1 ] = t;
7075 ub[ 1 ] = AST__DPIBY2;
7076
7077 /* Set the longitude range to 0 to 2PI */
7078 lb[ 0 ] = 0;
7079 ub[ 0 ] = 2*AST__DPI;
7080
7081 }
7082
7083 /* If the box includes the south pole... */
7084 if( xo[ 1 ] != AST__BAD ) {
7085
7086 /* Find the highest latitude after normalisation. */
7087 if( ub[ 1 ] != AST__BAD && lb[ 1 ] != AST__BAD ){
7088 t = palDrange( ub[ 1 ] );
7089 t2 = palDrange( lb[ 1 ] );
7090 if( t2 > t ) t = t2;
7091 } else {
7092 t = AST__BAD;
7093 }
7094
7095 /* Set the upper returned limit to this value and the lower returned limit
7096 to -90 degs */
7097 lb[ 1 ] = -AST__DPIBY2;
7098 ub[ 1 ] = t;
7099
7100 /* Set the longitude range to 0 to 2PI */
7101 lb[ 0 ] = 0;
7102 ub[ 0 ] = 2*AST__DPI;
7103 }
7104
7105 /* Return the modified limits. */
7106 lbnd[ 0 ] = lb[ perm[ 0 ] ];
7107 lbnd[ 1 ] = lb[ perm[ 1 ] ];
7108 ubnd[ 0 ] = ub[ perm[ 0 ] ];
7109 ubnd[ 1 ] = ub[ perm[ 1 ] ];
7110 }
7111 }
7112
Offset(AstFrame * this_frame,const double point1[],const double point2[],double offset,double point3[],int * status)7113 static void Offset( AstFrame *this_frame, const double point1[],
7114 const double point2[], double offset, double point3[], int *status ) {
7115 /*
7116 * Name:
7117 * Offset
7118
7119 * Purpose:
7120 * Calculate an offset along a geodesic curve.
7121
7122 * Type:
7123 * Private function.
7124
7125 * Synopsis:
7126 * #include "skyframe.h"
7127 * void Offset( AstFrame *this,
7128 * const double point1[], const double point2[],
7129 * double offset, double point3[], int *status )
7130
7131 * Class Membership:
7132 * SkyFrame member function (over-rides the astOffset method
7133 * inherited from the Frame class).
7134
7135 * Description:
7136 * This function finds the SkyFrame coordinate values of a point
7137 * which is offset a specified distance along the geodesic curve
7138 * (i.e. great circle) between two other points.
7139
7140 * Parameters:
7141 * this
7142 * Pointer to the SkyFrame.
7143 * point1
7144 * An array of double, with one element for each SkyFrame axis.
7145 * This should contain the coordinates of the point marking the
7146 * start of the geodesic curve.
7147 * point2
7148 * An array of double, with one element for each SkyFrame axis.
7149 * This should contain the coordinates of the point marking the
7150 * end of the geodesic curve.
7151 * offset
7152 * The required offset from the first point along the geodesic
7153 * curve, in radians. If this is positive, it will be towards
7154 * the second point. If it is negative, it will be in the
7155 * opposite direction. This offset need not imply a position
7156 * lying between the two points given, as the curve will be
7157 * extrapolated if necessary.
7158 * point3
7159 * An array of double, with one element for each SkyFrame axis
7160 * in which the coordinates of the required point will be
7161 * returned.
7162 * status
7163 * Pointer to the inherited status variable.
7164
7165 * Notes:
7166 * - The geodesic curve used by this function is the path of
7167 * shortest distance between two points, as defined by the
7168 * astDistance function.
7169 * - This function will return "bad" coordinate values (AST__BAD)
7170 * if any of the input coordinates has this value.
7171 * - "Bad" coordinate values will also be returned if the two
7172 * points supplied are coincident (or otherwise fail to uniquely
7173 * specify a geodesic curve) but the requested offset is non-zero.
7174 */
7175
7176 /* Local Variables: */
7177 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
7178 const int *perm; /* Pointer to axis permutation array */
7179 double mrot[ 3 ][ 3 ]; /* Rotation matrix */
7180 double p1[ 2 ]; /* Permuted coordinates for point1 */
7181 double p2[ 2 ]; /* Permuted coordinates for point2 */
7182 double p3[ 2 ]; /* Permuted coordinates for point3 */
7183 double scale; /* Scale factor */
7184 double v1[ 3 ]; /* 3-vector for p1 */
7185 double v2[ 3 ]; /* 3-vector for p2 */
7186 double v3[ 3 ]; /* 3-vector for p3 */
7187 double vmod; /* Modulus of vector */
7188 double vrot[ 3 ]; /* Vector along rotation axis */
7189
7190 /* Check the global error status. */
7191 if ( !astOK ) return;
7192
7193 /* Obtain a pointer to the SkyFrame structure. */
7194 this = (AstSkyFrame *) this_frame;
7195
7196 /* Obtain a pointer to the SkyFrame's axis permutation array. */
7197 perm = astGetPerm( this );
7198 if ( astOK ) {
7199
7200 /* Check that all supplied coordinates are OK. If not, generate "bad"
7201 output coordinates. */
7202 if ( ( point1[ 0 ] == AST__BAD ) || ( point1[ 1 ] == AST__BAD ) ||
7203 ( point2[ 0 ] == AST__BAD ) || ( point2[ 1 ] == AST__BAD ) ) {
7204 point3[ 0 ] = AST__BAD;
7205 point3[ 1 ] = AST__BAD;
7206
7207 /* Otherwise, apply the axis permutation array to obtain the
7208 coordinates of the two input points in the required
7209 (longitude,latitude) order. */
7210 } else {
7211 p1[ perm[ 0 ] ] = point1[ 0 ];
7212 p1[ perm[ 1 ] ] = point1[ 1 ];
7213 p2[ perm[ 0 ] ] = point2[ 0 ];
7214 p2[ perm[ 1 ] ] = point2[ 1 ];
7215
7216 /* Convert each point into a 3-vector of unit length. */
7217 palDcs2c( p1[ 0 ], p1[ 1 ], v1 );
7218 palDcs2c( p2[ 0 ], p2[ 1 ], v2 );
7219
7220 /* Find the cross product between these two vectors (the vector order
7221 is reversed here to compensate for the sense of rotation introduced
7222 by palDav2m and palDmxv below). */
7223 palDvxv( v2, v1, v3 );
7224
7225 /* Normalise the cross product vector, also obtaining its original
7226 modulus. */
7227 palDvn( v3, vrot, &vmod );
7228
7229 /* If the original modulus was zero, the input points are either
7230 coincident or diametrically opposite, so do not uniquely define a
7231 great circle. In either case, we can only generate output
7232 coordinates if the offset required is an exact multiple of pi. If
7233 it is, generate the 3-vector that results from rotating the first
7234 input point through this angle. */
7235 if ( vmod == 0.0 ) {
7236 if ( sin( offset ) == 0.0 ) {
7237 scale = cos( offset );
7238 v3[ 0 ] = v1[ 0 ] * scale;
7239 v3[ 1 ] = v1[ 1 ] * scale;
7240 v3[ 2 ] = v1[ 2 ] * scale;
7241
7242 /* Convert the 3-vector back into spherical cooordinates and then
7243 constrain the longitude result to lie in the range 0 to 2*pi
7244 (palDcc2s doesn't do this itself). */
7245 palDcc2s( v3, &p3[ 0 ], &p3[ 1 ] );
7246 p3[ 0 ] = palDranrm( p3[ 0 ] );
7247
7248 /* If the offset was not a multiple of pi, generate "bad" output
7249 coordinates. */
7250 } else {
7251 p3[ 0 ] = AST__BAD;
7252 p3[ 1 ] = AST__BAD;
7253 }
7254
7255 /* If the two input points define a great circle, scale the normalised
7256 cross product vector to make its length equal to the required
7257 offset (angle) between the first input point and the result. */
7258 } else {
7259 vrot[ 0 ] *= offset;
7260 vrot[ 1 ] *= offset;
7261 vrot[ 2 ] *= offset;
7262
7263 /* Generate the rotation matrix that implements this rotation and use
7264 it to rotate the first input point (3-vector) to give the required
7265 result (3-vector). */
7266 palDav2m( vrot, mrot );
7267 palDmxv( mrot, v1, v3 );
7268
7269 /* Convert the 3-vector back into spherical cooordinates and then
7270 constrain the longitude result to lie in the range 0 to 2*pi. */
7271 palDcc2s( v3, &p3[ 0 ], &p3[ 1 ] );
7272 p3[ 0 ] = palDranrm( p3[ 0 ] );
7273 }
7274
7275 /* Permute the result coordinates to undo the effect of the SkyFrame
7276 axis permutation array. */
7277 point3[ 0 ] = p3[ perm[ 0 ] ];
7278 point3[ 1 ] = p3[ perm[ 1 ] ];
7279 }
7280 }
7281 }
7282
SkyOffsetMap(AstSkyFrame * this,int * status)7283 static AstMapping *SkyOffsetMap( AstSkyFrame *this, int *status ){
7284 /*
7285 *++
7286 * Name:
7287 c astSkyOffsetMap
7288 f AST_SKYOFFSETMAP
7289
7290 * Purpose:
7291 * Returns a Mapping which goes from absolute coordinates to offset
7292 * coordinates.
7293
7294 * Type:
7295 * Public virtual function.
7296
7297 * Synopsis:
7298 c #include "skyframe.h"
7299 c AstMapping *astSkyOffsetMap( AstSkyFrame *this )
7300 f RESULT = AST_SKYOFFSETMAP( THIS, STATUS )
7301
7302 * Class Membership:
7303 * SkyFrame method.
7304
7305 * Description:
7306 * This function returns a Mapping in which the forward transformation
7307 * transforms a position in the coordinate system given by the System
7308 * attribute of the supplied SkyFrame, into the offset coordinate system
7309 * specified by the SkyRef, SkyRefP and SkyRefIs attributes of the
7310 * supplied SkyFrame.
7311 *
7312 * A UnitMap is returned if the SkyFrame does not define an offset
7313 * coordinate system.
7314
7315 * Parameters:
7316 c this
7317 f THIS = INTEGER (Given)
7318 * Pointer to the SkyFrame.
7319 f STATUS = INTEGER (Given and Returned)
7320 f The global status.
7321
7322 * Returned Value:
7323 c astSkyOffsetMap()
7324 f AST_SKYOFFSETMAP = INTEGER
7325 * Pointer to the returned Mapping.
7326
7327 * Notes:
7328 * - A null Object pointer (AST__NULL) will be returned if this
7329 c function is invoked with the AST error status set, or if it
7330 f function is invoked with STATUS set to an error value, or if it
7331 * should fail for any reason.
7332 *--
7333 */
7334
7335 /* Local Variables: */
7336 AstCmpMap *map3; /* Partial Mapping. */
7337 AstMapping *result; /* The returned Mapping. */
7338 AstMatrixMap *map1; /* Spherical rotation in 3D cartesian space */
7339 AstSphMap *map2; /* 3D Cartesian to 2D spherical Mapping */
7340 double *vx; /* Pointer to x unit vector. */
7341 double *vy; /* Pointer to y unit vector. */
7342 double *vz; /* Pointer to z unit vector. */
7343 double mat[ 9 ]; /* Spherical rotation matrix */
7344 double vmod; /* Length of vector (+ve) */
7345 double vp[ 3 ]; /* Unit vector representin SkyRefP position. */
7346 int lataxis; /* Index of the latitude axis */
7347 int lonaxis; /* Index of the longitude axis */
7348
7349 /* Initialise. */
7350 result = NULL;
7351
7352 /* Check the global error status. */
7353 if ( !astOK ) return result;
7354
7355 /* Return a UnitMap if the offset coordinate system is not defined. */
7356 if( astGetSkyRefIs( this ) == AST__IGNORED_REF ||
7357 ( !astTestSkyRef( this, 0 ) && !astTestSkyRef( this, 1 ) ) ) {
7358 result = (AstMapping *) astUnitMap( 2, "", status );
7359
7360 /* Otherwise... */
7361 } else {
7362
7363 /* Get the longitude and latitude at the reference point and at a point
7364 on the primary meridian. */
7365 lataxis = astGetLatAxis( this );
7366 lonaxis = 1 - lataxis;
7367
7368 /* Initialise pointers to the rows of the 3x3 matrix. Each row will be
7369 used to store a unit vector. */
7370 vx = mat;
7371 vy = mat + 3;
7372 vz = mat + 6;
7373
7374 /* The following trig converts between (longitude,latitude) and (x,y,z)
7375 on a unit sphere, in which (0,0) is at (1,0,0), (0,pi/2) is (0,0,1)
7376 and (pi/2,0) is at (0,1,0). */
7377
7378 /* First deal with cases where the SkyRef attribute holds the standard
7379 coords at the origin of the offset coordinate system. */
7380 if( astGetSkyRefIs( this ) == AST__ORIGIN_REF ) {
7381
7382 /* Convert each point into a 3-vector of unit length. The SkyRef position
7383 defines the X axis in the offset coord system. */
7384 palDcs2c( astGetSkyRef( this, lonaxis ), astGetSkyRef( this, lataxis ), vx );
7385 palDcs2c( astGetSkyRefP( this, lonaxis ), astGetSkyRefP( this, lataxis ), vp );
7386
7387 /* The Y axis is perpendicular to both the X axis and the skyrefp
7388 position. That is, it is parallel to the cross product of the 2 above
7389 vectors.*/
7390 palDvxv( vp, vx, vy );
7391
7392 /* Normalize the y vector. */
7393 palDvn( vy, vy, &vmod );
7394
7395 /* Report an error if the modulus of the vector is zero.*/
7396 if( vmod == 0.0 ) {
7397 astError( AST__BADOC, "astConvert(%s): The position specified by the SkyRefP "
7398 "attribute is either coincident, with or opposite to, the "
7399 "position specified by the SkyRef attribute.", status, astGetClass( this ) );
7400
7401 /* If OK, form the Z axis as the cross product of the x and y axes. */
7402 } else {
7403 palDvxv( vx, vy, vz );
7404
7405 }
7406
7407 /* Now deal with cases where the SkyRef attribute holds the standard
7408 coords at the north pole of the offset coordinate system. */
7409 } else {
7410
7411 /* Convert each point into a 3-vector of unit length. The SkyRef position
7412 defines the Z axis in the offset coord system. */
7413 palDcs2c( astGetSkyRef( this, lonaxis ), astGetSkyRef( this, lataxis ), vz );
7414 palDcs2c( astGetSkyRefP( this, lonaxis ), astGetSkyRefP( this, lataxis ), vp );
7415
7416 /* The Y axis is perpendicular to both the Z axis and the skyrefp
7417 position. That is, it is parallel to the cross product of the 2 above
7418 vectors.*/
7419 palDvxv( vz, vp, vy );
7420
7421 /* Normalize the y vector. */
7422 palDvn( vy, vy, &vmod );
7423
7424 /* Report an error if the modulus of the vector is zero.*/
7425 if( vmod == 0.0 ) {
7426 astError( AST__BADOC, "astConvert(%s): The position specified by the SkyRefP "
7427 "attribute is either coincident, with or opposite to, the "
7428 "position specified by the SkyRef attribute.", status, astGetClass( this ) );
7429
7430 /* If OK, form the X axis as the cross product of the y and z axes. */
7431 } else {
7432 palDvxv( vy, vz, vx );
7433 }
7434 }
7435
7436 /* Create a MatrixMap which implements the above spherical rotation. Each
7437 row in this matrix represents one of the unit axis vectors found above. */
7438 map1 = astMatrixMap( 3, 3, 0, mat, "", status );
7439
7440 /* Create a 3D cartesian to 2D spherical Mapping. */
7441 map2 = astSphMap( "UnitRadius=1", status );
7442
7443 /* Form a series CmpMap which converts from 2D (long,lat) in the base
7444 System to 2D (long,lat) in the offset coordinate system. */
7445 map3 = astCmpMap( map1, map2, 1, "", status );
7446 astInvert( map2 );
7447 result = (AstMapping *) astCmpMap( map2, map3, 1, "", status );
7448
7449 /* Free resources. */
7450 map1 = astAnnul( map1 );
7451 map2 = astAnnul( map2 );
7452 map3 = astAnnul( map3 );
7453 }
7454
7455 /* Annul the returned Mapping if anything has gone wrong. */
7456 if( !astOK ) result = astAnnul( result );
7457
7458 /* Return the result. */
7459 return result;
7460
7461 }
7462
Offset2(AstFrame * this_frame,const double point1[2],double angle,double offset,double point2[2],int * status)7463 static double Offset2( AstFrame *this_frame, const double point1[2],
7464 double angle, double offset, double point2[2], int *status ) {
7465 /*
7466 * Name:
7467 * Offset2
7468
7469 * Purpose:
7470 * Calculate an offset along a geodesic curve at a given bearing.
7471
7472 * Type:
7473 * Private function.
7474
7475 * Synopsis:
7476 * #include "skyframe.h"
7477 * double Offset2( AstFrame *this_frame, const double point1[2],
7478 * double angle, double offset, double point2[2], int *status )
7479
7480 * Class Membership:
7481 * SkyFrame member function (over-rides the astOffset2 method
7482 * inherited from the Frame class).
7483
7484 * Description:
7485 * This function finds the SkyFrame coordinate values of a point
7486 * which is offset a specified distance along the geodesic curve
7487 * (i.e. great circle) at a given angle from a given starting point.
7488
7489 * Parameters:
7490 * this
7491 * Pointer to the SkyFrame.
7492 * point1
7493 * An array of double, with one element for each SkyFrame axis.
7494 * This should contain the coordinates of the point marking the
7495 * start of the geodesic curve.
7496 * angle
7497 * The angle (in radians) from the positive direction of the second
7498 * axis, to the direction of the required position, as seen from
7499 * the starting position. Positive rotation is in the sense of
7500 * rotation from the positive direction of axis 2 to the positive
7501 * direction of axis 1.
7502 * offset
7503 * The required offset from the first point along the geodesic
7504 * curve, in radians. If this is positive, it will be towards
7505 * the given angle. If it is negative, it will be in the
7506 * opposite direction.
7507 * point2
7508 * An array of double, with one element for each SkyFrame axis
7509 * in which the coordinates of the required point will be
7510 * returned.
7511 * status
7512 * Pointer to the inherited status variable.
7513
7514 * Returned Value:
7515 * The direction of the geodesic curve at the end point. That is, the
7516 * angle (in radians) between the positive direction of the second
7517 * axis and the continuation of the geodesic curve at the requested
7518 * end point. Positive rotation is in the sense of rotation from
7519 * the positive direction of axis 2 to the positive direction of axis
7520 * 1.
7521
7522 * Notes:
7523 * - The geodesic curve used by this function is the path of
7524 * shortest distance between two points, as defined by the
7525 * astDistance function.
7526 * - This function will return "bad" coordinate values (AST__BAD)
7527 * if any of the input coordinates has this value.
7528 */
7529
7530 /* Local Variables: */
7531 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
7532 const int *perm; /* Pointer to axis permutation array */
7533 double p1[ 2 ]; /* Permuted coordinates for point1 */
7534 double p2[ 2 ]; /* Permuted coordinates for point2 */
7535 double result; /* The returned answer */
7536 double cosoff; /* Cosine of offset */
7537 double cosa1; /* Cosine of longitude at start */
7538 double cosb1; /* Cosine of latitude at start */
7539 double pa; /* A position angle measured from north */
7540 double q1[ 3 ]; /* Vector PI/2 away from R4 in meridian of R4 */
7541 double q2[ 3 ]; /* Vector PI/2 away from R4 on equator */
7542 double q3[ 3 ]; /* Vector PI/2 away from R4 on great circle */
7543 double r0[ 3 ]; /* Reference position vector */
7544 double r3[ 3 ]; /* Vector PI/2 away from R0 on great circle */
7545 double sinoff; /* Sine of offset */
7546 double sina1; /* Sine of longitude at start */
7547 double sinb1; /* Sine of latitude at start */
7548
7549 /* Initialise. */
7550 result = AST__BAD;
7551
7552 /* Check the global error status. */
7553 if ( !astOK ) return result;
7554
7555 /* Obtain a pointer to the SkyFrame structure. */
7556 this = (AstSkyFrame *) this_frame;
7557
7558 /* Obtain a pointer to the SkyFrame's axis permutation array. */
7559 perm = astGetPerm( this );
7560 if ( astOK ) {
7561
7562 /* Check that all supplied values are OK. If not, generate "bad"
7563 output coordinates. */
7564 if ( ( point1[ 0 ] == AST__BAD ) || ( point1[ 1 ] == AST__BAD ) ||
7565 ( angle == AST__BAD ) || ( offset == AST__BAD ) ) {
7566 point2[ 0 ] = AST__BAD;
7567 point2[ 1 ] = AST__BAD;
7568
7569 /* Otherwise, apply the axis permutation array to obtain the
7570 coordinates of the starting point in the required (longitude,latitude)
7571 order. */
7572 } else {
7573 p1[ perm[ 0 ] ] = point1[ 0 ];
7574 p1[ perm[ 1 ] ] = point1[ 1 ];
7575
7576 /* If the axes are permuted, convert the supplied angle into a position
7577 angle. */
7578 pa = ( perm[ 0 ] == 0 )? angle: piby2 - angle;
7579
7580 /* Use Shcal to calculate the required vectors R0 (representing
7581 the reference point) and R3 (representing the point which is 90
7582 degrees away from the reference point, along the required great
7583 circle). The XY plane defines zero latitude, Z is in the direction
7584 of increasing latitude, X is towards zero longitude, and Y is
7585 towards longitude 90 degrees. */
7586 Shcal( p1[ 0 ], p1[ 1 ], pa, r0, r3, status );
7587
7588 /* Use Shapp to use R0 and R3 to calculate the new position. */
7589 Shapp( offset, r0, r3, p1[ 0 ], p2, status );
7590
7591 /* Normalize the result. */
7592 astNorm( this, p2 );
7593
7594 /* Create the vector Q1 representing the point in the meridian of the
7595 required point which has latitude 90 degrees greater than the
7596 required point. */
7597 sina1 = sin( p2[ 0 ] );
7598 cosa1 = cos( p2[ 0 ] );
7599 sinb1 = sin( p2[ 1 ] );
7600 cosb1 = cos( p2[ 1 ] );
7601
7602 q1[ 0 ] = -sinb1*cosa1;
7603 q1[ 1 ] = -sinb1*sina1;
7604 q1[ 2 ] = cosb1;
7605
7606 /* Create the vector Q2 representing the point on the equator (i.e. a
7607 latitude of zero), which has a longitude 90 degrees to the west of
7608 the required point. */
7609 q2[ 0 ] = -sina1;
7610 q2[ 1 ] = cosa1;
7611 q2[ 2 ] = 0.0;
7612
7613 /* Create the vector Q3 representing the point which is 90 degrees away
7614 from the required point, along the required great circle. */
7615 cosoff = cos( offset );
7616 sinoff = sin( offset );
7617
7618 q3[ 0 ] = -sinoff*r0[ 0 ] + cosoff*r3[ 0 ];
7619 q3[ 1 ] = -sinoff*r0[ 1 ] + cosoff*r3[ 1 ];
7620 q3[ 2 ] = -sinoff*r0[ 2 ] + cosoff*r3[ 2 ];
7621
7622 /* Calculate the position angle of the great circle at the required
7623 point. */
7624 pa = atan2( palDvdv( q3, q2 ), palDvdv( q3, q1 ) );
7625
7626 /* Convert this from a pa into the required angle. */
7627 result = ( perm[ 0 ] == 0 )? pa: piby2 - pa;
7628
7629 /* Ensure that the end angle is in the range 0 to 2*pi. */
7630 result = palDranrm( result );
7631
7632 /* Permute the result coordinates to undo the effect of the SkyFrame
7633 axis permutation array. */
7634 point2[ 0 ] = p2[ perm[ 0 ] ];
7635 point2[ 1 ] = p2[ perm[ 1 ] ];
7636 }
7637 }
7638
7639 /* Return the result. */
7640 return result;
7641
7642 }
7643
Overlay(AstFrame * template,const int * template_axes,AstFrame * result,int * status)7644 static void Overlay( AstFrame *template, const int *template_axes,
7645 AstFrame *result, int *status ) {
7646 /*
7647 * Name:
7648 * Overlay
7649
7650 * Purpose:
7651 * Overlay the attributes of a template SkyFrame on to another Frame.
7652
7653 * Type:
7654 * Private function.
7655
7656 * Synopsis:
7657 * #include "skyframe.h"
7658 * void Overlay( AstFrame *template, const int *template_axes,
7659 * AstFrame *result, int *status )
7660
7661 * Class Membership:
7662 * SkyFrame member function (over-rides the protected astOverlay method
7663 * inherited from the Frame class).
7664
7665 * Description:
7666 * This function overlays attributes of a SkyFrame (the "template") on to
7667 * another Frame, so as to over-ride selected attributes of that second
7668 * Frame. Normally only those attributes which have been specifically set
7669 * in the template will be transferred. This implements a form of
7670 * defaulting, in which a Frame acquires attributes from the template, but
7671 * retains its original attributes (as the default) if new values have not
7672 * previously been explicitly set in the template.
7673 *
7674 * Note that if the result Frame is a SkyFrame and a change of sky
7675 * coordinate system occurs as a result of overlaying its System
7676 * attribute, then some of its original attribute values may no
7677 * longer be appropriate (e.g. the Title, or attributes describing
7678 * its axes). In this case, these will be cleared before overlaying
7679 * any new values.
7680
7681 * Parameters:
7682 * template
7683 * Pointer to the template SkyFrame, for which values should have been
7684 * explicitly set for any attribute which is to be transferred.
7685 * template_axes
7686 * Pointer to an array of int, with one element for each axis of the
7687 * "result" Frame (see below). For each axis in the result frame, the
7688 * corresponding element of this array should contain the (zero-based)
7689 * index of the template axis to which it corresponds. This array is used
7690 * to establish from which template axis any axis-dependent attributes
7691 * should be obtained.
7692 *
7693 * If any axis in the result Frame is not associated with a template
7694 * axis, the corresponding element of this array should be set to -1.
7695 *
7696 * If a NULL pointer is supplied, the template and result axis
7697 * indicies are assumed to be identical.
7698 * result
7699 * Pointer to the Frame which is to receive the new attribute values.
7700 * status
7701 * Pointer to the inherited status variable.
7702
7703 * Returned Value:
7704 * void
7705
7706 * Notes:
7707 * - In general, if the result Frame is not from the same class as the
7708 * template SkyFrame, or from a class derived from it, then attributes may
7709 * exist in the template SkyFrame which do not exist in the result Frame. In
7710 * this case, these attributes will not be transferred.
7711 */
7712
7713
7714 /* Local Variables: */
7715 AstSystemType new_alignsystem;/* Code identifying new alignment coords */
7716 AstSystemType new_system; /* Code identifying new sky cordinates */
7717 AstSystemType old_system; /* Code identifying old sky coordinates */
7718 int axis; /* Loop counter for result SkyFrame axes */
7719 int skyref_changed; /* Has the SkyRef attribute changed? */
7720 int reset_system; /* Was the template System value cleared? */
7721 int skyframe; /* Result Frame is a SkyFrame? */
7722 int tax0; /* Template axis for result axis 0 */
7723 int tax1; /* Template axis for result axis 1 */
7724
7725 /* Check the global error status. */
7726 if ( !astOK ) return;
7727
7728 /* Indicate that we do not need to reset the System attribute of the
7729 template. */
7730 reset_system = 0;
7731 new_system = AST__UNKNOWN;
7732
7733 /* If the result Frame is a SkyFrame, we must test to see if overlaying its
7734 System attribute will change the type of sky coordinate system it
7735 describes. Determine the value of this attribute for the result and template
7736 SkyFrames. We also need to do this if either SkyRef attribute would
7737 change. */
7738 skyframe = astIsASkyFrame( result );
7739 if ( skyframe ) {
7740 old_system = astGetSystem( result );
7741 new_system = astGetSystem( template );
7742 skyref_changed = ( astGetSkyRef( result, 0 ) !=
7743 astGetSkyRef( template, 0 ) ) ||
7744 ( astGetSkyRef( result, 1 ) !=
7745 astGetSkyRef( template, 1 ) );
7746
7747 /* If the coordinate system will change, any value already set for the result
7748 SkyFrame's Title will no longer be appropriate, so clear it. */
7749 if ( new_system != old_system || skyref_changed ) {
7750 astClearTitle( result );
7751
7752 /* Test if the old and new sky coordinate systems are similar enough to make
7753 use of the same axis attribute values (e.g. if they are both equatorial
7754 systems, then they can both use the same axis labels, etc.,so long as
7755 the SKyRefIs value has not changed). */
7756 if ( IsEquatorial( new_system, status ) != IsEquatorial( old_system, status ) ||
7757 skyref_changed ) {
7758
7759 /* If necessary, clear inappropriate values for all those axis attributes
7760 whose access functions are over-ridden by this class (these access functions
7761 will then provide suitable defaults appropriate to the new coordinate system
7762 instead). */
7763 for ( axis = 0; axis < 2; axis++ ) {
7764 astClearAsTime( result, axis );
7765 astClearDirection( result, axis );
7766 astClearFormat( result, axis );
7767 astClearLabel( result, axis );
7768 astClearSymbol( result, axis );
7769 astClearUnit( result, axis );
7770 }
7771 }
7772 }
7773
7774 /* If the result Frame is not a SkyFrame, we must temporarily clear the
7775 System and AlignSystem values since the values used by this class are only
7776 appropriate to this class. */
7777 } else {
7778 if( astTestSystem( template ) ) {
7779 new_system = astGetSystem( template );
7780 astClearSystem( template );
7781 new_alignsystem = astGetAlignSystem( template );
7782 astClearAlignSystem( template );
7783 reset_system = 1;
7784 }
7785 }
7786
7787 /* Invoke the parent class astOverlay method to transfer attributes inherited
7788 from the parent class. */
7789 (*parent_overlay)( template, template_axes, result, status );
7790
7791 /* Reset the System and AlignSystem values if necessary */
7792 if( reset_system ) {
7793 astSetSystem( template, new_system );
7794 astSetAlignSystem( template, new_alignsystem );
7795 }
7796
7797 /* Check if the result Frame is a SkyFrame or from a class derived from
7798 SkyFrame. If not, we cannot transfer SkyFrame attributes to it as it is
7799 insufficiently specialised. In this case simply omit these attributes. */
7800 if ( skyframe && astOK ) {
7801
7802 /* Define a macro that tests whether an attribute is set in the template and,
7803 if so, transfers its value to the result. */
7804 #define OVERLAY(attr) \
7805 if ( astTest##attr( template ) ) { \
7806 astSet##attr( result, astGet##attr( template ) ); \
7807 }
7808
7809 /* Store template axis indices */
7810 if( template_axes ) {
7811 tax0 = template_axes[ 0 ];
7812 tax1 = template_axes[ 1 ];
7813 } else {
7814 tax0 = 0;
7815 tax1 = 1;
7816 }
7817
7818 /* Define a similar macro that does the same for SkyFrame specific axis
7819 attributes. */
7820 #define OVERLAY2(attr) \
7821 if( astTest##attr( template, tax0 ) ) { \
7822 astSet##attr( result, 0, astGet##attr( template, tax0 ) ); \
7823 } \
7824 if( astTest##attr( template, tax1 ) ) { \
7825 astSet##attr( result, 1, astGet##attr( template, tax1 ) ); \
7826 }
7827
7828 /* Use the macro to transfer each SkyFrame attribute in turn. */
7829 OVERLAY(Equinox);
7830 OVERLAY(Projection);
7831 OVERLAY(NegLon);
7832 OVERLAY(AlignOffset);
7833 OVERLAY(SkyRefIs);
7834 OVERLAY2(SkyRef);
7835 OVERLAY2(SkyRefP);
7836 }
7837
7838 /* Undefine macros local to this function. */
7839 #undef OVERLAY
7840 #undef OVERLAY2
7841 }
7842
Resolve(AstFrame * this_frame,const double point1[],const double point2[],const double point3[],double point4[],double * d1,double * d2,int * status)7843 static void Resolve( AstFrame *this_frame, const double point1[],
7844 const double point2[], const double point3[],
7845 double point4[], double *d1, double *d2, int *status ){
7846 /*
7847 * Name:
7848 * Resolve
7849
7850 * Purpose:
7851 * Resolve a vector into two orthogonal components
7852
7853 * Type:
7854 * Private function.
7855
7856 * Synopsis:
7857 * #include "skyframe.h"
7858 * void Resolve( AstFrame *this, const double point1[],
7859 * const double point2[], const double point3[],
7860 * double point4[], double *d1, double *d2, int *status )
7861
7862 * Class Membership:
7863 * SkyFrame member function (over-rides the astResolve method
7864 * inherited from the Frame class).
7865
7866 * Description:
7867 * This function resolves a vector into two perpendicular components.
7868 * The vector from point 1 to point 2 is used as the basis vector.
7869 * The vector from point 1 to point 3 is resolved into components
7870 * parallel and perpendicular to this basis vector. The lengths of the
7871 * two components are returned, together with the position of closest
7872 * aproach of the basis vector to point 3.
7873 *
7874 * Each vector is a geodesic curve. For a SkyFrame, these are great
7875 * circles on the celestial sphere.
7876
7877 * Parameters:
7878 * this
7879 * Pointer to the Frame.
7880 * point1
7881 * An array of double, with one element for each Frame axis
7882 * (Naxes attribute). This marks the start of the basis vector,
7883 * and of the vector to be resolved.
7884 * point2
7885 * An array of double, with one element for each Frame axis
7886 * (Naxes attribute). This marks the end of the basis vector.
7887 * point3
7888 * An array of double, with one element for each Frame axis
7889 * (Naxes attribute). This marks the end of the vector to be
7890 * resolved.
7891 * point4
7892 * An array of double, with one element for each Frame axis
7893 * in which the coordinates of the point of closest approach of the
7894 * basis vector to point 3 will be returned.
7895 * d1
7896 * The address of a location at which to return the distance from
7897 * point 1 to point 4 (that is, the length of the component parallel
7898 * to the basis vector). Positive values are in the same sense as
7899 * movement from point 1 to point 2.
7900 * d2
7901 * The address of a location at which to return the distance from
7902 * point 4 to point 3 (that is, the length of the component
7903 * perpendicular to the basis vector). The returned value is always
7904 * positive.
7905 * status
7906 * Pointer to the inherited status variable.
7907
7908 * Notes:
7909 * - This function will return "bad" coordinate values (AST__BAD)
7910 * if any of the input coordinates has this value, or if the required
7911 * output values are undefined.
7912 */
7913
7914 /* Local Variables: */
7915 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
7916 const int *perm; /* Pointer to axis permutation array */
7917 double n1[ 3 ]; /* Unit normal to grt crcl thru p1 and p2 */
7918 double n2[ 3 ]; /* Unit normal to grt crcl thru p3 and p4 */
7919 double p1[ 2 ]; /* Permuted coordinates for point1 */
7920 double p2[ 2 ]; /* Permuted coordinates for point2 */
7921 double p3[ 2 ]; /* Permuted coordinates for point3 */
7922 double p4[ 2 ]; /* Permuted coordinates for point4 */
7923 double v1[ 3 ]; /* 3-vector for p1 */
7924 double v2[ 3 ]; /* 3-vector for p2 */
7925 double v3[ 3 ]; /* 3-vector for p3 */
7926 double v4[ 3 ]; /* 3-vector for p4 */
7927 double v5[ 3 ]; /* 3-vector 90 degs away from p1 */
7928 double vmod; /* Modulus of vector */
7929 double vtemp[ 3 ]; /* Temporary vector workspace */
7930
7931 /* Check the global error status. */
7932 if ( !astOK ) return;
7933
7934 /* Obtain a pointer to the SkyFrame structure. */
7935 this = (AstSkyFrame *) this_frame;
7936
7937 /* Store initial bad output values. */
7938 point4[ 0 ] = AST__BAD;
7939 point4[ 1 ] = AST__BAD;
7940 *d1 = AST__BAD;
7941 *d2 = AST__BAD;
7942
7943 /* Check that all supplied values are OK. */
7944 if ( ( point1[ 0 ] != AST__BAD ) && ( point1[ 1 ] != AST__BAD ) &&
7945 ( point2[ 0 ] != AST__BAD ) && ( point2[ 1 ] != AST__BAD ) &&
7946 ( point3[ 0 ] != AST__BAD ) && ( point3[ 1 ] != AST__BAD ) ) {
7947
7948 /* If so, obtain a pointer to the SkyFrame's axis permutation array. */
7949 perm = astGetPerm( this );
7950 if ( astOK ) {
7951
7952 /* Apply the axis permutation array to obtain the coordinates of the
7953 three supplied point in the required (longitude,latitude) order. */
7954 p1[ perm[ 0 ] ] = point1[ 0 ];
7955 p1[ perm[ 1 ] ] = point1[ 1 ];
7956 p2[ perm[ 0 ] ] = point2[ 0 ];
7957 p2[ perm[ 1 ] ] = point2[ 1 ];
7958 p3[ perm[ 0 ] ] = point3[ 0 ];
7959 p3[ perm[ 1 ] ] = point3[ 1 ];
7960
7961 /* Convert each point into a 3-vector of unit length. */
7962 palDcs2c( p1[ 0 ], p1[ 1 ], v1 );
7963 palDcs2c( p2[ 0 ], p2[ 1 ], v2 );
7964 palDcs2c( p3[ 0 ], p3[ 1 ], v3 );
7965
7966 /* Find the cross product between the first two vectors, and normalize is.
7967 This is the unit normal to the great circle plane defining parallel
7968 distance. */
7969 palDvxv( v2, v1, vtemp );
7970 palDvn( vtemp, n1, &vmod );
7971
7972 /* Return with bad values if the normal is undefined (i.e. if the first two
7973 vectors are identical or diametrically opposite). */
7974 if( vmod > 0.0 ) {
7975
7976 /* Now take the cross product of the normal vector and v1. This gives a
7977 point, v5, on the great circle which is 90 degrees away from v1, in the
7978 direction of v2. */
7979 palDvxv( v1, n1, v5 );
7980
7981 /* Find the cross product of the outlying point (point 3), and the vector
7982 n1 found above, and normalize it. This is the unit normal to the great
7983 circle plane defining perpendicular distance. */
7984 palDvxv( v3, n1, vtemp );
7985 palDvn( vtemp, n2, &vmod );
7986
7987 /* Return with bad values if the normal is undefined (i.e. if the
7988 outlying point is normal to the great circle defining the basis
7989 vector). */
7990 if( vmod > 0.0 ) {
7991
7992 /* The point of closest approach, point 4, is the point which is normal
7993 to both normal vectors (i.e. the intersection of the two great circles).
7994 This is the cross product of n1 and n2. No need to normalize this time
7995 since both n1 and n2 are unit vectors, and so v4 will already be a
7996 unit vector. */
7997 palDvxv( n1, n2, v4 );
7998
7999 /* The dot product of v4 and v1 is the cos of the parallel distance,
8000 d1, whilst the dot product of v4 and v5 is the sin of the parallel
8001 distance. Use these to get the parallel distance with the correct
8002 sign, in the range -PI to +PI. */
8003 *d1 = atan2( palDvdv( v4, v5 ), palDvdv( v4, v1 ) );
8004
8005 /* The dot product of v4 and v3 is the cos of the perpendicular distance,
8006 d2, whilst the dot product of n1 and v3 is the sin of the perpendicular
8007 distance. Use these to get the perpendicular distance. */
8008 *d2 = fabs( atan2( palDvdv( v3, n1 ), palDvdv( v3, v4 ) ) );
8009
8010 /* Convert the 3-vector representing the intersection of the two planes
8011 back into spherical cooordinates and then constrain the longitude result
8012 to lie in the range 0 to 2*pi. */
8013 palDcc2s( v4, &p4[ 0 ], &p4[ 1 ] );
8014 p4[ 0 ] = palDranrm( p4[ 0 ] );
8015
8016 /* Permute the result coordinates to undo the effect of the SkyFrame
8017 axis permutation array. */
8018 point4[ 0 ] = p4[ perm[ 0 ] ];
8019 point4[ 1 ] = p4[ perm[ 1 ] ];
8020 }
8021 }
8022 }
8023 }
8024
8025 return;
8026
8027 }
8028
ResolvePoints(AstFrame * this_frame,const double point1[],const double point2[],AstPointSet * in,AstPointSet * out,int * status)8029 static AstPointSet *ResolvePoints( AstFrame *this_frame, const double point1[],
8030 const double point2[], AstPointSet *in,
8031 AstPointSet *out, int *status ) {
8032 /*
8033 * Name:
8034 * ResolvePoints
8035
8036 * Purpose:
8037 * Resolve a set of vectors into orthogonal components
8038
8039 * Type:
8040 * Private function.
8041
8042 * Synopsis:
8043 * #include "frame.h"
8044 * AstPointSet *astResolvePoints( AstFrame *this, const double point1[],
8045 * const double point2[], AstPointSet *in,
8046 * AstPointSet *out )
8047
8048 * Class Membership:
8049 * SkyFrame member function (over-rides the astResolvePoints method
8050 * inherited from the Frame class).
8051
8052 * Description:
8053 * This function takes a Frame and a set of vectors encapsulated
8054 * in a PointSet, and resolves each one into two orthogonal components,
8055 * returning these two components in another PointSet.
8056 *
8057 * This is exactly the same as the public astResolve method, except
8058 * that this method allows many vectors to be processed in a single call,
8059 * thus reducing the computational cost of overheads of many
8060 * individual calls to astResolve.
8061
8062 * Parameters:
8063 * this
8064 * Pointer to the Frame.
8065 * point1
8066 * An array of double, with one element for each Frame axis
8067 * (Naxes attribute). This marks the start of the basis vector,
8068 * and of the vectors to be resolved.
8069 * point2
8070 * An array of double, with one element for each Frame axis
8071 * (Naxes attribute). This marks the end of the basis vector.
8072 * in
8073 * Pointer to the PointSet holding the ends of the vectors to be
8074 * resolved.
8075 * out
8076 * Pointer to a PointSet which will hold the length of the two
8077 * resolved components. A NULL value may also be given, in which
8078 * case a new PointSet will be created by this function.
8079
8080 * Returned Value:
8081 * Pointer to the output (possibly new) PointSet. The first axis will
8082 * hold the lengths of the vector components parallel to the basis vector.
8083 * These values will be signed (positive values are in the same sense as
8084 * movement from point 1 to point 2. The second axis will hold the lengths
8085 * of the vector components perpendicular to the basis vector. These
8086 * values will be signed only if the Frame is 2-dimensional, in which
8087 * case a positive value indicates that rotation from the basis vector
8088 * to the tested vector is in the same sense as rotation from the first
8089 * to the second axis of the Frame.
8090
8091 * Notes:
8092 * - The number of coordinate values per point in the input
8093 * PointSet must match the number of axes in the supplied Frame.
8094 * - If an output PointSet is supplied, it must have space for
8095 * sufficient number of points and 2 coordinate values per point.
8096 * - A null pointer will be returned if this function is invoked
8097 * with the global error status set, or if it should fail for any
8098 * reason.
8099 * - We assume spherical geometry throughout this function.
8100 */
8101
8102 /* Local Variables: */
8103 AstPointSet *result; /* Pointer to output PointSet */
8104 AstSkyFrame *this; /* Pointer to SkyFrame structure */
8105 const int *perm; /* Pointer to axis permutation array */
8106 double **ptr_in; /* Pointers to input axis values */
8107 double **ptr_out; /* Pointers to returned axis values */
8108 double *d1; /* Pointer to next parallel component value */
8109 double *d2; /* Pointer to next perpendicular component value */
8110 double *point3x; /* Pointer to next first axis value */
8111 double *point3y; /* Pointer to next second axis value */
8112 double n1[ 3 ]; /* Unit normal to grt crcl thru p1 and p2 */
8113 double n2[ 3 ]; /* Unit normal to grt crcl thru p3 and p4 */
8114 double p1[ 2 ]; /* Permuted coordinates for point1 */
8115 double p2[ 2 ]; /* Permuted coordinates for point2 */
8116 double p3[ 2 ]; /* Permuted coordinates for point3 */
8117 double sign; /* Sign for perpendicular distances */
8118 double v1[ 3 ]; /* 3-vector for p1 */
8119 double v2[ 3 ]; /* 3-vector for p2 */
8120 double v3[ 3 ]; /* 3-vector for p3 */
8121 double v4[ 3 ]; /* 3-vector for p4 */
8122 double v5[ 3 ]; /* 3-vector 90 degs away from p1 */
8123 double vmod; /* Modulus of vector */
8124 double vtemp[ 3 ]; /* Temporary vector workspace */
8125 int ipoint; /* Index of next point */
8126 int ncoord_in; /* Number of input PointSet coordinates */
8127 int ncoord_out; /* Number of coordinates in output PointSet */
8128 int npoint; /* Number of points to transform */
8129 int npoint_out; /* Number of points in output PointSet */
8130 int ok; /* OK to proceed? */
8131
8132 /* Initialise. */
8133 result = NULL;
8134
8135 /* Check the global error status. */
8136 if ( !astOK ) return result;
8137
8138 /* Get a pointer to the SkyFrame structure. */
8139 this = (AstSkyFrame *) this_frame;
8140
8141 /* Obtain the number of input vectors to resolve and the number of coordinate
8142 values per vector. */
8143 npoint = astGetNpoint( in );
8144 ncoord_in = astGetNcoord( in );
8145
8146 /* If OK, check that the number of input coordinates matches the number
8147 required by the Frame. Report an error if these numbers do not match. */
8148 if ( astOK && ( ncoord_in != 2 ) ) {
8149 astError( AST__NCPIN, "astResolvePoints(%s): Bad number of coordinate "
8150 "values (%d) in input %s.", status, astGetClass( this ), ncoord_in,
8151 astGetClass( in ) );
8152 astError( AST__NCPIN, "The %s given requires 2 coordinate values for "
8153 "each input point.", status, astGetClass( this ) );
8154 }
8155
8156 /* If still OK, and a non-NULL pointer has been given for the output PointSet,
8157 then obtain the number of points and number of coordinates per point for
8158 this PointSet. */
8159 if ( astOK && out ) {
8160 npoint_out = astGetNpoint( out );
8161 ncoord_out = astGetNcoord( out );
8162
8163 /* Check that the dimensions of this PointSet are adequate to accommodate the
8164 output coordinate values and report an error if they are not. */
8165 if ( astOK ) {
8166 if ( npoint_out < npoint ) {
8167 astError( AST__NOPTS, "astResolvePoints(%s): Too few points (%d) in "
8168 "output %s.", status, astGetClass( this ), npoint_out,
8169 astGetClass( out ) );
8170 astError( AST__NOPTS, "The %s needs space to hold %d transformed "
8171 "point(s).", status, astGetClass( this ), npoint );
8172 } else if ( ncoord_out < 2 ) {
8173 astError( AST__NOCTS, "astResolvePoints(%s): Too few coordinate "
8174 "values per point (%d) in output %s.", status,
8175 astGetClass( this ), ncoord_out, astGetClass( out ) );
8176 astError( AST__NOCTS, "The %s supplied needs space to store 2 "
8177 "coordinate value(s) per transformed point.", status,
8178 astGetClass( this ) );
8179 }
8180 }
8181 }
8182
8183 /* If all the validation stages are passed successfully, and a NULL output
8184 pointer was given, then create a new PointSet to encapsulate the output
8185 coordinate data. */
8186 if ( astOK ) {
8187 if ( !out ) {
8188 result = astPointSet( npoint, 2, "", status );
8189
8190 /* Otherwise, use the PointSet supplied. */
8191 } else {
8192 result = out;
8193 }
8194 }
8195
8196 /* Get pointers to the input and output axis values */
8197 ptr_in = astGetPoints( in );
8198 ptr_out = astGetPoints( result );
8199
8200 /* Obtain a pointer to the SkyFrame's axis permutation array. */
8201 perm = astGetPerm( this );
8202
8203 /* If the axes have been swapped we need to swap the sign of the returned
8204 perpendicular distances. */
8205 sign = ( perm[ 0 ] == 0 ) ? -1.0 : 1.0;
8206
8207 /* Check pointers can be used safely */
8208 if( astOK ) {
8209
8210 /* Apply the axis permutation array to obtain the coordinates of the
8211 two supplied points in the required (longitude,latitude) order. */
8212 p1[ perm[ 0 ] ] = point1[ 0 ];
8213 p1[ perm[ 1 ] ] = point1[ 1 ];
8214 p2[ perm[ 0 ] ] = point2[ 0 ];
8215 p2[ perm[ 1 ] ] = point2[ 1 ];
8216
8217 /* Convert these points into 3-vectors of unit length. */
8218 palDcs2c( p1[ 0 ], p1[ 1 ], v1 );
8219 palDcs2c( p2[ 0 ], p2[ 1 ], v2 );
8220
8221 /* Find the cross product between the vectors, and normalize it. This is the
8222 unit normal to the great circle plane defining parallel distance. */
8223 palDvxv( v2, v1, vtemp );
8224 palDvn( vtemp, n1, &vmod );
8225
8226 /* Return with bad values if the normal is undefined (i.e. if the first two
8227 vectors are identical or diametrically opposite). */
8228 ok = 0;
8229 if( vmod > 0.0 ) {
8230 ok = 1;
8231
8232 /* Now take the cross product of the normal vector and v1. This gives a
8233 point, v5, on the great circle which is 90 degrees away from v1, in the
8234 direction of v2. */
8235 palDvxv( v1, n1, v5 );
8236 }
8237
8238 /* Store pointers to the first two axis arrays in the returned PointSet. */
8239 d1 = ptr_out[ 0 ];
8240 d2 = ptr_out[ 1 ];
8241
8242 /* Store pointers to the axis values in the supplied PointSet. */
8243 point3x = ptr_in[ 0 ];
8244 point3y = ptr_in[ 1 ];
8245
8246 /* Check supplied values can be used */
8247 if( ok ) {
8248
8249 /* Loop round each supplied vector. */
8250 for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++,
8251 point3x++, point3y++ ) {
8252
8253 /* Store bad output values if either input axis value is bad. */
8254 if( *point3x == AST__BAD || *point3y == AST__BAD ){
8255 *d1 = AST__BAD;
8256 *d2 = AST__BAD;
8257
8258 /* If both are good... */
8259 } else {
8260
8261 /* Apply the axis permutation array to obtain the coordinates in the
8262 required (longitude,latitude) order. */
8263 p3[ perm[ 0 ] ] = *point3x;
8264 p3[ perm[ 1 ] ] = *point3y;
8265
8266 /* Convert into a 3-vector of unit length. */
8267 palDcs2c( p3[ 0 ], p3[ 1 ], v3 );
8268
8269 /* Find the cross product of the outlying point (point 3), and the vector
8270 n1 found above, and normalize it. This is the unit normal to the great
8271 circle plane defining perpendicular distance. */
8272 palDvxv( v3, n1, vtemp );
8273 palDvn( vtemp, n2, &vmod );
8274
8275 /* Return with bad values if the normal is undefined (i.e. if the
8276 outlying point is normal to the great circle defining the basis
8277 vector). */
8278 if( vmod <= 0.0 ) {
8279 *d1 = AST__BAD;
8280 *d2 = AST__BAD;
8281 } else {
8282
8283 /* The point of closest approach, point 4, is the point which is normal
8284 to both normal vectors (i.e. the intersection of the two great circles).
8285 This is the cross product of n1 and n2. No need to normalize this time
8286 since both n1 and n2 are unit vectors, and so v4 will already be a
8287 unit vector. */
8288 palDvxv( n1, n2, v4 );
8289
8290 /* The dot product of v4 and v1 is the cos of the parallel distance,
8291 d1, whilst the dot product of v4 and v5 is the sin of the parallel
8292 distance. Use these to get the parallel distance with the correct
8293 sign, in the range -PI to +PI. */
8294 *d1 = atan2( palDvdv( v4, v5 ), palDvdv( v4, v1 ) );
8295
8296 /* The dot product of v4 and v3 is the cos of the perpendicular distance,
8297 d2, whilst the dot product of n1 and v3 is the sin of the perpendicular
8298 distance. Use these to get the perpendicular distance. */
8299 *d2 = sign*atan2( palDvdv( v3, n1 ), palDvdv( v3, v4 ) );
8300 }
8301 }
8302 }
8303
8304 /* If supplied values cannot be used, fill the returned PointSet with bad
8305 values */
8306 } else {
8307 for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) {
8308 *d1 = AST__BAD;
8309 *d2 = AST__BAD;
8310 }
8311 }
8312 }
8313
8314 /* Annul the returned PointSet if an error occurred. */
8315 if( !astOK ) result = astAnnul( result );
8316
8317 /* Return a pointer to the output PointSet. */
8318 return result;
8319 }
8320
SetAsTime(AstSkyFrame * this,int axis,int value,int * status)8321 static void SetAsTime( AstSkyFrame *this, int axis, int value, int *status ) {
8322 /*
8323 * Name:
8324 * SetAsTime
8325
8326 * Purpose:
8327 * Set a value for the AsTime attribute for a SkyFrame's axis.
8328
8329 * Type:
8330 * Private function.
8331
8332 * Synopsis:
8333 * #include "skyframe.h"
8334 * void SetAsTime( AstSkyFrame *this, int axis, int value, int *status )
8335
8336 * Class Membership:
8337 * SkyFrame member function.
8338
8339 * Description:
8340 * This function sets the boolean value of the AsTime attribute for a
8341 * specified axis of a SkyFrame. This value indicates whether axis values
8342 * should be formatted as times (as opposed to angles) by default.
8343
8344 * Parameters:
8345 * this
8346 * Pointer to the SkyFrame.
8347 * axis
8348 * Index of the axis for which a value is to be set (zero based).
8349 * value
8350 * The boolean value to be set.
8351 * status
8352 * Pointer to the inherited status variable.
8353
8354 * Returned Value:
8355 * void.
8356 */
8357
8358 /* Local Variables: */
8359 AstAxis *ax; /* Pointer to Axis object */
8360 AstSkyAxis *new_ax; /* Pointer to new SkyAxis object */
8361
8362 /* Check the global error status. */
8363 if ( !astOK ) return;
8364
8365 /* Validate the axis index. */
8366 (void) astValidateAxis( this, axis, 1, "astSetAsTime" );
8367
8368 /* Obtain a pointer to the Axis object. */
8369 ax = astGetAxis( this, axis );
8370
8371 /* Check if the Axis object is a SkyAxis. If not, we will replace it with
8372 one. */
8373 if ( !astIsASkyAxis( ax ) ) {
8374
8375 /* Create a new SkyAxis and overlay the attributes of the original Axis. */
8376 new_ax = astSkyAxis( "", status );
8377 astAxisOverlay( ax, new_ax );
8378
8379 /* Modify the SkyFrame to use the new Skyaxis and annul the original Axis
8380 pointer. Retain a pointer to the new SkyAxis. */
8381 astSetAxis( this, axis, new_ax );
8382 ax = astAnnul( ax );
8383 ax = (AstAxis *) new_ax;
8384 }
8385
8386 /* Set a value for the Axis AsTime attribute. */
8387 astSetAxisAsTime( ax, value );
8388
8389 /* Annul the Axis pointer. */
8390 ax = astAnnul( ax );
8391 }
8392
SetAttrib(AstObject * this_object,const char * setting,int * status)8393 static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
8394 /*
8395 * Name:
8396 * SetAttrib
8397
8398 * Purpose:
8399 * Set an attribute value for a SkyFrame.
8400
8401 * Type:
8402 * Private function.
8403
8404 * Synopsis:
8405 * #include "skyframe.h"
8406 * void SetAttrib( AstObject *this, const char *setting, int *status )
8407
8408 * Class Membership:
8409 * SkyFrame member function (extends the astSetAttrib method inherited from
8410 * the Mapping class).
8411
8412 * Description:
8413 * This function assigns an attribute value for a SkyFrame, the attribute
8414 * and its value being specified by means of a string of the form:
8415 *
8416 * "attribute= value "
8417 *
8418 * Here, "attribute" specifies the attribute name and should be in lower
8419 * case with no white space present. The value to the right of the "="
8420 * should be a suitable textual representation of the value to be assigned
8421 * and this will be interpreted according to the attribute's data type.
8422 * White space surrounding the value is only significant for string
8423 * attributes.
8424
8425 * Parameters:
8426 * this
8427 * Pointer to the SkyFrame.
8428 * setting
8429 * Pointer to a null terminated string specifying the new attribute
8430 * value.
8431 * status
8432 * Pointer to the inherited status variable.
8433
8434 * Returned Value:
8435 * void
8436
8437 * Attributes:
8438 * As well as those attributes inherited from the parent class, this
8439 * function also accepts values for the following additional attributes:
8440 *
8441 * Equinox (double, read as a string)
8442
8443 * Notes:
8444 * This protected method is intended to be invoked by the Object astSet
8445 * method and makes additional attributes accessible to it.
8446 */
8447
8448 /* Local Vaiables: */
8449 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
8450 double dval; /* Floating point attribute value */
8451 double dval1; /* Floating point attribute value */
8452 double dval2; /* Floating point attribute value */
8453 double mjd; /* Modified Julian Date */
8454 int astime; /* Value of AsTime attribute */
8455 int axis; /* Axis index */
8456 int equinox; /* Offset of Equinox attribute value */
8457 int ival; /* Integer attribute value */
8458 int len; /* Length of setting string */
8459 int nc; /* Number of characters read by astSscanf */
8460 int neglon; /* Display -ve longitudes? */
8461 int ok; /* Can string be used? */
8462 int offset; /* Offset of start of attribute value */
8463 int projection; /* Offset of projection attribute value */
8464
8465 /* Check the global error status. */
8466 if ( !astOK ) return;
8467
8468 /* Obtain a pointer to the SkyFrame structure. */
8469 this = (AstSkyFrame *) this_object;
8470
8471 /* Obtain the length of the setting string. */
8472 len = strlen( setting );
8473
8474 /* Test for each recognised attribute in turn, using "astSscanf" to parse the
8475 setting string and extract the attribute value (or an offset to it in the
8476 case of string values). In each case, use the value set in "nc" to check
8477 that the entire string was matched. Once a value has been obtained, use the
8478 appropriate method to set it. */
8479
8480 /* AsTime(axis). */
8481 /* ------------- */
8482 if ( nc = 0,
8483 ( 2 == astSscanf( setting, "astime(%d)= %d %n", &axis, &astime, &nc ) )
8484 && ( nc >= len ) ) {
8485 astSetAsTime( this, axis - 1, astime );
8486
8487 /* Equinox. */
8488 /* -------- */
8489 } else if ( nc = 0,
8490 ( 0 == astSscanf( setting, "equinox=%n%*[^\n]%n",
8491 &equinox, &nc ) ) && ( nc >= len ) ) {
8492
8493 /* Convert the Equinox value to a Modified Julian Date before use. */
8494 mjd = astReadDateTime( setting + equinox );
8495 if ( astOK ) {
8496 astSetEquinox( this, mjd );
8497
8498 /* Report contextual information if the conversion failed. */
8499 } else {
8500 astError( AST__ATTIN, "astSetAttrib(%s): Invalid equinox value "
8501 "\"%s\" given for sky coordinate system.", status,
8502 astGetClass( this ), setting + equinox );
8503 }
8504
8505 /* NegLon. */
8506 /* ------- */
8507 } else if ( nc = 0,
8508 ( 1 == astSscanf( setting, "neglon= %d %n", &neglon, &nc ) )
8509 && ( nc >= len ) ) {
8510 astSetNegLon( this, neglon );
8511
8512 /* Projection. */
8513 /* ----------- */
8514 } else if ( nc = 0,
8515 ( 0 == astSscanf( setting, "projection=%n%*[^\n]%n",
8516 &projection, &nc ) )
8517 && ( nc >= len ) ) {
8518 astSetProjection( this, setting + projection );
8519
8520 /* SkyRef. */
8521 /* ------- */
8522 } else if ( nc = 0,
8523 ( 0 == astSscanf( setting, "skyref=%n%*[^\n]%n",
8524 &offset, &nc ) )
8525 && ( nc >= len ) ) {
8526 ok = 0;
8527 nc = astUnformat( this, 0, setting + offset, &dval1 );
8528 if( setting[ offset + nc ] == ',' ) {
8529 nc++;
8530 nc += astUnformat( this, 1, setting + offset + nc, &dval2 );
8531 if( nc == strlen( setting + offset ) ) {
8532 astSetSkyRef( this, 0, dval1 );
8533 astSetSkyRef( this, 1, dval2 );
8534 ok = 1;
8535 }
8536 }
8537
8538 if( !ok && astOK ) {
8539 astError( AST__BADOC, "astSetAttrib(%s): Invalid axis values string "
8540 "\"%.*s\" given for SkyRef attribute.", status, astGetClass( this ),
8541 (int) astChrLen( setting + offset ), setting + offset );
8542 }
8543
8544 /* SkyRef(axis). */
8545 /* ------------- */
8546 } else if ( nc = 0,
8547 ( 2 == astSscanf( setting, "skyref(%d)= %lg %n",
8548 &axis, &dval, &nc ) )
8549 && ( nc >= len ) ) {
8550 astSetSkyRef( this, axis - 1, dval );
8551
8552 /* SkyRefIs. */
8553 /* --------- */
8554 } else if ( nc = 0,
8555 ( 0 == astSscanf( setting, "skyrefis=%n%*[^\n]%n",
8556 &offset, &nc ) )
8557 && ( nc >= len ) ) {
8558
8559 if( astChrMatch( setting + offset, POLE_STRING ) ) {
8560 astSetSkyRefIs( this, AST__POLE_REF );
8561
8562 } else if( astChrMatch( setting + offset, ORIGIN_STRING ) ) {
8563 astSetSkyRefIs( this, AST__ORIGIN_REF );
8564
8565 } else if( astChrMatch( setting + offset, IGNORED_STRING ) ) {
8566 astSetSkyRefIs( this, AST__IGNORED_REF );
8567
8568 } else if( astOK ) {
8569 astError( AST__OPT, "astSet(%s): option '%s' is unknown in '%s'.", status,
8570 astGetClass( this ), setting+offset, setting );
8571 }
8572
8573 /* SkyRefP. */
8574 /* -------- */
8575 } else if ( nc = 0,
8576 ( 0 == astSscanf( setting, "skyrefp=%n%*[^\n]%n",
8577 &offset, &nc ) )
8578 && ( nc >= len ) ) {
8579
8580 ok = 0;
8581 nc = astUnformat( this, 0, setting + offset, &dval1 );
8582 if( setting[ offset + nc ] == ',' ) {
8583 nc++;
8584 nc += astUnformat( this, 1, setting + offset + nc, &dval2 );
8585 if( nc == strlen( setting + offset ) ) {
8586 astSetSkyRefP( this, 0, dval1 );
8587 astSetSkyRefP( this, 1, dval2 );
8588 ok = 1;
8589 }
8590 }
8591
8592 if( !ok && astOK ) {
8593 astError( AST__BADOC, "astSetAttrib(%s): Invalid axis values string "
8594 "\"%.*s\" given for SkyRefP attribute.", status, astGetClass( this ),
8595 (int) astChrLen( setting + offset ), setting + offset );
8596 }
8597
8598
8599 /* SkyRefP(axis). */
8600 /* -------------- */
8601 } else if ( nc = 0,
8602 ( 2 == astSscanf( setting, "skyrefp(%d)= %lg %n",
8603 &axis, &dval, &nc ) )
8604 && ( nc >= len ) ) {
8605 astSetSkyRefP( this, axis - 1, dval );
8606
8607 /* AlignOffset. */
8608 /* ------------ */
8609 } else if ( nc = 0,
8610 ( 1 == astSscanf( setting, "alignoffset= %d %n", &ival, &nc ) )
8611 && ( nc >= len ) ) {
8612 astSetAlignOffset( this, ival );
8613
8614 /* Define a macro to see if the setting string matches any of the
8615 read-only attributes of this class. */
8616 #define MATCH(attrib) \
8617 ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \
8618 ( nc >= len ) )
8619
8620 /* If the attribute was not recognised, use this macro to report an error
8621 if a read-only attribute has been specified. */
8622 } else if ( !strncmp( setting, "islataxis", 9 ) ||
8623 !strncmp( setting, "islonaxis", 9 ) ||
8624 MATCH( "lataxis" ) ||
8625 MATCH( "lonaxis" ) ) {
8626 astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status,
8627 setting, astGetClass( this ) );
8628 astError( AST__NOWRT, "This is a read-only attribute." , status);
8629
8630 /* Pass any unrecognised setting to the parent method for further
8631 interpretation. */
8632 } else {
8633 (*parent_setattrib)( this_object, setting, status );
8634 }
8635 }
8636
SetCachedLAST(AstSkyFrame * this,double last,double epoch,double obslon,double obslat,double obsalt,double dut1,int * status)8637 static void SetCachedLAST( AstSkyFrame *this, double last, double epoch,
8638 double obslon, double obslat, double obsalt,
8639 double dut1, int *status ) {
8640 /*
8641 * Name:
8642 * SetCachedLAST
8643
8644 * Purpose:
8645 * Store a LAST value in the cache in the SkyFrame vtab.
8646
8647 * Type:
8648 * Private function.
8649
8650 * Synopsis:
8651 * #include "skyframe.h"
8652 * void SetCachedLAST( AstSkyFrame *this, double last, double epoch,
8653 * double obslon, double obslat, double obsalt,
8654 * double dut1, int *status )
8655
8656 * Class Membership:
8657 * SkyFrame member function.
8658
8659 * Description:
8660 * This function stores the supplied LAST value in a cache in the
8661 * SkyFrame virtual function table for later use by GetCachedLAST.
8662
8663 * Parameters:
8664 * this
8665 * Pointer to the SkyFrame.
8666 * last
8667 * The Local Apparent Sidereal Time (radians).
8668 * epoch
8669 * The epoch (MJD).
8670 * obslon
8671 * Observatory geodetic longitude (radians)
8672 * obslat
8673 * Observatory geodetic latitude (radians)
8674 * obsalt
8675 * Observatory geodetic altitude (metres)
8676 * dut1
8677 * The UT1-UTC correction, in seconds.
8678 * status
8679 * Pointer to the inherited status variable.
8680
8681 */
8682
8683 /* Local Variables: */
8684 astDECLARE_GLOBALS
8685 AstSkyLastTable *table;
8686 double *ep;
8687 double *lp;
8688 double lp_ref;
8689 int i;
8690 int itable;
8691
8692 /* Get a pointer to the structure holding thread-specific global data. */
8693 astGET_GLOBALS(this);
8694
8695 /* Initialise */
8696 table = NULL;
8697
8698 /* Check the global error status. */
8699 if ( !astOK ) return;
8700
8701 /* Ensure no threads are allowed to read the table whilst we are writing
8702 to it. */
8703 LOCK_WLOCK1
8704
8705 /* Loop round every LAST table held in the vtab. Each table refers to a
8706 different observatory position and/or DUT1 value. */
8707 for( itable = 0; itable < nlast_tables; itable++ ) {
8708 table = last_tables[ itable ];
8709
8710 /* See if the table refers to the given position and dut1 value, allowing
8711 some small tolerance. If it does, leave the loop. */
8712 if( fabs( table->obslat - obslat ) < 2.0E-7 &&
8713 fabs( table->obslon - obslon ) < 2.0E-7 &&
8714 fabs( table->obsalt - obsalt ) < 1.0 &&
8715 fabs( table->dut1 - dut1 ) < 1.0E-5 ) break;
8716
8717 /* Ensure "table" ends up NULL if no suitable table is found. */
8718 table = NULL;
8719 }
8720
8721 /* If no table was found, create one now, and add it into the vtab cache. */
8722 if( !table ) {
8723
8724 astBeginPM;
8725 table = astMalloc( sizeof( AstSkyLastTable ) );
8726 itable = nlast_tables++;
8727 last_tables = astGrow( last_tables, nlast_tables,
8728 sizeof( AstSkyLastTable * ) );
8729 astEndPM;
8730
8731 if( astOK ) {
8732 last_tables[ itable ] = table;
8733 table->obslat = obslat;
8734 table->obslon = obslon;
8735 table->obsalt = obsalt;
8736 table->dut1 = dut1;
8737 table->nentry = 1;
8738
8739 astBeginPM;
8740 table->epoch = astMalloc( sizeof( double ) );
8741 table->last = astMalloc( sizeof( double ) );
8742 astEndPM;
8743
8744 if( astOK ) {
8745 table->epoch[ 0 ] = epoch;
8746 table->last[ 0 ] = last;
8747 }
8748 }
8749
8750
8751 /* If we have a table, add the new point into it. */
8752 } else {
8753
8754 /* Extend the epoch and last arrays. */
8755 astBeginPM;
8756 table->epoch = astGrow( table->epoch, ++(table->nentry), sizeof( double ) );
8757 table->last = astGrow( table->last, table->nentry, sizeof( double ) );
8758 astEndPM;
8759
8760 /* Check memory allocation was successful. */
8761 if( astOK ) {
8762
8763 /* Get pointers to the last original elements in the arrays of epoch and
8764 corresponding LAST values in the table. */
8765 ep = table->epoch + table->nentry - 2;
8766 lp = table->last + table->nentry - 2;
8767
8768 /* Starting from the end of the arrays, shuffle all entries up one
8769 element until an element is found which is less than the supplied epoch
8770 value. This maintains the epoch array in monotonic increasing order. */
8771 for( i = table->nentry - 2; i >= 0; i--,ep--,lp-- ) {
8772 if( *ep <= epoch ) break;
8773 ep[ 1 ] = *ep;
8774 lp[ 1 ] = *lp;
8775 }
8776
8777 /* Store the new epoch and LAST value. Add or subtract 2.PI as needed
8778 from the new LAST value to ensure it is continuous with an adjacent
8779 LAST value. This is needed for interpolation between the two values
8780 to be meaningful. */
8781 ep[ 1 ] = epoch;
8782
8783 /* For most cases, compare with the previous LAST value. If the new epoch
8784 value is smaller than any epoch already in the table, there will be no
8785 previous LAST value. So compare with the next value instead. */
8786 if( i >= 0 ) {
8787 lp_ref = lp[ 0 ];
8788 } else {
8789 lp_ref = lp[ 2 ];
8790 }
8791
8792 if( last > lp_ref + AST__DPI ) {
8793 lp[ 1 ] = last - 2*AST__DPI;
8794
8795 } else if( last < lp_ref - AST__DPI ) {
8796 lp[ 1 ] = last + 2*AST__DPI;
8797
8798 } else {
8799 lp[ 1 ] = last;
8800 }
8801 }
8802 }
8803
8804 /* Indicate other threads are now allowed to read the table. */
8805 UNLOCK_RWLOCK1
8806
8807 }
8808
SetDut1(AstFrame * this_frame,double val,int * status)8809 static void SetDut1( AstFrame *this_frame, double val, int *status ) {
8810 /*
8811 * Name:
8812 * SetDut1
8813
8814 * Purpose:
8815 * Set the value of the Dut1 attribute for a SkyFrame.
8816
8817 * Type:
8818 * Private function.
8819
8820 * Synopsis:
8821 * #include "skyframe.h"
8822 * void SetDut1( AstFrame *this, double val, int *status )
8823
8824 * Class Membership:
8825 * SkyFrame member function (over-rides the astSetDut1 method
8826 * inherited from the Frame class).
8827
8828 * Description:
8829 * This function clears the Dut1 value and updates the LAST value
8830 * stored in the SkyFrame.
8831
8832 * Parameters:
8833 * this
8834 * Pointer to the SkyFrame.
8835 * val
8836 * New Dut1 value.
8837 * status
8838 * Pointer to the inherited status variable.
8839
8840 */
8841
8842 /* Local Variables: */
8843 AstSkyFrame *this;
8844 double orig;
8845
8846 /* Check the global error status. */
8847 if ( !astOK ) return;
8848
8849 /* Obtain a pointer to the SkyFrame structure. */
8850 this = (AstSkyFrame *) this_frame;
8851
8852 /* Note the original Dut1 value. */
8853 orig = astGetDut1( this );
8854
8855 /* Invoke the parent method to set the Frame Dut1 value. */
8856 (*parent_setdut1)( this_frame, val, status );
8857
8858 /* If the DUT1 value has changed significantly, indicate that the LAST value
8859 will need to be re-calculated when it is next needed. */
8860 if( fabs( orig - val ) > 1.0E-6 ) {
8861 this->last = AST__BAD;
8862 this->eplast = AST__BAD;
8863 this->klast = AST__BAD;
8864 }
8865 }
8866
SetLast(AstSkyFrame * this,int * status)8867 static void SetLast( AstSkyFrame *this, int *status ) {
8868 /*
8869 * Name:
8870 * SetLast
8871
8872 * Purpose:
8873 * Set the Local Appearent Sidereal Time for a SkyFrame.
8874
8875 * Type:
8876 * Private function.
8877
8878 * Synopsis:
8879 * #include "skyframe.h"
8880 * void SetLast( AstSkyFrame *this, int *status )
8881
8882 * Class Membership:
8883 * SkyFrame member function.
8884
8885 * Description:
8886 * This function sets the Local Apparent Sidereal Time at the epoch
8887 * and geographical longitude given by the current values of the Epoch
8888 * and ObsLon attributes associated with the supplied SkyFrame.
8889
8890 * Parameters:
8891 * this
8892 * Pointer to the SkyFrame.
8893 * status
8894 * Pointer to the inherited status variable.
8895
8896 * Notes:
8897 * - A value of AST__BAD will be returned if this function is invoked
8898 * with the global error status set, or if it should fail for any reason.
8899 */
8900
8901 /* Local Variables: */
8902 double epoch; /* Epoch as a TDB MJD */
8903
8904 /* Check the global error status. */
8905 if ( !astOK ) return;
8906
8907 /* Get the SkyFrame Epoch as a TDB MJD. */
8908 epoch = astGetEpoch( this );
8909
8910 /* Calculate the LAST value (in rads) and store in the SkyFrame structure. */
8911 this->last = CalcLAST( this, epoch, astGetObsLon( this ),
8912 astGetObsLat( this ), astGetObsAlt( this ),
8913 astGetDut1( this ), status );
8914
8915 /* Save the TDB MJD to which this LAST corresponds. */
8916 this->eplast = epoch;
8917
8918 /* The ratio between solar and sidereal time is a slowly varying function
8919 of epoch. The GetLAST function returns a fast approximation to LAST
8920 by using the ratio between solar and sidereal time. Indicate that
8921 GetLAST should re-calculate the ratio by setting the ratio value bad. */
8922 this->klast = AST__BAD;
8923 }
8924
SetObsAlt(AstFrame * this,double val,int * status)8925 static void SetObsAlt( AstFrame *this, double val, int *status ) {
8926 /*
8927 * Name:
8928 * SetObsAlt
8929
8930 * Purpose:
8931 * Set the value of the ObsAlt attribute for a SkyFrame.
8932
8933 * Type:
8934 * Private function.
8935
8936 * Synopsis:
8937 * #include "skyframe.h"
8938 * void SetObsAlt( AstFrame *this, double val, int *status )
8939
8940 * Class Membership:
8941 * SkyFrame member function (over-rides the astSetObsAlt method
8942 * inherited from the Frame class).
8943
8944 * Description:
8945 * This function sets the ObsAlt value.
8946
8947 * Parameters:
8948 * this
8949 * Pointer to the SkyFrame.
8950 * val
8951 * New ObsAlt value.
8952 * status
8953 * Pointer to the inherited status variable.
8954
8955 */
8956
8957 /* Local Variables: */
8958 double orig;
8959
8960 /* Check the global error status. */
8961 if ( !astOK ) return;
8962
8963 /* Note the original ObsAlt value. */
8964 orig = astGetObsAlt( this );
8965
8966 /* Invoke the parent method to set the Frame ObsAlt. */
8967 (*parent_setobsalt)( this, val, status );
8968
8969 /* If the altitude has changed significantly, indicate that the LAST value
8970 and magnitude of the diurnal aberration vector will need to be
8971 re-calculated when next needed. */
8972 if( fabs( orig - val ) > 0.001 ) {
8973 ( (AstSkyFrame *) this )->last = AST__BAD;
8974 ( (AstSkyFrame *) this )->eplast = AST__BAD;
8975 ( (AstSkyFrame *) this )->klast = AST__BAD;
8976 ( (AstSkyFrame *) this )->diurab = AST__BAD;
8977 }
8978 }
8979
SetObsLat(AstFrame * this,double val,int * status)8980 static void SetObsLat( AstFrame *this, double val, int *status ) {
8981 /*
8982 * Name:
8983 * SetObsLat
8984
8985 * Purpose:
8986 * Set the value of the ObsLat attribute for a SkyFrame.
8987
8988 * Type:
8989 * Private function.
8990
8991 * Synopsis:
8992 * #include "skyframe.h"
8993 * void SetObsLat( AstFrame *this, double val, int *status )
8994
8995 * Class Membership:
8996 * SkyFrame member function (over-rides the astSetObsLat method
8997 * inherited from the Frame class).
8998
8999 * Description:
9000 * This function sets the ObsLat value.
9001
9002 * Parameters:
9003 * this
9004 * Pointer to the SkyFrame.
9005 * val
9006 * New ObsLat value.
9007 * status
9008 * Pointer to the inherited status variable.
9009
9010 */
9011
9012 /* Local Variables: */
9013 double orig;
9014
9015 /* Check the global error status. */
9016 if ( !astOK ) return;
9017
9018 /* Note the original ObsLat value. */
9019 orig = astGetObsLat( this );
9020
9021 /* Invoke the parent method to set the Frame ObsLat. */
9022 (*parent_setobslat)( this, val, status );
9023
9024 /* If the altitude has changed significantly, indicate that the LAST value
9025 and magnitude of the diurnal aberration vector will need to be
9026 re-calculated when next needed. */
9027 if( fabs( orig - val ) > 1.0E-8 ) {
9028 ( (AstSkyFrame *) this )->last = AST__BAD;
9029 ( (AstSkyFrame *) this )->eplast = AST__BAD;
9030 ( (AstSkyFrame *) this )->klast = AST__BAD;
9031 ( (AstSkyFrame *) this )->diurab = AST__BAD;
9032 }
9033 }
9034
SetObsLon(AstFrame * this,double val,int * status)9035 static void SetObsLon( AstFrame *this, double val, int *status ) {
9036 /*
9037 * Name:
9038 * SetObsLon
9039
9040 * Purpose:
9041 * Set the value of the ObsLon attribute for a SkyFrame.
9042
9043 * Type:
9044 * Private function.
9045
9046 * Synopsis:
9047 * #include "skyframe.h"
9048 * void SetObsLon( AstFrame *this, double val, int *status )
9049
9050 * Class Membership:
9051 * SkyFrame member function (over-rides the astSetObsLon method
9052 * inherited from the Frame class).
9053
9054 * Description:
9055 * This function sets the ObsLon value.
9056
9057 * Parameters:
9058 * this
9059 * Pointer to the SkyFrame.
9060 * val
9061 * New ObsLon value.
9062 * status
9063 * Pointer to the inherited status variable.
9064
9065 */
9066
9067 /* Local Variables: */
9068 double orig;
9069
9070 /* Check the global error status. */
9071 if ( !astOK ) return;
9072
9073 /* Note the original ObsLon value. */
9074 orig = astGetObsLon( this );
9075
9076 /* Invoke the parent method to set the Frame ObsLon. */
9077 (*parent_setobslon)( this, val, status );
9078
9079 /* If the longitude has changed significantly, indicate that the LAST value
9080 will need to be re-calculated when it is next needed. */
9081 if( fabs( orig - val ) > 1.0E-8 ) {
9082 ( (AstSkyFrame *) this )->last = AST__BAD;
9083 ( (AstSkyFrame *) this )->eplast = AST__BAD;
9084 ( (AstSkyFrame *) this )->klast = AST__BAD;
9085 }
9086 }
9087
SetSystem(AstFrame * this_frame,AstSystemType system,int * status)9088 static void SetSystem( AstFrame *this_frame, AstSystemType system, int *status ) {
9089 /*
9090 * Name:
9091 * SetSystem
9092
9093 * Purpose:
9094 * Set the System attribute for a SkyFrame.
9095
9096 * Type:
9097 * Private function.
9098
9099 * Synopsis:
9100 * #include "skyframe.h"
9101 * void SetSystem( AstFrame *this_frame, AstSystemType system, int *status )
9102
9103 * Class Membership:
9104 * SkyFrame member function (over-rides the astSetSystem protected
9105 * method inherited from the Frame class).
9106
9107 * Description:
9108 * This function assigns a new value to the System attribute for a SkyFrame.
9109
9110 * Parameters:
9111 * this
9112 * Pointer to the SkyFrame.
9113 * system
9114 * The new System value.
9115 * status
9116 * Pointer to the inherited status variable.
9117
9118 */
9119
9120 /* Local Variables: */
9121 AstFrameSet *fs; /* FrameSet to be used as the Mapping */
9122 AstSkyFrame *sfrm; /* Copy of original SkyFrame */
9123 AstSkyFrame *this; /* Pointer to SkyFrame structure */
9124 double xin[ 2 ]; /* Axis 0 values */
9125 double xout[ 2 ]; /* Axis 0 values */
9126 double yin[ 2 ]; /* Axis 1 values */
9127 double yout[ 2 ]; /* Axis 1 values */
9128 int aloff; /* The AlignOffset attribute value */
9129 int aloff_set; /* Is the AlignOffset attribute set? */
9130 int skyref_set; /* Is either SkyRef attribute set? */
9131 int skyrefis; /* The SkyRefIs attribute value */
9132 int skyrefis_set; /* Is the SkyRefIs attribute set? */
9133 int skyrefp_set; /* Is either SkyRefP attribute set? */
9134
9135 /* Check the global error status. */
9136 if ( !astOK ) return;
9137
9138 /* Obtain a pointer to the SkyFrame structure. */
9139 this = (AstSkyFrame *) this_frame;
9140
9141 /* See if either the SkyRef or SkyRefP attribute is set. */
9142 skyref_set = astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 );
9143 skyrefp_set = astTestSkyRefP( this, 0 ) || astTestSkyRefP( this, 1 );
9144
9145 /* If so, we will need to transform their values into the new coordinate
9146 system. Save a copy of the SkyFrame with its original System value. */
9147 sfrm = ( skyref_set || skyrefp_set )?astCopy( this ):NULL;
9148
9149 /* Use the parent method to set the new System value. */
9150 (*parent_setsystem)( this_frame, system, status );
9151
9152 /* Now modify the SkyRef and SkyRefP attributes if necessary. */
9153 if( sfrm ) {
9154
9155 /* Save the AlignOffset, SkyRefIs, SkyRef and SkyRefP values. */
9156 aloff_set = astTestAlignOffset( sfrm );
9157 aloff = astGetAlignOffset( sfrm );
9158 skyrefis_set = astTestSkyRefIs( sfrm );
9159 skyrefis = astGetSkyRefIs( sfrm );
9160
9161 xin[ 0 ] = astGetSkyRef( sfrm, 0 );
9162 xin[ 1 ] = astGetSkyRefP( sfrm, 0 );
9163 yin[ 0 ] = astGetSkyRef( sfrm, 1 );
9164 yin[ 1 ] = astGetSkyRefP( sfrm, 1 );
9165
9166 /* Clear the SkyRef and SkyRefP values to avoid infinite recursion in the
9167 following call to astConvert. */
9168 if( skyref_set ) {
9169 astClearSkyRef( sfrm, 0 );
9170 astClearSkyRef( sfrm, 1 );
9171 astClearSkyRef( this, 0 );
9172 astClearSkyRef( this, 1 );
9173 }
9174
9175 if( skyrefp_set ) {
9176 astClearSkyRefP( sfrm, 0 );
9177 astClearSkyRefP( sfrm, 1 );
9178 astClearSkyRefP( this, 0 );
9179 astClearSkyRefP( this, 1 );
9180 }
9181
9182 /* Also set AlignOffset and SkyRefIs so that the following call to
9183 astConvert does not align in offset coords. */
9184 astSetAlignOffset( sfrm, 0 );
9185 astSetSkyRefIs( sfrm, AST__IGNORED_REF );
9186
9187 /* Get the Mapping from the original System to the new System. Invoking
9188 astConvert will recursively invoke SetSystem again. This is why we need
9189 to be careful to ensure that SkyRef and SKyRefP are cleared above - doing
9190 so ensure we do not end up with infinite recursion. */
9191 fs = astConvert( sfrm, this, "" );
9192
9193 /* If the conversion is not possible, clear the SkyRef and SkyRefP
9194 values. */
9195 if( !fs ) {
9196 if( skyref_set ) {
9197 astClearSkyRef( this, 0 );
9198 astClearSkyRef( this, 1 );
9199 }
9200 if( skyrefp_set ) {
9201 astClearSkyRefP( this, 0 );
9202 astClearSkyRefP( this, 1 );
9203 }
9204
9205 /* Use the Mapping to find the SkyRef and SkyRefP positions in the new
9206 coordinate system. */
9207 } else {
9208 astTran2( fs, 2, xin, yin, 1, xout, yout );
9209
9210 /* Store the values as required. */
9211 if( skyref_set ) {
9212 astSetSkyRef( this, 0, xout[ 0 ] );
9213 astSetSkyRef( this, 1, yout[ 0 ] );
9214 }
9215
9216 if( skyrefp_set ) {
9217 astSetSkyRefP( this, 0, xout[ 1 ] );
9218 astSetSkyRefP( this, 1, yout[ 1 ] );
9219 }
9220
9221 /* Restore the original SkyRefIs and AlignOffset values. */
9222 if( aloff_set ) {
9223 astSetAlignOffset( this, aloff );
9224 } else {
9225 astClearAlignOffset( this );
9226 }
9227
9228 if( skyrefis_set ) {
9229 astSetSkyRefIs( this, skyrefis );
9230 } else {
9231 astClearSkyRefIs( this );
9232 }
9233
9234 /* Free resources. */
9235 fs = astAnnul( fs );
9236 }
9237 sfrm = astAnnul( sfrm );
9238 }
9239 }
9240
Shapp(double dist,double * r0,double * r3,double a0,double * p4,int * status)9241 static void Shapp( double dist, double *r0, double *r3, double a0,
9242 double *p4, int *status ){
9243 /*
9244 * Name:
9245 * Shapp
9246
9247 * Purpose:
9248 * Use the vectors calculated by Shcal to find a sky position
9249 * which is offset along a given position angle.
9250
9251 * Type:
9252 * Private function.
9253
9254 * Synopsis:
9255 * #include "skyframe.h"
9256 * void Shapp( double dist, double *r0, double *r3, double a0,
9257 * double *p4, int *status )
9258
9259 * Class Membership:
9260 * SkyFrame member function.
9261
9262 * Description:
9263 * This function uses the vectors R0 and R3 calculated previously by
9264 * Shcal to find the sky position which is offset away from the
9265 * "reference" position (see function Offset2) by a given arc
9266 * distance, along a given great circle.
9267 *
9268 * No checks are made for AST__BAD values.
9269
9270 * Parameters:
9271 * dist
9272 * The arc distance to move away from the reference position
9273 * in the given direction, in radians.
9274 * r0
9275 * Pointer to an array holding the 3-vector representing the reference
9276 * position.
9277 * r3
9278 * Pointer to an array holding the 3-vector representing the
9279 * point which is 90 degrees away from the reference point, along
9280 * the required great circle.
9281 * a0
9282 * The sky longitude of the reference position, in radians.
9283 * p4
9284 * Pointer to an array of 2 doubles in which to put the sky longitude
9285 * and latitude of the required point, in radians.
9286 * status
9287 * Pointer to the inherited status variable.
9288
9289 */
9290
9291 /* Local Variables: */
9292 double cosdst; /* Cosine of DIST */
9293 double r4[ 3 ]; /* Required position vector */
9294 double sindst; /* Sine of DIST */
9295
9296 /* Check the global error status. */
9297 if ( !astOK ) return;
9298
9299 /* Store commonly used values. */
9300 sindst = sin( dist );
9301 cosdst = cos( dist );
9302
9303 /* The vector R4 representing the required point is produced as a
9304 linear sum of R0 and R3. */
9305 r4[ 0 ] = cosdst*r0[ 0 ] + sindst*r3[ 0 ];
9306 r4[ 1 ] = cosdst*r0[ 1 ] + sindst*r3[ 1 ];
9307 r4[ 2 ] = cosdst*r0[ 2 ] + sindst*r3[ 2 ];
9308
9309 /* Create the longitude of the required point. If this point is at
9310 a pole it is assigned the same longitude as the reference point. */
9311 if( r4[ 0 ] != 0.0 || r4[ 1 ] != 0.0 ) {
9312 p4[ 0 ] = atan2( r4[ 1 ], r4[ 0 ] );
9313 } else {
9314 p4[ 0 ] = a0;
9315 }
9316
9317 /* Create the latitude of the required point. */
9318 if( r4[ 2 ] > 1.0 ) {
9319 r4[ 2 ] = 1.0;
9320 } else if( r4[ 2 ] < -1.0 ) {
9321 r4[ 2 ] = -1.0;
9322 }
9323 p4[ 1 ] = asin( r4[ 2 ] );
9324
9325 }
9326
Shcal(double a0,double b0,double angle,double * r0,double * r3,int * status)9327 static void Shcal( double a0, double b0, double angle, double *r0,
9328 double *r3, int *status ) {
9329 /*
9330 * Name:
9331 * Shcal
9332
9333 * Purpose:
9334 * Calculate vectors required by Offset2.
9335
9336 * Type:
9337 * Private function.
9338
9339 * Synopsis:
9340 * #include "skyframe.h"
9341 * void Shcal( double a0, double b0, double angle, double *r0,
9342 * double *r3, int *status )
9343
9344 * Class Membership:
9345 * SkyFrame member function.
9346
9347 * Description:
9348 * This function calculates the 3-vector R0, representing the given
9349 * sky position (A0,B0), and the 3-vector R3, representing the sky
9350 * position which is 90 degrees away from R0, along a great circle
9351 * passing through R0 at a position angle given by ANGLE. Each
9352 * 3-vector holds Cartesian (X,Y,Z) values with origin at the centre
9353 * of the celestial sphere. The XY plane is the "equator", the Z
9354 * axis is in the direction of the "north pole", X is towards zero
9355 * longitude (A=0), and Y is towards longitude 90 degrees.
9356 *
9357 * No checks are made for AST__BAD input values.
9358
9359 * Parameters:
9360 * a0
9361 * The sky longitude of the given position, in radians.
9362 * b0
9363 * The sky latitude of the given position, in radians.
9364 * angle
9365 * The position angle of a great circle passing through the given
9366 * position. That is, the angle from north to the required
9367 * direction, in radians. Positive angles are in the sense of
9368 * rotation from north to east.
9369 * r0
9370 * A pointer to an array to receive 3-vector R0. See above.
9371 * r3
9372 * A pointer to an array to receive 3-vector R3. See above.
9373 * status
9374 * Pointer to the inherited status variable.
9375
9376 */
9377
9378 /* Local Variables: */
9379 double cosa0; /* Cosine of A0 */
9380 double cosb0; /* Cosine of B0 */
9381 double cospa; /* Cosine of ANGLE */
9382 double r1[ 3 ]; /* Vector PI/2 away from R0 in meridian of R0 */
9383 double r2[ 3 ]; /* Vector PI/2 away from R0 on equator */
9384 double sinpa; /* Sine of ANGLE */
9385 double sina0; /* Sine of A0 */
9386 double sinb0; /* Sine of B0 */
9387
9388 /* Check the global error status. */
9389 if ( !astOK ) return;
9390
9391 /* Store commonly used values. */
9392 sina0 = sin( a0 );
9393 cosa0 = cos( a0 );
9394 sinb0 = sin( b0 );
9395 cosb0 = cos( b0 );
9396 sinpa = sin( angle );
9397 cospa = cos( angle );
9398
9399 /* Create the vector R0 representing the given point. The XY plane
9400 defines zero latitude, Z is in the direction of increasing latitude,
9401 X is towards zero longitude, and Y is towards longitude 90 degrees. */
9402 r0[ 0 ] = cosb0*cosa0;
9403 r0[ 1 ] = cosb0*sina0;
9404 r0[ 2 ] = sinb0;
9405
9406 /* Create the vector R1 representing the point in the meridian of the
9407 given point which has latitude 90 degrees greater than the
9408 given point. */
9409 r1[ 0 ] = -sinb0*cosa0;
9410 r1[ 1 ] = -sinb0*sina0;
9411 r1[ 2 ] = cosb0;
9412
9413 /* Create the vector R2 representing the point on the equator (i.e. a
9414 latitude of zero), which has a longitude 90 degrees to the west of
9415 the given point. */
9416 r2[ 0 ] = -sina0;
9417 r2[ 1 ] = cosa0;
9418 r2[ 2 ] = 0.0;
9419
9420 /* Create the vector R3 representing the point which is 90 degrees away
9421 from the given point, along the required great circle. */
9422 r3[ 0 ] = cospa*r1[ 0 ] + sinpa*r2[ 0 ];
9423 r3[ 1 ] = cospa*r1[ 1 ] + sinpa*r2[ 1 ];
9424 r3[ 2 ] = cospa*r1[ 2 ] + sinpa*r2[ 2 ];
9425
9426 /* Return */
9427 return;
9428 }
9429
SubFrame(AstFrame * target_frame,AstFrame * template,int result_naxes,const int * target_axes,const int * template_axes,AstMapping ** map,AstFrame ** result,int * status)9430 static int SubFrame( AstFrame *target_frame, AstFrame *template,
9431 int result_naxes, const int *target_axes,
9432 const int *template_axes, AstMapping **map,
9433 AstFrame **result, int *status ) {
9434 /*
9435 * Name:
9436 * SubFrame
9437
9438 * Purpose:
9439 * Select axes from a SkyFrame and convert to the new coordinate system.
9440
9441 * Type:
9442 * Private function.
9443
9444 * Synopsis:
9445 * #include "skyframe.h"
9446 * int SubFrame( AstFrame *target, AstFrame *template,
9447 * int result_naxes, const int *target_axes,
9448 * const int *template_axes, AstMapping **map,
9449 * AstFrame **result, int *status )
9450
9451 * Class Membership:
9452 * SkyFrame member function (over-rides the protected astSubFrame method
9453 * inherited from the Frame class).
9454
9455 * Description:
9456 * This function selects a requested sub-set (or super-set) of the axes from
9457 * a "target" SkyFrame and creates a new Frame with copies of the selected
9458 * axes assembled in the requested order. It then optionally overlays the
9459 * attributes of a "template" Frame on to the result. It returns both the
9460 * resulting Frame and a Mapping that describes how to convert between the
9461 * coordinate systems described by the target and result Frames. If
9462 * necessary, this Mapping takes account of any differences in the Frames'
9463 * attributes due to the influence of the template.
9464
9465 * Parameters:
9466 * target
9467 * Pointer to the target SkyFrame, from which axes are to be selected.
9468 * template
9469 * Pointer to the template Frame, from which new attributes for the
9470 * result Frame are to be obtained. Optionally, this may be NULL, in
9471 * which case no overlaying of template attributes will be performed.
9472 * result_naxes
9473 * Number of axes to be selected from the target Frame. This number may
9474 * be greater than or less than the number of axes in this Frame (or
9475 * equal).
9476 * target_axes
9477 * Pointer to an array of int with result_naxes elements, giving a list
9478 * of the (zero-based) axis indices of the axes to be selected from the
9479 * target SkyFrame. The order in which these are given determines the
9480 * order in which the axes appear in the result Frame. If any of the
9481 * values in this array is set to -1, the corresponding result axis will
9482 * not be derived from the target Frame, but will be assigned default
9483 * attributes instead.
9484 * template_axes
9485 * Pointer to an array of int with result_naxes elements. This should
9486 * contain a list of the template axes (given as zero-based axis indices)
9487 * with which the axes of the result Frame are to be associated. This
9488 * array determines which axes are used when overlaying axis-dependent
9489 * attributes of the template on to the result. If any element of this
9490 * array is set to -1, the corresponding result axis will not receive any
9491 * template attributes.
9492 *
9493 * If the template argument is given as NULL, this array is not used and
9494 * a NULL pointer may also be supplied here.
9495 * map
9496 * Address of a location to receive a pointer to the returned Mapping.
9497 * The forward transformation of this Mapping will describe how to
9498 * convert coordinates from the coordinate system described by the target
9499 * SkyFrame to that described by the result Frame. The inverse
9500 * transformation will convert in the opposite direction.
9501 * result
9502 * Address of a location to receive a pointer to the result Frame.
9503 * status
9504 * Pointer to the inherited status variable.
9505
9506 * Returned Value:
9507 * A non-zero value is returned if coordinate conversion is possible
9508 * between the target and the result Frame. Otherwise zero is returned and
9509 * *map and *result are returned as NULL (but this will not in itself
9510 * result in an error condition). In general, coordinate conversion should
9511 * always be possible if no template Frame is supplied but may not always
9512 * be possible otherwise.
9513
9514 * Notes:
9515 * - A value of zero will be returned if this function is invoked with the
9516 * global error status set, or if it should fail for any reason.
9517
9518 * Implementation Notes:
9519 * - This implementation addresses the selection of axes from a SkyFrame
9520 * object. This results in another object of the same class only if both
9521 * axes of the SkyFrame are selected, once each. Otherwise, the result is a
9522 * Frame class object which inherits the SkyFrame's axis information (if
9523 * appropriate) but none of the other properties of a SkyFrame.
9524 * - In the event that a SkyFrame results, the returned Mapping will take
9525 * proper account of the relationship between the target and result sky
9526 * coordinate systems.
9527 * - In the event that a Frame class object results, the returned Mapping
9528 * will only represent a selection/permutation of axes.
9529
9530 * Implementation Deficiencies:
9531 * - Any axis selection is currently permitted. Probably this should be
9532 * restricted so that each axis can only be selected once. The
9533 * astValidateAxisSelection method will do this but currently there are bugs
9534 * in the CmpFrame class that cause axis selections which will not pass this
9535 * test. Install the validation when these are fixed.
9536 */
9537
9538 /* Local Variables: */
9539 AstAxis *ax; /* Pointer to result Frame Axis object */
9540 AstMapping *tmpmap; /* Temporary Mapping pointer */
9541 AstPermMap *permmap; /* Pointer to PermMap */
9542 AstSkyFrame *target; /* Pointer to the SkyFrame structure */
9543 AstSkyFrame *temp; /* Pointer to copy of target SkyFrame */
9544 AstSystemType align_sys; /* System in which to align the SkyFrames */
9545 int match; /* Coordinate conversion is possible? */
9546 int perm[ 2 ]; /* Permutation array for axis swap */
9547 int result_swap; /* Swap result SkyFrame coordinates? */
9548 int set_usedefs; /* Set the returned UseDefs attribute zero?*/
9549 int target_axis; /* Target SkyFrame axis index */
9550 int target_swap; /* Swap target SkyFrame coordinates? */
9551
9552 /* Initialise the returned values. */
9553 *map = NULL;
9554 *result = NULL;
9555 match = 0;
9556
9557 /* Check the global error status. */
9558 if ( !astOK ) return match;
9559
9560 /* Obtain a pointer to the target SkyFrame structure. */
9561 target = (AstSkyFrame *) target_frame;
9562
9563 /* Result is a SkyFrame. */
9564 /* --------------------- */
9565 /* Check if the result Frame is to have two axes obtained by selecting
9566 both of the target SkyFrame axes, in either order. If so, the
9567 result will also be a SkyFrame. */
9568 if ( ( result_naxes == 2 ) &&
9569 ( ( ( target_axes[ 0 ] == 0 ) && ( target_axes[ 1 ] == 1 ) ) ||
9570 ( ( target_axes[ 0 ] == 1 ) && ( target_axes[ 1 ] == 0 ) ) ) ) {
9571
9572 /* If a template has not been supplied, or is the same object as the
9573 target, we are simply extracting axes from the supplied SkyFrame. In
9574 this case we temporarily force the UseDefs attribute to 1 so that (for
9575 instance) the astPickAxes method can function correctly. E.g. if you
9576 have a SkyFrame with no set Epoch and UseDefs set zero, and you try to
9577 swap the axes, the attempt would fail because MakeSkyMapping would be
9578 unable to determine the Mapping from original to swapped SkyFrame,
9579 because of the lack of an Epoch value. */
9580 set_usedefs = 0;
9581 if( !template || template == target_frame ) {
9582 if( !astGetUseDefs( target ) ) {
9583 astClearUseDefs( target );
9584 set_usedefs = 1;
9585 }
9586 }
9587
9588 /* Form the result from a copy of the target and then permute its axes
9589 into the order required. */
9590 *result = astCopy( target );
9591 astPermAxes( *result, target_axes );
9592
9593 /* If required, overlay the template attributes on to the result SkyFrame.
9594 Also get the system in which to align the two SkyFrames. This is the
9595 value of the AlignSystem attribute from the template (if there is a
9596 template). */
9597 if ( template ) {
9598 astOverlay( template, template_axes, *result );
9599 align_sys = astGetAlignSystem( template );
9600
9601 } else {
9602 align_sys = astGetAlignSystem( target );
9603 }
9604
9605 /* See whether alignment occurs in offset coordinates or absolute
9606 coordinates. If the current call to this function is part of the
9607 process of restoring a FrameSet's integrity following changes to
9608 the FrameSet's current Frame, then we ignore the setting of the
9609 AlignOffset attributes and use 0. This ensures that when the System
9610 attribute (for instance) is changed via a FrameSet pointer, the
9611 Mappings within the FrameSet are modified to produce offsets in the
9612 new System. If we are not currently restoring a FrameSet's integrity,
9613 then we align in offsets if the template is a SkyFrame and both template
9614 and target want alignment to occur in the offset coordinate system. In
9615 this case we use a UnitMap to connect them. */
9616 if( ( astGetFrameFlags( target_frame ) & AST__INTFLAG ) == 0 ) {
9617 if( astGetAlignOffset( target ) &&
9618 astGetSkyRefIs( target ) != AST__IGNORED_REF &&
9619 template && astIsASkyFrame( template ) ){
9620 if( astGetAlignOffset( (AstSkyFrame *) template ) &&
9621 astGetSkyRefIs( (AstSkyFrame *) template ) != AST__IGNORED_REF ) {
9622 match = 1;
9623 *map = (AstMapping *) astUnitMap( 2, "", status );
9624 }
9625 }
9626 }
9627
9628 /* Otherwise, generate a Mapping that takes account of changes in the sky
9629 coordinate system (equinox, epoch, etc.) between the target SkyFrame and
9630 the result SkyFrame. If this Mapping can be generated, set "match" to
9631 indicate that coordinate conversion is possible. */
9632 if( ! *map ) {
9633 match = ( MakeSkyMapping( target, (AstSkyFrame *) *result,
9634 align_sys, map, status ) != 0 );
9635 }
9636
9637 /* If required, re-instate the original zero value of UseDefs. */
9638 if( set_usedefs ) {
9639 astSetUseDefs( target, 0 );
9640 astSetUseDefs( *result, 0 );
9641 }
9642
9643 /* If a Mapping has been obtained, it will expect coordinate values to be
9644 supplied in (longitude,latitude) pairs. Test whether we need to swap the
9645 order of the target SkyFrame coordinates to conform with this. */
9646 if ( astOK && match ) {
9647 target_swap = ( astValidateAxis( target, 0, 1, "astSubFrame" ) != 0 );
9648
9649 /* Coordinates will also be delivered in (longitude,latitude) pairs, so check
9650 to see whether the result SkyFrame coordinate order should be swapped. */
9651 result_swap = ( target_swap != ( target_axes[ 0 ] != 0 ) );
9652
9653 /* If either set of coordinates needs swapping, create a PermMap that
9654 will swap a pair of coordinates. */
9655 permmap = NULL;
9656 if ( target_swap || result_swap ) {
9657 perm[ 0 ] = 1;
9658 perm[ 1 ] = 0;
9659 permmap = astPermMap( 2, perm, 2, perm, NULL, "", status );
9660 }
9661
9662 /* If necessary, prefix this PermMap to the main Mapping. */
9663 if ( target_swap ) {
9664 tmpmap = (AstMapping *) astCmpMap( permmap, *map, 1, "", status );
9665 *map = astAnnul( *map );
9666 *map = tmpmap;
9667 }
9668
9669 /* Also, if necessary, append it to the main Mapping. */
9670 if ( result_swap ) {
9671 tmpmap = (AstMapping *) astCmpMap( *map, permmap, 1, "", status );
9672 *map = astAnnul( *map );
9673 *map = tmpmap;
9674 }
9675
9676 /* Annul the pointer to the PermMap (if created). */
9677 if ( permmap ) permmap = astAnnul( permmap );
9678 }
9679
9680 /* Result is not a SkyFrame. */
9681 /* ------------------------- */
9682 /* In this case, we select axes as if the target were from the Frame
9683 class. However, since the resulting data will then be separated
9684 from their enclosing SkyFrame, default attribute values may differ
9685 if the methods for obtaining them were over-ridden by the SkyFrame
9686 class. To overcome this, we ensure that these values are explicitly
9687 set for the result Frame (rather than relying on their
9688 defaults). */
9689 } else {
9690
9691 /* Make a temporary copy of the target SkyFrame. We will explicitly
9692 set the attribute values in this copy so as not to modify the
9693 original. */
9694 temp = astCopy( target );
9695
9696 /* Define a macro to test if an attribute is set. If not, set it
9697 explicitly to its default value. */
9698 #define SET(attribute) \
9699 if ( !astTest##attribute( temp ) ) { \
9700 astSet##attribute( temp, astGet##attribute( temp ) ); \
9701 }
9702
9703 /* Set attribute values which apply to the Frame as a whole and which
9704 we want to retain, but whose defaults are over-ridden by the
9705 SkyFrame class. */
9706 SET(Domain)
9707 SET(Title)
9708
9709 /* Now loop to set explicit attribute values for each axis. */
9710 for ( target_axis = 0; target_axis < 2; target_axis++ ) {
9711
9712 /* Define a macro to test if an axis attribute is set. If not, set it
9713 explicitly to its default value. */
9714 #define SET_AXIS(attribute) \
9715 if ( !astTest##attribute( temp, target_axis ) ) { \
9716 astSet##attribute( temp, target_axis, \
9717 astGet##attribute( temp, target_axis ) ); \
9718 }
9719
9720 /* Use this macro to set explicit values for all the axis attributes
9721 for which the SkyFrame class over-rides the default value. */
9722 SET_AXIS(AsTime)
9723 SET_AXIS(Format)
9724 SET_AXIS(Label)
9725 SET_AXIS(Symbol)
9726 SET_AXIS(Unit)
9727
9728 /* Now handle axis attributes for which there are no SkyFrame access
9729 methods. For these we require a pointer to the temporary
9730 SkyFrame's Axis object. */
9731 ax = astGetAxis( temp, target_axis );
9732
9733 /* Set an explicit value for the IsLatitude and CentreZero attributes. */
9734 if( astValidateAxis( temp, target_axis, 1, "astSubFrame" ) == 1 ) {
9735 astSetAxisIsLatitude( ax, 1 );
9736 astSetAxisCentreZero( ax, 1 );
9737
9738 } else {
9739 astSetAxisIsLatitude( ax, 0 );
9740 astSetAxisCentreZero( ax, astGetNegLon( temp ) );
9741 }
9742
9743 /* Annul the Axis object pointer. */
9744 ax = astAnnul( ax );
9745 }
9746
9747 /* Clear attributes which have an extended range of values allowed by
9748 this class. */
9749 astClearSystem( temp );
9750 astClearAlignSystem( temp );
9751
9752 /* Invoke the astSubFrame method inherited from the Frame class to
9753 produce the result Frame by selecting the required set of axes and
9754 overlaying the template Frame's attributes. */
9755 match = (*parent_subframe)( (AstFrame *) temp, template,
9756 result_naxes, target_axes, template_axes,
9757 map, result, status );
9758
9759 /* Delete the temporary copy of the target SkyFrame. */
9760 temp = astDelete( temp );
9761 }
9762
9763 /* Ensure the returned Frame does not have active units. */
9764 astSetActiveUnit( *result, 0 );
9765
9766 /* If an error occurred or no match was found, annul the returned
9767 objects and reset the returned result. */
9768 if ( !astOK || !match ) {
9769 if( *map ) *map = astAnnul( *map );
9770 if( *result ) *result = astAnnul( *result );
9771 match = 0;
9772 }
9773
9774 /* Return the result. */
9775 return match;
9776
9777 /* Undefine macros local to this function. */
9778 #undef SET
9779 #undef SET_AXIS
9780 }
9781
SystemCode(AstFrame * this,const char * system,int * status)9782 static AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) {
9783 /*
9784 * Name:
9785 * SystemCode
9786
9787 * Purpose:
9788 * Convert a string into a coordinate system type code.
9789
9790 * Type:
9791 * Private function.
9792
9793 * Synopsis:
9794 * #include "skyframe.h"
9795 * AstSystemType SystemCode( AstFrame *this, const char *system, int *status )
9796
9797 * Class Membership:
9798 * SkyFrame member function (over-rides the astSystemCode method
9799 * inherited from the Frame class).
9800
9801 * Description:
9802 * This function converts a string used for the external
9803 * description of a sky coordinate system into a SkyFrame
9804 * coordinate system type code (System attribute value). It is the
9805 * inverse of the astSystemString function.
9806
9807 * Parameters:
9808 * this
9809 * The Frame.
9810 * system
9811 * Pointer to a constant null-terminated string containing the
9812 * external description of the sky coordinate system.
9813 * status
9814 * Pointer to the inherited status variable.
9815
9816 * Returned Value:
9817 * The System type code.
9818
9819 * Notes:
9820 * - A value of AST__BADSYSTEM is returned if the sky coordinate
9821 * system description was not recognised. This does not produce an
9822 * error.
9823 * - A value of AST__BADSYSTEM is also returned if this function
9824 * is invoked with the global error status set or if it should fail
9825 * for any reason.
9826 */
9827
9828 /* Local Variables: */
9829 AstSystemType result; /* Result value to return */
9830
9831 /* Initialise. */
9832 result = AST__BADSYSTEM;
9833
9834 /* Check the global error status. */
9835 if ( !astOK ) return result;
9836
9837 /* Match the "system" string against each possibility and assign the
9838 result. */
9839 if ( astChrMatch( "FK4", system ) ) {
9840 result = AST__FK4;
9841
9842 } else if ( astChrMatch( "FK4_NO_E", system ) ||
9843 astChrMatch( "FK4-NO-E", system ) ) {
9844 result = AST__FK4_NO_E;
9845
9846 } else if ( astChrMatch( "FK5", system ) ||
9847 astChrMatch( "Equatorial", system ) ) {
9848 result = AST__FK5;
9849
9850 } else if ( astChrMatch( "J2000", system ) ) {
9851 result = AST__J2000;
9852
9853 } else if ( astChrMatch( "ICRS", system ) ) {
9854 result = AST__ICRS;
9855
9856 } else if ( astChrMatch( "AZEL", system ) ) {
9857 result = AST__AZEL;
9858
9859 } else if ( astChrMatch( "GAPPT", system ) ||
9860 astChrMatch( "GEOCENTRIC", system ) ||
9861 astChrMatch( "APPARENT", system ) ) {
9862 result = AST__GAPPT;
9863
9864 } else if ( astChrMatch( "ECLIPTIC", system ) ) {
9865 result = AST__ECLIPTIC;
9866
9867 } else if ( astChrMatch( "HELIOECLIPTIC", system ) ) {
9868 result = AST__HELIOECLIPTIC;
9869
9870 } else if ( astChrMatch( "GALACTIC", system ) ) {
9871 result = AST__GALACTIC;
9872
9873 } else if ( astChrMatch( "SUPERGALACTIC", system ) ) {
9874 result = AST__SUPERGALACTIC;
9875
9876 } else if ( astChrMatch( "UNKNOWN", system ) ) {
9877 result = AST__UNKNOWN;
9878 }
9879
9880 /* Return the result. */
9881 return result;
9882 }
9883
SystemString(AstFrame * this,AstSystemType system,int * status)9884 static const char *SystemString( AstFrame *this, AstSystemType system, int *status ) {
9885 /*
9886 * Name:
9887 * SystemString
9888
9889 * Purpose:
9890 * Convert a coordinate system type code into a string.
9891
9892 * Type:
9893 * Private function.
9894
9895 * Synopsis:
9896 * #include "skyframe.h"
9897 * const char *SystemString( AstFrame *this, AstSystemType system, int *status )
9898
9899 * Class Membership:
9900 * SkyFrame member function (over-rides the astSystemString method
9901 * inherited from the Frame class).
9902
9903 * Description:
9904 * This function converts a SkyFrame coordinate system type code
9905 * (System attribute value) into a string suitable for use as an
9906 * external representation of the coordinate system type.
9907
9908 * Parameters:
9909 * this
9910 * The Frame.
9911 * system
9912 * The coordinate system type code.
9913 * status
9914 * Pointer to the inherited status variable.
9915
9916 * Returned Value:
9917 * Pointer to a constant null-terminated string containing the
9918 * textual equivalent of the type code supplied.
9919
9920 * Notes:
9921 * - A NULL pointer value is returned if the sky coordinate system
9922 * code was not recognised. This does not produce an error.
9923 * - A NULL pointer value is also returned if this function is
9924 * invoked with the global error status set or if it should fail
9925 * for any reason.
9926 */
9927
9928 /* Local Variables: */
9929 const char *result; /* Pointer value to return */
9930
9931 /* Initialise. */
9932 result = NULL;
9933
9934 /* Check the global error status. */
9935 if ( !astOK ) return result;
9936
9937 /* Match the "system" value against each possibility and convert to a
9938 string pointer. (Where possible, return the same string as would be
9939 used in the FITS WCS representation of the coordinate system). */
9940 switch ( system ) {
9941 case AST__FK4:
9942 result = "FK4";
9943 break;
9944
9945 case AST__FK4_NO_E:
9946 result = "FK4-NO-E";
9947 break;
9948
9949 case AST__FK5:
9950 result = "FK5";
9951 break;
9952
9953 case AST__J2000:
9954 result = "J2000";
9955 break;
9956
9957 case AST__ICRS:
9958 result = "ICRS";
9959 break;
9960
9961 case AST__GAPPT:
9962 result = "GAPPT";
9963 break;
9964
9965 case AST__AZEL:
9966 result = "AZEL";
9967 break;
9968
9969 case AST__ECLIPTIC:
9970 result = "ECLIPTIC";
9971 break;
9972
9973 case AST__HELIOECLIPTIC:
9974 result = "HELIOECLIPTIC";
9975 break;
9976
9977 case AST__GALACTIC:
9978 result = "GALACTIC";
9979 break;
9980
9981 case AST__SUPERGALACTIC:
9982 result = "SUPERGALACTIC";
9983 break;
9984
9985 case AST__UNKNOWN:
9986 result = "Unknown";
9987 break;
9988 }
9989
9990 /* Return the result pointer. */
9991 return result;
9992 }
9993
TestActiveUnit(AstFrame * this_frame,int * status)9994 static int TestActiveUnit( AstFrame *this_frame, int *status ) {
9995 /*
9996 * Name:
9997 * TestActiveUnit
9998
9999 * Purpose:
10000 * Test the ActiveUnit flag for a SkyFrame.
10001
10002 * Type:
10003 * Private function.
10004
10005 * Synopsis:
10006 * #include "skyframe.h"
10007 * int TestActiveUnit( AstFrame *this_frame, int *status )
10008
10009 * Class Membership:
10010 * SkyFrame member function (over-rides the astTestActiveUnit protected
10011 * method inherited from the Frame class).
10012
10013 * Description:
10014 * This function test the value of the ActiveUnit flag for a SkyFrame,
10015 * which is always "unset".
10016
10017 * Parameters:
10018 * this
10019 * Pointer to the SkyFrame.
10020 * status
10021 * Pointer to the inherited status variable.
10022
10023 * Returned Value:
10024 * The result of the test (0).
10025
10026 */
10027 return 0;
10028 }
10029
TestAsTime(AstSkyFrame * this,int axis,int * status)10030 static int TestAsTime( AstSkyFrame *this, int axis, int *status ) {
10031 /*
10032 * Name:
10033 * TestAsTime
10034
10035 * Purpose:
10036 * Determine if a value has been set for a SkyFrame's AsTime attribute.
10037
10038 * Type:
10039 * Private function.
10040
10041 * Synopsis:
10042 * #include "skyframe.h"
10043 * int TestAsTime( AstSkyFrame *this, int axis, int *status )
10044
10045 * Class Membership:
10046 * SkyFrame member function.
10047
10048 * Description:
10049 * This function returns a boolean value to indicate if a value has
10050 * previously been set for the AsTime attribute for a specified axis of a
10051 * SkyFrame. This attribute indicates whether axis values should be
10052 * formatted as times (as opposed to angles) by default.
10053
10054 * Parameters:
10055 * this
10056 * Pointer to the SkyFrame.
10057 * axis
10058 * Index of the axis for which information is required (zero based).
10059 * status
10060 * Pointer to the inherited status variable.
10061
10062 * Returned Value:
10063 * Zero or one, according to whether the AsTime attribute has been set.
10064
10065 * Notes:
10066 * - A value of zero will be returned if this function is invoked with the
10067 * global error status set, or if it should fail for any reason.
10068 */
10069
10070 /* Local Variables. */
10071 AstAxis *ax; /* Pointer to Axis object */
10072 int result; /* Result to be returned */
10073
10074 /* Check the global error status. */
10075 if ( !astOK ) return 0;
10076
10077 /* Validate the axis index. */
10078 (void) astValidateAxis( this, axis, 1, "astTestAsTime" );
10079
10080 /* Obtain a pointer to the Axis object. */
10081 ax = astGetAxis( this, axis );
10082
10083 /* Determine if the AsTime attribute has been set for it (it cannot have been
10084 set unless the object is a SkyAxis). */
10085 result = ( astIsASkyAxis( ax ) && astTestAxisAsTime( ax ) );
10086
10087 /* Annul the Axis pointer. */
10088 ax = astAnnul( ax );
10089
10090 /* Return the result. */
10091 return result;
10092 }
10093
TestAttrib(AstObject * this_object,const char * attrib,int * status)10094 static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
10095 /*
10096 * Name:
10097 * TestAttrib
10098
10099 * Purpose:
10100 * Test if a specified attribute value is set for a SkyFrame.
10101
10102 * Type:
10103 * Private function.
10104
10105 * Synopsis:
10106 * #include "skyframe.h"
10107 * int TestAttrib( AstObject *this, const char *attrib, int *status )
10108
10109 * Class Membership:
10110 * SkyFrame member function (over-rides the astTestAttrib protected
10111 * method inherited from the Frame class).
10112
10113 * Description:
10114 * This function returns a boolean result (0 or 1) to indicate whether
10115 * a value has been set for one of a SkyFrame's attributes.
10116
10117 * Parameters:
10118 * this
10119 * Pointer to the SkyFrame.
10120 * attrib
10121 * Pointer to a null terminated string specifying the attribute
10122 * name. This should be in lower case with no surrounding white
10123 * space.
10124 * status
10125 * Pointer to the inherited status variable.
10126
10127 * Returned Value:
10128 * One if a value has been set, otherwise zero.
10129
10130 * Notes:
10131 * - This function uses one-based axis numbering so that it is
10132 * suitable for external (public) use.
10133 * - A value of zero will be returned if this function is invoked
10134 * with the global status set, or if it should fail for any reason.
10135 */
10136
10137 /* Local Variables: */
10138 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
10139 int axis; /* SkyFrame axis number */
10140 int len; /* Length of attrib string */
10141 int nc; /* No. characters read by astSscanf */
10142 int result; /* Result value to return */
10143
10144 /* Initialise. */
10145 result = 0;
10146
10147 /* Check the global error status. */
10148 if ( !astOK ) return result;
10149
10150 /* Obtain a pointer to the SkyFrame structure. */
10151 this = (AstSkyFrame *) this_object;
10152
10153 /* Obtain the length of the attrib string. */
10154 len = strlen( attrib );
10155
10156 /* Check the attribute name and test the appropriate attribute. */
10157
10158 /* AsTime(axis). */
10159 /* ------------- */
10160 if ( nc = 0,
10161 ( 1 == astSscanf( attrib, "astime(%d)%n", &axis, &nc ) )
10162 && ( nc >= len ) ) {
10163 result = astTestAsTime( this, axis - 1 );
10164
10165 /* Equinox. */
10166 /* -------- */
10167 } else if ( !strcmp( attrib, "equinox" ) ) {
10168 result = astTestEquinox( this );
10169
10170 /* NegLon. */
10171 /* ------- */
10172 } else if ( !strcmp( attrib, "neglon" ) ) {
10173 result = astTestNegLon( this );
10174
10175 /* Projection. */
10176 /* ----------- */
10177 } else if ( !strcmp( attrib, "projection" ) ) {
10178 result = astTestProjection( this );
10179
10180 /* SkyRefIs. */
10181 /* --------- */
10182 } else if ( !strcmp( attrib, "skyrefis" ) ) {
10183 result = astTestSkyRefIs( this );
10184
10185 /* SkyRef. */
10186 /* ------- */
10187 } else if ( !strcmp( attrib, "skyref" ) ) {
10188 result = astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 );
10189
10190 /* SkyRef(axis). */
10191 /* ------------- */
10192 } else if ( nc = 0,
10193 ( 1 == astSscanf( attrib, "skyref(%d)%n", &axis, &nc ) )
10194 && ( nc >= len ) ) {
10195 result = astTestSkyRef( this, axis - 1 );
10196
10197 /* SkyRefP. */
10198 /* -------- */
10199 } else if ( !strcmp( attrib, "skyrefp" ) ) {
10200 result = astTestSkyRefP( this, 0 ) || astTestSkyRefP( this, 1 );
10201
10202 /* SkyRefP(axis). */
10203 /* ------------- */
10204 } else if ( nc = 0,
10205 ( 1 == astSscanf( attrib, "skyrefp(%d)%n", &axis, &nc ) )
10206 && ( nc >= len ) ) {
10207 result = astTestSkyRefP( this, axis - 1 );
10208
10209 /* AlignOffset */
10210 /* ----------- */
10211 } else if ( !strcmp( attrib, "alignoffset" ) ) {
10212 result = astTestAlignOffset( this );
10213
10214 /* If the name is not recognised, test if it matches any of the
10215 read-only attributes of this class. If it does, then return
10216 zero. */
10217 } else if ( !strncmp( attrib, "islataxis", 9 ) ||
10218 !strncmp( attrib, "islonaxis", 9 ) ||
10219 !strcmp( attrib, "lataxis" ) ||
10220 !strcmp( attrib, "lonaxis" ) ) {
10221 result = 0;
10222
10223 /* If the attribute is not recognised, pass it on to the parent method
10224 for further interpretation. */
10225 } else {
10226 result = (*parent_testattrib)( this_object, attrib, status );
10227 }
10228
10229 /* Return the result, */
10230 return result;
10231 }
10232
Unformat(AstFrame * this_frame,int axis,const char * string,double * value,int * status)10233 static int Unformat( AstFrame *this_frame, int axis, const char *string,
10234 double *value, int *status ) {
10235 /*
10236 * Name:
10237 * Unformat
10238
10239 * Purpose:
10240 * Read a formatted coordinate value for a SkyFrame axis.
10241
10242 * Type:
10243 * Private function.
10244
10245 * Synopsis:
10246 * #include "skyframe.h"
10247 * int Unformat( AstFrame *this, int axis, const char *string,
10248 * double *value, int *status )
10249
10250 * Class Membership:
10251 * SkyFrame member function (over-rides the public astUnformat
10252 * method inherited from the Frame class).
10253
10254 * Description:
10255 * This function reads a formatted coordinate value for a SkyFrame
10256 * axis (supplied as a string) and returns the equivalent numerical
10257 * value as a double. It also returns the number of characters read
10258 * from the string.
10259
10260 * Parameters:
10261 * this
10262 * Pointer to the SkyFrame.
10263 * axis
10264 * The number of the SkyFrame axis for which the coordinate
10265 * value is to be read (axis numbering starts at zero for the
10266 * first axis).
10267 * string
10268 * Pointer to a constant null-terminated string containing the
10269 * formatted coordinate value.
10270 * value
10271 * Pointer to a double in which the coordinate value read will
10272 * be returned (in radians).
10273 * status
10274 * Pointer to the inherited status variable.
10275
10276 * Returned Value:
10277 * The number of characters read from the string to obtain the
10278 * coordinate value.
10279
10280 * Notes:
10281 * - Any white space at the beginning of the string will be
10282 * skipped, as also will any trailing white space following the
10283 * coordinate value read. The function's return value will reflect
10284 * this.
10285 * - A function value of zero (and no coordinate value) will be
10286 * returned, without error, if the string supplied does not contain
10287 * a suitably formatted value.
10288 * - The string "<bad>" is recognised as a special case and will
10289 * generate the value AST__BAD, without error. The test for this
10290 * string is case-insensitive and permits embedded white space.
10291 * - A function result of zero will be returned and no coordinate
10292 * value will be returned via the "value" pointer if this function
10293 * is invoked with the global error status set, or if it should
10294 * fail for any reason.
10295 */
10296
10297 /* Local Variables: */
10298 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
10299 double coord; /* Coordinate value read */
10300 int format_set; /* Format attribute set? */
10301 int nc; /* Number of characters read */
10302
10303 /* Initialise. */
10304 nc = 0;
10305
10306 /* Check the global error status. */
10307 if ( !astOK ) return nc;
10308
10309 /* Obtain a pointer to the SkyFrame structure. */
10310 this = (AstSkyFrame *) this_frame;
10311
10312 /* Validate the axis index. */
10313 (void) astValidateAxis( this, axis, 1, "astUnformat" );
10314
10315 /* Determine if a Format value has been set for the axis and set a
10316 temporary value if it has not. Use the GetFormat member function
10317 for this class together with member functions inherited from the
10318 parent class (rather than using the object's methods directly)
10319 because if any of these methods have been over-ridden by a derived
10320 class the Format string syntax may no longer be compatible with
10321 this class. */
10322 format_set = (*parent_testformat)( this_frame, axis, status );
10323 if ( !format_set ) {
10324 (*parent_setformat)( this_frame, axis, GetFormat( this_frame, axis, status ), status );
10325 }
10326
10327 /* Use the Unformat member function inherited from the parent class to
10328 read the coordinate value. */
10329 nc = (*parent_unformat)( this_frame, axis, string, &coord, status );
10330
10331 /* If necessary, clear any temporary Format value that was set above. */
10332 if ( !format_set ) (*parent_clearformat)( this_frame, axis, status );
10333
10334 /* If an error occurred, clear the number of characters read. */
10335 if ( !astOK ) {
10336 nc = 0;
10337
10338 /* Otherwise, if characters were read, return the coordinate value. */
10339 } else if ( nc ) {
10340 *value = coord;
10341 }
10342
10343 /* Return the number of characters read. */
10344 return nc;
10345 }
10346
ValidateSystem(AstFrame * this,AstSystemType system,const char * method,int * status)10347 static int ValidateSystem( AstFrame *this, AstSystemType system, const char *method, int *status ) {
10348 /*
10349 *
10350 * Name:
10351 * ValidateSystem
10352
10353 * Purpose:
10354 * Validate a value for a Frame's System attribute.
10355
10356 * Type:
10357 * Protected virtual function.
10358
10359 * Synopsis:
10360 * #include "frame.h"
10361 * int ValidateSystem( AstFrame *this, AstSystemType system,
10362 * const char *method, int *status )
10363
10364 * Class Membership:
10365 * SkyFrame member function (over-rides the astValidateSystem method
10366 * inherited from the Frame class).
10367
10368 * Description:
10369 * This function checks the validity of the supplied system value.
10370 * If the value is valid, it is returned unchanged. Otherwise, an
10371 * error is reported and a value of AST__BADSYSTEM is returned.
10372
10373 * Parameters:
10374 * this
10375 * Pointer to the Frame.
10376 * system
10377 * The system value to be checked.
10378 * method
10379 * Pointer to a constant null-terminated character string
10380 * containing the name of the method that invoked this function
10381 * to validate an axis index. This method name is used solely
10382 * for constructing error messages.
10383 * status
10384 * Pointer to the inherited status variable.
10385
10386 * Returned Value:
10387 * The validated system value.
10388
10389 * Notes:
10390 * - A value of AST__BADSYSTEM will be returned if this function is invoked
10391 * with the global error status set, or if it should fail for any
10392 * reason.
10393 */
10394
10395 /* Local Variables: */
10396 AstSystemType result; /* Validated system value */
10397
10398 /* Initialise. */
10399 result = AST__BADSYSTEM;
10400
10401 /* Check the global error status. */
10402 if ( !astOK ) return result;
10403
10404 /* If the value is out of bounds, report an error. */
10405 if ( system < FIRST_SYSTEM || system > LAST_SYSTEM ) {
10406 astError( AST__AXIIN, "%s(%s): Bad value (%d) given for the System "
10407 "or AlignSystem attribute of a %s.", status, method,
10408 astGetClass( this ), (int) system, astGetClass( this ) );
10409
10410 /* Otherwise, return the supplied value. */
10411 } else {
10412 result = system;
10413 }
10414
10415 /* Return the result. */
10416 return result;
10417 }
10418
VerifyMSMAttrs(AstSkyFrame * target,AstSkyFrame * result,int which,const char * attrs,const char * method,int * status)10419 static void VerifyMSMAttrs( AstSkyFrame *target, AstSkyFrame *result,
10420 int which, const char *attrs, const char *method, int *status ) {
10421 /*
10422 * Name:
10423 * VerifyMSMAttrs
10424
10425 * Purpose:
10426 * Verify that usable attribute values are available.
10427
10428 * Type:
10429 * Private function.
10430
10431 * Synopsis:
10432 * #include "skyframe.h"
10433 * void VerifyMSMAttrs( AstSkyFrame *target, AstSkyFrame *result,
10434 * int which, const char *attrs, const char *method, int *status )
10435
10436 * Class Membership:
10437 * SkyFrame member function
10438
10439 * Description:
10440 * This function tests each attribute listed in "attrs". It returns
10441 * without action if 1) an explicit value has been set for each attribute
10442 * in the SkyFrame indicated by "which" or 2) the UseDefs attribute of the
10443 * "which" SkyFrame is non-zero.
10444 *
10445 * If UseDefs is zero (indicating that default values should not be
10446 * used for attributes), and any of the named attributes does not have
10447 * an explicitly set value, then an error is reported.
10448 *
10449 * The displayed error message assumes that tjis function was called
10450 * as part of the process of producing a Mapping from "target" to "result".
10451
10452 * Parameters:
10453 * target
10454 * Pointer to the target SkyFrame.
10455 * result
10456 * Pointer to the result SkyFrame.
10457 * which
10458 * If 2, both the target and result SkyFrames are checked for the
10459 * supplied attributes. If less than 2, only the target SkyFrame is
10460 * checked. If greater than 2, only the result SkyFrame is checked.
10461 * attrs
10462 * A string holding a space separated list of attribute names.
10463 * method
10464 * A string holding the name of the calling method for use in error
10465 * messages.
10466 * status
10467 * Pointer to the inherited status variable.
10468
10469 */
10470
10471 /* Local Variables: */
10472 const char *a;
10473 const char *p;
10474 const char *desc;
10475 int len;
10476 int set1;
10477 int set2;
10478 int state;
10479 int usedef1;
10480 int usedef2;
10481
10482 /* Check inherited status */
10483 if( !astOK ) return;
10484
10485 /* Get the UseDefs attributes of the two SkyFrames. */
10486 usedef1 = astGetUseDefs( target );
10487 usedef2 = astGetUseDefs( result );
10488
10489 /* If both SkyFrames have a non-zero value for its UseDefs attribute, then
10490 all attributes are assumed to have usable values, since the defaults
10491 will be used if no explicit value has been set. So we only need to do
10492 any checks if UseDefs is zero for either SkyFrame. */
10493 if( !usedef1 || !usedef2 ) {
10494
10495 /* Stop compiler warnings about uninitialised variables */
10496 a = NULL;
10497 desc = NULL;
10498 len = 0;
10499 set1 = 0;
10500 set2 = 0;
10501
10502 /* Loop round the "attrs" string identifying the start and length of each
10503 non-blank word in the string. */
10504 state = 0;
10505 p = attrs;
10506 while( 1 ) {
10507 if( state == 0 ) {
10508 if( !isspace( *p ) ) {
10509 a = p;
10510 len = 1;
10511 state = 1;
10512 }
10513 } else {
10514 if( isspace( *p ) || !*p ) {
10515
10516 /* The end of a word has just been reached. Compare it to each known
10517 attribute value. Get a flag indicating if the attribute has a set
10518 value, and a string describing the attribute.*/
10519 if( len > 0 ) {
10520
10521 if( !strncmp( "Equinox", a, len ) ) {
10522 set1 = astTestEquinox( target );
10523 set2 = astTestEquinox( result );
10524 desc = "reference equinox";
10525
10526 } else if( !strncmp( "Dut1", a, len ) ) {
10527 set1 = astTestDut1( target );
10528 set2 = astTestDut1( result );
10529 desc = "UT1-UTC correction";
10530
10531 } else if( !strncmp( "Epoch", a, len ) ) {
10532 set1 = astTestEpoch( target );
10533 set2 = astTestEpoch( result );
10534 desc = "epoch of observation";
10535
10536 } else if( !strncmp( "ObsLon", a, len ) ) {
10537 set1 = astTestObsLon( target );
10538 set2 = astTestObsLon( result );
10539 desc = "longitude of observer";
10540
10541 } else if( !strncmp( "ObsLat", a, len ) ) {
10542 set1 = astTestObsLat( target );
10543 set2 = astTestObsLat( result );
10544 desc = "latitude of observer";
10545
10546 } else if( !strncmp( "ObsAlt", a, len ) ) {
10547 set1 = astTestObsAlt( target );
10548 set2 = astTestObsAlt( result );
10549 desc = "altitude of observer";
10550
10551 } else {
10552 astError( AST__INTER, "VerifyMSMAttrs(SkyFrame): "
10553 "Unknown attribute name \"%.*s\" supplied (AST "
10554 "internal programming error).", status, len, a );
10555 }
10556
10557 /* If the attribute is not set in the target but should be, report an
10558 error. */
10559 if( !usedef1 && !set1 && which < 3 ) {
10560 astClearTitle( target );
10561 astClearTitle( result );
10562 astError( AST__NOVAL, "%s(%s): Cannot convert "
10563 "celestial coordinates from %s to %s.", status,
10564 method, astGetClass( target ),
10565 astGetC( target, "Title" ),
10566 astGetC( result, "Title" ) );
10567 astError( AST__NOVAL, "No value has been set for "
10568 "the \"%.*s\" attribute (%s) in the input %s.", status,
10569 len, a, desc, astGetClass( target ) );
10570 break;
10571 }
10572
10573 /* If the attribute is not set in the result but should be, report an
10574 error. */
10575 if( !usedef2 && !set2 && which > 1 ) {
10576 astClearTitle( target );
10577 astClearTitle( result );
10578 astError( AST__NOVAL, "%s(%s): Cannot convert "
10579 "celestial coordinates from %s to %s.", status,
10580 method, astGetClass( result ),
10581 astGetC( target, "Title" ),
10582 astGetC( result, "Title" ) );
10583 astError( AST__NOVAL, "No value has been set for "
10584 "the \"%.*s\" attribute (%s) in the output %s.", status,
10585 len, a, desc, astGetClass( result ) );
10586 break;
10587 }
10588
10589 /* Continue the word search algorithm. */
10590 }
10591 len = 0;
10592 state = 0;
10593 } else {
10594 len++;
10595 }
10596 }
10597 if( !*(p++) ) break;
10598 }
10599 }
10600 }
10601
10602 /* Functions which access class attributes. */
10603 /* ---------------------------------------- */
10604 /*
10605 *att++
10606 * Name:
10607 * AlignOffset
10608
10609 * Purpose:
10610 * Align SkyFrames using the offset coordinate system?
10611
10612 * Type:
10613 * Public attribute.
10614
10615 * Synopsis:
10616 * Integer (boolean).
10617
10618 * Description:
10619 * This attribute is a boolean value which controls how a SkyFrame
10620 * behaves when it is used (by
10621 c astFindFrame or astConvert) as a template to match another (target)
10622 f AST_FINDFRAME or AST_CONVERT) as a template to match another (target)
10623 * SkyFrame. It determines the coordinate system in which the two
10624 * SkyFrames are aligned if a match occurs.
10625 *
10626 * If the template and target SkyFrames both have defined offset coordinate
10627 * systems (i.e. the SkyRefIs attribute is set to either "Origin" or "
10628 * Pole"), and they both have a non-zero value for AlignOffset, then
10629 * alignment occurs within the offset coordinate systems (that is, a
10630 * UnitMap will always be used to align the two SkyFrames). If either
10631 * the template or target SkyFrame has zero (the default value) for
10632 * AlignOffset, or if either SkyFrame has SkyRefIs set to "Ignored", then
10633 * alignment occurring within the coordinate system specified by the
10634 * AlignSystem attribute.
10635
10636 * Applicability:
10637 * SkyFrame
10638 * All SkyFrames have this attribute.
10639 *att--
10640 */
10641 astMAKE_CLEAR(SkyFrame,AlignOffset,alignoffset,-INT_MAX)
10642 astMAKE_GET(SkyFrame,AlignOffset,int,0,( ( this->alignoffset != -INT_MAX ) ?
10643 this->alignoffset : 0 ))
10644 astMAKE_SET(SkyFrame,AlignOffset,int,alignoffset,( value != 0 ))
10645 astMAKE_TEST(SkyFrame,AlignOffset,( this->alignoffset != -INT_MAX ))
10646
10647 /*
10648 *att++
10649 * Name:
10650 * AsTime(axis)
10651
10652 * Purpose:
10653 * Format celestal coordinates as times?
10654
10655 * Type:
10656 * Public attribute.
10657
10658 * Synopsis:
10659 * Integer (boolean).
10660
10661 * Description:
10662 * This attribute specifies the default style of formatting to be
10663 c used (e.g. by astFormat) for the celestial coordinate values
10664 f used (e.g. by AST_FORMAT) for the celestial coordinate values
10665 * described by a SkyFrame. It takes a separate boolean value for
10666 * each SkyFrame axis so that, for instance, the setting
10667 * "AsTime(2)=0" specifies the default formatting style for
10668 * celestial latitude values.
10669 *
10670 * If the AsTime attribute for a SkyFrame axis is zero, then
10671 * coordinates on that axis will be formatted as angles by default
10672 * (using degrees, minutes and seconds), otherwise they will be
10673 * formatted as times (using hours, minutes and seconds).
10674 *
10675 * The default value of AsTime is chosen according to the sky
10676 * coordinate system being represented, as determined by the
10677 * SkyFrame's System attribute. This ensures, for example, that
10678 * right ascension values will be formatted as times by default,
10679 * following normal conventions.
10680
10681 * Applicability:
10682 * SkyFrame
10683 * All SkyFrames have this attribute.
10684
10685 * Notes:
10686 * - The AsTime attribute operates by changing the default value of
10687 * the corresponding Format(axis) attribute. This, in turn, may
10688 * also affect the value of the Unit(axis) attribute.
10689 * - Only the default style of formatting is affected by the AsTime
10690 * value. If an explicit Format(axis) value is set, it will
10691 * over-ride any effect from the AsTime attribute.
10692 *att--
10693 */
10694
10695 /*
10696 *att++
10697 * Name:
10698 * Equinox
10699
10700 * Purpose:
10701 * Epoch of the mean equinox.
10702
10703 * Type:
10704 * Public attribute.
10705
10706 * Synopsis:
10707 * Floating point.
10708
10709 * Description:
10710 * This attribute is used to qualify those celestial coordinate
10711 * systems described by a SkyFrame which are notionally based on
10712 * the ecliptic (the plane of the Earth's orbit around the Sun)
10713 * and/or the Earth's equator.
10714 *
10715 * Both of these planes are in motion and their positions are
10716 * difficult to specify precisely. In practice, therefore, a model
10717 * ecliptic and/or equator are used instead. These, together with
10718 * the point on the sky that defines the coordinate origin (the
10719 * intersection of the two planes termed the "mean equinox") move
10720 * with time according to some model which removes the more rapid
10721 * fluctuations. The SkyFrame class supports both the FK4 and
10722 * FK5 models.
10723 *
10724 * The position of a fixed source expressed in any of these
10725 * coordinate systems will appear to change with time due to
10726 * movement of the coordinate system itself (rather than motion of
10727 * the source). Such coordinate systems must therefore be
10728 * qualified by a moment in time (the "epoch of the mean equinox"
10729 * or "equinox" for short) which allows the position of the model
10730 * coordinate system on the sky to be determined. This is the role
10731 * of the Equinox attribute.
10732 *
10733 * The Equinox attribute is stored as a Modified Julian Date, but
10734 * when setting or getting its value you may use the same formats
10735 * as for the Epoch attribute (q.v.).
10736 *
10737 * The default Equinox value is B1950.0 (Besselian) for the old
10738 * FK4-based coordinate systems (see the System attribute) and
10739 * J2000.0 (Julian) for all others.
10740
10741 * Applicability:
10742 * SkyFrame
10743 * All SkyFrames have this attribute.
10744
10745 * Notes:
10746 * - Care must be taken to distinguish the Equinox value, which
10747 * relates to the definition of a time-dependent coordinate system
10748 * (based on solar system reference planes which are in motion),
10749 * from the superficially similar Epoch value. The latter is used
10750 * to qualify coordinate systems where the positions of sources
10751 * change with time (or appear to do so) for a variety of other
10752 * reasons, such as aberration of light caused by the observer's
10753 * motion, etc.
10754 * - See the description of the System attribute for details of
10755 * which qualifying attributes apply to each celestial coordinate
10756 * system.
10757 *att--
10758 */
10759 /* Clear the Equinox value by setting it to AST__BAD. */
astMAKE_CLEAR(SkyFrame,Equinox,equinox,AST__BAD)10760 astMAKE_CLEAR(SkyFrame,Equinox,equinox,AST__BAD)
10761
10762 /* Provide a default value of B1950.0 or J2000.0 depending on the System
10763 setting. */
10764 astMAKE_GET(SkyFrame,Equinox,double,AST__BAD,(
10765 ( this->equinox != AST__BAD ) ? this->equinox :
10766 ( ( ( astGetSystem( this ) == AST__FK4 ) ||
10767 ( astGetSystem( this ) == AST__FK4_NO_E ) ) ?
10768 palEpb2d( 1950.0 ) : palEpj2d( 2000.0 ) ) ))
10769
10770 /* Allow any Equinox value to be set, unless the System is Helio-ecliptic
10771 (in which case clear the value so that J2000 is used). */
10772 astMAKE_SET(SkyFrame,Equinox,double,equinox,((astGetSystem(this)!=AST__HELIOECLIPTIC)?value:AST__BAD))
10773
10774 /* An Equinox value is set if it is not equal to AST__BAD. */
10775 astMAKE_TEST(SkyFrame,Equinox,( this->equinox != AST__BAD ))
10776
10777
10778 /*
10779 *att++
10780 * Name:
10781 * IsLatAxis(axis)
10782
10783 * Purpose:
10784 * Is the specified celestial axis a latitude axis?
10785
10786 * Type:
10787 * Public attribute.
10788
10789 * Synopsis:
10790 * Integer (boolean), read-only.
10791
10792 * Description:
10793 * This is a read-only boolean attribute that indicates the nature of
10794 * the specified axis. The attribute has a non-zero value if the
10795 * specified axis is a celestial latitude axis (Declination, Galactic
10796 * latitude, etc), and is zero otherwise.
10797
10798 * Applicability:
10799 * SkyFrame
10800 * All SkyFrames have this attribute.
10801
10802 * Notes:
10803 * - When specifying this attribute by name, it should be
10804 * subscripted with the number of the SkyFrame axis to be tested.
10805 *att--
10806 */
10807
10808 /*
10809 *att++
10810 * Name:
10811 * IsLonAxis(axis)
10812
10813 * Purpose:
10814 * Is the specified celestial axis a longitude axis?
10815
10816 * Type:
10817 * Public attribute.
10818
10819 * Synopsis:
10820 * Integer (boolean), read-only.
10821
10822 * Description:
10823 * This is a read-only boolean attribute that indicates the nature of
10824 * the specified axis. The attribute has a non-zero value if the
10825 * specified axis is a celestial longitude axis (Right Ascension, Galactic
10826 * longitude, etc), and is zero otherwise.
10827
10828 * Applicability:
10829 * SkyFrame
10830 * All SkyFrames have this attribute.
10831
10832 * Notes:
10833 * - When specifying this attribute by name, it should be
10834 * subscripted with the number of the SkyFrame axis to be tested.
10835 *att--
10836 */
10837
10838 /*
10839 *att++
10840 * Name:
10841 * LatAxis
10842
10843 * Purpose:
10844 * Index of the latitude axis.
10845
10846 * Type:
10847 * Public attribute.
10848
10849 * Synopsis:
10850 * Integer.
10851
10852 * Description:
10853 * This read-only attribute gives the index (1 or 2) of the latitude
10854 * axis within the SkyFrame (taking into account any current axis
10855 * permutations).
10856
10857 * Applicability:
10858 * SkyFrame
10859 * All SkyFrames have this attribute.
10860
10861 *att--
10862 */
10863
10864 /*
10865 *att++
10866 * Name:
10867 * LonAxis
10868
10869 * Purpose:
10870 * Index of the longitude axis.
10871
10872 * Type:
10873 * Public attribute.
10874
10875 * Synopsis:
10876 * Integer.
10877
10878 * Description:
10879 * This read-only attribute gives the index (1 or 2) of the longitude
10880 * axis within the SkyFrame (taking into account any current axis
10881 * permutations).
10882
10883 * Applicability:
10884 * SkyFrame
10885 * All SkyFrames have this attribute.
10886
10887 *att--
10888 */
10889
10890 /*
10891 *att++
10892 * Name:
10893 * NegLon
10894
10895 * Purpose:
10896 * Display negative longitude values?
10897
10898 * Type:
10899 * Public attribute.
10900
10901 * Synopsis:
10902 * Integer (boolean).
10903
10904 * Description:
10905 * This attribute is a boolean value which controls how longitude values
10906 c are normalized for display by astNorm.
10907 f are normalized for display by AST_NORM.
10908 *
10909 * If the NegLon attribute is zero, then normalized
10910 * longitude values will be in the range zero to 2.pi. If NegLon is
10911 * non-zero, then normalized longitude values will be in the range -pi
10912 * to pi.
10913 *
10914 * The default value depends on the current value of the SkyRefIs
10915 * attribute, If SkyRefIs has a value of "Origin", then the default for
10916 * NegLon is one, otherwise the default is zero.
10917
10918 * Applicability:
10919 * SkyFrame
10920 * All SkyFrames have this attribute.
10921 *att--
10922 */
10923 /* Clear the NegLon value by setting it to -INT_MAX. */
10924 astMAKE_CLEAR(SkyFrame,NegLon,neglon,-INT_MAX)
10925
10926 /* Supply a default of 0 for absolute coords and 1 for offset coords if
10927 no NegLon value has been set. */
10928 astMAKE_GET(SkyFrame,NegLon,int,0,( ( this->neglon != -INT_MAX ) ?
10929 this->neglon : (( astGetSkyRefIs( this ) == AST__ORIGIN_REF )? 1 : 0)))
10930
10931 /* Set a NegLon value of 1 if any non-zero value is supplied. */
10932 astMAKE_SET(SkyFrame,NegLon,int,neglon,( value != 0 ))
10933
10934 /* The NegLon value is set if it is not -INT_MAX. */
10935 astMAKE_TEST(SkyFrame,NegLon,( this->neglon != -INT_MAX ))
10936
10937 /*
10938 *att++
10939 * Name:
10940 * Projection
10941
10942 * Purpose:
10943 * Sky projection description.
10944
10945 * Type:
10946 * Public attribute.
10947
10948 * Synopsis:
10949 * String.
10950
10951 * Description:
10952 * This attribute provides a place to store a description of the
10953 * type of sky projection used when a SkyFrame is attached to a
10954 * 2-dimensional object, such as an image or plotting surface. For
10955 * example, typical values might be "orthographic", "Hammer-Aitoff"
10956 * or "cylindrical equal area".
10957 *
10958 * The Projection value is purely descriptive and does not affect
10959 * the celestial coordinate system represented by the SkyFrame in
10960 * any way. If it is set to a non-blank string, the description
10961 * provided may be used when forming the default value for the
10962 * SkyFrame's Title attribute (so that typically it will appear in
10963 * graphical output, for instance). The default value is an empty
10964 * string.
10965
10966 * Applicability:
10967 * SkyFrame
10968 * All SkyFrames have this attribute.
10969 *att--
10970 */
10971 /* Clear the Projection value by freeing the allocated memory and
10972 assigning a NULL pointer. */
10973 astMAKE_CLEAR(SkyFrame,Projection,projection,astFree( this->projection ))
10974
10975 /* If the Projection value is not set, return a pointer to an empty
10976 string. */
10977 astMAKE_GET(SkyFrame,Projection,const char *,NULL,( this->projection ?
10978 this->projection : "" ))
10979
10980 /* Set a Projection value by freeing any previously allocated memory,
10981 allocating new memory, storing the string and saving the pointer to
10982 the copy. */
10983 astMAKE_SET(SkyFrame,Projection,const char *,projection,astStore(
10984 this->projection, value, strlen( value ) + (size_t) 1 ))
10985
10986 /* The Projection value is set if the pointer to it is not NULL. */
10987 astMAKE_TEST(SkyFrame,Projection,( this->projection != NULL ))
10988
10989 /*
10990 *att++
10991 * Name:
10992 * SkyRefIs
10993
10994 * Purpose:
10995 * Selects the nature of the offset coordinate system.
10996
10997 * Type:
10998 * Public attribute.
10999
11000 * Synopsis:
11001 * String.
11002
11003 * Description:
11004 * This attribute controls how the values supplied for the SkyRef and
11005 * SkyRefP attributes are used. These three attributes together allow
11006 * a SkyFrame to represent offsets relative to some specified origin
11007 * or pole within the coordinate system specified by the System attribute,
11008 * rather than absolute axis values. SkyRefIs can take one of the
11009 * case-insensitive values "Origin", "Pole" or "Ignored".
11010 *
11011 * If SkyRefIs is set to "Origin", then the coordinate system
11012 * represented by the SkyFrame is modified to put the origin of longitude
11013 * and latitude at the position specified by the SkyRef attribute.
11014 *
11015 * If SkyRefIs is set to "Pole", then the coordinate system represented
11016 * by the SkyFrame is modified to put the north pole at the position
11017 * specified by the SkyRef attribute.
11018 *
11019 * If SkyRefIs is set to "Ignored" (the default), then any value set for the
11020 * SkyRef attribute is ignored, and the SkyFrame represents the coordinate
11021 * system specified by the System attribute directly without any rotation.
11022
11023 * Applicability:
11024 * SkyFrame
11025 * All SkyFrames have this attribute.
11026
11027 *att--
11028 */
11029 astMAKE_CLEAR(SkyFrame,SkyRefIs,skyrefis,AST__BAD_REF)
11030 astMAKE_SET(SkyFrame,SkyRefIs,int,skyrefis,value)
11031 astMAKE_TEST(SkyFrame,SkyRefIs,( this->skyrefis != AST__BAD_REF ))
11032 astMAKE_GET(SkyFrame,SkyRefIs,int,AST__IGNORED_REF,(this->skyrefis == AST__BAD_REF ? AST__IGNORED_REF : this->skyrefis))
11033
11034 /*
11035 *att++
11036 * Name:
11037 * SkyRef(axis)
11038
11039 * Purpose:
11040 * Position defining the offset coordinate system.
11041
11042 * Type:
11043 * Public attribute.
11044
11045 * Synopsis:
11046 * Floating point.
11047
11048 * Description:
11049 * This attribute allows a SkyFrame to represent offsets, rather than
11050 * absolute axis values, within the coordinate system specified by the
11051 * System attribute. If supplied, SkyRef should be set to hold the
11052 * longitude and latitude of a point within the coordinate system
11053 * specified by the System attribute. The coordinate system represented
11054 * by the SkyFrame will then be rotated in order to put the specified
11055 * position at either the pole or the origin of the new coordinate system
11056 * (as indicated by the SkyRefIs attribute). The orientation of the
11057 * modified coordinate system is then controlled using the SkyRefP
11058 * attribute.
11059 *
11060 * If an integer axis index is included in the attribute name (e.g.
11061 * "SkyRef(1)") then the attribute value should be supplied as a single
11062 * floating point axis value, in radians, when setting a value for the
11063 * attribute, and will be returned in the same form when getting the value
11064 * of the attribute. In this case the integer axis index should be "1"
11065 * or "2" (the values to use for longitude and latitude axes are
11066 * given by the LonAxis and LatAxis attributes).
11067 *
11068 * If no axis index is included in the attribute name (e.g. "SkyRef") then
11069 * the attribute value should be supplied as a character string
11070 * containing two formatted axis values (an axis 1 value followed by a
11071 * comma, followed by an axis 2 value). The same form
11072 * will be used when getting the value of the attribute.
11073 *
11074 * The default values for SkyRef are zero longitude and zero latitude.
11075
11076 * Aligning SkyFrames with Offset Coordinate Systems:
11077 * The offset coordinate system within a SkyFrame should normally be
11078 * considered as a superficial "re-badging" of the axes of the coordinate
11079 * system specified by the System attribute - it merely provides an
11080 * alternative numerical "label" for each position in the System coordinate
11081 * system. The SkyFrame retains full knowledge of the celestial coordinate
11082 * system on which the offset coordinate system is based (given by the
11083 * System attribute). For instance, the SkyFrame retains knowledge of the
11084 * way that one celestial coordinate system may "drift" with respect to
11085 * another over time. Normally, if you attempt to align two SkyFrames (e.g.
11086 f using the AST_CONVERT or AST_FINDFRAME routine),
11087 c using the astConvert or astFindFrame routine),
11088 * the effect of any offset coordinate system defined in either SkyFrame
11089 * will be removed, resulting in alignment being performed in the
11090 * celestial coordinate system given by the AlignSystem attribute.
11091 * However, by setting the AlignOffset attribute ot a non-zero value, it
11092 * is possible to change this behaviour so that the effect of the offset
11093 * coordinate system is not removed when aligning two SkyFrames.
11094
11095 * Applicability:
11096 * SkyFrame
11097 * All SkyFrames have this attribute.
11098
11099 * Notes:
11100 * - If the System attribute of the SkyFrame is changed, any position
11101 * given for SkyRef is transformed into the new System.
11102 * - If a value has been assigned to SkyRef attribute, then
11103 * the default values for certain attributes are changed as follows:
11104 * the default axis Labels for the SkyFrame are modified by appending
11105 * " offset" to the end, the default axis Symbols for the SkyFrame are
11106 * modified by prepending the character "D" to the start, and the
11107 * default title is modified by replacing the projection information by the
11108 * origin information.
11109
11110 *att--
11111 */
11112 MAKE_CLEAR(SkyRef,skyref,AST__BAD,2)
11113 MAKE_SET(SkyRef,double,skyref,value,2)
11114 MAKE_TEST(SkyRef,( this->skyref[axis_p] != AST__BAD ),2)
11115 MAKE_GET(SkyRef,double,0.0,((this->skyref[axis_p]!=AST__BAD)?this->skyref[axis_p]:0.0),2)
11116
11117 /*
11118 *att++
11119 * Name:
11120 * SkyRefP(axis)
11121
11122 * Purpose:
11123 * Position on primary meridian of offset coordinate system.
11124
11125 * Type:
11126 * Public attribute.
11127
11128 * Synopsis:
11129 * Floating point.
11130
11131 * Description:
11132 * This attribute is used to control the orientation of the offset
11133 * coordinate system defined by attributes SkyRef and SkyRefIs. If used,
11134 * it should be set to hold the longitude and latitude of a point within
11135 * the coordinate system specified by the System attribute. The offset
11136 * coordinate system represented by the SkyFrame will then be rotated in
11137 * order to put the position supplied for SkyRefP on the zero longitude
11138 * meridian. This rotation is about an axis from the centre of the
11139 * celestial sphere to the point specified by the SkyRef attribute.
11140 * The default value for SkyRefP is usually the north pole (that is, a
11141 * latitude of +90 degrees in the coordinate system specified by the System
11142 * attribute). The exception to this is if the SkyRef attribute is
11143 * itself set to either the north or south pole. In these cases the
11144 * default for SkyRefP is the origin (that is, a (0,0) in the coordinate
11145 * system specified by the System attribute).
11146 *
11147 * If an integer axis index is included in the attribute name (e.g.
11148 * "SkyRefP(1)") then the attribute value should be supplied as a single
11149 * floating point axis value, in radians, when setting a value for the
11150 * attribute, and will be returned in the same form when getting the value
11151 * of the attribute. In this case the integer axis index should be "1"
11152 * or "2" (the values to use for longitude and latitude axes are
11153 * given by the LonAxis and LatAxis attributes).
11154 *
11155 * If no axis index is included in the attribute name (e.g. "SkyRefP") then
11156 * the attribute value should be supplied as a character string
11157 * containing two formatted axis values (an axis 1 value followed by a
11158 * comma, followed by an axis 2 value). The same form
11159 * will be used when getting the value of the attribute.
11160
11161 * Applicability:
11162 * SkyFrame
11163 * All SkyFrames have this attribute.
11164
11165 * Notes:
11166 * - If the position given by the SkyRef attribute defines the origin
11167 * of the offset coordinate system (that is, if the SkyRefIs attribute
11168 * is set to "origin"), then there will in general be two orientations
11169 * which will put the supplied SkyRefP position on the zero longitude
11170 * meridian. The orientation which is actually used is the one which
11171 * gives the SkyRefP position a positive latitude in the offset coordinate
11172 * system (the other possible orientation would give the SkyRefP position
11173 * a negative latitude).
11174 * - An error will be reported if an attempt is made to use a
11175 * SkyRefP value which is co-incident with SkyRef or with the point
11176 * diametrically opposite to SkyRef on the celestial sphere. The
11177 * reporting of this error is deferred until the SkyRef and SkyRefP
11178 * attribute values are used within a calculation.
11179 * - If the System attribute of the SkyFrame is changed, any position
11180 * given for SkyRefP is transformed into the new System.
11181
11182 *att--
11183 */
11184 MAKE_CLEAR(SkyRefP,skyrefp,AST__BAD,2)
11185 MAKE_SET(SkyRefP,double,skyrefp,value,2)
11186 MAKE_TEST(SkyRefP,( this->skyrefp[axis_p] != AST__BAD ),2)
11187
11188 /* Copy constructor. */
11189 /* ----------------- */
11190 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
11191 /*
11192 * Name:
11193 * Copy
11194
11195 * Purpose:
11196 * Copy constructor for SkyFrame objects.
11197
11198 * Type:
11199 * Private function.
11200
11201 * Synopsis:
11202 * void Copy( const AstObject *objin, AstObject *objout, int *status )
11203
11204 * Description:
11205 * This function implements the copy constructor for SkyFrame objects.
11206
11207 * Parameters:
11208 * objin
11209 * Pointer to the object to be copied.
11210 * objout
11211 * Pointer to the object being constructed.
11212 * status
11213 * Pointer to the inherited status variable.
11214
11215 * Notes:
11216 * - This constructor makes a deep copy.
11217 */
11218
11219 /* Local Variables: */
11220 AstSkyFrame *in; /* Pointer to input SkyFrame */
11221 AstSkyFrame *out; /* Pointer to output SkyFrame */
11222
11223 /* Check the global error status. */
11224 if ( !astOK ) return;
11225
11226 /* Obtain pointers to the input and output SkyFrames. */
11227 in = (AstSkyFrame *) objin;
11228 out = (AstSkyFrame *) objout;
11229
11230 /* For safety, first clear any references to the input memory from
11231 the output SkyFrame. */
11232 out->projection = NULL;
11233
11234 /* If necessary, allocate memory in the output SkyFrame and store a
11235 copy of the input Projection string. */
11236 if ( in->projection ) out->projection = astStore( NULL, in->projection,
11237 strlen( in->projection ) + (size_t) 1 );
11238
11239 /* If an error occurred, free any allocated memory. */
11240 if ( !astOK ) {
11241 out->projection = astFree( out->projection );
11242 }
11243 }
11244
11245 /* Destructor. */
11246 /* ----------- */
Delete(AstObject * obj,int * status)11247 static void Delete( AstObject *obj, int *status ) {
11248 /*
11249 * Name:
11250 * Delete
11251
11252 * Purpose:
11253 * Destructor for SkyFrame objects.
11254
11255 * Type:
11256 * Private function.
11257
11258 * Synopsis:
11259 * void Delete( AstObject *obj, int *status )
11260
11261 * Description:
11262 * This function implements the destructor for SkyFrame objects.
11263
11264 * Parameters:
11265 * obj
11266 * Pointer to the object to be deleted.
11267 * status
11268 * Pointer to the inherited status variable.
11269
11270 * Notes:
11271 * This function attempts to execute even if the global error status is
11272 * set.
11273 */
11274
11275 /* Local Variables: */
11276 AstSkyFrame *this; /* Pointer to SkyFrame */
11277
11278 /* Obtain a pointer to the SkyFrame structure. */
11279 this = (AstSkyFrame *) obj;
11280
11281 /* Free the memory used for the Projection string if necessary. */
11282 this->projection = astFree( this->projection );
11283 }
11284
11285 /* Dump function. */
11286 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)11287 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
11288 /*
11289 * Name:
11290 * Dump
11291
11292 * Purpose:
11293 * Dump function for SkyFrame objects.
11294
11295 * Type:
11296 * Private function.
11297
11298 * Synopsis:
11299 * void Dump( AstObject *this, AstChannel *channel, int *status )
11300
11301 * Description:
11302 * This function implements the Dump function which writes out data
11303 * for the SkyFrame class to an output Channel.
11304
11305 * Parameters:
11306 * this
11307 * Pointer to the SkyFrame whose data are being written.
11308 * channel
11309 * Pointer to the Channel to which the data are being written.
11310 * status
11311 * Pointer to the inherited status variable.
11312 */
11313
11314 /* Local Variables: */
11315 AstSkyFrame *this; /* Pointer to the SkyFrame structure */
11316 AstSystemType system; /* System attribute value */
11317 char buf[ 100 ]; /* Comment buffer */
11318 char key[ 10 ]; /* Buffer for keywords */
11319 const char *sval; /* Pointer to string value */
11320 const int *perm; /* Pointer to axis permutation array */
11321 double dval; /* Double value */
11322 int bessyr; /* Use a Besselian year value ?*/
11323 int helpful; /* Helpful to display un-set value? */
11324 int invperm[ 2 ]; /* Inverse permutation array */
11325 int ival; /* Integer value */
11326 int set; /* Attribute value set? */
11327 int axis; /* External (i.e. permuted) zero-based axis index */
11328 int axis_p; /* Internal zero-based axis index */
11329
11330 /* Check the global error status. */
11331 if ( !astOK ) return;
11332
11333 /* Obtain a pointer to the SkyFrame structure. */
11334 this = (AstSkyFrame *) this_object;
11335
11336 /* Get a pointer to the SkyFrame's axis permutation array (using a method,
11337 to allow for any over-ride by a derived class). */
11338 perm = astGetPerm( this );
11339
11340 /* Generate an inverse axis permutation array from the forward permutation
11341 values. This will be used to determine which axis should be enquired
11342 about (using possibly over-ridden methods) to obtain data to
11343 correspond with a particular internal value (i.e. instance variable)
11344 relating to an axis. This step is needed so that the effect of any
11345 axis permutation can be un-done before values are written out, as
11346 output values are written by this function in un-permuted order. */
11347 for ( axis = 0; axis < 2; axis++ ) invperm[ perm[ axis ] ] = axis;
11348
11349 /* Write out values representing the instance variables for the
11350 SkyFrame class. Accompany these with appropriate comment strings,
11351 possibly depending on the values being written.*/
11352
11353 /* In the case of attributes, we first use the appropriate (private)
11354 Test... member function to see if they are set. If so, we then use
11355 the (private) Get... function to obtain the value to be written
11356 out.
11357
11358 For attributes which are not set, we use the astGet... method to
11359 obtain the value instead. This will supply a default value
11360 (possibly provided by a derived class which over-rides this method)
11361 which is more useful to a human reader as it corresponds to the
11362 actual default attribute value. Since "set" will be zero, these
11363 values are for information only and will not be read back. */
11364
11365 /* Projection. */
11366 /* ----------- */
11367 set = TestProjection( this, status );
11368 sval = set ? GetProjection( this, status ) : astGetProjection( this );
11369 astWriteString( channel, "Proj", set, 0, sval,
11370 "Description of sky projection" );
11371
11372 /* NegLon. */
11373 /* ------- */
11374 set = TestNegLon( this, status );
11375 ival = set ? GetNegLon( this, status ) : astGetNegLon( this );
11376 astWriteInt( channel, "NegLon", set, 0, ival,
11377 ival ? "Display negative longitude values" :
11378 "Display positive longitude values" );
11379
11380 /* Equinox. */
11381 /* -------- */
11382 set = TestEquinox( this, status );
11383 dval = set ? GetEquinox( this, status ) : astGetEquinox( this );
11384
11385 /* Decide whether the Equinox value is relevant to the current
11386 coordinate system. */
11387 system = astGetSystem( this );
11388 helpful = ( ( system == AST__FK4 ) ||
11389 ( system == AST__FK4_NO_E ) ||
11390 ( system == AST__FK5 ) ||
11391 ( system == AST__ECLIPTIC ) );
11392
11393 /* Convert MJD to Besselian or Julian years, depending on the value. */
11394 bessyr = ( dval < palEpj2d( 1984.0 ) );
11395 dval = bessyr ? palEpb( dval ) : palEpj( dval );
11396 astWriteDouble( channel, "Eqnox", set, helpful, dval,
11397 bessyr ? "Besselian epoch of mean equinox" :
11398 "Julian epoch of mean equinox" );
11399
11400 /* SkyRefIs. */
11401 /* --------- */
11402 set = TestSkyRefIs( this, status );
11403 ival = set ? GetSkyRefIs( this, status ) : astGetSkyRefIs( this );
11404 if( ival == AST__POLE_REF ) {
11405 astWriteString( channel, "SRefIs", set, 0, POLE_STRING,
11406 "Rotated to put pole at ref. pos." );
11407
11408 } else if( ival == AST__IGNORED_REF ) {
11409 astWriteString( channel, "SRefIs", set, 0, IGNORED_STRING,
11410 "Not rotated (ref. pos. is ignored)" );
11411
11412 } else {
11413 astWriteString( channel, "SRefIs", set, 0, ORIGIN_STRING,
11414 "Rotated to put origin at ref. pos." );
11415 }
11416
11417 /* SkyRef. */
11418 /* ------- */
11419 /* The inverse axis permutation array is used to obtain the axis index
11420 to use when accessing the SkyRef attribute. This reverses the effect
11421 of the SkyFrame's axis permutation array and yields a value appropriate
11422 to the axis with internal index "axis". */
11423 for ( axis_p = 0; axis_p < 2; axis_p++ ) {
11424 axis = invperm[ axis_p ];
11425
11426 set = TestSkyRef( this, axis, status );
11427 dval = set ? GetSkyRef( this, axis, status ) : astGetSkyRef( this, axis );
11428 sprintf( buf, "Ref. pos. %s %s", astGetSymbol( this, axis ),
11429 astFormat( this, axis, dval ) );
11430 sprintf( key, "SRef%d", axis_p + 1 );
11431 astWriteDouble( channel, key, set, 0, dval, buf );
11432 }
11433
11434 /* SkyRefP. */
11435 /* -------- */
11436 for ( axis_p = 0; axis_p < 2; axis_p++ ) {
11437 axis = invperm[ axis_p ];
11438
11439 set = TestSkyRefP( this, axis, status );
11440 dval = set ? GetSkyRefP( this, axis, status ) : astGetSkyRefP( this, axis );
11441 sprintf( buf, "Ref. north %s %s", astGetSymbol( this, axis ),
11442 astFormat( this, axis, dval ) );
11443 sprintf( key, "SRefP%d", axis_p + 1 );
11444 astWriteDouble( channel, key, set, 0, dval, buf );
11445 }
11446
11447 /* AlignOffset. */
11448 /* ------------ */
11449 set = TestAlignOffset( this, status );
11450 ival = set ? GetAlignOffset( this, status ) : astGetAlignOffset( this );
11451 astWriteInt( channel, "AlOff", set, 0, ival,
11452 ival ? "Align in offset coords" :
11453 "Align in system coords" );
11454 }
11455
11456 /* Standard class functions. */
11457 /* ========================= */
11458 /* Implement the astIsASkyFrame and astCheckSkyFrame functions using the macros
11459 defined for this purpose in the "object.h" header file. */
astMAKE_ISA(SkyFrame,Frame)11460 astMAKE_ISA(SkyFrame,Frame)
11461 astMAKE_CHECK(SkyFrame)
11462
11463 AstSkyFrame *astSkyFrame_( const char *options, int *status, ...) {
11464 /*
11465 *+
11466 * Name:
11467 * astSkyFrame
11468
11469 * Purpose:
11470 * Create a SkyFrame.
11471
11472 * Type:
11473 * Protected function.
11474
11475 * Synopsis:
11476 * #include "skyframe.h"
11477 * AstSkyFrame *astSkyFrame( const char *options, int *status, ... )
11478
11479 * Class Membership:
11480 * SkyFrame constructor.
11481
11482 * Description:
11483 * This function creates a new SkyFrame and optionally initialises its
11484 * attributes.
11485
11486 * Parameters:
11487 * options
11488 * Pointer to a null terminated string containing an optional
11489 * comma-separated list of attribute assignments to be used for
11490 * initialising the new SkyFrame. The syntax used is the same as for the
11491 * astSet method and may include "printf" format specifiers identified
11492 * by "%" symbols in the normal way.
11493 * status
11494 * Pointer to the inherited status variable.
11495 * ...
11496 * If the "options" string contains "%" format specifiers, then an
11497 * optional list of arguments may follow it in order to supply values to
11498 * be substituted for these specifiers. The rules for supplying these
11499 * are identical to those for the astSet method (and for the C "printf"
11500 * function).
11501
11502 * Returned Value:
11503 * A pointer to the new SkyFrame.
11504
11505 * Notes:
11506 * - A NULL pointer will be returned if this function is invoked with the
11507 * global error status set, or if it should fail for any reason.
11508 *-
11509
11510 * Implementation Notes:
11511 * - This function implements the basic SkyFrame constructor which
11512 * is available via the protected interface to the SkyFrame class.
11513 * A public interface is provided by the astSkyFrameId_ function.
11514 */
11515
11516 /* Local Variables: */
11517 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
11518 AstSkyFrame *new; /* Pointer to new SkyFrame */
11519 va_list args; /* Variable argument list */
11520
11521 /* Get a pointer to the thread specific global data structure. */
11522 astGET_GLOBALS(NULL);
11523
11524 /* Check the global status. */
11525 if ( !astOK ) return NULL;
11526
11527 /* Initialise the SkyFrame, allocating memory and initialising the virtual
11528 function table as well if necessary. */
11529 new = astInitSkyFrame( NULL, sizeof( AstSkyFrame ), !class_init, &class_vtab,
11530 "SkyFrame" );
11531
11532 /* If successful, note that the virtual function table has been initialised. */
11533 if ( astOK ) {
11534 class_init = 1;
11535
11536 /* Obtain the variable argument list and pass it along with the options string
11537 to the astVSet method to initialise the new SkyFrame's attributes. */
11538 va_start( args, status );
11539 astVSet( new, options, NULL, args );
11540 va_end( args );
11541
11542 /* If an error occurred, clean up by deleting the new object. */
11543 if ( !astOK ) new = astDelete( new );
11544 }
11545
11546 /* Return a pointer to the new SkyFrame. */
11547 return new;
11548 }
11549
astInitSkyFrame_(void * mem,size_t size,int init,AstSkyFrameVtab * vtab,const char * name,int * status)11550 AstSkyFrame *astInitSkyFrame_( void *mem, size_t size, int init,
11551 AstSkyFrameVtab *vtab, const char *name, int *status ) {
11552 /*
11553 *+
11554 * Name:
11555 * astInitSkyFrame
11556
11557 * Purpose:
11558 * Initialise a SkyFrame.
11559
11560 * Type:
11561 * Protected function.
11562
11563 * Synopsis:
11564 * #include "skyframe.h"
11565 * AstSkyFrame *astInitSkyFrame( void *mem, size_t size, int init,
11566 * AstFrameVtab *vtab, const char *name )
11567
11568 * Class Membership:
11569 * SkyFrame initialiser.
11570
11571 * Description:
11572 * This function is provided for use by class implementations to initialise
11573 * a new SkyFrame object. It allocates memory (if necessary) to accommodate
11574 * the SkyFrame plus any additional data associated with the derived class.
11575 * It then initialises a SkyFrame structure at the start of this memory. If
11576 * the "init" flag is set, it also initialises the contents of a virtual
11577 * function table for a SkyFrame at the start of the memory passed via the
11578 * "vtab" parameter.
11579
11580 * Parameters:
11581 * mem
11582 * A pointer to the memory in which the SkyFrame is to be created. This
11583 * must be of sufficient size to accommodate the SkyFrame data
11584 * (sizeof(SkyFrame)) plus any data used by the derived class. If a value
11585 * of NULL is given, this function will allocate the memory itself using
11586 * the "size" parameter to determine its size.
11587 * size
11588 * The amount of memory used by the SkyFrame (plus derived class data).
11589 * This will be used to allocate memory if a value of NULL is given for
11590 * the "mem" parameter. This value is also stored in the SkyFrame
11591 * structure, so a valid value must be supplied even if not required for
11592 * allocating memory.
11593 * init
11594 * A logical flag indicating if the SkyFrame's virtual function table is
11595 * to be initialised. If this value is non-zero, the virtual function
11596 * table will be initialised by this function.
11597 * vtab
11598 * Pointer to the start of the virtual function table to be associated
11599 * with the new SkyFrame.
11600 * name
11601 * Pointer to a constant null-terminated character string which contains
11602 * the name of the class to which the new object belongs (it is this
11603 * pointer value that will subsequently be returned by the astGetClass
11604 * method).
11605
11606 * Returned Value:
11607 * A pointer to the new SkyFrame.
11608
11609 * Notes:
11610 * - A null pointer will be returned if this function is invoked with the
11611 * global error status set, or if it should fail for any reason.
11612 *-
11613 */
11614
11615 /* Local Variables: */
11616 AstSkyAxis *ax; /* Pointer to SkyAxis object */
11617 AstSkyFrame *new; /* Pointer to the new SkyFrame */
11618 int axis; /* Loop counter for axes */
11619
11620 /* Check the global status. */
11621 if ( !astOK ) return NULL;
11622
11623 /* If necessary, initialise the virtual function table. */
11624 if ( init ) astInitSkyFrameVtab( vtab, name );
11625
11626 /* Initialise a Frame structure (the parent class) as the first component
11627 within the SkyFrame structure, allocating memory if necessary. */
11628 new = (AstSkyFrame *) astInitFrame( mem, size, 0,
11629 (AstFrameVtab *) vtab, name, 2 );
11630
11631 if ( astOK ) {
11632
11633 /* Initialise the SkyFrame data. */
11634 /* ----------------------------- */
11635 /* Initialise all attributes to their "undefined" values. */
11636 new->equinox = AST__BAD;
11637 new->projection = NULL;
11638 new->neglon = -INT_MAX;
11639 new->alignoffset = -INT_MAX;
11640 new->skyrefis = AST__BAD_REF;
11641 new->skyref[ 0 ] = AST__BAD;
11642 new->skyref[ 1 ] = AST__BAD;
11643 new->skyrefp[ 0 ] = AST__BAD;
11644 new->skyrefp[ 1 ] = AST__BAD;
11645 new->last = AST__BAD;
11646 new->eplast = AST__BAD;
11647 new->klast = AST__BAD;
11648 new->diurab = AST__BAD;
11649
11650 /* Loop to replace the Axis object associated with each SkyFrame axis with
11651 a SkyAxis object instead. */
11652 for ( axis = 0; axis < 2; axis++ ) {
11653
11654 /* Create the new SkyAxis, assign it to the required SkyFrame axis and then
11655 annul the SkyAxis pointer. */
11656 ax = astSkyAxis( "", status );
11657 astSetAxis( new, axis, ax );
11658 ax = astAnnul( ax );
11659 }
11660
11661 /* If an error occurred, clean up by deleting the new object. */
11662 if ( !astOK ) new = astDelete( new );
11663 }
11664
11665 /* Return a pointer to the new object. */
11666 return new;
11667 }
11668
astLoadSkyFrame_(void * mem,size_t size,AstSkyFrameVtab * vtab,const char * name,AstChannel * channel,int * status)11669 AstSkyFrame *astLoadSkyFrame_( void *mem, size_t size,
11670 AstSkyFrameVtab *vtab, const char *name,
11671 AstChannel *channel, int *status ) {
11672 /*
11673 *+
11674 * Name:
11675 * astLoadSkyFrame
11676
11677 * Purpose:
11678 * Load a SkyFrame.
11679
11680 * Type:
11681 * Protected function.
11682
11683 * Synopsis:
11684 * #include "skyframe.h"
11685 * AstSkyFrame *astLoadSkyFrame( void *mem, size_t size,
11686 * AstSkyFrameVtab *vtab, const char *name,
11687 * AstChannel *channel )
11688
11689 * Class Membership:
11690 * SkyFrame loader.
11691
11692 * Description:
11693 * This function is provided to load a new SkyFrame using data read
11694 * from a Channel. It first loads the data used by the parent class
11695 * (which allocates memory if necessary) and then initialises a
11696 * SkyFrame structure in this memory, using data read from the
11697 * input Channel.
11698
11699 * Parameters:
11700 * mem
11701 * A pointer to the memory into which the SkyFrame is to be
11702 * loaded. This must be of sufficient size to accommodate the
11703 * SkyFrame data (sizeof(SkyFrame)) plus any data used by
11704 * derived classes. If a value of NULL is given, this function
11705 * will allocate the memory itself using the "size" parameter to
11706 * determine its size.
11707 * size
11708 * The amount of memory used by the SkyFrame (plus derived class
11709 * data). This will be used to allocate memory if a value of
11710 * NULL is given for the "mem" parameter. This value is also
11711 * stored in the SkyFrame structure, so a valid value must be
11712 * supplied even if not required for allocating memory.
11713 *
11714 * If the "vtab" parameter is NULL, the "size" value is ignored
11715 * and sizeof(AstSkyFrame) is used instead.
11716 * vtab
11717 * Pointer to the start of the virtual function table to be
11718 * associated with the new SkyFrame. If this is NULL, a pointer
11719 * to the (static) virtual function table for the SkyFrame class
11720 * is used instead.
11721 * name
11722 * Pointer to a constant null-terminated character string which
11723 * contains the name of the class to which the new object
11724 * belongs (it is this pointer value that will subsequently be
11725 * returned by the astGetClass method).
11726 *
11727 * If the "vtab" parameter is NULL, the "name" value is ignored
11728 * and a pointer to the string "SkyFrame" is used instead.
11729
11730 * Returned Value:
11731 * A pointer to the new SkyFrame.
11732
11733 * Notes:
11734 * - A null pointer will be returned if this function is invoked
11735 * with the global error status set, or if it should fail for any
11736 * reason.
11737 *-
11738 */
11739
11740 /* Local Variables: */
11741 AstSkyFrame *new; /* Pointer to the new SkyFrame */
11742 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
11743 char *sval; /* Pointer to string value */
11744 const int *perm; /* Pointer to axis permutation array */
11745 double dval; /* Floating point attribute value */
11746 int axis; /* External axis index */
11747 int invperm[ 2 ]; /* Inverse permutation array */
11748
11749 /* Initialise. */
11750 new = NULL;
11751
11752 /* Get a pointer to the thread specific global data structure. */
11753 astGET_GLOBALS(channel);
11754
11755 /* Check the global error status. */
11756 if ( !astOK ) return new;
11757
11758 /* If a NULL virtual function table has been supplied, then this is
11759 the first loader to be invoked for this SkyFrame. In this case the
11760 SkyFrame belongs to this class, so supply appropriate values to be
11761 passed to the parent class loader (and its parent, etc.). */
11762 if ( !vtab ) {
11763 size = sizeof( AstSkyFrame );
11764 vtab = &class_vtab;
11765 name = "SkyFrame";
11766
11767 /* If required, initialise the virtual function table for this class. */
11768 if ( !class_init ) {
11769 astInitSkyFrameVtab( vtab, name );
11770 class_init = 1;
11771 }
11772 }
11773
11774 /* Invoke the parent class loader to load data for all the ancestral
11775 classes of the current one, returning a pointer to the resulting
11776 partly-built SkyFrame. */
11777 new = astLoadFrame( mem, size, (AstFrameVtab *) vtab, name,
11778 channel );
11779
11780 if ( astOK ) {
11781
11782 /* Get a pointer to the SkyFrame's axis permutation array (using a method,
11783 to allow for any over-ride by a derived class). */
11784 perm = astGetPerm( new );
11785
11786 /* Generate an inverse axis permutation array from the forward permutation
11787 values. This will be used to determine which axis should be enquired
11788 about (using possibly over-ridden methods) to obtain data to
11789 correspond with a particular internal value (i.e. instance variable)
11790 relating to an axis. This step is needed so that the effect of any
11791 axis permutation can be un-done before values are written out, as
11792 output values are written by this function in un-permuted order. */
11793 for( axis = 0; axis < 2; axis++ ) invperm[ perm[ axis ] ] = axis;
11794
11795 /* Read input data. */
11796 /* ================ */
11797 /* Request the input Channel to read all the input data appropriate to
11798 this class into the internal "values list". */
11799 astReadClassData( channel, "SkyFrame" );
11800
11801 /* Now read each individual data item from this list and use it to
11802 initialise the appropriate instance variable(s) for this class. */
11803
11804 /* In the case of attributes, we first read the "raw" input value,
11805 supplying the "unset" value as the default. If a "set" value is
11806 obtained, we then use the appropriate (private) Set... member
11807 function to validate and set the value properly. */
11808
11809 /* The attributes defining the offset coordinate system must be loaded
11810 before the System attrivbute, since SetSystem uses them. */
11811
11812 /* AlignOffset */
11813 /* ----------- */
11814 new->alignoffset = astReadInt( channel, "aloff", -INT_MAX );
11815 if ( TestAlignOffset( new, status ) ) SetAlignOffset( new, new->alignoffset, status );
11816
11817 /* SkyRefIs. */
11818 /* --------- */
11819 sval = astReadString( channel, "srefis", " " );
11820 if( sval ){
11821 new->skyrefis = AST__BAD_REF;
11822 if( astChrMatch( sval, POLE_STRING ) ) {
11823 new->skyrefis = AST__POLE_REF;
11824 } else if( astChrMatch( sval, ORIGIN_STRING ) ) {
11825 new->skyrefis = AST__ORIGIN_REF;
11826 } else if( astChrMatch( sval, IGNORED_STRING ) ) {
11827 new->skyrefis = AST__IGNORED_REF;
11828 } else if( !astChrMatch( sval, " " ) && astOK ){
11829 astError( AST__INTER, "astRead(SkyFrame): Corrupt SkyFrame contains "
11830 "invalid SkyRefIs attribute value (%s).", status, sval );
11831 }
11832 if( TestSkyRefIs( new, status ) ) SetSkyRefIs( new, new->skyrefis, status );
11833 sval = astFree( sval );
11834 }
11835
11836 /* SkyRef. */
11837 /* ------- */
11838 new->skyref[ 0 ] = astReadDouble( channel, "sref1", AST__BAD );
11839 axis = invperm[ 0 ];
11840 if ( TestSkyRef( new, axis, status ) ) SetSkyRef( new, axis, new->skyref[ 0 ], status );
11841
11842 new->skyref[ 1 ] = astReadDouble( channel, "sref2", AST__BAD );
11843 axis = invperm[ 1 ];
11844 if ( TestSkyRef( new, axis, status ) ) SetSkyRef( new, axis, new->skyref[ 1 ], status );
11845
11846 /* SkyRefP. */
11847 /* -------- */
11848 new->skyrefp[ 0 ] = astReadDouble( channel, "srefp1", AST__BAD );
11849 axis = invperm[ 0 ];
11850 if ( TestSkyRefP( new, axis, status ) ) SetSkyRefP( new, axis, new->skyrefp[ 0 ], status );
11851
11852 new->skyrefp[ 1 ] = astReadDouble( channel, "srefp2", AST__BAD );
11853 axis = invperm[ 1 ];
11854 if ( TestSkyRefP( new, axis, status ) ) SetSkyRefP( new, axis, new->skyrefp[ 1 ], status );
11855
11856 /* System. */
11857 /* ------- */
11858 /* The System attribute is now part of the Frame class, but this code is
11859 retained to allow this version of AST to read SkyFrames dumped by
11860 previous versions. */
11861
11862 /* Check a value has not already been assigned to the Frames System
11863 attribute. */
11864 if( !astTestSystem( new ) ){
11865
11866 /* Read the external representation as a string. */
11867 sval = astReadString( channel, "system", NULL );
11868
11869 /* If a value was read, use the SetAttrib method to validate and store the
11870 new value in the correct place, then free the string. */
11871 if ( sval ) {
11872 astSet( new, "System=%s", status, sval);
11873 sval = astFree( sval );
11874 }
11875 }
11876
11877 /* Epoch. */
11878 /* ------ */
11879 /* The Epoch attribute is now part of the Frame class, but this code is
11880 retained to allow this version of AST to read SkyFrames dumped by
11881 previous versions. */
11882
11883 /* Check a value has not already been assigned to the Frames Epoch
11884 attribute. */
11885 if( !astTestEpoch( new ) ){
11886
11887 /* Get the value. */
11888 dval = astReadDouble( channel, "epoch", AST__BAD );
11889
11890 /* If a value was read, use the SetAttrib method to validate and store the
11891 new value in the correct place. */
11892 if( dval != AST__BAD ) {
11893 if( dval < 1984.0 ) {
11894 astSet( new, "Epoch=B%.*g", status, DBL_DIG, dval);
11895 } else {
11896 astSet( new, "Epoch=J%.*g", status, DBL_DIG, dval);
11897 }
11898 }
11899 }
11900
11901 /* Projection. */
11902 /* ----------- */
11903 new->projection = astReadString( channel, "proj", NULL );
11904
11905 /* Equinox. */
11906 /* -------- */
11907 /* Interpret this as Besselian or Julian depending on its value. */
11908 new->equinox = astReadDouble( channel, "eqnox", AST__BAD );
11909 if ( TestEquinox( new, status ) ) {
11910 SetEquinox( new, ( new->equinox < 1984.0 ) ? palEpb2d( new->equinox ) :
11911 palEpj2d( new->equinox ), status );
11912 }
11913
11914 /* NegLon. */
11915 /* ------- */
11916 new->neglon = astReadInt( channel, "neglon", -INT_MAX );
11917 if ( TestNegLon( new, status ) ) SetNegLon( new, new->neglon, status );
11918
11919 /* Other values */
11920 /* ------------ */
11921 new->last = AST__BAD;
11922 new->eplast = AST__BAD;
11923 new->klast = AST__BAD;
11924 new->diurab = AST__BAD;
11925
11926 /* If an error occurred, clean up by deleting the new SkyFrame. */
11927 if ( !astOK ) new = astDelete( new );
11928 }
11929
11930 /* Return the new SkyFrame pointer. */
11931 return new;
11932 }
11933
11934 /* Virtual function interfaces. */
11935 /* ============================ */
11936 /* These provide the external interface to the virtual functions defined by
11937 this class. Each simply checks the global error status and then locates and
11938 executes the appropriate member function, using the function pointer stored
11939 in the object's virtual function table (this pointer is located using the
11940 astMEMBER macro defined in "object.h").
11941
11942 Note that the member function may not be the one defined here, as it may
11943 have been over-ridden by a derived class. However, it should still have the
11944 same interface. */
astClearAsTime_(AstSkyFrame * this,int axis,int * status)11945 void astClearAsTime_( AstSkyFrame *this, int axis, int *status ) {
11946 if ( !astOK ) return;
11947 (**astMEMBER(this,SkyFrame,ClearAsTime))( this, axis, status );
11948 }
astGetAsTime_(AstSkyFrame * this,int axis,int * status)11949 int astGetAsTime_( AstSkyFrame *this, int axis, int *status ) {
11950 if ( !astOK ) return 0;
11951 return (**astMEMBER(this,SkyFrame,GetAsTime))( this, axis, status );
11952 }
astSetAsTime_(AstSkyFrame * this,int axis,int value,int * status)11953 void astSetAsTime_( AstSkyFrame *this, int axis, int value, int *status ) {
11954 if ( !astOK ) return;
11955 (**astMEMBER(this,SkyFrame,SetAsTime))( this, axis, value, status );
11956 }
astTestAsTime_(AstSkyFrame * this,int axis,int * status)11957 int astTestAsTime_( AstSkyFrame *this, int axis, int *status ) {
11958 if ( !astOK ) return 0;
11959 return (**astMEMBER(this,SkyFrame,TestAsTime))( this, axis, status );
11960 }
astGetIsLatAxis_(AstSkyFrame * this,int axis,int * status)11961 int astGetIsLatAxis_( AstSkyFrame *this, int axis, int *status ) {
11962 if ( !astOK ) return 0;
11963 return (**astMEMBER(this,SkyFrame,GetIsLatAxis))( this, axis, status );
11964 }
astGetIsLonAxis_(AstSkyFrame * this,int axis,int * status)11965 int astGetIsLonAxis_( AstSkyFrame *this, int axis, int *status ) {
11966 if ( !astOK ) return 0;
11967 return (**astMEMBER(this,SkyFrame,GetIsLonAxis))( this, axis, status );
11968 }
astGetLatAxis_(AstSkyFrame * this,int * status)11969 int astGetLatAxis_( AstSkyFrame *this, int *status ) {
11970 if ( !astOK ) return 1;
11971 return (**astMEMBER(this,SkyFrame,GetLatAxis))( this, status );
11972 }
astGetLonAxis_(AstSkyFrame * this,int * status)11973 int astGetLonAxis_( AstSkyFrame *this, int *status ) {
11974 if ( !astOK ) return 0;
11975 return (**astMEMBER(this,SkyFrame,GetLonAxis))( this, status );
11976 }
astGetSkyRefP_(AstSkyFrame * this,int axis,int * status)11977 double astGetSkyRefP_( AstSkyFrame *this, int axis, int *status ) {
11978 if ( !astOK ) return 0.0;
11979 return (**astMEMBER(this,SkyFrame,GetSkyRefP))( this, axis, status );
11980 }
astSkyOffsetMap_(AstSkyFrame * this,int * status)11981 AstMapping *astSkyOffsetMap_( AstSkyFrame *this, int *status ) {
11982 if ( !astOK ) return NULL;
11983 return (**astMEMBER(this,SkyFrame,SkyOffsetMap))( this, status );
11984 }
11985
11986 /* Special public interface functions. */
11987 /* =================================== */
11988 /* These provide the public interface to certain special functions
11989 whose public interface cannot be handled using macros (such as
11990 astINVOKE) alone. In general, they are named after the
11991 corresponding protected version of the function, but with "Id"
11992 appended to the name. */
11993
11994 /* Public Interface Function Prototypes. */
11995 /* ------------------------------------- */
11996 /* The following functions have public prototypes only (i.e. no
11997 protected prototypes), so we must provide local prototypes for use
11998 within this module. */
11999 AstSkyFrame *astSkyFrameId_( const char *, ... );
12000
12001 /* Special interface function implementations. */
12002 /* ------------------------------------------- */
astSkyFrameId_(const char * options,...)12003 AstSkyFrame *astSkyFrameId_( const char *options, ... ) {
12004 /*
12005 *++
12006 * Name:
12007 c astSkyFrame
12008 f AST_SKYFRAME
12009
12010 * Purpose:
12011 * Create a SkyFrame.
12012
12013 * Type:
12014 * Public function.
12015
12016 * Synopsis:
12017 c #include "skyframe.h"
12018 c AstSkyFrame *astSkyFrame( const char *options, ... )
12019 f RESULT = AST_SKYFRAME( OPTIONS, STATUS )
12020
12021 * Class Membership:
12022 * SkyFrame constructor.
12023
12024 * Description:
12025 * This function creates a new SkyFrame and optionally initialises
12026 * its attributes.
12027 *
12028 * A SkyFrame is a specialised form of Frame which describes
12029 * celestial longitude/latitude coordinate systems. The particular
12030 * celestial coordinate system to be represented is specified by
12031 * setting the SkyFrame's System attribute (currently, the default
12032 * is ICRS) qualified, as necessary, by a mean Equinox value and/or
12033 * an Epoch.
12034 *
12035 * For each of the supported celestial coordinate systems, a SkyFrame
12036 * can apply an optional shift of origin to create a coordinate system
12037 * representing offsets within the celestial coordinate system from some
12038 * specified point. This offset coordinate system can also be rotated to
12039 * define new longitude and latitude axes. See attributes SkyRef, SkyRefIs
12040 * and SkyRefP
12041 *
12042 * All the coordinate values used by a SkyFrame are in
12043 * radians. These may be formatted in more conventional ways for
12044 c display by using astFormat.
12045 f display by using AST_FORMAT.
12046
12047 * Parameters:
12048 c options
12049 f OPTIONS = CHARACTER * ( * ) (Given)
12050 c Pointer to a null-terminated string containing an optional
12051 c comma-separated list of attribute assignments to be used for
12052 c initialising the new SkyFrame. The syntax used is identical to
12053 c that for the astSet function and may include "printf" format
12054 c specifiers identified by "%" symbols in the normal way.
12055 c If no initialisation is required, a zero-length string may be
12056 c supplied.
12057 f A character string containing an optional comma-separated
12058 f list of attribute assignments to be used for initialising the
12059 f new SkyFrame. The syntax used is identical to that for the
12060 f AST_SET routine. If no initialisation is required, a blank
12061 f value may be supplied.
12062 c ...
12063 c If the "options" string contains "%" format specifiers, then
12064 c an optional list of additional arguments may follow it in
12065 c order to supply values to be substituted for these
12066 c specifiers. The rules for supplying these are identical to
12067 c those for the astSet function (and for the C "printf"
12068 c function).
12069 f STATUS = INTEGER (Given and Returned)
12070 f The global status.
12071
12072 * Returned Value:
12073 c astSkyFrame()
12074 f AST_SKYFRAME = INTEGER
12075 * A pointer to the new SkyFrame.
12076
12077 * Examples:
12078 c frame = astSkyFrame( "" );
12079 c Creates a SkyFrame to describe the default ICRS celestial
12080 c coordinate system.
12081 c frame = astSkyFrame( "System = FK5, Equinox = J2005, Digits = 10" );
12082 c Creates a SkyFrame to describe the FK5 celestial
12083 c coordinate system, with a mean Equinox of J2005.0.
12084 c Because especially accurate coordinates will be used,
12085 c additional precision (10 digits) has been requested. This will
12086 c be used when coordinate values are formatted for display.
12087 c frame = astSkyFrame( "System = FK4, Equinox = 1955-sep-2" );
12088 c Creates a SkyFrame to describe the old FK4 celestial
12089 c coordinate system. A default Epoch value (B1950.0) is used,
12090 c but the mean Equinox value is given explicitly as "1955-sep-2".
12091 c frame = astSkyFrame( "System = GAPPT, Epoch = %s", date );
12092 c Creates a SkyFrame to describe the Geocentric Apparent
12093 c celestial coordinate system. The Epoch value, which specifies
12094 c the date of observation, is obtained from a date/time string
12095 c supplied via the string pointer "date".
12096 f FRAME = AST_SKYFRAME( ' ', STATUS )
12097 f Creates a SkyFrame to describe the default ICRS celestial
12098 f coordinate system.
12099 f FRAME = AST_SKYFRAME( 'System = FK5, Equinox = J2005, Digits = 10', STATUS )
12100 f Creates a SkyFrame to describe the FK5 celestial
12101 f coordinate system, with a mean Equinox of J2005.0.
12102 f Because especially accurate coordinates will be used,
12103 f additional precision (10 digits) has been requested. This will
12104 f be used when coordinate values are formatted for display.
12105 f FRAME = AST_SKYFRAME( 'System = FK4, Equinox = 1955-SEP-2', STATUS )
12106 f Creates a SkyFrame to describe the old FK4 celestial
12107 f coordinate system. A default Epoch value (B1950.0) is used,
12108 f but the mean Equinox value is given explicitly as "1955-SEP-2".
12109 f FRAME = AST_SKYFRAME( 'System = GAPPT, Epoch = ' // DATE, STATUS )
12110 f Creates a SkyFrame to describe the Geocentric Apparent
12111 f celestial coordinate system. The Epoch value, which specifies
12112 f the date of observation, is obtained from a date/time string
12113 f contained in the character variable DATE.
12114
12115 * Notes:
12116 * - Currently, the default celestial coordinate system is
12117 * ICRS. However, this default may change in future as new
12118 * astrometric standards evolve. The intention is to track the most
12119 * modern appropriate standard. For this reason, you should use the
12120 * default only if this is what you intend (and can tolerate any
12121 * associated slight change in behaviour with future versions of
12122 * this function). If you intend to use the ICRS system
12123 * indefinitely, then you should specify it explicitly using an
12124 c "options" value of "System=ICRS".
12125 f OPTIONS value of "System=ICRS".
12126 * - Whichever celestial coordinate system is represented, it will
12127 * have two axes. The first of these will be the longitude axis
12128 * and the second will be the latitude axis. This order can be
12129 c changed using astPermAxes if required.
12130 f changed using AST_PERMAXES if required.
12131 * - When conversion between two SkyFrames is requested (as when
12132 c supplying SkyFrames to astConvert),
12133 f supplying SkyFrames AST_CONVERT),
12134 * account will be taken of the nature of the celestial coordinate
12135 * systems they represent, together with any qualifying mean Equinox or
12136 * Epoch values, etc. The AlignSystem attribute will also be taken into
12137 * account. The results will therefore fully reflect the
12138 * relationship between positions on the sky measured in the two
12139 * systems.
12140 * - A null Object pointer (AST__NULL) will be returned if this
12141 c function is invoked with the AST error status set, or if it
12142 f function is invoked with STATUS set to an error value, or if it
12143 * should fail for any reason.
12144 *--
12145
12146 * Implementation Notes:
12147 * - This function implements the external (public) interface to
12148 * the astSkyFrame constructor function. It returns an ID value
12149 * (instead of a true C pointer) to external users, and must be
12150 * provided because astSkyFrame_ has a variable argument list which
12151 * cannot be encapsulated in a macro (where this conversion would
12152 * otherwise occur).
12153 * - The variable argument list also prevents this function from
12154 * invoking astSkyFrame_ directly, so it must be a
12155 * re-implementation of it in all respects, except for the final
12156 * conversion of the result to an ID value.
12157 */
12158
12159 /* Local Variables: */
12160 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
12161 AstSkyFrame *new; /* Pointer to new SkyFrame */
12162 va_list args; /* Variable argument list */
12163
12164 int *status; /* Pointer to inherited status value */
12165
12166 /* Get a pointer to the inherited status value. */
12167 status = astGetStatusPtr;
12168
12169 /* Get a pointer to the thread specific global data structure. */
12170 astGET_GLOBALS(NULL);
12171
12172 /* Check the global status. */
12173 if ( !astOK ) return NULL;
12174
12175 /* Initialise the SkyFrame, allocating memory and initialising the virtual
12176 function table as well if necessary. */
12177 new = astInitSkyFrame( NULL, sizeof( AstSkyFrame ), !class_init, &class_vtab,
12178 "SkyFrame" );
12179
12180 /* If successful, note that the virtual function table has been initialised. */
12181 if ( astOK ) {
12182 class_init = 1;
12183
12184 /* Obtain the variable argument list and pass it along with the options string
12185 to the astVSet method to initialise the new SkyFrame's attributes. */
12186 va_start( args, options );
12187 astVSet( new, options, NULL, args );
12188 va_end( args );
12189
12190 /* If an error occurred, clean up by deleting the new object. */
12191 if ( !astOK ) new = astDelete( new );
12192 }
12193
12194 /* Return an ID value for the new SkyFrame. */
12195 return astMakeId( new );
12196 }
12197
12198
12199
12200
12201
12202
12203
12204