1 /*
2 *class++
3 *  Name:
4 *     Plot3D
5 
6 *  Purpose:
7 *     Provide facilities for 3D graphical output.
8 
9 *  Constructor Function:
10 c     astPlot3D
11 f     AST_PLOT3D
12 
13 *  Description:
14 *     A Plot3D is a specialised form of Plot that provides facilities
15 *     for producing 3D graphical output, including fully annotated 3D
16 *     coordinate grids. The base Frame in a Plot3D describes a 3-dimensional
17 *     "graphical" coordinate system. The axes of this coordinate system are
18 *     assumed to be right-handed (that is, if X appears horizontally to the
19 *     right and Y vertically upwards, then Z is out of the screen towards
20 *     the viewer), and are assumed to be equally scaled (that is, the same
21 *     units are used to measure positions on each of the 3 axes). The upper
22 *     and lower bounds of a volume within this graphical coordinate system
23 *     is specified when the Plot3D is created, and all subsequent graphics
24 *     are "drawn" in this volume.
25 *
26 *     The Plot3D class does not itself include any ability to draw on a
27 *     graphics device. Instead it calls upon function in an externally
28 *     supplied module (the "grf3d" module) to do the required drawing.
29 *     A module should be written that implements the functions of the
30 *     grf3d interface using the facilities of a specific graphics system
31 *     This module should then be linked into the application so that the
32 *     Plot3D class can use its functions (see the description of the
33 *     ast_link commands for details of how to do this). The grf3d interface
34 *     defines a few simple functions for drawing primitives such as straight
35 *     lines, markers and character strings. These functions all accept
36 *     positions in the 3D graphics coordinate system (the base Frame of the
37 *     Plot3D), and so the grf3d module must also manage the projection of
38 *     these 3D coordinates onto the 2D viewing surface, including the choice
39 *     of "eye"/"camera" position, direction of viewing, etc. The AST
40 *     library includes a sample implementation of the grf3d interface
41 *     based on the PGPLOT graphics system (see file grf3d_pgplot.c). This
42 *     implementation also serves to document the grf3d interface itself and
43 *     should be consulted for details before writing a new implementation.
44 *
45 *     The current Frame of a Plot3D describes a "physical" 3-dimensional
46 *     coordinate system, which is the coordinate system in which plotting
47 *     operations are specified when invoking the methods of the Plot3D
48 *     class. The results of each plotting operation are automatically
49 *     transformed into 3D graphical coordinates before being plotted
50 *     using the facilities of the grf3d module linked into the application.
51 *     Note, at least one of the three axes of the current Frame must be
52 *     independent of the other two current Frame axes.
53 *
54 *     You may select different physical coordinate systems in which to
55 *     plot (including the native graphical coordinate system itself)
56 *     by selecting different Frames as the current Frame of a Plot3D,
57 *     using its Current attribute.
58 *
59 *     Like any FrameSet, a Plot3D may also be used as a Frame. In this
60 *     case, it behaves like its current Frame, which describes the
61 *     physical coordinate system.
62 *
63 *     When used as a Mapping, a Plot3D describes the inter-relation
64 *     between 3D graphical coordinates (its base Frame) and 3D physical
65 *     coordinates (its current Frame).
66 *
67 *     Although the Plot3D class inherits from the Plot class, several of
68 *     the facilities of the Plot class are not available in the Plot3D
69 *     class, and an error will be reported if any attempt is made to use
70 *     them. Specifically, the Plot3D class does not support clipping
71 *     using the
72 *     astClip function.
73 f     AST_CLIP routine.
74 *     Nor does it support the specification of graphics primitive functions
75 *     at run-time using the
76 c     astGrfSet, astGrfPop, astGrfPush and astGetGrfContext functions.
77 f     AST_GRFSET, AST_GRFPOP, AST_GRFPUSH, and AST_GETGRFCONTEXT routines.
78 
79 *  Inheritance:
80 *     The Plot3D class inherits from the Plot class.
81 
82 *  Attributes:
83 *     In addition to those attributes common to all Plots, every
84 *     Plot3D also has the following attributes:
85 *
86 *     - Norm: Normal vector defining the 2D plane used for text and markers
87 *     - RootCorner: Specifies which edges of the 3D box should be annotated.
88 *
89 *     Some attributes of the Plot class refer to specific physical
90 *     coordinate axes (e.g. Gap, LabelUp, DrawAxes, etc). For a basic
91 *     Plot, the axis index must be 1 or 2, but for a Plot3D the axis index
92 *     can be 1, 2 or 3.
93 *
94 *     Certain Plot attributes are ignored by the Plot3D class (e.g. Edge,
95 *     DrawTitle, TitleGap, etc). Consult the Plot attribute documentation
96 *     for details.
97 
98 *  Functions:
99 c     The Plot3D class does not define any new functions beyond those
100 f     The Plot3D class does not define any new routines beyond those
101 *     which are applicable to all Plots. Note, however, that the
102 *     following methods inherited from the Plot class cannot be used with
103 *     a Plot3D and will report an error if called:
104 c    - astBoundingBox, astClip, astCurve, astGenCurve,
105 c    astGetGrfContext, astGrfPop, astGrfPush, astGrfSet, astGridLine,
106 c    astPolyCurve.
107 f    - AST_BOUNDINGBOX, AST_CLIP, AST_CURVE, AST_GENCURVE,
108 f    AST_GETGRFCONTEXT, AST_GRFPOP, AST_GRFPUSH, AST_GRFSET,
109 f    AST_GRIDLINE, AST_POLYCURVE.
110 
111 *  Copyright:
112 *     Copyright (C) 2007 Science & Technology Facilities Council.
113 *     All Rights Reserved.
114 
115 *  Licence:
116 *     This program is free software: you can redistribute it and/or
117 *     modify it under the terms of the GNU Lesser General Public
118 *     License as published by the Free Software Foundation, either
119 *     version 3 of the License, or (at your option) any later
120 *     version.
121 *
122 *     This program is distributed in the hope that it will be useful,
123 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
124 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
125 *     GNU Lesser General Public License for more details.
126 *
127 *     You should have received a copy of the GNU Lesser General
128 *     License along with this program.  If not, see
129 *     <http://www.gnu.org/licenses/>.
130 
131 *  Authors:
132 *     DSB: David S. Berry (Starlink)
133 
134 *  History:
135 *     6-JUN-2007 (DSB):
136 *        Original version.
137 *     6-SEP-2007 (DSB):
138 *        Re-code the astGrid function.
139 *     12-NOV-2007 (DSB):
140 *        Clear up compiler warnings.
141 *     4-MAY-2012 (DSB):
142 *        Avoid segvio in Grid if no ticks are drawn.
143 *     21-MAY-2012 (DSB):
144 *        In astLoadPlot3D, do not call SetRootCorner as it requires an
145 *        active graphics system to be present which may not yet have been
146 *        established. Also establish the grf routines to be used.
147 *class--
148 */
149 
150 /* Module Macros. */
151 /* ============== */
152 /* Set the name of the class we are implementing. This indicates to
153    the header files that define class interfaces that they should make
154    "protected" symbols available. */
155 #define astCLASS Plot3D
156 
157 /* Macros which return the maximum and minimum of two values. */
158 #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb))
159 #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb))
160 
161 /* Macro to check for equality of floating point values. We cannot
162    compare bad values directory because of the danger of floating point
163    exceptions, so bad values are dealt with explicitly. */
164 #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN))))
165 
166 /* Integers identifying the 3 plotting surfaces */
167 #define XY 1
168 #define XZ 2
169 #define YZ 3
170 
171 /* Integers identifying the 8 corners of the graphics cube. */
172 #define LLL 0
173 #define ULL 1
174 #define LUL 2
175 #define UUL 3
176 #define LLU 4
177 #define ULU 5
178 #define LUU 6
179 #define UUU 7
180 
181 /* Identify the 4 edges of a Plot */
182 #define LEFT   0
183 #define TOP    1
184 #define RIGHT  2
185 #define BOTTOM 3
186 
187 /* A macros that returns a pointer to the Plot that spans a given plane. */
188 #define GET_PLOT(plane) ( \
189      ( plane == XY ) ? this->plotxy : ( \
190      ( plane == XZ ) ? this->plotxz : ( \
191      ( plane == YZ ) ? this->plotyz : NULL ) ) )
192 
193 
194 /*
195 *
196 *  Name:
197 *     MAKE_CLEAR3
198 
199 *  Purpose:
200 *     Implement a method to clear a single value in a multi-valued attribute.
201 
202 *  Type:
203 *     Private macro.
204 
205 *  Synopsis:
206 *     #include "plot3d.h"
207 *     MAKE_CLEAR3(attr,component,assign,nval)
208 
209 *  Class Membership:
210 *     Defined by the Plot3D class.
211 
212 *  Description:
213 *     This macro expands to an implementation of a private member function of
214 *     the form:
215 *
216 *        static void Clear<Attribute>( AstPlot *this, int axis )
217 *
218 *     and an external interface function of the form:
219 *
220 *        void astClear<Attribute>_( AstPlot *this, int axis )
221 *
222 *     which implement a method for clearing a single value in a specified
223 *     multi-valued attribute for an axis of a Plot3D.
224 
225 *  Parameters:
226 *     attr
227 *        The name of the attribute to be cleared, as it appears in the function
228 *        name (e.g. LabelAt in "astClearLabelAt").
229 *     component
230 *        The name of the class structure component that holds the attribute
231 *        value.
232 *     assign
233 *        An expression that evaluates to the value to assign to the component
234 *        to clear its value.
235 *     nval
236 *        Specifies the number of values in the multi-valued attribute. The
237 *        "axis" values supplied to the created function should be in the
238 *        range zero to (nval - 1).
239 
240 *  Notes:
241 *     -  To avoid problems with some compilers, you should not leave any white
242 *     space around the macro arguments.
243 *
244 */
245 
246 /* Define the macro. */
247 #define MAKE_CLEAR3(attr,component,assign,nval) \
248 \
249 /* Private member function. */ \
250 /* ------------------------ */ \
251 static void Clear##attr( AstPlot3D *this, int axis, int *status ) { \
252 \
253 /* Check the global error status. */ \
254    if ( !astOK ) return; \
255 \
256 /* Validate the axis index. */ \
257    if( axis < 0 || axis >= nval ){ \
258       astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \
259                 #attr " - it should be in the range 1 to %d.", status, \
260                 "astClear" #attr, astGetClass( this ), \
261                 axis + 1, nval ); \
262 \
263 /* Assign the "clear" value. */ \
264    } else { \
265       this->component[ axis ] = (assign); \
266    } \
267 } \
268 \
269 /* External interface. */ \
270 /* ------------------- */ \
271 void astClear##attr##_( AstPlot3D *this, int axis, int *status ) { \
272 \
273 /* Check the global error status. */ \
274    if ( !astOK ) return; \
275 \
276 /* Invoke the required method via the virtual function table. */ \
277    (**astMEMBER(this,Plot3D,Clear##attr))( this, axis, status ); \
278 }
279 
280 
281 /*
282 *
283 *  Name:
284 *     MAKE_GET3
285 
286 *  Purpose:
287 *     Implement a method to get a single value in a multi-valued attribute.
288 
289 *  Type:
290 *     Private macro.
291 
292 *  Synopsis:
293 *     #include "plot3d.h"
294 *     MAKE_GET3(attr,type,bad_value,assign,nval)
295 
296 *  Class Membership:
297 *     Defined by the Plot3D class.
298 
299 *  Description:
300 *     This macro expands to an implementation of a private member function of
301 *     the form:
302 *
303 *        static <Type> Get<Attribute>( AstPlot3D *this, int axis )
304 *
305 *     and an external interface function of the form:
306 *
307 *        <Type> astGet<Attribute>_( AstPlot3D *this, int axis )
308 *
309 *     which implement a method for getting a single value from a specified
310 *     multi-valued attribute for an axis of a Plot3D.
311 
312 *  Parameters:
313 *     attr
314 *        The name of the attribute whose value is to be obtained, as it
315 *        appears in the function name (e.g. Label in "astGetLabel").
316 *     type
317 *        The C type of the attribute.
318 *     bad_value
319 *        A constant value to return if the global error status is set, or if
320 *        the function fails.
321 *     assign
322 *        An expression that evaluates to the value to be returned. This can
323 *        use the string "axis" to represent the zero-based value index.
324 *     nval
325 *        Specifies the number of values in the multi-valued attribute. The
326 *        "axis" values supplied to the created function should be in the
327 *        range zero to (nval - 1).
328 
329 *  Notes:
330 *     -  To avoid problems with some compilers, you should not leave any white
331 *     space around the macro arguments.
332 *
333 */
334 
335 /* Define the macro. */
336 #define MAKE_GET3(attr,type,bad_value,assign,nval) \
337 \
338 /* Private member function. */ \
339 /* ------------------------ */ \
340 static type Get##attr( AstPlot3D *this, int axis, int *status ) { \
341    type result;                  /* Result to be returned */ \
342 \
343 /* Initialise */ \
344    result = (bad_value); \
345 \
346 /* Check the global error status. */ \
347    if ( !astOK ) return result; \
348 \
349 /* Validate the axis index. */ \
350    if( axis < 0 || axis >= nval ){ \
351       astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \
352                 #attr " - it should be in the range 1 to %d.", status, \
353                 "astGet" #attr, astGetClass( this ), \
354                 axis + 1, nval ); \
355 \
356 /* Assign the result value. */ \
357    } else { \
358       result = (assign); \
359    } \
360 \
361 /* Check for errors and clear the result if necessary. */ \
362    if ( !astOK ) result = (bad_value); \
363 \
364 /* Return the result. */ \
365    return result; \
366 } \
367 /* External interface. */ \
368 /* ------------------- */  \
369 type astGet##attr##_( AstPlot3D *this, int axis, int *status ) { \
370 \
371 /* Check the global error status. */ \
372    if ( !astOK ) return (bad_value); \
373 \
374 /* Invoke the required method via the virtual function table. */ \
375    return (**astMEMBER(this,Plot3D,Get##attr))( this, axis, status ); \
376 }
377 
378 /*
379 *
380 *  Name:
381 *     MAKE_SET3
382 
383 *  Purpose:
384 *     Implement a method to set a single value in a multi-valued attribute
385 *     for a Plot3D.
386 
387 *  Type:
388 *     Private macro.
389 
390 *  Synopsis:
391 *     #include "plot3d.h"
392 *     MAKE_SET3(attr,type,component,assign,nval)
393 
394 *  Class Membership:
395 *     Defined by the Plot3D class.
396 
397 *  Description:
398 *     This macro expands to an implementation of a private member function of
399 *     the form:
400 *
401 *        static void Set<Attribute>( AstPlot3D *this, int axis, <Type> value )
402 *
403 *     and an external interface function of the form:
404 *
405 *        void astSet<Attribute>_( AstPlot3D *this, int axis, <Type> value )
406 *
407 *     which implement a method for setting a single value in a specified
408 *     multi-valued attribute for a Plot3D.
409 
410 *  Parameters:
411 *      attr
412 *         The name of the attribute to be set, as it appears in the function
413 *         name (e.g. LabelAt in "astSetLabelAt").
414 *      type
415 *         The C type of the attribute.
416 *      component
417 *         The name of the class structure component that holds the attribute
418 *         value.
419 *      assign
420 *         An expression that evaluates to the value to be assigned to the
421 *         component.
422 *      nval
423 *        Specifies the number of values in the multi-valued attribute. The
424 *        "axis" values supplied to the created function should be in the
425 *        range zero to (nval - 1). If a value of 0 is supplied, the
426 *        value of the Plot3D's Nin attribute is used instead.
427 
428 *  Notes:
429 *     -  To avoid problems with some compilers, you should not leave any white
430 *     space around the macro arguments.
431 *-
432 */
433 
434 /* Define the macro. */
435 #define MAKE_SET3(attr,type,component,assign,nval) \
436 \
437 /* Private member function. */ \
438 /* ------------------------ */ \
439 static void Set##attr( AstPlot3D *this, int axis, type value, int *status ) { \
440 \
441 /* Check the global error status. */ \
442    if ( !astOK ) return; \
443 \
444 /* Validate the axis index. */ \
445    if( axis < 0 || axis >= nval ){ \
446       astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \
447                 #attr " - it should be in the range 1 to %d.", status, \
448                 "astSet" #attr, astGetClass( this ), \
449                 axis + 1, nval ); \
450 \
451 /* Store the new value in the structure component. */ \
452    } else { \
453       this->component[ axis ] = (assign); \
454    } \
455 } \
456 \
457 /* External interface. */ \
458 /* ------------------- */ \
459 void astSet##attr##_( AstPlot3D *this, int axis, type value, int *status ) { \
460 \
461 /* Check the global error status. */ \
462    if ( !astOK ) return; \
463 \
464 /* Invoke the required method via the virtual function table. */ \
465    (**astMEMBER(this,Plot3D,Set##attr))( this, axis, value, status ); \
466 }
467 
468 /*
469 *
470 *  Name:
471 *     MAKE_TEST3
472 
473 *  Purpose:
474 *     Implement a method to test if a single value has been set in a
475 *     multi-valued attribute for a class.
476 
477 *  Type:
478 *     Private macro.
479 
480 *  Synopsis:
481 *     #include "plot3d.h"
482 *     MAKE_TEST3(attr,assign,nval)
483 
484 *  Class Membership:
485 *     Defined by the Plot3D class.
486 
487 *  Description:
488 *     This macro expands to an implementation of a private member function of
489 *     the form:
490 *
491 *        static int Test<Attribute>( AstPlot3D *this, int axis )
492 *
493 *     and an external interface function of the form:
494 *
495 *        int astTest<Attribute>_( AstPlot3D *this, int axis )
496 *
497 *     which implement a method for testing if a single value in a specified
498 *     multi-valued attribute has been set for a class.
499 
500 *  Parameters:
501 *      attr
502 *         The name of the attribute to be tested, as it appears in the function
503 *         name (e.g. LabelAt in "astTestLabelAt").
504 *      assign
505 *         An expression that evaluates to 0 or 1, to be used as the returned
506 *         value. This can use the string "axis" to represent the zero-based
507 *         index of the value within the attribute.
508 *      nval
509 *        Specifies the number of values in the multi-valued attribute. The
510 *        "axis" values supplied to the created function should be in the
511 *        range zero to (nval - 1).
512 
513 *  Notes:
514 *     -  To avoid problems with some compilers, you should not leave any white
515 *     space around the macro arguments.
516 *-
517 */
518 
519 /* Define the macro. */
520 #define MAKE_TEST3(attr,assign,nval) \
521 \
522 /* Private member function. */ \
523 /* ------------------------ */ \
524 static int Test##attr( AstPlot3D *this, int axis, int *status ) { \
525    int result;                   /* Value to return */ \
526 \
527 /* Initialise */ \
528    result = 0; \
529 \
530 /* Check the global error status. */ \
531    if ( !astOK ) return result; \
532 \
533 /* Validate the axis index. */ \
534    if( axis < 0 || axis >= nval ){ \
535       astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \
536                 #attr " - it should be in the range 1 to %d.", status, \
537                 "astTest" #attr, astGetClass( this ), \
538                 axis + 1, nval ); \
539 \
540 /* Assign the result value. */ \
541    } else { \
542       result = (assign); \
543    } \
544 \
545 /* Check for errors and clear the result if necessary. */ \
546    if ( !astOK ) result = 0; \
547 \
548 /* Return the result. */ \
549    return result; \
550 } \
551 /* External interface. */ \
552 /* ------------------- */ \
553 int astTest##attr##_( AstPlot3D *this, int axis, int *status ) { \
554 \
555 /* Check the global error status. */ \
556    if ( !astOK ) return 0; \
557 \
558 /* Invoke the required method via the virtual function table. */ \
559    return (**astMEMBER(this,Plot3D,Test##attr))( this, axis, status ); \
560 }
561 
562 /*
563 *
564 *  Name:
565 *     MAKE_CLEAR2
566 
567 *  Purpose:
568 *     Implement a method to clear an element-specific attribute inherited
569 *     from the Plot class.
570 
571 *  Type:
572 *     Private macro.
573 
574 *  Synopsis:
575 *     #include "plot3d.h"
576 *     MAKE_CLEAR2(attr)
577 
578 *  Class Membership:
579 *     Defined by the Plot3d class.
580 
581 *  Description:
582 *     This macro expands to an implementation of a private member function of
583 *     the form:
584 *
585 *        static void Clear<Attribute>( AstPlot *this, int element )
586 *
587 *     which implements a method for clearing one of the element-specific
588 *     attributes (e.g. Size, Colour, Width, etc) inherited from the
589 *     parent Plot class.
590 
591 *  Parameters:
592 *     attr
593 *        The name of the attribute to be cleared, as it appears in the function
594 *        name (e.g. LabelAt in "astClearSize").
595 
596 *  Notes:
597 *     -  To avoid problems with some compilers, you should not leave any white
598 *     space around the macro arguments.
599 *
600 */
601 
602 /* Define the macro. */
603 #define MAKE_CLEAR2(attr) \
604 \
605 /* Private member function. */ \
606 /* ------------------------ */ \
607 static void Clear##attr( AstPlot *this_plot, int element, int *status ) { \
608 \
609 /* Local Variables: */ \
610    AstPlot3D *this; \
611    int axis3d; \
612    int elem2d1; \
613    int elem2d2; \
614 \
615 /* Check the global error status. */ \
616    if ( !astOK ) return; \
617 \
618 /* Clear the attribute value in the parent Plot structure. */ \
619    (*parent_clear##attr)( this_plot, element, status ); \
620 \
621 /* If OK, clear the attribute in the encapsulated Plots. */ \
622    if( astOK ) { \
623       this = (AstPlot3D *) this_plot; \
624 \
625 /* Get the zero-based index of the 3D axis to which the supplied element \
626    refers. Use an index of -1 to indicate that the element does not \
627    relate to a specific axis. Also get the corresponding elements to use \
628    with the two Plots that share the specified 3D axis. */ \
629       axis3d = Element2D( this, element, &elem2d1, &elem2d2, status ); \
630 \
631 /* If the element is not axis-specific, clear the attribute value in all \
632    three plots. */ \
633       if( axis3d == -1 ) { \
634          astClear##attr( this->plotxy, element ); \
635          astClear##attr( this->plotxz, element ); \
636          astClear##attr( this->plotyz, element ); \
637 \
638 /* Otherwise, clear the attribute in the two plots that share the \
639    specified 3D axis. */ \
640       } else { \
641          astClear##attr( GET_PLOT(this->axis_plot1[ axis3d ]), elem2d1 ); \
642          astClear##attr( GET_PLOT(this->axis_plot2[ axis3d ]), elem2d2 ); \
643       } \
644    } \
645 }
646 
647 /*
648 *
649 *  Name:
650 *     MAKE_SET2
651 
652 *  Purpose:
653 *     Implement a method to set an element-specific attribute inherited
654 *     from the Plot class.
655 
656 *  Type:
657 *     Private macro.
658 
659 *  Synopsis:
660 *     #include "plot3d.h"
661 *     MAKE_SET2(attr,type)
662 
663 *  Class Membership:
664 *     Defined by the Plot3d class.
665 
666 *  Description:
667 *     This macro expands to an implementation of a private member function of
668 *     the form:
669 *
670 *        static void Set<Attribute>( AstPlot *this, int element, type value )
671 *
672 *     which implements a method for setting one of the element-specific
673 *     attributes (e.g. Size, Colour, Width, etc) inherited from the
674 *     parent Plot class.
675 
676 *  Parameters:
677 *     attr
678 *        The name of the attribute to be cleared, as it appears in the function
679 *        name (e.g. LabelAt in "astClearSize").
680 *     type
681 *        The attribute data type.
682 
683 *  Notes:
684 *     -  To avoid problems with some compilers, you should not leave any white
685 *     space around the macro arguments.
686 *
687 */
688 
689 /* Define the macro. */
690 #define MAKE_SET2(attr,type) \
691 \
692 /* Private member function. */ \
693 /* ------------------------ */ \
694 static void Set##attr( AstPlot *this_plot, int element, type value, int *status ) { \
695 \
696 /* Local Variables: */ \
697    AstPlot3D *this; \
698    int axis3d; \
699    int elem2d1; \
700    int elem2d2; \
701 \
702 /* Check the global error status. */ \
703    if ( !astOK ) return; \
704 \
705 /* Set the attribute value in the parent Plot structure. */ \
706    (*parent_set##attr)( this_plot, element, value, status ); \
707 \
708 /* If OK, set the attribute in the encapsulated Plots. */ \
709    if( astOK ) { \
710       this = (AstPlot3D *) this_plot; \
711 \
712 /* Get the zero-based index of the 3D axis to which the supplied element \
713    refers. Use an index of -1 to indicate that the element does not \
714    relate to a specific axis. Also get the corresponding elements to use \
715    with the two Plots that share the specified 3D axis. */ \
716       axis3d = Element2D( this, element, &elem2d1, &elem2d2, status ); \
717 \
718 /* If the element is not axis-specific, clear the attribute value in all \
719    three plots. */ \
720       if( axis3d == -1 ) { \
721          astSet##attr( this->plotxy, element, value ); \
722          astSet##attr( this->plotxz, element, value ); \
723          astSet##attr( this->plotyz, element, value ); \
724 \
725 /* Otherwise, clear the attribute in the two plots that share the \
726    specified 3D axis. */ \
727       } else { \
728          astSet##attr( GET_PLOT(this->axis_plot1[ axis3d ]), elem2d1, value ); \
729          astSet##attr( GET_PLOT(this->axis_plot2[ axis3d ]), elem2d2, value ); \
730       } \
731    } \
732 }
733 
734 
735 /*
736 *
737 *  Name:
738 *     MAKE_CLEAR1
739 
740 *  Purpose:
741 *     Implement a method to clear an attribute inherited from the Plot class.
742 
743 *  Type:
744 *     Private macro.
745 
746 *  Synopsis:
747 *     #include "plot3d.h"
748 *     MAKE_CLEAR1(attr)
749 
750 *  Class Membership:
751 *     Defined by the Plot3d class.
752 
753 *  Description:
754 *     This macro expands to an implementation of a private member function of
755 *     the form:
756 *
757 *        static void Clear<Attribute>( AstPlot *this )
758 *
759 *     which implements a method for clearing a Plot3D attribute inherited
760 *     from the parent Plot class. It clears the attribute in all three
761 *     plots encapsulated within the Plot3D.
762 
763 *  Parameters:
764 *     attr
765 *        The name of the attribute to be cleared, as it appears in the function
766 *        name (e.g. LabelAt in "astClearLabelAt").
767 
768 *  Notes:
769 *     -  To avoid problems with some compilers, you should not leave any white
770 *     space around the macro arguments.
771 *
772 */
773 
774 /* Define the macro. */
775 #define MAKE_CLEAR1(attr) \
776 \
777 /* Private member function. */ \
778 /* ------------------------ */ \
779 static void Clear##attr( AstPlot *this_plot, int *status ) { \
780 \
781 /* Local Variables: */ \
782    AstPlot3D *this; \
783 \
784 /* Check the global error status. */ \
785    if ( !astOK ) return; \
786 \
787 /* Clear the attribute value in the parent Plot structure. */ \
788    (*parent_clear##attr)( this_plot, status ); \
789 \
790 /* If OK, clear the attribute in all three of the encapsulated Plots. */ \
791    if( astOK ) { \
792       this = (AstPlot3D *) this_plot; \
793       astClear##attr( this->plotxy ); \
794       astClear##attr( this->plotxz ); \
795       astClear##attr( this->plotyz ); \
796    } \
797 }
798 
799 /*
800 *
801 *  Name:
802 *     MAKE_SET1
803 
804 *  Purpose:
805 *     Implement a method to set an attribute inherited from the Plot class.
806 
807 *  Type:
808 *     Private macro.
809 
810 *  Synopsis:
811 *     #include "plot3d.h"
812 *     MAKE_SET1(attr,type)
813 
814 *  Class Membership:
815 *     Defined by the Plot3d class.
816 
817 *  Description:
818 *     This macro expands to an implementation of a private member function of
819 *     the form:
820 *
821 *        static void Set<Attribute>( AstPlot *this, type value )
822 *
823 *     which implements a method for setting a Plot3D attribute inherited
824 *     from the parent Plot class. It sets the attribute in all three
825 *     plots encapsulated within the Plot3D.
826 
827 *  Parameters:
828 *     attr
829 *        The name of the attribute to be set, as it appears in the function
830 *        name (e.g. LabelAt in "astSetLabelAt").
831 *     type
832 *        The C data type for the attribute value.
833 
834 *  Notes:
835 *     -  To avoid problems with some compilers, you should not leave any white
836 *     space around the macro arguments.
837 *
838 */
839 
840 /* Define the macro. */
841 #define MAKE_SET1(attr,type) \
842 \
843 /* Private member function. */ \
844 /* ------------------------ */ \
845 static void Set##attr( AstPlot *this_plot, type value, int *status ) { \
846 \
847 /* Local Variables: */ \
848    AstPlot3D *this; \
849 \
850 /* Check the global error status. */ \
851    if ( !astOK ) return; \
852 \
853 /* Set the attribute value in the parent Plot structure. */ \
854    (*parent_set##attr)( this_plot, value, status ); \
855 \
856 /* If OK, set the attribute in all three of the encapsulated Plots. */ \
857    if( astOK ) { \
858       this = (AstPlot3D *) this_plot; \
859       astSet##attr( this->plotxy, value ); \
860       astSet##attr( this->plotxz, value ); \
861       astSet##attr( this->plotyz, value ); \
862    } \
863 }
864 
865 /*
866 *
867 *  Name:
868 *     MAKE_CLEAR
869 
870 *  Purpose:
871 *     Implement a method to clear an attribute inherited from the Plot class.
872 
873 *  Type:
874 *     Private macro.
875 
876 *  Synopsis:
877 *     #include "plot3d.h"
878 *     MAKE_CLEAR(attr,whichplots)
879 
880 *  Class Membership:
881 *     Defined by the Plot3d class.
882 
883 *  Description:
884 *     This macro expands to an implementation of a private member function of
885 *     the form:
886 *
887 *        static void Clear<Attribute>( AstPlot *this, int axis )
888 *
889 *     which implements a method for clearing an axis specific Plot3D
890 *     attribute inherited from the parent Plot class.
891 
892 *  Parameters:
893 *     attr
894 *        The name of the attribute to be cleared, as it appears in the function
895 *        name (e.g. LabelAt in "astClearLabelAt").
896 *     whichplots
897 *        A value indicating which Plots should be affected. A negative value
898 *        means "all threee plots", a value of zero means "just the two plots
899 *        that touch at the specified axis in 3D space", a positive value
900 *        means "just the Plot that is used to label th 3D axis."
901 
902 *  Notes:
903 *     -  To avoid problems with some compilers, you should not leave any white
904 *     space around the macro arguments.
905 *
906 */
907 
908 /* Define the macro. */
909 #define MAKE_CLEAR(attr,whichplots) \
910 \
911 /* Private member function. */ \
912 /* ------------------------ */ \
913 static void Clear##attr( AstPlot *this_plot, int axis, int *status ) { \
914 \
915 /* Local Variables: */ \
916    AstPlot *plot; \
917    AstPlot3D *this; \
918    int axis2d; \
919 \
920 /* Check the global error status. */ \
921    if ( !astOK ) return; \
922 \
923 /* Clear the attribute value in the parent Plot structure. This will \
924    validate the axis index. */ \
925    (*parent_clear##attr)( this_plot, axis, status ); \
926 \
927 /* If OK, clear the attribute for the relevant axis, or axes, of the Plots  \
928    encapsulated inside the Plot3D. First get a pointer to the Plot3D \
929    structure. */ \
930    if( astOK ) { \
931       this = (AstPlot3D *) this_plot; \
932 \
933 /* If requested clear the attribute in all three Plots. */ \
934       if( whichplots < 0 ) { \
935          astClear##attr( this->plotxy, axis ); \
936          astClear##attr( this->plotxz, axis ); \
937          astClear##attr( this->plotyz, axis ); \
938 \
939 /* Each axis in 3D graphics space is described by two of the encapsulated \
940    Plots, but only one of these two Plots is used to generate labels for \
941    the axis. Now deal with cases where we are clearing the attribute \
942    value in both of the two Plots that describe the axis. */ \
943       } else if ( whichplots == 0 ) { \
944          if( axis == 0 ) { \
945             astClear##attr( this->plotxy, 0 ); \
946             astClear##attr( this->plotxz, 0 ); \
947 \
948          } else if( axis == 1 ) { \
949             astClear##attr( this->plotxy, 1 ); \
950             astClear##attr( this->plotyz, 0 ); \
951 \
952          } else { \
953             astClear##attr( this->plotxz, 1 ); \
954             astClear##attr( this->plotyz, 1 ); \
955          } \
956 \
957 /* Now deal with cases where we are clearing the attribute value only in  \
958    the Plot that is used to label the axis. */ \
959       } else { \
960          plot = AxisPlot( this, axis, &axis2d, status ); \
961          astClear##attr( plot, axis2d ); \
962       } \
963    } \
964 }
965 
966 
967 /*
968 *
969 *  Name:
970 *     MAKE_GET
971 
972 *  Purpose:
973 *     Implement a method to get the value of an attribute inherited from the
974 *     Plot class.
975 
976 *  Type:
977 *     Private macro.
978 
979 *  Synopsis:
980 *     #include "plot.h"
981 *     MAKE_GET(attr,type,bad_value)
982 
983 *  Class Membership:
984 *     Defined by the Plot3D class.
985 
986 *  Description:
987 *     This macro expands to an implementation of a private member function of
988 *     the form:
989 *
990 *        static <Type> Get<Attribute>( AstPlot *this, int axis )
991 *
992 *     which implements a method for getting a value for an axis specific
993 *     attribute for a Plot3D.
994 
995 *  Parameters:
996 *     attr
997 *        The name of the attribute whose value is to be obtained, as it
998 *        appears in the function name (e.g. Label in "astGetLabel").
999 *     type
1000 *        The C type of the attribute.
1001 *     bad_value
1002 *        A constant value to return if the global error status is set, or if
1003 *        the function fails.
1004 
1005 *  Notes:
1006 *     -  To avoid problems with some compilers, you should not leave any white
1007 *     space around the macro arguments.
1008 *
1009 */
1010 
1011 /* Define the macro. */
1012 #define MAKE_GET(attr,type,bad_value) \
1013 \
1014 /* Private member function. */ \
1015 /* ------------------------ */ \
1016 static type Get##attr( AstPlot *this_plot, int axis, int *status ) { \
1017 \
1018 /* Local Variables: */ \
1019    AstPlot *plot; \
1020    AstPlot3D *this; \
1021    int axis2d; \
1022    type result; \
1023 \
1024 /* Initialise */ \
1025    result = (bad_value); \
1026 \
1027 /* Check the global error status. */ \
1028    if ( !astOK ) return result; \
1029 \
1030 /* See if the attribute value is set in the parent Plot structure. If so, \
1031    use the parent get method to get its value. */ \
1032    if( astTest##attr( this_plot, axis ) ) { \
1033       result = (*parent_get##attr)( this_plot, axis, status ); \
1034 \
1035 /* If the attribute value is not set in the parent Plot structure, get \
1036    the default value from the Plot that is used to label the 3D axis. The \
1037    parent test method called above will have reported an error if the axis \
1038    index is invalid, so check astOK here. */ \
1039    } else if( astOK ) { \
1040       this = (AstPlot3D *) this_plot; \
1041       plot = AxisPlot( this, axis, &axis2d, status ); \
1042       result = astGet##attr( plot, axis2d ); \
1043    } \
1044 \
1045 /* Return the result. */ \
1046    return result; \
1047 }
1048 
1049 /*
1050 *
1051 *  Name:
1052 *     MAKE_SET
1053 
1054 *  Purpose:
1055 *     Implement a method to set a value for an attribute inherited from the
1056 *     Plot class.
1057 
1058 *  Type:
1059 *     Private macro.
1060 
1061 *  Synopsis:
1062 *     #include "plot3d.h"
1063 *     MAKE_SET(attr,type,whichplots)
1064 
1065 *  Class Membership:
1066 *     Defined by the Plot3d class.
1067 
1068 *  Description:
1069 *     This macro expands to an implementation of a private member function of
1070 *     the form:
1071 *
1072 *        static void Set<Attribute>( AstPlot *this, int axis, <Type> value )
1073 *
1074 *     which implements a method for setting a value for an axis specific
1075 *     attribute inherited from the parent Plot class.
1076 
1077 *  Parameters:
1078 *      attr
1079 *         The name of the attribute to be set, as it appears in the function
1080 *         name (e.g. LabelAt in "astSetLabelAt").
1081 *      type
1082 *         The C type of the attribute.
1083 *     whichplots
1084 *        A value indicating which Plots should be affected. A negative value
1085 *        means "all threee plots", a value of zero means "just the two plots
1086 *        that touch at the specified axis in 3D space", a positive value
1087 *        means "just the Plot that is used to label the 3D axis."
1088 
1089 *  Notes:
1090 *     -  To avoid problems with some compilers, you should not leave any white
1091 *     space around the macro arguments.
1092 *-
1093 */
1094 
1095 /* Define the macro. */
1096 #define MAKE_SET(attr,type,whichplots) \
1097 \
1098 /* Private member function. */ \
1099 /* ------------------------ */ \
1100 static void Set##attr( AstPlot *this_plot, int axis, type value, int *status ) { \
1101 \
1102 /* Local Variables: */ \
1103    AstPlot3D *this; \
1104    AstPlot *plot; \
1105    int axis2d; \
1106 \
1107 /* Check the global error status. */ \
1108    if ( !astOK ) return; \
1109 \
1110 /* Set the supplied value in the parent Plot class. This will validate \
1111    the axis index. */ \
1112    (*parent_set##attr)( this_plot, axis, value, status ); \
1113 \
1114 /* If this went OK, also set the value for the appropriate axis of the \
1115    appropriate encapsulated Plot(s). First get a pointer to the Plot3D \
1116    structure. */ \
1117    if( astOK ) { \
1118       this = (AstPlot3D *) this_plot; \
1119 \
1120 /* If requested set the attribute in all three Plots. */ \
1121       if( whichplots < 0 ) { \
1122          astSet##attr( this->plotxy, axis, value ); \
1123          astSet##attr( this->plotxz, axis, value ); \
1124          astSet##attr( this->plotyz, axis, value ); \
1125 \
1126 /* Each axis in 3D graphics space is described by two of the encapsulated \
1127    Plots, but only one of these two Plots is used to generate labels for \
1128    the axis. First deal with cases where we are setting the attribute \
1129    value in both of the two Plots that describe the axis. */ \
1130       } else if( whichplots == 0 ) { \
1131          if( axis == 0 ) { \
1132             astSet##attr( this->plotxy, 0, value ); \
1133             astSet##attr( this->plotxz, 0, value ); \
1134 \
1135          } else if( axis == 1 ) { \
1136             astSet##attr( this->plotxy, 1, value ); \
1137             astSet##attr( this->plotyz, 0, value ); \
1138 \
1139          } else { \
1140             astSet##attr( this->plotxz, 1, value ); \
1141             astSet##attr( this->plotyz, 1, value ); \
1142          } \
1143 \
1144 /* Now deal with cases where we are setting the attribute value only in  \
1145    the Plot that is used to label the axis. */ \
1146       } else { \
1147          plot = AxisPlot( this, axis, &axis2d, status ); \
1148          astSet##attr( plot, axis2d, value ); \
1149       } \
1150    } \
1151 }
1152 
1153 
1154 /* Header files. */
1155 /* ============= */
1156 /* Interface definitions. */
1157 /* ---------------------- */
1158 
1159 #include "globals.h"             /* Thread-safe global data access */
1160 #include "error.h"               /* Error reporting facilities */
1161 #include "memory.h"              /* Memory allocation facilities */
1162 #include "object.h"              /* Base Object class */
1163 #include "cmpframe.h"            /* Compound Frames */
1164 #include "cmpmap.h"              /* Compound Mappings */
1165 #include "unitmap.h"             /* Unit mappings */
1166 #include "permmap.h"             /* Axis permutations */
1167 #include "winmap.h"              /* Scale and shift mappings */
1168 #include "frame.h"               /* Coordinate systems */
1169 #include "frameset.h"            /* Inter-related coordinate systems */
1170 #include "keymap.h"              /* Hash array */
1171 #include "plot.h"                /* Interface definition for parent class */
1172 #include "plot3d.h"              /* Interface definition for this class */
1173 #include "grf3d.h"               /* The grf3D interface */
1174 #include "pointset.h"            /* Sets of points */
1175 #include "globals.h"             /* Thread-safe global data access */
1176 
1177 /* Error code definitions. */
1178 /* ----------------------- */
1179 #include "ast_err.h"             /* AST error codes */
1180 
1181 /* C header files. */
1182 /* --------------- */
1183 #include <stdarg.h>
1184 #include <stdio.h>
1185 #include <string.h>
1186 #include <ctype.h>
1187 #include <stddef.h>
1188 #include <math.h>
1189 #include <limits.h>
1190 
1191 /* Module Variables. */
1192 /* ================= */
1193 
1194 /* Address of this static variable is used as a unique identifier for
1195    member of this class. */
1196 static int class_check;
1197 
1198 /* Pointers to parent class methods which are used or extended by this
1199    class. */
1200 static AstObject *(* parent_cast)( AstObject *, AstObject *, int * );
1201 static void (* parent_removeframe)( AstFrameSet *, int, int * );
1202 static int (* parent_getobjsize)( AstObject *, int * );
1203 static int (* parent_equal)( AstObject *, AstObject *, int * );
1204 static void (* parent_vset)( AstObject *, const char *, char **, va_list, int * );
1205 static void (* parent_clear)( AstObject *, const char *, int * );
1206 static void (* parent_clearcurrent)( AstFrameSet *, int * );
1207 static void (* parent_setcurrent)( AstFrameSet *, int, int * );
1208 static const char *(* parent_getattrib)( AstObject *, const char *, int * );
1209 static int (* parent_testattrib)( AstObject *, const char *, int * );
1210 static void (* parent_clearattrib)( AstObject *, const char *, int * );
1211 static void (* parent_setattrib)( AstObject *, const char *, int * );
1212 
1213 /* A FrameSet pointer that is used when calling astCast. */
1214 static AstFrameSet *dummy_frameset = NULL;
1215 
1216 #if defined(THREAD_SAFE)
1217 static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
1218 #endif
1219 
1220 /* Define macros for accessing each item of thread specific global data. */
1221 #ifdef THREAD_SAFE
1222 
1223 /* Define how to initialise thread-specific globals. */
1224 #define GLOBAL_inits \
1225    globals->Class_Init = 0; \
1226    globals->GetAttrib_Buff[ 0 ] = 0;
1227 
1228 /* Create the function that initialises global data for this module. */
1229 astMAKE_INITGLOBALS(Plot3D)
1230 
1231 /* Define macros for accessing each item of thread specific global data. */
1232 #define class_init astGLOBAL(Plot3D,Class_Init)
1233 #define class_vtab astGLOBAL(Plot3D,Class_Vtab)
1234 #define getattrib_buff astGLOBAL(Plot3D,GetAttrib_Buff)
1235 
1236 static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
1237 #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 );
1238 #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 );
1239 
1240 static pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
1241 #define LOCK_MUTEX3 pthread_mutex_lock( &mutex3 );
1242 #define UNLOCK_MUTEX3 pthread_mutex_unlock( &mutex3 );
1243 
1244 /* If thread safety is not needed, declare and initialise globals at static
1245    variables. */
1246 #else
1247 
1248 static char getattrib_buff[ 101 ];
1249 
1250 
1251 /* Define the class virtual function table and its initialisation flag
1252    as static variables. */
1253 static AstPlot3DVtab class_vtab;   /* Virtual function table */
1254 static int class_init = 0;       /* Virtual function table initialised? */
1255 
1256 #define LOCK_MUTEX2
1257 #define UNLOCK_MUTEX2
1258 
1259 #define LOCK_MUTEX3
1260 #define UNLOCK_MUTEX3
1261 
1262 #endif
1263 
1264 /* Prototypes for Private Member Functions. */
1265 /* ======================================== */
1266 static AstFrameSet *Fset3D( AstFrameSet *, int, int * );
1267 static AstKeyMap *GetGrfContext( AstPlot *, int * );
1268 static AstObject *Cast( AstObject *, AstObject *, int * );
1269 static AstPlot *AxisPlot( AstPlot3D *, int, int *, int * );
1270 static AstPointSet *ExtendTicks( AstPlot *, AstPointSet *, int * );
1271 static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
1272 static const char *RootCornerString( int, int * );
1273 static int Attr3D( AstKeyMap *, int, double, double *, int, int * );
1274 static int Border( AstPlot *, int * );
1275 static int Element2D( AstPlot3D *, int, int *, int *, int * );
1276 static int Equal( AstObject *, AstObject *, int * );
1277 static int GetObjSize( AstObject *, int * );
1278 static int Plot3DAttr( AstKeyMap *, int, double, double *, int );
1279 static int Plot3DCap( AstKeyMap *, int, int );
1280 static int Plot3DFlush( AstKeyMap * );
1281 static int Plot3DLine( AstKeyMap *, int, const float *, const float * );
1282 static int Plot3DMark( AstKeyMap *, int, const float *, const float *, int );
1283 static int Plot3DQch( AstKeyMap *, float *, float * );
1284 static int Plot3DScales( AstKeyMap *, float *, float * );
1285 static int Plot3DText( AstKeyMap *, const char *, float, float, const char *, float, float );
1286 static int Plot3DTxExt( AstKeyMap *, const char *, float, float, const char *, float, float, float *, float * );
1287 static int RootCornerInt( const char *, int * );
1288 static void BoundingBox( AstPlot *, float[2], float[2], int * );
1289 static void ChangeRootCorner( AstPlot3D *, int, int, int * );
1290 static void Clear( AstObject *, const char *, int * );
1291 static void ClearCurrent( AstFrameSet *, int * );
1292 static void Clip( AstPlot *, int, const double [], const double [], int * );
1293 static void Copy( const AstObject *, AstObject *, int * );
1294 static void CreatePlots( AstPlot3D *, AstFrameSet *, const float *, const double *, int * );
1295 static void Curve( AstPlot *, const double [], const double [], int * );
1296 static void Delete( AstObject *, int * );
1297 static void Dump( AstObject *, AstChannel *, int * );
1298 static void GenCurve( AstPlot *, AstMapping *, int * );
1299 static void GrfPop( AstPlot *, int * );
1300 static void GrfPush( AstPlot *, int * );
1301 static void GrfSet( AstPlot *, const char *,  AstGrfFun, int * );
1302 static void Grid( AstPlot *, int * );
1303 static void GridLine( AstPlot *, int, const double [], double, int * );
1304 static void Mark( AstPlot *, int, int, int, const double *, int, int * );
1305 static void PolyCurve( AstPlot *, int, int, int, const double *, int * );
1306 static void RemoveFrame( AstFrameSet *, int, int * );
1307 static void Set3DGrf( AstPlot3D *, AstPlot *, int, int * );
1308 static void SetCurrent( AstFrameSet *, int, int * );
1309 static void SetPlotAttr( AstPlot *, int, int[ 2 ], int * );
1310 static void SetTickValues( AstPlot *, int, int, double *, int, double *, int * );
1311 static void SplitFrameSet( AstFrameSet *, AstFrameSet **, int[2], int[2], AstFrameSet **, int[2], int[2], AstFrameSet **, int[2], int[2], int *, int * );
1312 static void StoreAxisInfo( AstPlot3D *, int[2], int[2], int[2], int[2], int[2], int[2], int * );
1313 static void Text( AstPlot *, const char *, const double [], const float [2], const char *, int * );
1314 static void UpdatePlots( AstPlot3D *, int * );
1315 static void VSet( AstObject *, const char *, char **, va_list, int * );
1316 
1317 static const char *GetAttrib( AstObject *, const char *, int * );
1318 static int TestAttrib( AstObject *, const char *, int * );
1319 static void ClearAttrib( AstObject *, const char *, int * );
1320 static void SetAttrib( AstObject *, const char *, int * );
1321 
1322 #if defined(THREAD_SAFE)
1323 static int ManageLock( AstObject *, int, int, AstObject **, int * );
1324 #endif
1325 
1326 /* Declare private member functions that access Plot3D attributes.
1327    --------------------------------------------------------------*/
1328 
1329 /* Axis independent... */
1330 
1331 #define DECLARE_PLOT3D_ACCESSORS(attr,type) \
1332    static type Get##attr(AstPlot3D *,int *); \
1333    static void Set##attr(AstPlot3D *,type,int *); \
1334    static void Clear##attr(AstPlot3D *,int *); \
1335    static int Test##attr(AstPlot3D *,int *);
1336 
DECLARE_PLOT3D_ACCESSORS(RootCorner,int)1337 DECLARE_PLOT3D_ACCESSORS(RootCorner,int)
1338 
1339 #undef DECLARE_PLOT3D_ACCESSORS
1340 
1341 
1342 /* Axis specific... */
1343 
1344 #define DECLARE_PLOT3D_ACCESSORS(attr,type) \
1345    static type Get##attr(AstPlot3D *,int,int *); \
1346    static void Set##attr(AstPlot3D *,int,type,int *); \
1347    static void Clear##attr(AstPlot3D *,int,int *); \
1348    static int Test##attr(AstPlot3D *,int,int *);
1349 
1350 DECLARE_PLOT3D_ACCESSORS(Norm,double)
1351 
1352 #undef DECLARE_PLOT3D_ACCESSORS
1353 
1354 
1355 /* Declare private member functions that access axis-specific attributes
1356    inherited from the Plot class. Also declare pointers to hold the parent
1357    function pointers.
1358    ----------------------------------------------------------------------*/
1359 
1360 #define DECLARE_PLOT_ACCESSORS(attr,type) \
1361    static type Get##attr(AstPlot *,int,int *); \
1362    static void Set##attr(AstPlot *,int,type,int *); \
1363    static void Clear##attr(AstPlot *,int,int *); \
1364    static type (*parent_get##attr)(AstPlot *,int,int *); \
1365    static void (*parent_set##attr)(AstPlot *,int,type,int *); \
1366    static void (*parent_clear##attr)(AstPlot *,int,int *);
1367 
1368 DECLARE_PLOT_ACCESSORS(MinTick,int)
1369 DECLARE_PLOT_ACCESSORS(Abbrev,int)
1370 DECLARE_PLOT_ACCESSORS(Gap,double)
1371 DECLARE_PLOT_ACCESSORS(LogGap,double)
1372 DECLARE_PLOT_ACCESSORS(LogPlot,int)
1373 DECLARE_PLOT_ACCESSORS(LogTicks,int)
1374 DECLARE_PLOT_ACCESSORS(LogLabel,int)
1375 DECLARE_PLOT_ACCESSORS(LabelUp,int)
1376 DECLARE_PLOT_ACCESSORS(DrawAxes,int)
1377 DECLARE_PLOT_ACCESSORS(LabelUnits,int)
1378 DECLARE_PLOT_ACCESSORS(MinTickLen,double)
1379 DECLARE_PLOT_ACCESSORS(MajTickLen,double)
1380 DECLARE_PLOT_ACCESSORS(NumLab,int)
1381 DECLARE_PLOT_ACCESSORS(NumLabGap,double)
1382 DECLARE_PLOT_ACCESSORS(TextLab,int)
1383 DECLARE_PLOT_ACCESSORS(TextLabGap,double)
1384 
1385 #undef DECLARE_PLOT_ACCESSORS
1386 
1387 
1388 /* Declare private member functions that access element-specific attributes
1389    inherited from the Plot class. Also declare pointers to hold the parent
1390    function pointers.
1391    ----------------------------------------------------------------------*/
1392 
1393 #define DECLARE_PLOT_ACCESSORS(attr,type) \
1394    static void Set##attr(AstPlot *,int,type,int *); \
1395    static void Clear##attr(AstPlot *,int,int *); \
1396    static void (*parent_set##attr)(AstPlot *,int,type,int *); \
1397    static void (*parent_clear##attr)(AstPlot *,int,int *);
1398 
1399 DECLARE_PLOT_ACCESSORS(Style,int)
1400 DECLARE_PLOT_ACCESSORS(Font,int)
1401 DECLARE_PLOT_ACCESSORS(Colour,int)
1402 DECLARE_PLOT_ACCESSORS(Width,double)
1403 DECLARE_PLOT_ACCESSORS(Size,double)
1404 
1405 #undef DECLARE_PLOT_ACCESSORS
1406 
1407 
1408 /* Declare private member functions that access attributes inherited from
1409    the Plot class that do not need to override the Get method. This
1410    includes attributes that are not axis-specific or that do not have
1411    dynamic defaults. Also declare pointers to hold the parent function
1412    pointers.
1413    ----------------------------------------------------------------------*/
1414 #define DECLARE_PLOT_ACCESSORS(attr,type) \
1415    static void Set##attr(AstPlot *,type,int *); \
1416    static void Clear##attr(AstPlot *,int *); \
1417    static void (*parent_set##attr)(AstPlot *,type,int *); \
1418    static void (*parent_clear##attr)(AstPlot *,int *);
1419 
1420 DECLARE_PLOT_ACCESSORS(Ink,int)
1421 DECLARE_PLOT_ACCESSORS(Tol,double)
1422 DECLARE_PLOT_ACCESSORS(Invisible,int)
1423 DECLARE_PLOT_ACCESSORS(TickAll,int)
1424 DECLARE_PLOT_ACCESSORS(ForceExterior,int)
1425 DECLARE_PLOT_ACCESSORS(Border,int)
1426 DECLARE_PLOT_ACCESSORS(Clip,int)
1427 DECLARE_PLOT_ACCESSORS(ClipOp,int)
1428 DECLARE_PLOT_ACCESSORS(Escape,int)
1429 DECLARE_PLOT_ACCESSORS(Grid,int)
1430 DECLARE_PLOT_ACCESSORS(Labelling,int)
1431 
1432 #undef DECLARE_PLOT_ACCESSORS
1433 
1434 
1435 
1436 /* Member functions. */
1437 /* ================= */
1438 
1439 static int Attr3D( AstKeyMap *grfconID, int attr, double value,
1440                    double *old_value, int prim, int *status ){
1441 /*
1442 *  Name:
1443 *     Attr3D
1444 
1445 *  Purpose:
1446 *     Get or set the value of a 3D grf attribute.
1447 
1448 *  Type:
1449 *     Private function.
1450 
1451 *  Synopsis:
1452 *     #include "plot3d.h"
1453 *     Attr3D( AstKeyMap *grfconID, int attr, double value, double *old_value,
1454 *             int prim, int *status )
1455 
1456 *  Class Membership:
1457 *     Plot3D member function.
1458 
1459 *  Description:
1460 *     This function gets or sets the current value of a specified graphics
1461 *     attribute in the parent Plot structure of a Plot3D. It forwards the
1462 *     call to the grf3D module being used by this Plot3D. It should be
1463 *     registered with the parent Plot using astGrfSet.
1464 
1465 *  Parameters:
1466 *     grfconID
1467 *       The Plot's GrfContext KeyMap.
1468 *     attr
1469 *       An integer value identifying the required attribute. This should
1470 *       be one of the symbolic values defined in grf.h.
1471 *     value
1472 *       A new value to store for the attribute. If this is AST__BAD
1473 *       no value is stored.
1474 *     old_value
1475 *       A pointer to a double in which to return the attribute value.
1476 *       If this is NULL, no value is returned.
1477 *     prim
1478 *       The sort of graphics primitive to be drawn with the new attribute.
1479 *       Identified by one of the values defined in grf.h.
1480 *     status
1481 *        Pointer to the inherited status variable.
1482 
1483 *  Returned Value:
1484 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
1485 
1486 */
1487 
1488 /* Local Variables: */
1489    int result;
1490 
1491 /* Check the inherited status. */
1492    if( !astOK ) return 0;
1493 
1494 /* Since we are about to call an external function which may not be
1495    thread safe, prevent any other thread from executing the following code
1496    until the current thread has finished executing it. */
1497    LOCK_MUTEX2;
1498 
1499 /* Use the function in the external Grf3D module, selected at link-time
1500    using ast_link options. */
1501    result = astG3DAttr( attr, value, old_value, prim );
1502 
1503 /* Allow the next thread to proceed. */
1504    UNLOCK_MUTEX2;
1505 
1506 /* Return the result. */
1507    return result;
1508 }
1509 
AxisPlot(AstPlot3D * this,int axis3d,int * axis2d,int * status)1510 static AstPlot *AxisPlot( AstPlot3D *this, int axis3d, int *axis2d, int *status ){
1511 /*
1512 *  Name:
1513 *     AxisPlot
1514 
1515 *  Purpose:
1516 *     Find the Plot used to label a 3D axis.
1517 
1518 *  Type:
1519 *     Private function.
1520 
1521 *  Synopsis:
1522 *     #include "plot3d.h"
1523 *     AstPlot *AxisPlot( AstPlot3D *this, int axis3d, int *axis2d, int *status )
1524 
1525 *  Class Membership:
1526 *     Plot method.
1527 
1528 *  Description:
1529 *     This function returns a pointer to the encapsulated 2D Plot that
1530 *     is used to label the given 3D axis. It also returns the index
1531 *     of the labelled axis within the 2D Plot.
1532 
1533 *  Parameters:
1534 *     this
1535 *        Pointer to a Plot3D.
1536 *     axis3d
1537 *        A zero-based axis index within the Plot3D.
1538 *     axis2d
1539 *        Pointer to an int in which to put the index of the labelled axis
1540 *        within the returned 2D Plot.
1541 *     status
1542 *        Pointer to the inherited status variable.
1543 
1544 *  Returned Value:
1545 *     Pointer to the Plot used to label the 3D axis. Do not annul this
1546 *     pointer.
1547 
1548 *-
1549 */
1550 
1551 /* Local Variables: */
1552    AstPlot *plot;
1553 
1554 /* Check the global status. */
1555    if( !astOK ) return NULL;
1556 
1557 /* Return the required information form the Plot3D structure. */
1558    plot = GET_PLOT( this->axis_plot1[ axis3d ] );
1559    if( ! plot ) {
1560       astError( AST__INTER, "AxisPlot(Plot3D): Illegal value %d "
1561                 "for axis3d (internal AST programming error).", status,
1562                 this->axis_plot1[ axis3d ] );
1563    }
1564 
1565    *axis2d = this->axis_index1[ axis3d ];
1566 
1567    return plot;
1568 }
1569 
Border(AstPlot * this_plot,int * status)1570 static int Border( AstPlot *this_plot, int *status ){
1571 /*
1572 *  Name:
1573 *     Border
1574 
1575 *  Purpose:
1576 *     Draw a border around valid regions of a Plot.
1577 
1578 *  Type:
1579 *     Private member function.
1580 
1581 *  Synopsis:
1582 *     #include "plot3d.h"
1583 *     int Border( AstPlot *this, int *status )
1584 
1585 *  Class Membership:
1586 *     Plot method (overrides the astBorder method inherited from the
1587 *     Plot class)
1588 
1589 *  Description:
1590 *     This function draws a (line) border around regions of the
1591 *     plotting area of a Plot which correspond to valid, unclipped
1592 *     physical coordinates. For example, when plotting using an
1593 *     all-sky map projection, this function could be used to draw the
1594 *     boundary of the celestial sphere when it is projected on to the
1595 *     plotting surface.
1596 *
1597 *     If the entire plotting area contains valid, unclipped physical
1598 *     coordinates, then the boundary will just be a rectangular box
1599 *     around the edges of the plotting area.
1600 
1601 *  Parameters:
1602 *     this
1603 *        Pointer to the Plot.
1604 *     status
1605 *        Pointer to the inherited status variable.
1606 
1607 *  Returned Value:
1608 *     Zero is returned if the plotting area is completely filled by
1609 *     valid, unclipped physical coordinates (so that only a
1610 *     rectangular box was drawn around the edge). Otherwise, one is
1611 *     returned.
1612 
1613 *  Notes:
1614 *     - The Plot3D implementation of this method, invokes the astBorder
1615 *     method on each of the three encapsulated Plots, and returns the
1616 *     logical OR of the three returned flags.
1617 *     - A value of zero will be returned if this function is invoked
1618 *     with the AST error status set, or if it should fail for any
1619 *     reason.
1620 *     - An error results if either the current Frame or the base Frame
1621 *     of the Plot is not 2-dimensional, or (for a Plot3D) 3-dimensional.
1622 *     - An error also results if the transformation between the base
1623 *     and current Frames of the Plot is not defined (i.e. the Plot's
1624 *     TranForward attribute is zero).
1625 */
1626 
1627 /* Local Variables: */
1628    AstPlot3D *this;
1629    const char *class;
1630    const char *method;
1631    float x1;
1632    float y1;
1633    float z1;
1634    float x[ 2 ];
1635    float y[ 2 ];
1636    float z[ 2 ];
1637    int flag1;
1638    int flag2;
1639    int flag3;
1640    int naxes;
1641    int ok;
1642    int result;
1643    int root_corner;
1644 
1645 /* Check the global error status. */
1646    if ( !astOK ) return 0;
1647 
1648 /* Get a pointer to the Plot3D structure. */
1649    this = (AstPlot3D *) this_plot;
1650 
1651 /* Store the current method, and the class of the supplied object for use
1652    in error messages.*/
1653    method = "astBorder";
1654    class = astGetClass( this );
1655 
1656 /* Check the base Frame of the Plot is 3-D. */
1657    naxes = astGetNin( this );
1658    if( naxes != 3 && astOK ){
1659       astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base "
1660                 "Frame of the supplied %s is invalid - this number should "
1661                 "be 3.", status, method, class, naxes, class );
1662    }
1663 
1664 /* Check the current Frame of the Plot is 3-D. */
1665    naxes = astGetNout( this );
1666    if( naxes != 3 && astOK ){
1667       astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the current "
1668                 "Frame of the supplied %s is invalid - this number should "
1669                 "be 3.", status, method, class, naxes, class );
1670    }
1671 
1672 /* Invoke the astBorder method on each of the three encapsulated Plots. */
1673    flag1 = astBorder( this->plotxy );
1674    flag2 = astBorder( this->plotxz );
1675    flag3 = astBorder( this->plotyz );
1676 
1677 /* If no bad values were encountered in any of the Plots, draw lines
1678    along the remaining plot edges. */
1679    result = ( flag1 || flag2 || flag3 );
1680    if( !result ) {
1681 
1682 /* The three remaining edges ot be drawn all meet at the corner
1683    diagonally opposite the root corner. Get the root corner. */
1684       root_corner = astGetRootCorner( this );
1685 
1686 /* The (x0,y0,z0) position is the graphics coords at the corner
1687    diagonally opposite the root corner. The x1, y1 and z1 values
1688    are the graphics x, y and z values at the ends of the three
1689    lines that remain to be drawn. */
1690       if( root_corner & 1 ) {
1691          x[ 0 ] = this->gbox[ 0 ];
1692          x1 = this->gbox[ 3 ];
1693       } else {
1694          x[ 0 ] = this->gbox[ 3 ];
1695          x1 = this->gbox[ 0 ];
1696       }
1697 
1698       if( root_corner & 2 ) {
1699          y[ 0 ] = this->gbox[ 1 ];
1700          y1 = this->gbox[ 4 ];
1701       } else {
1702          y[ 0 ] = this->gbox[ 4 ];
1703          y1 = this->gbox[ 1 ];
1704       }
1705 
1706       if( root_corner & 4 ) {
1707          z[ 0 ] = this->gbox[ 2 ];
1708          z1 = this->gbox[ 5 ];
1709       } else {
1710          z[ 0 ] = this->gbox[ 5 ];
1711          z1 = this->gbox[ 2 ];
1712       }
1713 
1714 /* Establish the correct graphical attributes as defined by attributes
1715    with the supplied Plot. */
1716       astGrfAttrs( this, AST__BORDER_ID, 1, GRF__LINE, method, class );
1717 
1718 /* Since we are about to call an external function which may not be
1719    thread safe, prevent any other thread from executing the following code
1720    until the current thread has finished executing it. */
1721       LOCK_MUTEX2;
1722 
1723 /* Draw the remaining line parallel to the X axis. */
1724       x[ 1 ] = x1;
1725       y[ 1 ] = y[ 0 ];
1726       z[ 1 ] = z[ 0 ];
1727       ok = astG3DLine( 2, x, y, z );
1728 
1729 /* Draw the remaining line parallel to the Y axis. */
1730       x[ 1 ] = x[ 0 ];
1731       y[ 1 ] = y1;
1732       z[ 1 ] = z[ 0 ];
1733       ok = ok && astG3DLine( 2, x, y, z );
1734 
1735 /* Draw the remaining line parallel to the X axis. */
1736       x[ 1 ] = x[ 0 ];
1737       y[ 1 ] = y[ 0 ];
1738       z[ 1 ] = z1;
1739       ok = ok && astG3DLine( 2, x, y, z );
1740 
1741 /* Allow the next thread to proceed. */
1742       UNLOCK_MUTEX2;
1743 
1744 /* Re-establish the original graphical attributes. */
1745       astGrfAttrs( this, AST__BORDER_ID, 0, GRF__LINE, method, class );
1746 
1747 /* Report an error if anything went wrong in the grf3d module. */
1748       if( !ok && astOK ) {
1749          astError( AST__GRFER, "%s(%s): Graphics error in astG3DLine. ", status,
1750                    method, class );
1751       }
1752    }
1753 
1754 /* Return zero if an error has occurrred. */
1755    if( !astOK ) result = 0;
1756 
1757 /* Return a flag indicating if any bad values were encountered in any of
1758    the Plots. */
1759    return result;
1760 }
1761 
Cast(AstObject * this_object,AstObject * obj,int * status)1762 static AstObject *Cast( AstObject *this_object, AstObject *obj, int *status ) {
1763 /*
1764 *  Name:
1765 *     Cast
1766 
1767 *  Purpose:
1768 *     Cast an Object into an instance of a sub-class.
1769 
1770 *  Type:
1771 *     Private function.
1772 
1773 *  Synopsis:
1774 *     #include "plot3d.h"
1775 *     AstObject *Cast( AstObject *this, AstObject *obj, int *status )
1776 
1777 *  Class Membership:
1778 *     Plot3D member function (over-rides the protected astCast
1779 *     method inherited from the Frame class).
1780 
1781 *  Description:
1782 *     This function returns a deep copy of an ancestral component of the
1783 *     supplied object. The required class of the ancestral component is
1784 *     specified by another object. Specifically, if "this" and "new" are
1785 *     of the same class, a copy of "this" is returned. If "this" is an
1786 *     instance of a subclass of "obj", then a copy of the component
1787 *     of "this" that matches the class of "obj" is returned. Otherwise,
1788 *     a NULL pointer is returned without error.
1789 
1790 *  Parameters:
1791 *     this
1792 *        Pointer to the Object to be cast.
1793 *     obj
1794 *        Pointer to an Object that defines the class of the returned Object.
1795 *        The returned Object will be of the same class as "obj".
1796 
1797 *  Returned Value:
1798 *     A pointer to the new Object. NULL if "this" is not a sub-class of
1799 *     "obj", or if an error occurs.
1800 
1801 *  Notes:
1802 *     - A NULL pointer will be returned if this function is invoked
1803 *     with the global error status set, or if it should fail for any
1804 *     reason.
1805 */
1806 
1807 /* Local Variables; */
1808    AstObject *new;
1809    astDECLARE_GLOBALS
1810    int generation_gap;
1811 
1812 /* Initialise */
1813    new = NULL;
1814 
1815 /* Check inherited status */
1816    if( !astOK ) return new;
1817 
1818 /* Get a pointer to the thread specific global data structure. */
1819    astGET_GLOBALS(NULL);
1820 
1821 /* See how many steps up the class inheritance ladder it is from "obj"
1822    to this class (Plot3D). A positive value is returned if Plot3D
1823    is a sub-class of "obj". A negative value is returned if "obj" is
1824    a sub-class of Plot3D. Zero is returned if "obj" is a Plot3D.
1825    AST__COUSIN is returned if "obj" is not on the same line of descent
1826    as Plot3D. */
1827    generation_gap = astClassCompare( (AstObjectVtab *) &class_vtab,
1828                                      astVTAB( obj ) );
1829 
1830 /* If "obj" is a Plot3D or a sub-class of Plot3D, we can cast by
1831    truncating the vtab for "this" so that it matches the vtab of "obJ",
1832    and then taking a deep copy of "this". */
1833    if( generation_gap <= 0 && generation_gap != AST__COUSIN ) {
1834       new = astCastCopy( this_object, obj );
1835 
1836 /* If "obj" is a Plot (the parent class), we cast by returning a deep
1837    copy of the Plot covering the XY face. */
1838    } else if( generation_gap == 1 ) {
1839       new = astCopy( ( (AstPlot3D *) this_object)->plotxy );
1840 
1841 /* If "obj" is a FrameSet or higher, we attempt to use the implementation
1842    inherited from the parent class to cast the FrameSet component into the
1843    class indicated by "obj". */
1844    } else {
1845       new = (*parent_cast)( this_object, obj, status );
1846    }
1847 
1848 /* Return the new pointer. */
1849    return new;
1850 }
1851 
ChangeRootCorner(AstPlot3D * this,int old,int new,int * status)1852 static void ChangeRootCorner( AstPlot3D *this, int old, int new, int *status ){
1853 /*
1854 *  Name:
1855 *     ChangeRootCorner
1856 
1857 *  Purpose:
1858 *     Use a new RootCorner value.
1859 
1860 *  Type:
1861 *     Private function.
1862 
1863 *  Synopsis:
1864 *     #include "plot3d.h"
1865 *     void ChangeRootCorner( AstPlot3D *this, int old, int new, int *status )
1866 
1867 *  Class Membership:
1868 *     Plot method.
1869 
1870 *  Description:
1871 *     This function sets the attributes of the encapsulated Plots so that
1872 *     labels appear on the edges of the 3D graphics cube that join at the
1873 *     specified new root corner. It also reverses the graphics axes in
1874 *     the encapsulated Plots as required in order to ensure that the Plots
1875 *     look "normal" when viewed from the outside of the 3D graphics cube.
1876 *     This happens if a the Plot used to label a specific axis moves from
1877 *     one face the the 3D graphics cube to the opposite face.
1878 
1879 *  Parameters:
1880 *     this
1881 *        Pointer to a Plot3D.
1882 *     old
1883 *        The old RootCorner value.
1884 *     new
1885 *        The new RootCorner value.
1886 *     status
1887 *        Pointer to the inherited status variable.
1888 
1889 *  Notes:
1890 *     - Each RootCorner value is in the range 0 to 7 and is a 3 bit
1891 *     bit-mask. Bit 0 describes the 3D graphics X axis, bit 1 describes
1892 *     the graphics Y axis and bit 2 describes the graphics Z axis. If a
1893 *     bit is set it means that the corner is at the upper bound on the
1894 *     corresponding axis. If a bit is unset it means that the corner is
1895 *     at the lower bound on the corresponding axis.
1896 
1897 *-
1898 */
1899 
1900 /* Local Variables: */
1901    AstKeyMap *grfcon;
1902    AstPlot *plot;
1903    AstPlot *plots[ 24 ];
1904    int edges[ 24 ];
1905    int axes[ 24 ];
1906    int axis2d;
1907    int edge;
1908    int i;
1909    int np;
1910    int xeqy;
1911    int xeqz;
1912 
1913 /* Check the global status. */
1914    if( !astOK ) return;
1915 
1916 /* If the corner has moved on the 3D X axis (from upper X bound to lower X
1917    bound or vice-versa), mirror the axis of the encapsulated Plot that is
1918    perpendicular to the 3D X axis. This means that the Plot can be thought
1919    of as being viewed from the outside of the 3D graphics cube. Also,
1920    update the constant X axis value at which the YZ plane is drawn. */
1921    if( ( old & 1 ) != ( new & 1 ) ) astMirror( this->plotyz, 0 );
1922    grfcon = (AstKeyMap *) astGetGrfContext( this->plotyz );
1923    astMapPut0D( grfcon, "Gcon", this->gbox[ ( new & 1 ) ? 3 : 0 ], "Constant X value" );
1924    astMapPut0I( grfcon, "RootCorner", new, "Labelled corner" );
1925    grfcon= astAnnul( grfcon );
1926 
1927 /* Likewise mirror the other two axes if required. */
1928    if( ( old & 2 ) != ( new & 2 ) ) astMirror( this->plotxz, 0 );
1929    grfcon = (AstKeyMap *) astGetGrfContext( this->plotxz );
1930    astMapPut0D( grfcon, "Gcon", this->gbox[ ( new & 2 ) ? 4 : 1 ], "Constant Y value" );
1931    astMapPut0I( grfcon, "RootCorner", new, "Labelled corner" );
1932    grfcon= astAnnul( grfcon );
1933 
1934    if( ( old & 4 ) != ( new & 4 ) ) astMirror( this->plotxy, 0 );
1935    grfcon = (AstKeyMap *) astGetGrfContext( this->plotxy );
1936    astMapPut0D( grfcon, "Gcon", this->gbox[ ( new & 4 ) ? 5 : 2 ], "Constant Z value" );
1937    astMapPut0I( grfcon, "RootCorner", new, "Labelled corner" );
1938    grfcon= astAnnul( grfcon );
1939 
1940 /* Set a flag saying whether the limits are equal at the new corner for
1941    the X and Y axes. */
1942    xeqy = ( ( ( new & 1 ) > 0 ) == ( ( new & 2 ) > 0 ) );
1943 
1944 /* Set a flag saying whether the limits are equal at the new corner for
1945    the X and Z axes. */
1946    xeqz = ( ( ( new & 1 ) > 0 ) == ( ( new & 4 ) > 0 ) );
1947 
1948 /* Ensure all Edge attributes are clear. This means that the public
1949    attribute accessors routines used below will return dynamic defaults for
1950    the Edge attributes. */
1951    astClearEdge( this->plotxy, 0 );
1952    astClearEdge( this->plotxy, 1 );
1953    astClearEdge( this->plotxz, 0 );
1954    astClearEdge( this->plotxz, 1 );
1955    astClearEdge( this->plotyz, 0 );
1956    astClearEdge( this->plotyz, 1 );
1957 
1958 /* So far we have recorded no edges changes. */
1959    np = 0;
1960 
1961 /* We now adjust the Edge attributes in the Plot used to annotate the 3D
1962    X axis in order to get the X axis labels on the correct edge of the 3D
1963    graphics cube. Get the Plot used to produce X axis labels (this will
1964    be either this->plotxy or this->plotxz). */
1965    plot = AxisPlot( this, 0, &axis2d, status );
1966 
1967 /* See what edge of the Plot is used to annotate the first of the two WCS
1968    axis described by the 2D Plot. If the Edge(1) attribute has not been
1969    assigned a value, then a dynamic default will be used by the Plot class.
1970    We want to know what this dynamic default is, so we first cleared the
1971    attribute above. Now we set the attribute value explicitly to the dynamic
1972    default returned by astGetC. Note, we use astGetC rather than astGetEdge
1973    because the dynamic default is not calculated when calling astGetEdge. */
1974    astSetC( plot, "Edge(1)", astGetC( plot, "Edge(1)" ));
1975    edge = astGetEdge( plot, 0 );
1976    astClearEdge( plot, 0 );
1977 
1978 /* If the 3D X axis is labelled using the Plot that spans the XY plane... */
1979    if( plot == this->plotxy ) {
1980 
1981 /* ... and if the new root corner is at the upper limit on the Y axis... */
1982       if( new & 2 ) {
1983 
1984 /* If the first WCS axis is currently labelled on either the top or bottom
1985    edge, ensure it is labelled on the upper Y (top) edge. */
1986          if( edge == 3 || edge == 1 ) {
1987             plots[ np ] = plot;
1988             axes[ np ] = 0;
1989             edges[ np++ ] = TOP;
1990 
1991 /* Otherwise ensure that the second WCS axis is labelled on the upper Y (top)
1992    edge. */
1993          } else {
1994             plots[ np ] = plot;
1995             axes[ np ] = 1;
1996             edges[ np++ ] = TOP;
1997          }
1998 
1999 /* If the new root corner is at the lower limit on the Y axis... */
2000       } else {
2001 
2002 /* If the first WCS axis is currently labelled on either the top or bottom
2003    edge, ensure it is labelled on the lower Y (bottom) edge. */
2004          if( edge == 3 || edge == 1 ) {
2005             plots[ np ] = plot;
2006             axes[ np ] = 0;
2007             edges[ np++ ] = BOTTOM;
2008 
2009 /* Otherwise ensure that the second WCS axis is labelled on the lower Y
2010    (bottom) edge. */
2011          } else {
2012             plots[ np ] = plot;
2013             axes[ np ] = 1;
2014             edges[ np++ ] = BOTTOM;
2015          }
2016       }
2017 
2018 /* If the 3D X axis is labelled using the Plot that spans the XZ plane... */
2019    } else {
2020 
2021 /* ... and if the new root corner is at the upper limit on the Z axis... */
2022       if( new & 4 ) {
2023 
2024 /* If the first WCS axis is currently labelled on either the top or bottom
2025    edge, ensure it is labelled on the upper Z (top) edge. */
2026          if( edge == 3 || edge == 1 ) {
2027             plots[ np ] = plot;
2028             axes[ np ] = 0;
2029             edges[ np++ ] = TOP;
2030 
2031 /* Otherwise ensure that the second WCS axis is labelled on the upper Y (top)
2032    edge. */
2033          } else {
2034             plots[ np ] = plot;
2035             axes[ np ] = 1;
2036             edges[ np++ ] = TOP;
2037          }
2038 
2039 /* If the new root corner is at the lower limit on the Z axis... */
2040       } else {
2041 
2042 /* If the first WCS axis is currently labelled on either the top or bottom
2043    edge, ensure it is labelled on the lower Z (bottom) edge. */
2044          if( edge == 3 || edge == 1 ) {
2045             plots[ np ] = plot;
2046             axes[ np ] = 0;
2047             edges[ np++ ] = BOTTOM;
2048 
2049 /* Otherwise ensure that the second WCS axis is labelled on the lower Z
2050    (bottom) edge. */
2051          } else {
2052             plots[ np ] = plot;
2053             axes[ np ] = 1;
2054             edges[ np++ ] = BOTTOM;
2055          }
2056       }
2057    }
2058 
2059 /* We now adjust the Edge attributes in the Plot used to annotate the 3D
2060    Y axis in order to get the Y axis labels on the correct edge of the 3D
2061    graphics cube. Get the Plot used to produce Y axis labels. */
2062    plot = AxisPlot( this, 1, &axis2d, status );
2063 
2064 /* See what edge of the Plot is used to annotate the first of the two WCS
2065    axis described by the Plot. */
2066    astSetC( plot, "Edge(1)", astGetC( plot, "Edge(1)" ));
2067    edge = astGetEdge( plot, 0 );
2068    astClearEdge( plot, 0 );
2069 
2070 /* If the 3D Y axis is labelled using the Plot that spans the XY plane... */
2071    if( plot == this->plotxy ) {
2072 
2073 /* ... and if the new root corner is at the same limit on the X and Z axes,
2074    put Y labels on the right side of the Plot.  */
2075       if( xeqz ) {
2076          if( edge == 0 || edge == 2 ) {
2077             plots[ np ] = plot;
2078             axes[ np ] = 0;
2079             edges[ np++ ] = RIGHT;
2080          } else {
2081             plots[ np ] = plot;
2082             axes[ np ] = 1;
2083             edges[ np++ ] = RIGHT;
2084          }
2085 
2086 /* If the new root corner is at a different limit on the X and Z axes,
2087    put Y labels on the left side of the Plot.  */
2088       } else {
2089          if( edge == 0 || edge == 2 ) {
2090             plots[ np ] = plot;
2091             axes[ np ] = 0;
2092             edges[ np++ ] = LEFT;
2093          } else {
2094             plots[ np ] = plot;
2095             axes[ np ] = 1;
2096             edges[ np++ ] = LEFT;
2097          }
2098       }
2099 
2100 /* If the 3D Y axis is labelled using the Plot that spans the YZ plane... */
2101    } else {
2102 
2103 /* ... and if the new root corner is at the upper Z limit, put Y labels on
2104    the top of the Plot.  */
2105       if( new & 4 ) {
2106          if( edge == 1 || edge == 3 ) {
2107             plots[ np ] = plot;
2108             axes[ np ] = 0;
2109             edges[ np++ ] = TOP;
2110          } else {
2111             plots[ np ] = plot;
2112             axes[ np ] = 1;
2113             edges[ np++ ] = TOP;
2114          }
2115 
2116 /* If the new root corner is at the lower Z limit, put Y labels on the
2117    bottom of the Plot.  */
2118       } else {
2119          if( edge == 1 || edge == 3 ) {
2120             plots[ np ] = plot;
2121             axes[ np ] = 0;
2122             edges[ np++ ] = BOTTOM;
2123          } else {
2124             plots[ np ] = plot;
2125             axes[ np ] = 1;
2126             edges[ np++ ] = BOTTOM;
2127          }
2128       }
2129    }
2130 
2131 /* We now adjust the Edge attributes in the Plot used to annotate the 3D
2132    Z axis in order to get the Z axis labels on the correct edge of the 3D
2133    graphics cube. Get the Plot used to produce Z axis labels. */
2134    plot = AxisPlot( this, 2, &axis2d, status );
2135 
2136 /* See what edge of the Plot is used to annotate the first of the two WCS
2137    axis described by the Plot. */
2138    astSetC( plot, "Edge(1)", astGetC( plot, "Edge(1)" ));
2139    edge = astGetEdge( plot, 0 );
2140    astClearEdge( plot, 0 );
2141 
2142 /* If the 3D Z axis is labelled using the Plot that spans the XZ plane... */
2143    if( plot == this->plotxz ) {
2144 
2145 /* ... and if the new root corner is at the same limit on the X and Y axes,
2146    put Z labels on the left side of the Plot.  */
2147       if( xeqy ) {
2148          if( edge == 0 || edge == 2 ) {
2149             plots[ np ] = plot;
2150             axes[ np ] = 0;
2151             edges[ np++ ] = LEFT;
2152          } else {
2153             plots[ np ] = plot;
2154             axes[ np ] = 1;
2155             edges[ np++ ] = LEFT;
2156          }
2157 
2158 /* If the new root corner is at a different limit on the X and Y axes,
2159    put Y labels on the right side of the Plot.  */
2160       } else {
2161          if( edge == 0 || edge == 2 ) {
2162             plots[ np ] = plot;
2163             axes[ np ] = 0;
2164             edges[ np++ ] = RIGHT;
2165          } else {
2166             plots[ np ] = plot;
2167             axes[ np ] = 1;
2168             edges[ np++ ] = RIGHT;
2169          }
2170       }
2171 
2172 /* If the 3D Z axis is labelled using the Plot that spans the YZ plane... */
2173    } else {
2174 
2175 /* ... and if the new root corner is at the same limit on the X and Y axes,
2176    put Z labels on the right side of the Plot.  */
2177       if( xeqz ) {
2178          if( edge == 0 || edge == 2 ) {
2179             plots[ np ] = plot;
2180             axes[ np ] = 0;
2181             edges[ np++ ] = RIGHT;
2182          } else {
2183             plots[ np ] = plot;
2184             axes[ np ] = 1;
2185             edges[ np++ ] = RIGHT;
2186          }
2187 
2188 /* If the new root corner is at a different limit on the X and Y axes,
2189    put Y labels on the left side of the Plot.  */
2190       } else {
2191          if( edge == 0 || edge == 2 ) {
2192             plots[ np ] = plot;
2193             axes[ np ] = 0;
2194             edges[ np++ ] = LEFT;
2195          } else {
2196             plots[ np ] = plot;
2197             axes[ np ] = 1;
2198             edges[ np++ ] = LEFT;
2199          }
2200       }
2201    }
2202 
2203 /* Apply the set of edge changes determined above. */
2204    for( i = 0; i < np; i++ ) {
2205       astSetEdge( plots[ i ], axes[ i ], edges[ i ] );
2206    }
2207 
2208 /* Ensure that the 2 Plot axes that are not being used have suitable values
2209    for their attributes. That is, no labels are drawn, and the ticked
2210    edges are the one that meet at the new RootCorner. */
2211 
2212    if( !astTestEdge( this->plotxy, 0 ) ) {
2213       astSetEdge( this->plotxy, 0, ( new & 2 ) ? TOP : BOTTOM );
2214    }
2215 
2216    if( !astTestEdge( this->plotxy, 1 ) ) {
2217       astSetEdge( this->plotxy, 1, xeqz ? RIGHT: LEFT );
2218    }
2219 
2220    if( !astTestEdge( this->plotxz, 0 ) ) {
2221       astSetEdge( this->plotxz, 0, ( new & 4 ) ? TOP : BOTTOM );
2222    }
2223 
2224    if( !astTestEdge( this->plotxz, 1 ) ) {
2225       astSetEdge( this->plotxz, 1, xeqy ? LEFT : RIGHT );
2226    }
2227 
2228    if( !astTestEdge( this->plotyz, 0 ) ) {
2229       astSetEdge( this->plotyz, 0, ( new & 4 ) ? TOP : BOTTOM );
2230    }
2231 
2232    if( !astTestEdge( this->plotyz, 1 ) ) {
2233       astSetEdge( this->plotyz, 1, xeqy ? RIGHT : LEFT );
2234    }
2235 
2236 
2237 }
2238 
Clear(AstObject * this_object,const char * attrib,int * status)2239 static void Clear( AstObject *this_object, const char *attrib, int *status ) {
2240 /*
2241 *  Name:
2242 *     Clear
2243 
2244 *  Purpose:
2245 *     Clear attribute values for a Plot3D.
2246 
2247 *  Type:
2248 *     Private function.
2249 
2250 *  Synopsis:
2251 *     #include "plot3d.h"
2252 *     void Clear( AstObject *this, const char *attrib, int *status )
2253 
2254 *  Class Membership:
2255 *     Plot3D member function (over-rides the public astClear method
2256 *     inherited from the Object class).
2257 
2258 *  Description:
2259 *     This function clears the values of a specified set of attributes
2260 *     for a Plot3D. Clearing an attribute cancels any value that has
2261 *     previously been explicitly set for it, so that the standard
2262 *     default attribute value will subsequently be used instead. This
2263 *     also causes the astTest function to return the value zero for
2264 *     the attribute, indicating that no value has been set.
2265 
2266 *  Parameters:
2267 *     this
2268 *        Pointer to the Plot3D.
2269 *     attrib
2270 *        Pointer to a null-terminated character string containing a
2271 *        comma-separated list of the names of the attributes to be
2272 *        cleared.
2273 *     status
2274 *        Pointer to the inherited status variable.
2275 
2276 *  Notes:
2277 *     - This function preserves the integrity of the Plot3D (if
2278 *     possible) by appropriately modifying the three encapsulated Plots.
2279 */
2280 
2281 /* Check the global error status. */
2282    if ( !astOK ) return;
2283 
2284 /* Invoke the parent astClear method to clear the Plot3D's attribute values. */
2285    (*parent_clear)( this_object, attrib, status );
2286 
2287 /* Update the three 2D Plots stored in the Plot3D structure so that they
2288    reflect this modified FrameSet. */
2289    UpdatePlots( (AstPlot3D *) this_object, status );
2290 
2291 }
2292 
ClearAttrib(AstObject * this_object,const char * attrib,int * status)2293 static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
2294 /*
2295 *  Name:
2296 *     ClearAttrib
2297 
2298 *  Purpose:
2299 *     Clear an attribute value for a Plot3D.
2300 
2301 *  Type:
2302 *     Private function.
2303 
2304 *  Synopsis:
2305 *     #include "plot.h"
2306 *     void ClearAttrib( AstObject *this, const char *attrib )
2307 
2308 *  Class Membership:
2309 *     Plot3D member function (over-rides the astClearAttrib protected
2310 *     method inherited from the Plot class).
2311 
2312 *  Description:
2313 *     This function clears the value of a specified attribute for a
2314 *     Plot3D, so that the default value will subsequently be used.
2315 
2316 *  Parameters:
2317 *     this
2318 *        Pointer to the Plot3D.
2319 *     attrib
2320 *        Pointer to a null terminated string specifying the attribute
2321 *        name.  This should be in lower case with no surrounding white
2322 *        space.
2323 */
2324 
2325 /* Local Variables: */
2326    AstPlot3D *this;              /* Pointer to the Plot3D structure */
2327    int axis;                     /* Axis index */
2328    int len;                      /* Length of attrib string */
2329    int nc;                       /* Number of characters read */
2330 
2331 /* Check the global error status. */
2332    if ( !astOK ) return;
2333 
2334 /* Obtain a pointer to the Plot3D structure. */
2335    this = (AstPlot3D *) this_object;
2336 
2337 /* Obtain the length of the "attrib" string. */
2338    len = strlen( attrib );
2339 
2340 /* Check the attribute name and clear the appropriate attribute. */
2341 
2342 /* Norm. */
2343 /* ----------- */
2344    if ( !strcmp( attrib, "norm" ) ) {
2345       astClearNorm( this, 0 );
2346       astClearNorm( this, 1 );
2347       astClearNorm( this, 2 );
2348 
2349 /* Norm(axis). */
2350 /* ----------- */
2351    } else if ( nc = 0,
2352                ( 1 == astSscanf( attrib, "norm(%d)%n", &axis, &nc ) )
2353                && ( nc >= len ) ) {
2354       astClearNorm( this, axis - 1 );
2355 
2356 /* RootCorner. */
2357 /* ----------- */
2358    } else if ( !strcmp( attrib, "rootcorner" ) ) {
2359       astClearRootCorner( this );
2360 
2361 /* If the attribute is still not recognised, pass it on to the parent
2362    method for further interpretation. */
2363    } else {
2364       (*parent_clearattrib)( this_object, attrib, status );
2365    }
2366 }
2367 
ClearCurrent(AstFrameSet * this_frameset,int * status)2368 static void ClearCurrent( AstFrameSet *this_frameset, int *status ) {
2369 /*
2370 *  Name:
2371 *     ClearCurrent
2372 
2373 *  Purpose:
2374 *     Clear the value of the Current attribute for a Plot3D.
2375 
2376 *  Type:
2377 *     Private function.
2378 
2379 *  Synopsis:
2380 *     #include "plot3d.h"
2381 *     int astClearCurrent( AstFrameSet *this )
2382 
2383 *  Class Membership:
2384 *     Plot3D member function (over-rides the public astClearCurrent method
2385 *     inherited from the FrameSet class).
2386 
2387 *  Description:
2388 *     This function clears the value of the Current attribute for a
2389 *     Plot3D. This attribute is an index that identifies the current
2390 *     Frame for the Plot3D.
2391 
2392 *  Parameters:
2393 *     this
2394 *        Pointer to the Plot3D.
2395 */
2396 
2397 /* Invoke the parent astClearCurrent method. */
2398    (*parent_clearcurrent)( this_frameset, status );
2399 
2400 /* Update the three 2D Plots stored in the Plot3D structure so that they
2401    reflect this modified FrameSet. */
2402    UpdatePlots( (AstPlot3D *) this_frameset, status );
2403 }
2404 
ClearRootCorner(AstPlot3D * this,int * status)2405 static void ClearRootCorner( AstPlot3D *this, int *status ){
2406 /*
2407 *+
2408 *  Name:
2409 *     astClearRootCorner
2410 
2411 *  Purpose:
2412 *     Clear the RootCorner attribute.
2413 
2414 *  Type:
2415 *     Protected virtual function.
2416 
2417 *  Synopsis:
2418 *     #include "plot3d.h"
2419 *     void astClearRootCorner( AstPlot3D *this )
2420 
2421 *  Class Membership:
2422 *     Plot method.
2423 
2424 *  Description:
2425 *     This function clears the RootCorner attribute.
2426 
2427 *  Parameters:
2428 *     this
2429 *        Pointer to a Plot3D.
2430 
2431 *-
2432 */
2433 
2434 /* Local Variables: */
2435    int old;
2436    int new;
2437 
2438 /* Check the global status. */
2439    if( !astOK ) return;
2440 
2441 /* Get the current rootcorner value. */
2442    old = astGetRootCorner( this );
2443 
2444 /* Clear the RootCorner attribute. */
2445    this->rootcorner = -1;
2446 
2447 /* Get the new (default) rootcorner value. */
2448    new = astGetRootCorner( this );
2449 
2450 /* If the root corner has changed, mirror any axes of the encapsulated Plots
2451    that need mirroring (this is done to ensure that Plots look right when
2452    viewed from the outside of the graphics cube), and modify the Edge
2453    attributes in the encapsulated Plots to ensure the labels appear on the
2454    requested edges of the 3D graphics cube. . */
2455    if( old != new ) ChangeRootCorner( this, old, new, status );
2456 }
2457 
CreatePlots(AstPlot3D * this,AstFrameSet * fset,const float * gbox,const double * bbox,int * status)2458 static void CreatePlots( AstPlot3D *this, AstFrameSet *fset, const float *gbox,
2459                          const double *bbox, int *status ) {
2460 /*
2461 *  Name:
2462 *     CreatePlots
2463 
2464 *  Purpose:
2465 *     Create three 2D plots and store in the Plot3D.
2466 
2467 *  Type:
2468 *     Private function.
2469 
2470 *  Synopsis:
2471 *     #include "plot3d.h"
2472 *     void CreatePlots( AstPlot3D *this, AstFrameSet *fset, const float *gbox,
2473                         const double *bbox, int *status )
2474 
2475 *  Class Membership:
2476 *     Plot3D method.
2477 
2478 *  Description:
2479 *     This function splits the supplied FrameSet up into 3 independent 2D
2480 *     FrameSets, each describing a 2D plane in the supplied 3D FrameSet.
2481 *     It then uses these 2D FrameSets to create three Plots, one for each
2482 *     plane in the graphics plotting space, and stores them in the Plot3D.
2483 *
2484 *     Each of the three Plots is notionally pasted onto one face of the
2485 *     3D graphics cube (the RootCorner attribute is used to determine which
2486 *     of the two parallel faces a particular Plot is pasted onto). The
2487 *     Plot is pasted in such a way that, when viewed from the outside of
2488 *     the graphics cube, the first graphics axis increases left to right
2489 *     and the second increases bottom to top (this assumes that "up" is
2490 *     parallel to the 3D Z axis).
2491 *
2492 *     Initially, the Plots are created assuming the default RootCorner
2493 *     value ("LLL"). They will be changed later if the value of the
2494 *     RootCorner attribute is changed.
2495 
2496 *  Parameters:
2497 *     this
2498 *        Pointer to the Plot3D.
2499 *     fset
2500 *        Pointer to the FrameSet.
2501 *     gbox
2502 *        A pointer to an array of 6 values giving the graphics coordinates
2503 *        of the bottom left and top right corners of a box on the graphics
2504 *        output device. The first triple of values should be the graphics
2505 *        coordinates of the bottom left corner of the box and the second
2506 *        triple of values are the graphics coordinates of the top right corner.
2507 *     bbox
2508 *        A pointer to an array of 6 values giving the coordinates in the
2509 *        supplied Frame or base Frame of the supplied FrameSet at the bottom
2510 *        left and top right corners of the box specified by parameter gbox.
2511 *        These should be supplied in the same order as for parameter "gbox".
2512 *     status
2513 *        Pointer to the inherited status variable.
2514 
2515 *  Notes:
2516 *     - Each returned plot has 3 Frames: Frame 1 is the base (GRAPHICS)
2517 *     Frame; Frame 2 is spanned by 2 of the 3 axes in the base Frame of
2518 *     the supplied FrameSet; Frame 3 is the current Frame and is spanned
2519 *     by 2 of the 3 axes in the current Frame of the supplied FrameSet.
2520 *     Any future changes to this function that alter this structure should
2521 *     reflected in equivalent changes to function UpdatePlots.
2522 
2523 */
2524 
2525 /* Local Variables: */
2526    AstFrameSet *fsetxy;
2527    AstFrameSet *fsetxz;
2528    AstFrameSet *fsetyz;
2529    double basebox2d[ 4 ];
2530    float graphbox2d[ 4 ];
2531    int baseplane;
2532    int labelxy[ 2 ];
2533    int labelxz[ 2 ];
2534    int labelyz[ 2 ];
2535    int wcsxy[ 2 ];
2536    int wcsxz[ 2 ];
2537    int wcsyz[ 2 ];
2538 
2539 /* Check the inherited status. */
2540    if( !astOK ) return;
2541 
2542 /* Split the supplied FrameSet up into 3 FrameSets, each with a 2D base
2543    and current Frame. Each of these FrameSets describes one plane of
2544    the 3D cube. One of them will be spanned by two axes picked from the
2545    supplied 3D FrameSet. The other two FrameSets will each include a copy
2546    of the remaining 3rd axis from the supplied FrameSet, plus an extra
2547    dummy axis. These dummy axes will never be labelled. */
2548    SplitFrameSet( fset, &fsetxy, labelxy, wcsxy, &fsetxz, labelxz, wcsxz,
2549                   &fsetyz, labelyz, wcsyz, &baseplane, status );
2550 
2551 /* If OK, annul any existing 2D plots. */
2552    if( astOK ) {
2553       if( this->plotxy ) this->plotxy = astAnnul( this->plotxy );
2554       if( this->plotxz ) this->plotxz = astAnnul( this->plotxz );
2555       if( this->plotyz ) this->plotyz = astAnnul( this->plotyz );
2556 
2557 /* Create three Plots; one for each 2D plane in the graphics plotting
2558    space. Set the attributes of these plots so that the required axes are
2559    labelled and other axes are left blank. The "graphbox2d" and "basebox2d"
2560    values used to create each Plot define the sense, as well as the extent,
2561    of each axis. The first pair of values in each give the lower left corner
2562    of the Plot and the second pair give the top right corner. We want each
2563    Plot to have X increasing left to right and Y increasing bottom to
2564    top when viewed from the outside of the cube. We assume an initial
2565    RootCorner value of "LLL" (that is, the Plots are pasted onto the cube
2566    faces that meet at the lower limit on every axis). */
2567       graphbox2d[ 0 ] = gbox[ 3 ];
2568       graphbox2d[ 1 ] = gbox[ 1 ];
2569       graphbox2d[ 2 ] = gbox[ 0 ];
2570       graphbox2d[ 3 ] = gbox[ 4 ];
2571 
2572       basebox2d[ 0 ] = bbox[ 3 ];
2573       basebox2d[ 1 ] = bbox[ 1 ];
2574       basebox2d[ 2 ] = bbox[ 0 ];
2575       basebox2d[ 3 ] = bbox[ 4 ];
2576 
2577       if( this->plotxy ) this->plotxy = astAnnul( this->plotxy );
2578       this->plotxy = astPlot( fsetxy, graphbox2d, basebox2d, "", status );
2579       SetPlotAttr( this->plotxy, XY, labelxy, status );
2580 
2581       graphbox2d[ 0 ] = gbox[ 0 ];
2582       graphbox2d[ 1 ] = gbox[ 2 ];
2583       graphbox2d[ 2 ] = gbox[ 3 ];
2584       graphbox2d[ 3 ] = gbox[ 5 ];
2585 
2586       basebox2d[ 0 ] = bbox[ 0 ];
2587       basebox2d[ 1 ] = bbox[ 2 ];
2588       basebox2d[ 2 ] = bbox[ 3 ];
2589       basebox2d[ 3 ] = bbox[ 5 ];
2590 
2591       this->plotxz = astPlot( fsetxz, graphbox2d, basebox2d, "", status );
2592       SetPlotAttr( this->plotxz, XZ, labelxz, status );
2593 
2594       graphbox2d[ 0 ] = gbox[ 4 ];
2595       graphbox2d[ 1 ] = gbox[ 2 ];
2596       graphbox2d[ 2 ] = gbox[ 1 ];
2597       graphbox2d[ 3 ] = gbox[ 5 ];
2598 
2599       basebox2d[ 0 ] = bbox[ 4 ];
2600       basebox2d[ 1 ] = bbox[ 2 ];
2601       basebox2d[ 2 ] = bbox[ 1 ];
2602       basebox2d[ 3 ] = bbox[ 5 ];
2603 
2604       this->plotyz = astPlot( fsetyz, graphbox2d, basebox2d, "", status );
2605       SetPlotAttr( this->plotyz, YZ, labelyz, status );
2606 
2607 /* Store information that allows each 3D WCS axis to be associatedf with
2608    a pair of Plots. Also store the WCS axis within each Plot that
2609    corresponds to the 3D WCS axis. */
2610       StoreAxisInfo( this, labelxy, wcsxy, labelxz, wcsxz, labelyz, wcsyz, status );
2611 
2612 /* Store the Plot that spans two connected 3D axes. */
2613       this->baseplot = baseplane;
2614 
2615 /* Free resources */
2616       fsetxy = astAnnul( fsetxy );
2617       fsetxz = astAnnul( fsetxz );
2618       fsetyz = astAnnul( fsetyz );
2619 
2620    }
2621 }
2622 
Element2D(AstPlot3D * this,int element,int * elem2d1,int * elem2d2,int * status)2623 static int Element2D( AstPlot3D *this, int element, int *elem2d1,
2624                       int *elem2d2, int *status ){
2625 /*
2626 *  Name:
2627 *     Element2D
2628 
2629 *  Purpose:
2630 *     Convert a 3D graphics element identifier to a corresponding pair of
2631 *     2D identifiers.
2632 
2633 *  Type:
2634 *     Private function.
2635 
2636 *  Synopsis:
2637 *     #include "plot3d.h"
2638 *     int Element2D( AstPlot3D *this, int element, int *elem2d1,
2639 *                    int *elem2d2, int *status )
2640 
2641 *  Class Membership:
2642 *     Plot3D method.
2643 
2644 *  Description:
2645 *     This function takes an integer identifier for an element of a 3D
2646 *     annotated grid (e.g. ticks, axis 1 labels, border, etc), and returns
2647 *     a element identifers that can be used with the encapsualted 2D Plots.
2648 
2649 *  Parameters:
2650 *     this
2651 *        Pointer to the Plot2D structure.
2652 *     element
2653 *        The 3D element identifier to convert.
2654 *     elem2d1
2655 *        Pointer to an int in which to return the 2D element identifier
2656 *        to use with the first of the two Plots that span the axis to
2657 *        which the 3D element identifier refers. Returned holding 0 if
2658 *        the given 3D element identifier is not axis specific.
2659 *     elem2d2
2660 *        Pointer to an int in which to return the 2D element identifier
2661 *        to use with the second of the two Plots that span the axis to
2662 *        which the 3D element identifier refers. Returned holding 0 if
2663 *        the given 3D element identifier is not axis specific.
2664 *     status
2665 *        Pointer to the inherited status variable.
2666 
2667 *  Returned Value:
2668 *     The zero-based index of the 3D axis to which the given element
2669 *     identifier refers, or -1 if the element identifier is not axis
2670 *     specific.
2671 
2672 */
2673 
2674 /* Local Variables: */
2675    int axis3d;
2676 
2677 /* Check the global error status. */
2678    if ( !astOK ) return 0;
2679 
2680 /* Get the zero-based index of the 3D axis to which the supplied element
2681    refers. Use an index of -1 to indicate that the element does not
2682    relate to a specific axis. Also get the corresponding element to use
2683    with the two Plots that share the speified 3D axis. */
2684 
2685 /* Define a macro used to set the 2d element identifiers for a given 3d
2686    element identifier. */
2687 
2688 #define SET_ELEM2D(id1,id2) \
2689    *elem2d1 = this->axis_index1[ axis3d ] ? id2 : id1; \
2690    *elem2d2 = this->axis_index2[ axis3d ] ? id2 : id1;
2691 
2692    if( element == AST__BORDER_ID ){
2693       axis3d = -1;
2694 
2695    } else if( element == AST__CURVE_ID ){
2696       axis3d = -1;
2697 
2698    } else if( element == AST__TITLE_ID ){
2699       axis3d = -1;
2700 
2701    } else if( element == AST__MARKS_ID ){
2702       axis3d = -1;
2703 
2704    } else if( element == AST__TEXT_ID ){
2705       axis3d = -1;
2706 
2707    } else if( element == AST__AXIS1_ID ){
2708       axis3d = 0;
2709       SET_ELEM2D(AST__AXIS1_ID,AST__AXIS2_ID)
2710 
2711    } else if( element == AST__AXIS2_ID ){
2712       axis3d = 1;
2713       SET_ELEM2D(AST__AXIS1_ID,AST__AXIS2_ID)
2714 
2715    } else if( element == AST__AXIS3_ID ){
2716       axis3d = 2;
2717       SET_ELEM2D(AST__AXIS1_ID,AST__AXIS2_ID)
2718 
2719    } else if( element == AST__NUMLAB1_ID ){
2720       axis3d = 0;
2721       SET_ELEM2D(AST__NUMLAB1_ID,AST__NUMLAB2_ID)
2722 
2723    } else if( element == AST__NUMLAB2_ID ){
2724       axis3d = 1;
2725       SET_ELEM2D(AST__NUMLAB1_ID,AST__NUMLAB2_ID)
2726 
2727    } else if( element == AST__NUMLAB3_ID ){
2728       axis3d = 2;
2729       SET_ELEM2D(AST__NUMLAB1_ID,AST__NUMLAB2_ID)
2730 
2731    } else if( element == AST__TEXTLAB1_ID ){
2732       axis3d = 0;
2733       SET_ELEM2D(AST__TEXTLAB1_ID,AST__TEXTLAB2_ID)
2734 
2735    } else if( element == AST__TEXTLAB2_ID ){
2736       axis3d = 1;
2737       SET_ELEM2D(AST__TEXTLAB1_ID,AST__TEXTLAB2_ID)
2738 
2739    } else if( element == AST__TEXTLAB3_ID ){
2740       axis3d = 2;
2741       SET_ELEM2D(AST__TEXTLAB1_ID,AST__TEXTLAB2_ID)
2742 
2743    } else if( element == AST__TICKS1_ID ){
2744       axis3d = 0;
2745       SET_ELEM2D(AST__TICKS1_ID,AST__TICKS2_ID)
2746 
2747    } else if( element == AST__TICKS2_ID ){
2748       axis3d = 1;
2749       SET_ELEM2D(AST__TICKS1_ID,AST__TICKS2_ID)
2750 
2751    } else if( element == AST__TICKS3_ID ){
2752       axis3d = 2;
2753       SET_ELEM2D(AST__TICKS1_ID,AST__TICKS2_ID)
2754 
2755    } else if( element == AST__GRIDLINE1_ID ){
2756       axis3d = 0;
2757       SET_ELEM2D(AST__GRIDLINE1_ID,AST__GRIDLINE2_ID)
2758 
2759    } else if( element == AST__GRIDLINE2_ID ){
2760       axis3d = 1;
2761       SET_ELEM2D(AST__GRIDLINE1_ID,AST__GRIDLINE2_ID)
2762 
2763    } else if( element == AST__GRIDLINE3_ID ){
2764       axis3d = 2;
2765       SET_ELEM2D(AST__GRIDLINE1_ID,AST__GRIDLINE2_ID)
2766 
2767    } else {
2768       axis3d = 0;
2769       astError( AST__INTER, "Element2D(Plot3D): The MAKE_CLEAR2 macro "
2770                 "does not yet support element index %d (internal "
2771                 "AST programming error).", status, element );
2772    }
2773 
2774 #undef SET_ELEM2D
2775 
2776    return axis3d;
2777 
2778 }
2779 
Equal(AstObject * this_object,AstObject * that_object,int * status)2780 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
2781 /*
2782 *  Name:
2783 *     Equal
2784 
2785 *  Purpose:
2786 *     Test if two Plot3Ds are equivalent.
2787 
2788 *  Type:
2789 *     Private function.
2790 
2791 *  Synopsis:
2792 *     #include "plot3d.h"
2793 *     int Equal( AstObject *this, AstObject *that, int *status )
2794 
2795 *  Class Membership:
2796 *     Plot3D member function (over-rides the astEqual protected
2797 *     method inherited from the Plot Object class).
2798 
2799 *  Description:
2800 *     This function returns a boolean result (0 or 1) to indicate whether
2801 *     two Plot3Ds are equivalent.
2802 
2803 *  Parameters:
2804 *     this
2805 *        Pointer to the first Plot3D.
2806 *     that
2807 *        Pointer to the second Plot3D.
2808 *     status
2809 *        Pointer to the inherited status variable.
2810 
2811 *  Returned Value:
2812 *     One if the Plot3Ds are equivalent, zero otherwise.
2813 
2814 *  Notes:
2815 *     - A value of zero will be returned if this function is invoked
2816 *     with the global status set, or if it should fail for any reason.
2817 */
2818 
2819 /* Local Variables: */
2820    AstPlot3D *that;         /* Pointer to the second Plot3D structure */
2821    AstPlot3D *this;         /* Pointer to the first Plot3D structure */
2822    int result;                /* Result value to return */
2823 
2824 /* Initialise. */
2825    result = 0;
2826 
2827 /* Check the global error status. */
2828    if ( !astOK ) return result;
2829 
2830 /* Invoke the Equal method inherited from the parent Plot class. This checks
2831    that the Plots are both of the same class (amongst other things). */
2832    if( (*parent_equal)( this_object, that_object, status ) ) {
2833 
2834 /* Obtain pointers to the two Plot3D structures. */
2835       this = (AstPlot3D *) this_object;
2836       that = (AstPlot3D *) that_object;
2837 
2838 /* Check the encapsulated Plots for equality. */
2839       result = ( astEqual( this->plotxz, that->plotxz ) &&
2840                  astEqual( this->plotyz, that->plotyz ) &&
2841                  astEqual( this->plotxy, that->plotxy ) );
2842    }
2843 
2844 /* If an error occurred, clear the result value. */
2845    if ( !astOK ) result = 0;
2846 
2847 /* Return the result, */
2848    return result;
2849 }
2850 
ExtendTicks(AstPlot * plot,AstPointSet * ticks,int * status)2851 static AstPointSet *ExtendTicks( AstPlot *plot, AstPointSet *ticks, int *status ){
2852 /*
2853 *  Name:
2854 *     ExtendTicks
2855 
2856 *  Purpose:
2857 *     Add an extra tick to the start and end of a list of tick marks.
2858 
2859 *  Type:
2860 *     Private function.
2861 
2862 *  Synopsis:
2863 *     #include "plot3d.h"
2864 *     AstPointSet *ExtendTicks( AstPlot *plot, AstPointSet *ticks, int *status )
2865 
2866 *  Class Membership:
2867 *     Plot3D method.
2868 
2869 *  Description:
2870 *     This function takes a list of tick marks drawn using the supplied
2871 *     Plot, and adds in an extra tick mark at the start and end of the
2872 *     supplied list of ticks, returning the expanded list in a new
2873 *     PointSet. The extra points are guaranteed to fall outside the area
2874 *     enclosed within the supplied Plot.
2875 
2876 *  Parameters:
2877 *     plot
2878 *        The Plot that was used to generate the list of tick marks.
2879 *     ticks
2880 *        A PointSet holding the 2D graphics coordinates (within the base
2881 *        Frame of the supplied Plot) at which each tick mark starts.
2882 *     status
2883 *        Pointer to the inherited status variable.
2884 
2885 *  Returned Value:
2886 *     A pointer to a new PointSet that has 2 more entries than the
2887 *     supplied PointSet. The first point is a new tick mark, then comes
2888 *     all the ticks mark positions supplied in "ticks", and finally there
2889 *     is another new tick mark.
2890 
2891 */
2892 
2893 /* Local Variables: */
2894    AstPointSet *result;
2895    double **ptr_in;
2896    double **ptr_out;
2897    double *a_in;
2898    double *a_out;
2899    double *b_in;
2900    double *b_out;
2901    double *p;
2902    double delta;
2903    double hi;
2904    double lo;
2905    double range[ 2 ];
2906    double v;
2907    int axis;
2908    int i;
2909    int increasing;
2910    int np;
2911 
2912 /* Check inherited status */
2913    if( !astOK || !ticks ) return NULL;
2914 
2915 /* Get the number of tick marsk in the supplied PointSet and get pointers
2916    to the 3D Graphics values contained in the PointSet. */
2917    np = astGetNpoint( ticks );
2918    ptr_in = astGetPoints( ticks );
2919 
2920 /* Create the returned PointSet with room for an extra pair of ticks. Get
2921    pointers to its data arrays */
2922    result = astPointSet( np + 2, 2, "", status );
2923    ptr_out = astGetPoints( result );
2924 
2925 /* Check the pointers can be used safely. */
2926    if( astOK ) {
2927 
2928 /* Find the index of the 2D graphics axis (0 or 1) that varies along the
2929    set of tick marks. We do this by finding the max and min value
2930    supplied for each axis, and then choosing the axis that has the highest
2931    range. */
2932       for( axis = 0; axis < 2; axis++ ) {
2933          hi = -DBL_MAX;
2934          lo = DBL_MAX;
2935          p = ptr_in[ axis ];
2936 
2937          for( i = 0; i < np; i++, p++ ) {
2938             v = *p;
2939             if( v != AST__BAD ) {
2940                if( v > hi ) hi = v;
2941                if( v < lo ) lo = v;
2942             }
2943          }
2944 
2945          if( lo != DBL_MAX ) {
2946             range[ axis ] = hi - lo;
2947          } else {
2948             astError( AST__INTER, "ExtendTicks{Plot3D): no good ticks on "
2949                       "axis %d (internal AST prgramming error).", status, axis );
2950          }
2951       }
2952 
2953 
2954 /* Get the index of the axis with the largest range (the other range
2955    should be zero). */
2956       axis = ( range[ 0 ] > range[ 1 ] ) ? 0 : 1;
2957 
2958 /* Copy the input graphics positions to the output PointSet, and add an
2959    extra position at the beginning and end of the output PointSet. */
2960       if( axis == 0 ) {
2961          lo = plot->xlo;
2962          hi = plot->xhi;
2963          a_in = ptr_in[ 0 ];
2964          b_in = ptr_in[ 1 ];
2965          a_out = ptr_out[ 0 ];
2966          b_out = ptr_out[ 1 ];
2967 
2968       } else {
2969          lo = plot->ylo;
2970          hi = plot->yhi;
2971          a_in = ptr_in[ 1 ];
2972          b_in = ptr_in[ 0 ];
2973          a_out = ptr_out[ 1 ];
2974          b_out = ptr_out[ 0 ];
2975       }
2976 
2977       delta = 0.2*( hi - lo );
2978 
2979       if( a_in[ 0 ] < a_in[ 1 ] ) {
2980          increasing = 1;
2981          *(a_out++) = lo - delta;
2982       } else {
2983          increasing = 0;
2984          *(a_out++) = hi + delta;
2985       }
2986 
2987       *(b_out++) = *b_in;
2988       for( i = 0; i < np; i++ ) {
2989          *(a_out++) = *(a_in++);
2990          *(b_out++) = *(b_in++);
2991       }
2992       *(b_out++) = b_in[ -1 ];
2993 
2994 
2995       if( increasing ) {
2996          *(a_out++) = hi + delta;
2997       } else {
2998          *(a_out++) = lo - delta;
2999       }
3000    }
3001 
3002 /* Return the extended PointSet. */
3003    return result;
3004 }
3005 
Fset3D(AstFrameSet * fset,int ifrm,int * status)3006 static AstFrameSet *Fset3D( AstFrameSet *fset, int ifrm, int *status ) {
3007 /*
3008 *  Name:
3009 *     Fset3D
3010 
3011 *  Purpose:
3012 *     Create a FrameSet with no more than 3 dimensions for a given Frame.
3013 
3014 *  Type:
3015 *     Private function.
3016 
3017 *  Synopsis:
3018 *     #include "plot3d.h"
3019 *     AstFrameSet *Fset3D( AstFrameSet *fset, int ifrm, int *status )
3020 
3021 *  Class Membership:
3022 *     Plot3D method.
3023 
3024 *  Description:
3025 *     This function checks a specified Frame in the supplied FrameSet.
3026 *     If the Frame has more than 3 dimensions, a new Frame is added to
3027 *     the FrameSet containing just the first three axes of the specified
3028 *     Frame. A PermMap is used to connect this Frame to the specified
3029 *     Frame, which supplied bad values for any missing axes. If the
3030 *     specified Frame is the base Frame in the supplied FrameSet, then the
3031 *     new Frame becomes the base Frame in the returned FrameSet. Like-wise,
3032 *     if the specified Frame is the current Frame, then the new Frame
3033 *     will be the current Frame in the returned FrameSet.
3034 *
3035 *     If the specified Frame does not have more than 3 axes, then a clone
3036 *     of the FrameSet pointer is returned, otherwise the returned pointer
3037 *     points to a copy of the supplied FrameSet with the new 3-D Frame
3038 *     added.
3039 
3040 *  Parameters:
3041 *     fset
3042 *        Pointer to the FrameSet.
3043 *     ifrm
3044 *        The index of the Frame to check. This should be AST__BASE or
3045 *        AST_CURRENT.
3046 *     status
3047 *        Pointer to the inherited status variable.
3048 
3049 *  Returned Value:
3050 *     A pointer to a FrameSet in which the Frame with index given by ifrm
3051 *     has no more than 3 axes.
3052 */
3053 
3054 /* Local Variables: */
3055    AstFrame *frm;
3056    AstFrame *newfrm;
3057    AstFrameSet *ret;
3058    AstPermMap *map;
3059    double zero;
3060    int *inperm;
3061    int axes[3];
3062    int i;
3063    int ic;
3064    int nax;
3065 
3066 /* Check the inherited status. */
3067    if( !astOK ) return NULL;
3068 
3069 /* Initialise variables to avoid "used of uninitialised variable"
3070    messages from dumb compilers. */
3071    map = NULL;
3072 
3073 /* Get a pointer to the requested Frame in the supplied FrameSet. */
3074    frm = astGetFrame( fset, ifrm );
3075 
3076 /* See how many dimensions the specified Frame of the supplied FrameSet
3077    has. */
3078    nax = astGetNaxes( frm );
3079 
3080 /* If it is more than 3-dimensionbal, create a 3D Frame by picking
3081    axes 1, 2 and 3 from the original Frame. */
3082    if( nax > 3 ) {
3083       axes[ 0 ] = 0;
3084       axes[ 1 ] = 1;
3085       axes[ 2 ] = 2;
3086       newfrm = astPickAxes( frm, 3, axes, NULL );
3087 
3088 /* Create a PermMap to describe the mapping between the two Frames.
3089    Use zero as the value for unknown axes (the optional mapping which
3090    can be returned by astPickAxes uses AST__BAD for unknown axes). */
3091       inperm = (int *) astMalloc( sizeof(int)*(size_t) nax );
3092       if( astOK ){
3093          inperm[ 0 ] = 0;
3094          inperm[ 1 ] = 1;
3095          inperm[ 2 ] = 2;
3096          for( i = 3; i < nax; i++ ) inperm[ i ] = -1;
3097          zero = 0.0;
3098          map = astPermMap( nax, inperm, 3, axes, &zero, "", status );
3099          inperm = (int *) astFree( (void *) inperm );
3100       }
3101 
3102 /* Get a copy of the supplied FrameSet. */
3103       ret = astCopy( fset );
3104 
3105 /* Add the new Frame to the FrameSet (it becomes the current Frame). */
3106       ic = astGetCurrent( ret );
3107       astAddFrame( ret, ifrm, map, newfrm );
3108       newfrm = astAnnul( newfrm );
3109 
3110 /* If the new Frame was derived from the base frame, set the new base
3111    Frame, and re-instate the original current Frame */
3112       if( ifrm == AST__BASE ){
3113          astSetBase( ret, astGetCurrent( ret ) );
3114          astSetCurrent( ret, ic );
3115       }
3116 
3117 /* If the specified Frame in the supplied FrameSet is 3-dimensional, just
3118    return a clone of it. */
3119    } else {
3120       ret = astClone( fset );
3121    }
3122 
3123 /* Annul the pointer to the original Frame. */
3124    frm = astAnnul( frm );
3125 
3126    return ret;
3127 
3128 }
3129 
GetAttrib(AstObject * this_object,const char * attrib,int * status)3130 static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
3131 /*
3132 *  Name:
3133 *     GetAttrib
3134 
3135 *  Purpose:
3136 *     Get the value of a specified attribute for a Plot3D.
3137 
3138 *  Type:
3139 *     Private function.
3140 
3141 *  Synopsis:
3142 *     #include "plot3d.h"
3143 *     const char *GetAttrib( AstObject *this, const char *attrib, int *status )
3144 
3145 *  Class Membership:
3146 *     Plot3D member function (over-rides the protected astGetAttrib
3147 *     method inherited from the FrameSet class).
3148 
3149 *  Description:
3150 *     This function returns a pointer to the value of a specified
3151 *     attribute for a Plot3D, formatted as a character string.
3152 
3153 *  Parameters:
3154 *     this
3155 *        Pointer to the Plot3D.
3156 *     attrib
3157 *        Pointer to a null terminated string containing the name of
3158 *        the attribute whose value is required. This name should be in
3159 *        lower case, with all white space removed.
3160 *     status
3161 *        Pointer to the inherited status variable.
3162 
3163 *  Returned Value:
3164 *     - Pointer to a null terminated string containing the attribute
3165 *     value.
3166 
3167 *  Notes:
3168 *     - The returned string pointer may point at memory allocated
3169 *     within the Plot3D, or at static memory. The contents of the
3170 *     string may be over-written or the pointer may become invalid
3171 *     following a further invocation of the same function or any
3172 *     modification of the Plot3D. A copy of the string should
3173 *     therefore be made if necessary.
3174 *     - A NULL pointer will be returned if this function is invoked
3175 *     with the global error status set, or if it should fail for any
3176 *     reason.
3177 */
3178 
3179 /* Local Variables: */
3180    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
3181    AstPlot3D *this;              /* Pointer to the Plot3D structure */
3182    const char *result;           /* Pointer value to return */
3183    double dval;                  /* Floating point attribute value */
3184    int axis;                     /* Axis index */
3185    int ival;                     /* Int attribute value */
3186    int len;                      /* Length of attrib string */
3187    int nc;                       /* Number of character read */
3188 
3189 /* Initialise. */
3190    result = NULL;
3191 
3192 /* Check the global error status. */
3193    if ( !astOK ) return result;
3194 
3195 /* Get a pointer to the thread specific global data structure. */
3196    astGET_GLOBALS(this_object);
3197 
3198 /* Obtain a pointer to the Plot3D structure. */
3199    this = (AstPlot3D *) this_object;
3200 
3201 /* Obtain the length of the attrib string. */
3202    len = strlen( attrib );
3203 
3204 /* Compare "attrib" with each recognised attribute name in turn,
3205    obtaining the value of the required attribute. If necessary, write
3206    the value into "getattrib_buff" as a null terminated string in an appropriate
3207    format.  Set "result" to point at the result string. */
3208 
3209 /* Norm(axis). */
3210 /* ----------- */
3211    if ( nc = 0,
3212         ( 1 == astSscanf( attrib, "norm(%d)%n", &axis, &nc ) )
3213           && ( nc >= len ) ) {
3214       dval = astGetNorm( this, axis - 1 );
3215       if ( astOK ) {
3216          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
3217          result = getattrib_buff;
3218       }
3219 
3220 /* RootCorner. */
3221 /* ----------- */
3222    } else if ( !strcmp( attrib, "rootcorner" ) ) {
3223       ival = astGetRootCorner( this );
3224       result = RootCornerString( ival, status );
3225       if( !result && astOK ) {
3226          astError( AST__INTER, "astGetAttrib(Plot3D): Illegal value %d "
3227                    "for RootCorner attribute (internal AST programming "
3228                    "error).", status, ival );
3229       }
3230 
3231 /* If the attribute name was not recognised, pass it on to the parent
3232    method for further interpretation. */
3233    } else {
3234       result = (*parent_getattrib)( this_object, attrib, status );
3235    }
3236 
3237 /* Return the result. */
3238    return result;
3239 }
3240 
GetObjSize(AstObject * this_object,int * status)3241 static int GetObjSize( AstObject *this_object, int *status ) {
3242 /*
3243 *  Name:
3244 *     GetObjSize
3245 
3246 *  Purpose:
3247 *     Return the in-memory size of an Object.
3248 
3249 *  Type:
3250 *     Private function.
3251 
3252 *  Synopsis:
3253 *     #include "plot3d.h"
3254 *     int GetObjSize( AstObject *this, int *status )
3255 
3256 *  Class Membership:
3257 *     Plot3D member function (over-rides the astGetObjSize protected
3258 *     method inherited from the parent class).
3259 
3260 *  Description:
3261 *     This function returns the in-memory size of the supplied Plot3D,
3262 *     in bytes.
3263 
3264 *  Parameters:
3265 *     this
3266 *        Pointer to the Plot3D.
3267 *     status
3268 *        Pointer to the inherited status variable.
3269 
3270 *  Returned Value:
3271 *     The Object size, in bytes.
3272 
3273 *  Notes:
3274 *     - A value of zero will be returned if this function is invoked
3275 *     with the global status set, or if it should fail for any reason.
3276 */
3277 
3278 /* Local Variables: */
3279    AstPlot3D *this;         /* Pointer to Plot3D structure */
3280    int result;              /* Result value to return */
3281 
3282 /* Initialise. */
3283    result = 0;
3284 
3285 /* Check the global error status. */
3286    if ( !astOK ) return result;
3287 
3288 /* Obtain a pointers to the Plot3D structure. */
3289    this = (AstPlot3D *) this_object;
3290 
3291 /* Invoke the GetObjSize method inherited from the parent class, and then
3292    add on any components of the class structure defined by this class
3293    which are stored in dynamically allocated memory. */
3294    result = (*parent_getobjsize)( this_object, status );
3295 
3296    result += astGetObjSize( this->plotxy );
3297    result += astGetObjSize( this->plotxz );
3298    result += astGetObjSize( this->plotyz );
3299 
3300 /* If an error occurred, clear the result value. */
3301    if ( !astOK ) result = 0;
3302 
3303 /* Return the result, */
3304    return result;
3305 }
3306 
Grid(AstPlot * this_plot,int * status)3307 static void Grid( AstPlot *this_plot, int *status ) {
3308 /*
3309 *  Name:
3310 *     Grid
3311 
3312 *  Purpose:
3313 *     Draw a set of labelled coordinate axes.
3314 
3315 *  Type:
3316 *     Private function.
3317 
3318 *  Synopsis:
3319 *     #include "plot3d.h"
3320 *     void Grid( AstPlot *this, int *status )
3321 
3322 *  Class Membership:
3323 *     Plot member function (over-rides the astGrid method inherited from
3324 *     the Plot class).
3325 
3326 *  Description:
3327 *     This function draws a complete annotated set of 3-dimensional
3328 *     coordinate axes for a Plot3D with (optionally) a coordinate grid
3329 *     superimposed.
3330 
3331 *  Parameters:
3332 *     this
3333 *        Pointer to the Plot3D.
3334 *     status
3335 *        Pointer to the inherited status variable.
3336 
3337 */
3338 
3339 /* Local Variables: */
3340    AstPlot *baseplot;
3341    AstPlot *plot;
3342    AstPlot3D *this;
3343    AstPointSet *majticks;
3344    AstPointSet *minticks;
3345    AstPointSet *tmp;
3346    AstPointSet *wcsmajticks;
3347    AstPointSet *wcsminticks;
3348    const char *edge;
3349    double **ptrmin;
3350    double **ptrmaj;
3351    double gcon;
3352    int base_wax2d;
3353    int itick;
3354    int new_gaxis;
3355    int new_plot;
3356    int new_wax2d;
3357    int nmaj;
3358    int nmin;
3359    int perm[ 2 ];
3360    int rootcorner;
3361 
3362 /* Check the global error status. */
3363    if ( !astOK ) return;
3364 
3365 /* Obtain a pointer to the Plot3D structure. */
3366    this = (AstPlot3D *) this_plot;
3367 
3368 /* Invoke the astGrid method on the 2D base Plot. Both WCS axes in this
3369    Plot are inherited from the 3D FrameSet that was supplied when the Plot3D
3370    was constructed, and will be labelled. The other two Plots encapsulated
3371    in the Plot3D only inherit a single axis from the original 3D FrameSet
3372    (a dummy axis is used for the second WCS axis in these Plots). */
3373    baseplot = GET_PLOT( this->baseplot );
3374    astGrid( baseplot );
3375 
3376 /* We next use astGrid to draw a grid on the 2D plane that shares the first
3377    base plot graphics axis. Get the identifier for this Plot and the 2D
3378    graphics axis index within the Plot that corresponds to the first base
3379    plot graphics axis. Also get the constant value on the 3rd graphics
3380    axis over the base plot */
3381    rootcorner = astGetRootCorner( this );
3382    if( this->baseplot == XY ) {
3383       new_plot = XZ;
3384       new_gaxis = 0;
3385       gcon = this->gbox[ ( rootcorner & 4 ) ? 5 : 2 ];
3386 
3387    } else if( this->baseplot == XZ ) {
3388       new_plot = XY;
3389       new_gaxis = 0;
3390       gcon = this->gbox[ ( rootcorner & 2 ) ? 4 : 1 ];
3391 
3392    } else {
3393       new_plot = XY;
3394       new_gaxis = 1;
3395       gcon = this->gbox[ ( rootcorner & 1 ) ? 3 : 0 ];
3396    }
3397 
3398 /* Get a pointer to the Plot upon which astGrid is about to be invoked. */
3399    plot = GET_PLOT( new_plot );
3400 
3401 /* Find which 2D WCS axis was labelled on graphics axis 0 (the bottom or
3402    top edge) of the base plot. */
3403    if( ( edge = astGetC( baseplot, "Edge(1)" ) ) ) {
3404       base_wax2d = ( !strcmp( edge, "bottom" ) || !strcmp( edge, "top" ) ) ? 0 : 1;
3405    } else {
3406       base_wax2d = 0;
3407    }
3408 
3409 /* Get the 2D graphics coords within the base Plot at which the tick
3410    marks were drawn for this 2D WCS axis. Extend the PointSets holding
3411    the major tick values to include an extra tick above and below the
3412    ticks drawn by astGrid. These extra ticks are placed outside the
3413    bounds of the plot. This ensures that the curves on the other axis
3414    extend the full width of the plot. */
3415    tmp = astGetDrawnTicks( baseplot, base_wax2d, 1 );
3416    if( tmp ) {
3417       majticks = ExtendTicks( baseplot, tmp, status );
3418       nmaj = astGetNpoint( majticks );
3419       ptrmaj = astGetPoints( majticks );
3420       tmp = astAnnul( tmp );
3421    } else {
3422       majticks = NULL;
3423       nmaj = 0;
3424       ptrmaj = NULL;
3425    }
3426 
3427    minticks = astGetDrawnTicks( baseplot, base_wax2d, 0 );
3428    if( minticks ) {
3429       nmin = astGetNpoint( minticks );
3430       ptrmin = astGetPoints( minticks );
3431    } else {
3432       nmin = 0;
3433       ptrmin = NULL;
3434    }
3435 
3436 /* All the tick marks will have a constant value for the 2D graphics axis
3437    that is not being ticked (axis 1 at the moment). Change this constant
3438    value to be the value appropriate to the new Plot. */
3439    if( ptrmaj && ptrmin ) {
3440       for( itick = 0; itick < nmaj; itick++ ) ptrmaj[ 1 ][ itick ] = gcon;
3441       for( itick = 0; itick < nmin; itick++ ) ptrmin[ 1 ][ itick ] = gcon;
3442    }
3443 
3444 /* If required, permute the axes in the tick mark positions. */
3445    if( new_gaxis != 0 ) {
3446       perm[ 0 ] = 1;
3447       perm[ 1 ] = 0;
3448       if( majticks ) astPermPoints( majticks, 1, perm );
3449       if( minticks ) astPermPoints( minticks, 1, perm );
3450    }
3451 
3452 /* Transform the tick mark positions from 2D graphics coords to 2D WCS
3453    coords. */
3454    wcsmajticks = majticks ? astTransform( plot, majticks, 1, NULL ) : NULL;
3455    wcsminticks = minticks ? astTransform( plot, minticks, 1, NULL ) : NULL;
3456 
3457 /* Find the index of the 2D WCS axis that will be labelled on the bottom
3458    or top edge (i.e. 2D graphics axis zero) of the new Plot. */
3459    if( ( edge = astGetC( plot, "Edge(1)" ) ) ) {
3460       new_wax2d = ( !strcmp( edge, "bottom" ) || !strcmp( edge, "top" ) ) ? 0 : 1;
3461    } else {
3462       new_wax2d = 0;
3463    }
3464 
3465 /* Use the other WCS axis if we are ticking the left or right edge (i.e.
3466    2D graphics axis one) of the new Plot. This gives us the index of the
3467    2D WCS axis for which tick values are to be stored in the Plot. */
3468    if( new_gaxis == 1 ) new_wax2d = 1 - new_wax2d;
3469 
3470 /* Store the tick mark values to be used on this WCS axis. */
3471    ptrmaj = wcsmajticks ? astGetPoints( wcsmajticks ) : NULL;
3472    ptrmin = wcsminticks ? astGetPoints( wcsminticks ) : NULL;
3473    if( ptrmaj && ptrmin ) {
3474       astSetTickValues( plot, new_wax2d, nmaj, ptrmaj[ new_gaxis ],
3475                                          nmin, ptrmin[ new_gaxis ] );
3476    }
3477 
3478 /* Invoke the astGrid method on this plot. */
3479    astGrid( plot );
3480 
3481 /* Clear the stored tick values in the plot. */
3482    astSetTickValues( plot, new_wax2d, 0, NULL, 0, NULL );
3483 
3484 /* Free resources */
3485    if( wcsmajticks ) wcsmajticks = astAnnul( wcsmajticks );
3486    if( wcsminticks ) wcsminticks = astAnnul( wcsminticks );
3487    if( majticks ) majticks = astAnnul( majticks );
3488    if( minticks ) minticks = astAnnul( minticks );
3489 
3490 /* We next use astGrid to draw a grid on the 2D plane that shares the
3491    second base plot graphics axis. Get the identifier for this Plot and the
3492    2D graphics axis index within the Plot that corresponds to the first
3493    base plot graphics axis. */
3494    if( this->baseplot == XY ) {
3495       new_plot = YZ;
3496       new_gaxis = 0;
3497 
3498    } else if( this->baseplot == XZ ) {
3499       new_plot = YZ;
3500       new_gaxis = 1;
3501 
3502    } else {
3503       new_plot = XZ;
3504       new_gaxis = 1;
3505    }
3506 
3507 /* Get a pointer to the Plot upon which astGrid is about to be invoked. */
3508    plot = GET_PLOT( new_plot );
3509 
3510 /* Find which 2D WCS axis was labelled on graphics axis 1 (the left or
3511    right edge) of the base plot. */
3512    base_wax2d = 1 - base_wax2d;
3513 
3514 /* Get the 2D graphics coords within the base Plot at which the tick
3515    marks were drawn for this 2D WCS axis. Extend the PointSets holding
3516    the major tick values to include an extra tick above and below the
3517    ticks drawn by astGrid. These extra ticks are placed outside the
3518    bounds of the plot. This ensures that the curves on the other axis
3519    extend the full width of the plot. */
3520    tmp = astGetDrawnTicks( baseplot, base_wax2d, 1 );
3521    if( tmp ) {
3522       majticks = ExtendTicks( baseplot, tmp, status );
3523       nmaj = astGetNpoint( majticks );
3524       ptrmaj = astGetPoints( majticks );
3525       tmp = astAnnul( tmp );
3526    } else {
3527       majticks = NULL;
3528       nmaj = 0;
3529       ptrmaj = NULL;
3530    }
3531 
3532    minticks = astGetDrawnTicks( baseplot, base_wax2d, 0 );
3533    if( minticks ) {
3534       nmin = astGetNpoint( minticks );
3535       ptrmin = astGetPoints( minticks );
3536    } else {
3537       nmin = 0;
3538       ptrmin = NULL;
3539    }
3540 
3541 /* All the tick marks will have a constant value for the 2D graphics axis
3542    that is not being ticked (axis 0 at the moment). Change this constant
3543    value to be the value appropriate to the new Plot. */
3544    if( ptrmaj && ptrmin ) {
3545       for( itick = 0; itick < nmaj; itick++ ) ptrmaj[ 0 ][ itick ] = gcon;
3546       for( itick = 0; itick < nmin; itick++ ) ptrmin[ 0 ][ itick ] = gcon;
3547    }
3548 
3549 /* If required, permute the axes in the tick mark positions. */
3550    if( new_gaxis != 1 ) {
3551       perm[ 0 ] = 1;
3552       perm[ 1 ] = 0;
3553       if( majticks ) astPermPoints( majticks, 1, perm );
3554       if( minticks ) astPermPoints( minticks, 1, perm );
3555    }
3556 
3557 /* Transform the tick mark positions from 2D graphics coords to 2D WCS
3558    coords. */
3559    wcsmajticks = majticks ? astTransform( plot, majticks, 1, NULL ) : NULL;
3560    wcsminticks = minticks ? astTransform( plot, minticks, 1, NULL ) : NULL;
3561 
3562 /* Find the index of the 2D WCS axis that will be labelled on the bottom
3563    or top edge (i.e. 2D graphics axis zero) of the new Plot. */
3564    if( ( edge = astGetC( plot, "Edge(1)" ) ) ) {
3565       new_wax2d = ( !strcmp( edge, "bottom" ) || !strcmp( edge, "top" ) ) ? 0 : 1;
3566    } else {
3567       new_wax2d = 0;
3568    }
3569 
3570 /* Use the other WCS axis if we are ticking the left or right edge (i.e.
3571    2D graphics axis one) of the new Plot. This gives us the index of the
3572    2D WCS axis for which tick values are to be stored in the Plot. */
3573    if( new_gaxis == 1 ) new_wax2d = 1 - new_wax2d;
3574 
3575 /* Store the tick mark values to be used on this WCS axis. */
3576    ptrmaj = wcsmajticks ? astGetPoints( wcsmajticks ) : NULL;
3577    ptrmin = wcsminticks ? astGetPoints( wcsminticks ) : NULL;
3578    if( ptrmaj && ptrmin ) {
3579       astSetTickValues( plot, new_wax2d, nmaj, ptrmaj[ new_gaxis ],
3580                                          nmin, ptrmin[ new_gaxis ] );
3581    }
3582 
3583 /* Invoke the astGrid method on this plot. */
3584    astGrid( plot );
3585 
3586 /* Clear the stored tick values in the plot. */
3587    astSetTickValues( plot, new_wax2d, 0, NULL, 0, NULL );
3588 
3589 /* Free resources */
3590    if( wcsmajticks ) wcsmajticks = astAnnul( wcsmajticks );
3591    if( wcsminticks ) wcsminticks = astAnnul( wcsminticks );
3592    if( majticks ) majticks = astAnnul( majticks );
3593    if( minticks ) minticks = astAnnul( minticks );
3594 
3595 }
3596 
astInitPlot3DVtab_(AstPlot3DVtab * vtab,const char * name,int * status)3597 void astInitPlot3DVtab_(  AstPlot3DVtab *vtab, const char *name, int *status ) {
3598 /*
3599 *+
3600 *  Name:
3601 *     astInitPlot3DVtab
3602 
3603 *  Purpose:
3604 *     Initialise a virtual function table for a Plot3D.
3605 
3606 *  Type:
3607 *     Protected function.
3608 
3609 *  Synopsis:
3610 *     #include "plot3d.h"
3611 *     void astInitPlot3DVtab( AstPlot3DVtab *vtab, const char *name )
3612 
3613 *  Class Membership:
3614 *     Plot3D vtab initialiser.
3615 
3616 *  Description:
3617 *     This function initialises the component of a virtual function
3618 *     table which is used by the Plot3D class.
3619 
3620 *  Parameters:
3621 *     vtab
3622 *        Pointer to the virtual function table. The components used by
3623 *        all ancestral classes will be initialised if they have not already
3624 *        been initialised.
3625 *     name
3626 *        Pointer to a constant null-terminated character string which contains
3627 *        the name of the class to which the virtual function table belongs (it
3628 *        is this pointer value that will subsequently be returned by the Object
3629 *        astClass function).
3630 *-
3631 */
3632 
3633 /* Local Variables: */
3634    astDECLARE_GLOBALS          /* Pointer to thread-specific global data */
3635    AstFrame *dummy_frame;      /* The Frame to put in dummy_frameset */
3636    AstPlotVtab *plot;          /* Pointer to Plot component of Vtab */
3637    AstFrameSetVtab *fset;      /* Pointer to FrameSet component of Vtab */
3638    AstMappingVtab *mapping;    /* Pointer to Mapping component of Vtab */
3639    AstObjectVtab *object;      /* Pointer to Object component of Vtab */
3640 
3641 /* Check the local error status. */
3642    if ( !astOK ) return;
3643 
3644 /* Get a pointer to the thread specific global data structure. */
3645    astGET_GLOBALS(NULL);
3646 
3647 /* Initialize the component of the virtual function table used by the
3648    parent class. */
3649    astInitPlotVtab( (AstPlotVtab *) vtab, name );
3650 
3651 /* Store a unique "magic" value in the virtual function table. This
3652    will be used (by astIsAPlot3D) to determine if an object belongs
3653    to this class.  We can conveniently use the address of the (static)
3654    class_check variable to generate this unique value. */
3655    vtab->id.check = &class_check;
3656    vtab->id.parent = &(((AstPlotVtab *) vtab)->id);
3657 
3658 /* Initialise member function pointers. */
3659 /* ------------------------------------ */
3660 /* Store pointers to the member functions (implemented here) that
3661    provide virtual methods for this class. */
3662 
3663 #define SET_PLOT3D_ACCESSORS(attr) \
3664    vtab->Set##attr = Set##attr; \
3665    vtab->Get##attr = Get##attr; \
3666    vtab->Test##attr = Test##attr; \
3667    vtab->Clear##attr = Clear##attr;
3668 
3669 SET_PLOT3D_ACCESSORS(RootCorner)
3670 SET_PLOT3D_ACCESSORS(Norm)
3671 
3672 #undef SET_PLOT3D_ACCESSORS
3673 
3674 
3675 
3676 
3677 /* Save the inherited pointers to methods that will be extended, and
3678    replace them with pointers to the new member functions. */
3679    object = (AstObjectVtab *) vtab;
3680    fset = (AstFrameSetVtab *) vtab;
3681    mapping = (AstMappingVtab *) vtab;
3682    plot = (AstPlotVtab *) vtab;
3683 
3684    parent_getobjsize = object->GetObjSize;
3685    object->GetObjSize = GetObjSize;
3686 
3687    parent_equal = object->Equal;
3688    object->Equal = Equal;
3689 
3690    parent_vset = object->VSet;
3691    object->VSet = VSet;
3692 
3693    parent_cast = object->Cast;
3694    object->Cast = Cast;
3695 
3696    parent_clear = object->Clear;
3697    object->Clear = Clear;
3698 
3699    parent_clearattrib = object->ClearAttrib;
3700    object->ClearAttrib = ClearAttrib;
3701 
3702    parent_getattrib = object->GetAttrib;
3703    object->GetAttrib = GetAttrib;
3704 
3705    parent_setattrib = object->SetAttrib;
3706    object->SetAttrib = SetAttrib;
3707 
3708    parent_testattrib = object->TestAttrib;
3709    object->TestAttrib = TestAttrib;
3710 
3711    parent_clearcurrent = fset->ClearCurrent;
3712    fset->ClearCurrent = ClearCurrent;
3713 
3714    parent_setcurrent = fset->SetCurrent;
3715    fset->SetCurrent = SetCurrent;
3716 
3717    parent_removeframe = fset->RemoveFrame;
3718    fset->RemoveFrame = RemoveFrame;
3719 
3720 #if defined(THREAD_SAFE)
3721    parent_managelock = object->ManageLock;
3722    object->ManageLock = ManageLock;
3723 #endif
3724 
3725 /* Define a macro to override attribute accessors inherited from the
3726    parent Plot class. First do axis specific attributes. */
3727 
3728 #define SET_PLOT_ACCESSORS(attr) \
3729    parent_get##attr = plot->Get##attr; \
3730    plot->Get##attr = Get##attr; \
3731    parent_set##attr = plot->Set##attr; \
3732    plot->Set##attr = Set##attr; \
3733    parent_clear##attr = plot->Clear##attr; \
3734    plot->Clear##attr = Clear##attr;
3735 
3736 /* Use the above macro to override all the inherited attribute accessors. */
3737 SET_PLOT_ACCESSORS(MinTick)
3738 SET_PLOT_ACCESSORS(Abbrev)
3739 SET_PLOT_ACCESSORS(Gap)
3740 SET_PLOT_ACCESSORS(LogGap)
3741 SET_PLOT_ACCESSORS(LogPlot)
3742 SET_PLOT_ACCESSORS(LogTicks)
3743 SET_PLOT_ACCESSORS(LogLabel)
3744 SET_PLOT_ACCESSORS(LabelUp)
3745 SET_PLOT_ACCESSORS(DrawAxes)
3746 SET_PLOT_ACCESSORS(LabelUnits)
3747 SET_PLOT_ACCESSORS(MinTickLen)
3748 SET_PLOT_ACCESSORS(MajTickLen)
3749 SET_PLOT_ACCESSORS(NumLab)
3750 SET_PLOT_ACCESSORS(NumLabGap)
3751 SET_PLOT_ACCESSORS(TextLab)
3752 SET_PLOT_ACCESSORS(TextLabGap)
3753 
3754 #undef SET_PLOT_ACCESSORS
3755 
3756 
3757 /* Now do attributes that are not axis specific. */
3758 
3759 #define SET_PLOT_ACCESSORS(attr) \
3760    parent_set##attr = plot->Set##attr; \
3761    plot->Set##attr = Set##attr; \
3762    parent_clear##attr = plot->Clear##attr; \
3763    plot->Clear##attr = Clear##attr;
3764 
3765 SET_PLOT_ACCESSORS(Ink)
3766 SET_PLOT_ACCESSORS(Tol)
3767 SET_PLOT_ACCESSORS(Invisible)
3768 SET_PLOT_ACCESSORS(TickAll)
3769 SET_PLOT_ACCESSORS(ForceExterior)
3770 SET_PLOT_ACCESSORS(Border)
3771 SET_PLOT_ACCESSORS(Clip)
3772 SET_PLOT_ACCESSORS(ClipOp)
3773 SET_PLOT_ACCESSORS(Escape)
3774 SET_PLOT_ACCESSORS(Grid)
3775 SET_PLOT_ACCESSORS(Labelling)
3776 SET_PLOT_ACCESSORS(Style)
3777 SET_PLOT_ACCESSORS(Font)
3778 SET_PLOT_ACCESSORS(Colour)
3779 SET_PLOT_ACCESSORS(Width)
3780 SET_PLOT_ACCESSORS(Size)
3781 
3782 #undef SET_PLOT_ACCESSORS
3783 
3784 
3785 /* Store replacement pointers for methods which will be over-ridden by new
3786    member functions implemented here. */
3787    plot->Grid = Grid;
3788    plot->Text = Text;
3789    plot->SetTickValues = SetTickValues;
3790    plot->PolyCurve = PolyCurve;
3791    plot->Border = Border;
3792    plot->BoundingBox = BoundingBox;
3793    plot->GetGrfContext = GetGrfContext;
3794    plot->GrfPop = GrfPop;
3795    plot->GrfPush = GrfPush;
3796    plot->GrfSet = GrfSet;
3797    plot->GridLine = GridLine;
3798    plot->Mark = Mark;
3799    plot->Curve = Curve;
3800    plot->GenCurve = GenCurve;
3801    plot->Clip = Clip;
3802    mapping->Transform = Transform;
3803 
3804 /* Declare the copy constructor, destructor and class dump
3805    function. */
3806    astSetCopy( vtab, Copy );
3807    astSetDelete( vtab, Delete );
3808    astSetDump( vtab, Dump, "Plot3D", "Provide facilities for 3D graphical output" );
3809 
3810 /* Create a FrameSet that can be used when calling astCast to indicate
3811    the class to which we want to cast. */
3812    LOCK_MUTEX3
3813    if( !dummy_frameset ) {
3814       dummy_frame = astFrame( 1, " ", status );
3815       dummy_frameset = astFrameSet( dummy_frame, " ", status );
3816       dummy_frame = astAnnul( dummy_frame );
3817    }
3818    UNLOCK_MUTEX3
3819 
3820 /* If we have just initialised the vtab for the current class, indicate
3821    that the vtab is now initialised, and store a pointer to the class
3822    identifier in the base "object" level of the vtab. */
3823    if( vtab == &class_vtab ) {
3824       class_init = 1;
3825       astSetVtabClassIdentifier( vtab, &(vtab->id) );
3826    }
3827 }
3828 
3829 #if defined(THREAD_SAFE)
ManageLock(AstObject * this_object,int mode,int extra,AstObject ** fail,int * status)3830 static int ManageLock( AstObject *this_object, int mode, int extra,
3831                        AstObject **fail, int *status ) {
3832 /*
3833 *  Name:
3834 *     ManageLock
3835 
3836 *  Purpose:
3837 *     Manage the thread lock on an Object.
3838 
3839 *  Type:
3840 *     Private function.
3841 
3842 *  Synopsis:
3843 *     #include "object.h"
3844 *     AstObject *ManageLock( AstObject *this, int mode, int extra,
3845 *                            AstObject **fail, int *status )
3846 
3847 *  Class Membership:
3848 *     CmpMap member function (over-rides the astManageLock protected
3849 *     method inherited from the parent class).
3850 
3851 *  Description:
3852 *     This function manages the thread lock on the supplied Object. The
3853 *     lock can be locked, unlocked or checked by this function as
3854 *     deteremined by parameter "mode". See astLock for details of the way
3855 *     these locks are used.
3856 
3857 *  Parameters:
3858 *     this
3859 *        Pointer to the Object.
3860 *     mode
3861 *        An integer flag indicating what the function should do:
3862 *
3863 *        AST__LOCK: Lock the Object for exclusive use by the calling
3864 *        thread. The "extra" value indicates what should be done if the
3865 *        Object is already locked (wait or report an error - see astLock).
3866 *
3867 *        AST__UNLOCK: Unlock the Object for use by other threads.
3868 *
3869 *        AST__CHECKLOCK: Check that the object is locked for use by the
3870 *        calling thread (report an error if not).
3871 *     extra
3872 *        Extra mode-specific information.
3873 *     fail
3874 *        If a non-zero function value is returned, a pointer to the
3875 *        Object that caused the failure is returned at "*fail". This may
3876 *        be "this" or it may be an Object contained within "this". Note,
3877 *        the Object's reference count is not incremented, and so the
3878 *        returned pointer should not be annulled. A NULL pointer is
3879 *        returned if this function returns a value of zero.
3880 *     status
3881 *        Pointer to the inherited status variable.
3882 
3883 *  Returned Value:
3884 *    A local status value:
3885 *        0 - Success
3886 *        1 - Could not lock or unlock the object because it was already
3887 *            locked by another thread.
3888 *        2 - Failed to lock a POSIX mutex
3889 *        3 - Failed to unlock a POSIX mutex
3890 *        4 - Bad "mode" value supplied.
3891 
3892 *  Notes:
3893 *     - This function attempts to execute even if an error has already
3894 *     occurred.
3895 */
3896 
3897 /* Local Variables: */
3898    AstPlot3D *this;       /* Pointer to Plot3D structure */
3899    int result;            /* Returned status value */
3900 
3901 /* Initialise */
3902    result = 0;
3903 
3904 /* Check the supplied pointer is not NULL. */
3905    if( !this_object ) return result;
3906 
3907 /* Obtain a pointers to the Plot3D structure. */
3908    this = (AstPlot3D *) this_object;
3909 
3910 /* Invoke the ManageLock method inherited from the parent class. */
3911    if( !result ) result = (*parent_managelock)( this_object, mode, extra,
3912                                                 fail, status );
3913 
3914 /* Invoke the astManageLock method on any Objects contained within
3915    the supplied Object. */
3916    if( !result ) result = astManageLock( this->plotxy, mode, extra, fail );
3917    if( !result ) result = astManageLock( this->plotxz, mode, extra, fail );
3918    if( !result ) result = astManageLock( this->plotyz, mode, extra, fail );
3919 
3920    return result;
3921 
3922 }
3923 #endif
3924 
Mark(AstPlot * this_plot,int nmark,int ncoord,int indim,const double * in,int type,int * status)3925 static void Mark( AstPlot *this_plot, int nmark, int ncoord, int indim,
3926                   const double *in, int type, int *status ){
3927 /*
3928 *  Name:
3929 *     Mark
3930 
3931 *  Purpose:
3932 *     Draw a set of markers for a Plot3D.
3933 
3934 *  Type:
3935 *     Private member function.
3936 
3937 *  Synopsis:
3938 *     #include "plot3d.h"
3939 *     void Mark( AstPlot *this, int nmark, int ncoord, int indim,
3940 *                const double *in, int type, int *status )
3941 
3942 *  Class Membership:
3943 *     Plot3d member function (overrides the astMark method inherited form
3944 *     the parent Plot class).
3945 
3946 *  Description:
3947 *     This function draws a set of markers (symbols) at positions
3948 *     specified in the physical coordinate system of a Plot3D. The
3949 *     positions are transformed into graphical coordinates to
3950 *     determine where the markers should appear within the plotting
3951 *     area.
3952 *
3953 *     They are drawn on a 2D plane that has a normal vector given by the
3954 *     current value of the Plot3D's "Norm" attribute.
3955 
3956 *  Parameters:
3957 *     this
3958 *        Pointer to the Plot3D.
3959 *     nmark
3960 *        The number of markers to draw. This may be zero, in which
3961 *        case nothing will be drawn.
3962 *     ncoord
3963 *        The number of coordinates being supplied for each mark
3964 *        (i.e. the number of axes in the current Frame of the Plot, as
3965 *        given by its Naxes attribute).
3966 *     indim
3967 *        The number of elements along the second dimension of the "in"
3968 *        array (which contains the marker coordinates). This value is
3969 *        required so that the coordinate values can be correctly
3970 *        located if they do not entirely fill this array. The value
3971 *        given should not be less than "nmark".
3972 *     in
3973 *        The address of the first element of a 2-dimensional array of
3974 *        shape "[ncoord][indim]" giving the
3975 *        physical coordinates of the points where markers are to be
3976 *        drawn. These should be stored such that the value of
3977 *        coordinate number "coord" for input mark number "mark" is
3978 *        found in element "in[coord][mark]".
3979 *     type
3980 *        A value specifying the type (e.g. shape) of marker to be
3981 *        drawn. The set of values which may be used (and the shapes
3982 *        that will result) is determined by the underlying graphics
3983 *        system.
3984 *     status
3985 *        Pointer to the inherited status variable.
3986 
3987 *  Notes:
3988 *     - Markers are not drawn at positions which have any coordinate
3989 *     equal to the value AST__BAD (or where the transformation into
3990 *     graphical coordinates yields coordinates containing the value
3991 *     AST__BAD).
3992 *     - An error results if the base Frame of the Plot is not 3-dimensional.
3993 *     - An error also results if the transformation between the
3994 *     current and base Frames of the Plot is not defined (i.e. the
3995 *     Plot's TranInverse attribute is zero).
3996 */
3997 
3998 /* Local Variables: */
3999    AstMapping *mapping;    /* Pointer to graphics->physical mapping */
4000    AstPlot3D *this;        /* Pointer to the Plot3D structure */
4001    AstPointSet *pset1;     /* PointSet holding physical positions */
4002    AstPointSet *pset2;     /* PointSet holding graphics positions */
4003    const char *class;      /* Object class */
4004    const char *method;     /* Current method */
4005    const double **ptr1;    /* Pointer to physical positions */
4006    double **ptr2;          /* Pointer to graphics positions */
4007    double *xpd;            /* Pointer to next double precision x value */
4008    double *ypd;            /* Pointer to next double precision y value */
4009    double *zpd;            /* Pointer to next double precision z value */
4010    float *x;               /* Pointer to single precision x values */
4011    float *xpf;             /* Pointer to next single precision x value */
4012    float *y;               /* Pointer to single precision y values */
4013    float *ypf;             /* Pointer to next single precision y value */
4014    float *z;               /* Pointer to single precision z values */
4015    float *zpf;             /* Pointer to next single precision z value */
4016    float norm[ 3 ];        /* Single precision normal vector */
4017    int axis;               /* Axis index */
4018    int i;                  /* Loop count */
4019    int naxes;              /* No. of axes in the base Frame */
4020    int nn;                 /* Number of good marker positions */
4021 
4022 /* Check the global error status. */
4023    if ( !astOK ) return;
4024 
4025 /* Get a pointer to the Plot3D structure. */
4026    this = (AstPlot3D *) this_plot;
4027 
4028 /* Store the current method and class for inclusion in error messages
4029    generated by lower level functions. */
4030    method = "astMark";
4031    class = astClass( this );
4032 
4033 /* Check the base Frame of the Plot is 3-D. */
4034    naxes = astGetNin( this );
4035    if( naxes != 3 && astOK ){
4036       astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base "
4037                 "Frame of the supplied %s is invalid - this number should "
4038                 "be 3.", status, method, class, naxes, class );
4039    }
4040 
4041 /* Also validate the input array dimension argument. */
4042    if ( astOK && ( indim < nmark ) ) {
4043       astError( AST__DIMIN, "%s(%s): The input array dimension value "
4044                 "(%d) is invalid.", status, method, class, indim );
4045       astError( AST__DIMIN, "This should not be less than the number of "
4046                 "markers being drawn (%d).", status, nmark );
4047    }
4048 
4049 /* Establish the correct graphical attributes as defined by attributes
4050    with the supplied Plot. */
4051    astGrfAttrs( this, AST__MARKS_ID, 1, GRF__MARK, method, class );
4052 
4053 /* Create a PointSet to hold the supplied physical coordinates. */
4054    pset1 = astPointSet( nmark, ncoord, "", status );
4055 
4056 /* Allocate memory to hold pointers to the first value on each axis. */
4057    ptr1 = (const double **) astMalloc( sizeof( const double * )*
4058                                        (size_t)( ncoord ));
4059 
4060 /* Check the pointer can be used, then store pointers to the first value
4061    on each axis. */
4062    if( astOK ){
4063       for( axis = 0; axis < ncoord; axis++ ){
4064          ptr1[ axis ] = in + axis*indim;
4065       }
4066    }
4067 
4068 /* Store these pointers in the PointSet. */
4069    astSetPoints( pset1, (double **) ptr1 );
4070 
4071 /* Transform the supplied data from the current frame (i.e. physical
4072    coordinates) to the base frame (i.e. graphics coordinates) using
4073    the inverse Mapping defined by the Plot. */
4074    mapping = astGetMapping( this, AST__BASE, AST__CURRENT );
4075    pset2 = astTransform( mapping, pset1, 0, NULL );
4076    mapping = astAnnul( mapping );
4077 
4078 /* Get pointers to the graphics coordinates. */
4079    ptr2 = astGetPoints( pset2 );
4080 
4081 /* Allocate memory to hold single precision versions of the graphics
4082    coordinates. */
4083    x = (float *) astMalloc( sizeof( float )*(size_t) nmark );
4084    y = (float *) astMalloc( sizeof( float )*(size_t) nmark );
4085    z = (float *) astMalloc( sizeof( float )*(size_t) nmark );
4086 
4087 /* Check the pointers can be used. */
4088    if( astOK ){
4089 
4090 /* Store pointers to the next single and double precision x, y and z
4091    values. */
4092       xpf = x;
4093       ypf = y;
4094       zpf = z;
4095       xpd = ptr2[ 0 ];
4096       ypd = ptr2[ 1 ];
4097       zpd = ptr2[ 2 ];
4098 
4099 /* Convert the double precision values to single precision, rejecting
4100    any bad marker positions. */
4101       nn = 0;
4102       for( i = 0; i < nmark; i++ ){
4103          if( *xpd != AST__BAD && *ypd != AST__BAD && *zpd != AST__BAD ){
4104             nn++;
4105             *(xpf++) = (float) *(xpd++);
4106             *(ypf++) = (float) *(ypd++);
4107             *(zpf++) = (float) *(zpd++);
4108          } else {
4109             xpd++;
4110             ypd++;
4111             zpd++;
4112          }
4113       }
4114 
4115 /* If the nornmal vector has non-zero length, draw the remaining markers. */
4116       norm[ 0 ] = (float) astGetNorm( this, 0 );
4117       norm[ 1 ] = (float) astGetNorm( this, 1 );
4118       norm[ 2 ] = (float) astGetNorm( this, 2 );
4119 
4120       if( norm[ 0 ] != 0.0 || norm[ 1 ] != 0.0 || norm[ 2 ] != 0.0 ){
4121 
4122 /* Since we are about to call an external function which may not be
4123    thread safe, prevent any other thread from executing the following code
4124    until the current thread has finished executing it. */
4125          LOCK_MUTEX2;
4126 
4127          if( !astG3DMark( nn, x, y, z, type, norm ) ) {
4128             astError( AST__GRFER, "%s(%s): Graphics error in astG3DMark. ", status,
4129                    method, class );
4130          }
4131 
4132 /* Allow the next thread to proceed. */
4133          UNLOCK_MUTEX2;
4134 
4135       } else if( astOK ) {
4136          astError( AST__ATTIN, "%s(%s): The vector specified by the Norm "
4137                    "attribute has zero length.", status, method, class );
4138       }
4139    }
4140 
4141 /* Free the memory used to store single precision graphics coordinates. */
4142    x = (float *) astFree( (void *) x );
4143    y = (float *) astFree( (void *) y );
4144    z = (float *) astFree( (void *) z );
4145 
4146 /* Annul the PointSets. */
4147    pset1 = astAnnul( pset1 );
4148    pset2 = astAnnul( pset2 );
4149 
4150 /* Free the memory holding the pointers to the first value on each axis. */
4151    ptr1 = (const double **) astFree( (void *) ptr1 );
4152 
4153 /* Re-establish the original graphical attributes. */
4154    astGrfAttrs( this, AST__MARKS_ID, 0, GRF__MARK, method, class );
4155 
4156 /* Return */
4157    return;
4158 }
4159 
Plot3DAttr(AstKeyMap * grfconID,int attr,double value,double * old_value,int prim)4160 static int Plot3DAttr( AstKeyMap *grfconID, int attr, double value,
4161                        double *old_value, int prim ){
4162 /*
4163 *  Name:
4164 *     Plot3DAttr
4165 
4166 *  Purpose:
4167 *     Get or set the value of a 3D grf attribute.
4168 
4169 *  Type:
4170 *     Private function.
4171 
4172 *  Synopsis:
4173 *     #include "plot3d.h"
4174 *     int Plot3DAttr( AstKeyMap *grfconID, int attr, double value,
4175 *                     double *old_value, int prim )
4176 
4177 *  Class Membership:
4178 *     Plot3D member function.
4179 
4180 *  Description:
4181 *     This function is called by one of the three encapsulated 2D Plots to
4182 *     get or set the current value of a specified graphics attribute. It
4183 *     forwards the call to the grf3D module being used by this Plot3D. It
4184 *     should be registered with each of the 2D Plots using astGrfSet.
4185 
4186 *  Parameters:
4187 *     grfconID
4188 *       The Plot's GrfContext KeyMap. This is used to identify which of
4189 *       the three Plots is calling this function.
4190 *     attr
4191 *       An integer value identifying the required attribute. This should
4192 *       be one of the symbolic values defined in grf.h.
4193 *     value
4194 *       A new value to store for the attribute. If this is AST__BAD
4195 *       no value is stored.
4196 *     old_value
4197 *       A pointer to a double in which to return the attribute value.
4198 *       If this is NULL, no value is returned.
4199 *     prim
4200 *       The sort of graphics primitive to be drawn with the new attribute.
4201 *       Identified by one of the values defined in grf.h.
4202 
4203 *  Returned Value:
4204 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
4205 
4206 */
4207 
4208 /* Local Variables: */
4209    int result;
4210    int *status;
4211 
4212 /* Get a pointer to the inherited status value. */
4213    status = astGetStatusPtr;
4214 
4215 /* Check the inherited status. */
4216    if( !astOK ) return 0;
4217 
4218 /* Since we are about to call an external function which may not be
4219    thread safe, prevent any other thread from executing the following code
4220    until the current thread has finished executing it. */
4221    LOCK_MUTEX2;
4222 
4223 /* Use the function in the external Grf3D module, selected at link-time
4224    using ast_link options. Note, attribute values are the same for each
4225    of the three Plot. */
4226    result = astG3DAttr( attr, value, old_value, prim );
4227 
4228 /* Allow the next thread to proceed. */
4229    UNLOCK_MUTEX2;
4230 
4231 /* Return the result. */
4232    return result;
4233 }
4234 
Plot3DCap(AstKeyMap * grfconID,int cap,int value)4235 static int Plot3DCap( AstKeyMap *grfconID, int cap, int value ){
4236 /*
4237 *  Name:
4238 *     Plot3DCap
4239 
4240 *  Purpose:
4241 *     Determine if the 3D grf module has a given capability.
4242 
4243 *  Type:
4244 *     Private function.
4245 
4246 *  Synopsis:
4247 *     #include "plot3d.h"
4248 *     int Plot3DCap( AstKeyMap *grfconID, int cap, int value )
4249 
4250 *  Class Membership:
4251 *     Plot3D member function.
4252 
4253 *  Description:
4254 *     This function is called by one of the three encapsulated 2D Plots to
4255 *     determine if a given graphics capability is available. It forwards
4256 *     the call to the grf3D module being used by this Plot3D. It should be
4257 *     registered with each of the 2D Plots using astGrfSet.
4258 
4259 *  Parameters:
4260 *     grfconID
4261 *       The Plot's GrfContext KeyMap. This is
4262 *       used to identify which of the three Plots is calling this function.
4263 *     cap
4264 *       The capability being inquired about. This will be one of the
4265 *       following constants defined in grf.h: GRF__SCALES, GRF__MJUST,
4266 *       GRF__ESC,
4267 *     value
4268 *       The use of this parameter depends on the value of "cap" as
4269 *       described in the documentation for the astGrfSet function in the
4270 *       Plot class.
4271 
4272 *  Returned Value:
4273 *     The value returned by the function depends on the value of "cap"
4274 *     as described in the astGrfSet documentation. Zero is returned if
4275 *     the supplied capability is not recognised.
4276 
4277 */
4278 
4279 /* Local Variables: */
4280    int result;
4281    int *status;
4282 
4283 /* Get a pointer to the inherited status value. */
4284    status = astGetStatusPtr;
4285 
4286 /* Check the inherited status. */
4287    if( !astOK ) return 0;
4288 
4289 /* The astGScales function is implemented by code within the Plot3D class
4290    (not within the grf3D module). The Plot3D class assumes all axes are
4291    equally scaled. */
4292    if( cap == GRF__SCALES ) {
4293       result = 1;
4294 
4295 /* All grf3D modules are assumed to support "M" justification. */
4296    } else if( cap == GRF__MJUST ) {
4297       result = 1;
4298 
4299 /* Forward all other capability requests to the grf3D module. */
4300    } else {
4301 
4302 /* Since we are about to call an external function which may not be
4303    thread safe, prevent any other thread from executing the following code
4304    until the current thread has finished executing it. */
4305       LOCK_MUTEX2;
4306 
4307       result = astG3DCap( cap, value );
4308 
4309 /* Allow the next thread to proceed. */
4310       UNLOCK_MUTEX2;
4311    }
4312 
4313 /* Return the result. */
4314    return result;
4315 }
4316 
Plot3DFlush(AstKeyMap * grfconID)4317 static int Plot3DFlush( AstKeyMap *grfconID ){
4318 /*
4319 *  Name:
4320 *     Plot3DFlush
4321 
4322 *  Purpose:
4323 *     Flush any buffered graphical output.
4324 
4325 *  Type:
4326 *     Private function.
4327 
4328 *  Synopsis:
4329 *     #include "plot3d.h"
4330 *     int Plot3DFlush( AstKeyMap *grfconID )
4331 
4332 *  Class Membership:
4333 *     Plot3D member function.
4334 
4335 *  Description:
4336 *     This function is called by one of the three encapsulated 2D Plots to
4337 *     ensure that the display device is up-to-date by flushing any pending
4338 *     graphics to the output device. It forwards the call to the grf3D module
4339 *     being used by this Plot3D. It should be registered with each of the
4340 *     2D Plots using astGrfSet.
4341 
4342 *  Parameters:
4343 *     grfconID
4344 *       The Plot's GrfContext KeyMap. This is
4345 *       used to identify which of the three Plots is calling this function.
4346 
4347 *  Returned Value:
4348 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
4349 
4350 */
4351 
4352 /* Local Variables: */
4353    int result;
4354    int *status;
4355 
4356 /* Get a pointer to the inherited status value. */
4357    status = astGetStatusPtr;
4358 
4359 /* Check the inherited status. */
4360    if( !astOK ) return 0;
4361 
4362 /* Since we are about to call an external function which may not be
4363    thread safe, prevent any other thread from executing the following code
4364    until the current thread has finished executing it. */
4365    LOCK_MUTEX2;
4366 
4367 /* Use the function in the external Grf3D module, selected at link-time
4368    using ast_link options. */
4369    result = astG3DFlush();
4370 
4371 /* Allow the next thread to proceed. */
4372    UNLOCK_MUTEX2;
4373 
4374 /* Return the result. */
4375    return result;
4376 }
4377 
Plot3DLine(AstKeyMap * grfconID,int n,const float * x,const float * y)4378 static int Plot3DLine( AstKeyMap *grfconID, int n, const float *x, const float *y ){
4379 /*
4380 *  Name:
4381 *     Plot3DLine
4382 
4383 *  Purpose:
4384 *     Draw a polyline on a 2D surface.
4385 
4386 *  Type:
4387 *     Private function.
4388 
4389 *  Synopsis:
4390 *     #include "plot3d.h"
4391 *     int Plot3DLine( AstKeyMap *grfconID, int n, const float *x,
4392 *                     const float *y )
4393 
4394 *  Class Membership:
4395 *     Plot3D member function.
4396 
4397 *  Description:
4398 *     This function is called by one of the three encapsulated 2D Plots to
4399 *     draw a polyline. It forwards the call to the grf3D module being used
4400 *     by this Plot3D. It should be registered with each of the 2D Plots
4401 *     using astGrfSet.
4402 
4403 *  Parameters:
4404 *     grfconID
4405 *       The Plot's GrfContext KeyMap. This is
4406 *       used to identify which of the three Plots is calling this function.
4407 *     n
4408 *       The number of positions to be joined together.
4409 *     x
4410 *       A pointer to an array holding the "n" x values.
4411 *     y
4412 *       A pointer to an array holding the "n" y values.
4413 
4414 *  Returned Value:
4415 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
4416 
4417 */
4418 
4419 /* Local Variables: */
4420    AstKeyMap *grfcon;
4421    double gcon;
4422    float *work;
4423    float *x3d = NULL;
4424    float *y3d = NULL;
4425    float *z3d = NULL;
4426    int i;
4427    int plane;
4428    int result = 0;
4429    int *status;
4430 
4431 /* Get a pointer to the inherited status value. */
4432    status = astGetStatusPtr;
4433 
4434 /* Check the inherited status. */
4435    if( !astOK ) return result;
4436 
4437 /* Get a genuine pointer from the supplied grfcon identifier. */
4438    grfcon = astMakePointer( grfconID );
4439 
4440 /* Report an error if no grfcon object was supplied. */
4441    if( !grfcon ) {
4442       astError( AST__INTER, "astG3DLine(Plot3D): No grfcon Object supplied "
4443                 "(internal AST programming error)." , status);
4444 
4445 /* If a grfcon Object was supplied, get the graphics box array out of it. */
4446    } else if( !astMapGet0D( grfcon, "Gcon", &gcon ) ) {
4447       astError( AST__INTER, "astG3DLine(Plot3D): No \"Gcon\" key found "
4448                 "in the supplied grfcon Object (internal AST programming "
4449                 "error)." , status);
4450 
4451 /* Also get the plane index out of it. */
4452    } else if( !astMapGet0I( grfcon, "Plane", &plane ) ) {
4453       astError( AST__INTER, "astG3DLine(Plot3D): No \"Plane\" key found "
4454                 "in the supplied grfcon Object (internal AST programming "
4455                 "error)." , status);
4456    }
4457 
4458 /* Allocate memory to hold the "n" values for the missing coordinate. */
4459    work = astMalloc( sizeof( float )*(size_t) n );
4460    if( work ) {
4461 
4462 /* Set up pointers to the x, y and z arrays in the 3D graphics system.
4463    Fill the missing array with suitable values (the constant value of
4464    the third axis on the plane being drawn). */
4465       if( plane == XY ) {
4466          x3d = (float *) x;
4467          y3d = (float *) y;
4468          z3d = work;
4469 
4470          for( i = 0; i < n; i++ ) z3d[ i ] = gcon;
4471 
4472       } else if( plane == XZ ) {
4473          x3d = (float *) x;
4474          y3d = work;
4475          z3d = (float *) y;
4476          for( i = 0; i < n; i++ ) y3d[ i ] = gcon;
4477 
4478       } else if( plane == YZ ) {
4479          x3d = work;
4480          y3d = (float *) x;
4481          z3d = (float *) y;
4482          for( i = 0; i < n; i++ ) x3d[ i ] = gcon;
4483 
4484       } else {
4485          astError( AST__INTER, "astG3DLine(Plot3D): Illegal plane "
4486                    "identifier %d supplied (internal AST programming "
4487                    "error).", status, plane );
4488       }
4489 
4490 /* If ok, draw the lines in the 3D graphics coordinate space. */
4491       if( x3d ) {
4492 
4493 /* Since we are about to call an external function which may not be
4494    thread safe, prevent any other thread from executing the following code
4495    until the current thread has finished executing it. */
4496          LOCK_MUTEX2;
4497 
4498 /* Draw the line */
4499          result = astG3DLine( n, x3d, y3d, z3d );
4500 
4501 /* Allow the next thread to proceed. */
4502          UNLOCK_MUTEX2;
4503       }
4504    }
4505 
4506 /* Free resources. */
4507    work = astFree( work );
4508 
4509 /* Return the result. */
4510    return result;
4511 }
4512 
Plot3DMark(AstKeyMap * grfconID,int n,const float * x,const float * y,int type)4513 static int Plot3DMark( AstKeyMap *grfconID, int n, const float *x,
4514                        const float *y, int type ){
4515 /*
4516 *  Name:
4517 *     Plot3DMark
4518 
4519 *  Purpose:
4520 *     Draw a set of markers.
4521 
4522 *  Type:
4523 *     Private function.
4524 
4525 *  Synopsis:
4526 *     #include "plot3d.h"
4527 *     int Plot3DMark( AstKeyMap *grfconID, int n, const float *x,
4528 *                     const float *y, int type )
4529 
4530 *  Class Membership:
4531 *     Plot3D member function.
4532 
4533 *  Description:
4534 *     This function is called by one of the three encapsulated 2D Plots to
4535 *     draw a set of markers. It forwards the call to the grf3D module being
4536 *     used by this Plot3D. It should be registered with each of the 2D Plots
4537 *     using astGrfSet.
4538 
4539 *  Parameters:
4540 *     grfconID
4541 *       The Plot's GrfContext KeyMap. This is
4542 *       used to identify which of the three Plots is calling this function.
4543 *     n
4544 *       The number of markers to draw.
4545 *     x
4546 *       A pointer to an array holding the "n" x values.
4547 *     y
4548 *       A pointer to an array holding the "n" y values.
4549 *     type
4550 *       An integer which can be used to indicate the type of marker symbol
4551 *       required.
4552 
4553 *  Returned Value:
4554 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
4555 
4556 */
4557 
4558 /* Local Variables: */
4559    AstKeyMap *grfcon;
4560    double gcon;
4561    float *work;
4562    float *x3d = NULL;
4563    float *y3d = NULL;
4564    float *z3d = NULL;
4565    float norm[ 3 ];
4566    int i;
4567    int plane;
4568    int rc;
4569    int result = 0;
4570    int *status;
4571 
4572 /* Get a pointer to the inherited status value. */
4573    status = astGetStatusPtr;
4574 
4575 /* Check the inherited status. */
4576    if( !astOK ) return result;
4577 
4578 /* Get a genuine pointer from the supplied grfcon identifier. */
4579    grfcon = astMakePointer( grfconID );
4580 
4581 /* Report an error if no grfcon object was supplied. */
4582    if( !grfcon ) {
4583       astError( AST__INTER, "astG3DMark(Plot3D): No grfcon Object supplied "
4584                 "(internal AST programming error)." , status);
4585 
4586 /* If a grfcon Object was supplied, get the graphics box array out of it. */
4587    } else if( !astMapGet0D( grfcon, "Gcon", &gcon ) ) {
4588       astError( AST__INTER, "astG3DMark(Plot3D): No \"Gcon\" key found "
4589                 "in the supplied grfcon Object (internal AST programming "
4590                 "error)." , status);
4591 
4592 /* If a grfcon Object was supplied, get the RootCorner value out of it. */
4593    } else if( !astMapGet0I( grfcon, "RootCorner", &rc ) ) {
4594       astError( AST__INTER, "astG3DLine(Plot3D): No \"RootCornern\" key found "
4595                 "in the supplied grfcon Object (internal AST programming "
4596                 "error)." , status);
4597 
4598 /* Also get the plane index out of it. */
4599    } else if( !astMapGet0I( grfcon, "Plane", &plane ) ) {
4600       astError( AST__INTER, "astG3DMark(Plot3D): No \"Plane\" key found "
4601                 "in the supplied grfcon Object (internal AST programming "
4602                 "error)." , status);
4603    }
4604 
4605 /* Allocate memory to hold the "n" values for the missing coordinate. */
4606    work = astMalloc( sizeof( float )*(size_t) n );
4607    if( work ) {
4608 
4609 /* Set up pointers to the x, y and z arrays in the 3D graphics system.
4610    Fill the missing array with suitable values (the constant value of
4611    the third axis on the plane being drawn). Set the normal vector for
4612    the markers so that they are drawn in the plane described by the Plot.*/
4613       if( plane == XY ) {
4614          x3d = (float *) x;
4615          y3d = (float *) y;
4616          z3d = work;
4617          for( i = 0; i < n; i++ ) z3d[ i ] = gcon;
4618          norm[ 0 ] = 0;
4619          norm[ 1 ] = 0;
4620          norm[ 2 ] = ( rc & 4 ) ? 1 : -1;
4621 
4622       } else if( plane == XZ ) {
4623          x3d = (float *) x;
4624          y3d = work;
4625          z3d = (float *) y;
4626          for( i = 0; i < n; i++ ) y3d[ i ] = gcon;
4627          norm[ 0 ] = 0;
4628          norm[ 1 ] = ( rc & 2 ) ? 1 : -1;
4629          norm[ 2 ] = 0;
4630 
4631       } else if( plane == YZ ) {
4632          x3d = work;
4633          y3d = (float *) x;
4634          z3d = (float *) y;
4635          for( i = 0; i < n; i++ ) x3d[ i ] = gcon;
4636          norm[ 0 ] = ( rc & 1 ) ? 1 : -1;
4637          norm[ 1 ] = 0;
4638          norm[ 2 ] = 0;
4639 
4640       } else {
4641          astError( AST__INTER, "astG3DMark(Plot3D): Illegal plane "
4642                    "identifier %d supplied (internal AST programming "
4643                    "error).", status, plane );
4644       }
4645 
4646 /* If ok, draw the markers in the 3D graphics coordinate space. */
4647       if( x3d ) {
4648 
4649 /* Since we are about to call an external function which may not be
4650    thread safe, prevent any other thread from executing the following code
4651    until the current thread has finished executing it. */
4652          LOCK_MUTEX2;
4653 
4654 /* Draw the markers */
4655          result = astG3DMark( n, x3d, y3d, z3d, type, norm );
4656 
4657 /* Allow the next thread to proceed. */
4658          UNLOCK_MUTEX2;
4659       }
4660    }
4661 
4662 /* Free resources. */
4663    work = astFree( work );
4664 
4665 /* Return the result. */
4666    return result;
4667 }
4668 
Plot3DQch(AstKeyMap * grfconID,float * chv,float * chh)4669 static int Plot3DQch( AstKeyMap *grfconID, float *chv, float *chh ){
4670 /*
4671 *  Name:
4672 *     Plot3DQch
4673 
4674 *  Purpose:
4675 *     Get the current text size.
4676 
4677 *  Type:
4678 *     Private function.
4679 
4680 *  Synopsis:
4681 *     #include "plot3d.h"
4682 *     int Plot3DQch( AstKeyMap *grfconID, float *chv, float *chh )
4683 
4684 *  Class Membership:
4685 *     Plot3D member function.
4686 
4687 *  Description:
4688 *     This function is called by one of the three encapsulated 2D Plots to
4689 *     get the current text size. It forwards the call to the grf3D module
4690 *     being used by this Plot3D. It should be registered with each of the
4691 *     2D Plots using astGrfSet.
4692 *
4693 *     The grf3D module assumes that the 3D graphics axes are equally
4694 *     scaled and therefore the text height does not depend on the text
4695 *     orientation. Therefore, "chv" and "chh" are returned holding the
4696 *     same value.
4697 
4698 *  Parameters:
4699 *     grfconID
4700 *       The Plot's GrfContext KeyMap. This is
4701 *       used to identify which of the three Plots is calling this function.
4702 *     chv
4703 *        A pointer to the float which is to receive the height of
4704 *        characters drawn with a vertical baseline in the 2D Plot. This
4705 *        will be an increment in the 2D X axis.
4706 *     chh
4707 *       A pointer to the float which is to receive the height of
4708 *       characters drawn with a horizontal baseline in the 2D Plot. This
4709 *       will be an increment in the 2D Y axis.
4710 
4711 *  Returned Value:
4712 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
4713 
4714 */
4715 
4716 /* Local Variables: */
4717    int result;
4718    float ch;
4719    int *status;
4720 
4721 /* Get a pointer to the inherited status value. */
4722    status = astGetStatusPtr;
4723 
4724 /* Check the inherited status. */
4725    if( !astOK ) return 0;
4726 
4727 /* Since we are about to call an external function which may not be
4728    thread safe, prevent any other thread from executing the following code
4729    until the current thread has finished executing it. */
4730    LOCK_MUTEX2;
4731 
4732 /* Use the function in the external Grf3D module, selected at link-time
4733    using ast_link options. Note, text height is the same for each
4734    of the three Plot. */
4735    result = astG3DQch( &ch );
4736 
4737 /* Allow the next thread to proceed. */
4738    UNLOCK_MUTEX2;
4739 
4740 /* Store the value in both the returned values. */
4741    *chv = ch;
4742    *chh = ch;
4743 
4744 /* Return the error flag. */
4745    return result;
4746 }
4747 
Plot3DScales(AstKeyMap * grfconID,float * alpha,float * beta)4748 static int Plot3DScales( AstKeyMap *grfconID, float *alpha, float *beta ){
4749 /*
4750 *  Name:
4751 *     Plot3DScales
4752 
4753 *  Purpose:
4754 *     Get the 2D axis scales.
4755 
4756 *  Type:
4757 *     Private function.
4758 
4759 *  Synopsis:
4760 *     #include "plot3d.h"
4761 *      int Plot3DScales( AstKeyMap *grfconID, float *alpha, float *beta )
4762 
4763 *  Class Membership:
4764 *     Plot3D member function.
4765 
4766 *  Description:
4767 *     This function is called by one of the three encapsulated 2D Plots to
4768 *     get the relative scales of the 2D axes. Since the grf3D module
4769 *     assumes that all graphics axes are equally scaled, it just returns 1.0
4770 *     for alpha and beta.
4771 
4772 *  Parameters:
4773 *     grfconID
4774 *       The Plot's GrfContext KeyMap. This is
4775 *       used to identify which of the three Plots is calling this function.
4776 *     alpha
4777 *       A pointer to the float which is to receive the scale for the X
4778 *       axis
4779 *     beta
4780 *       A pointer to the float which is to receive the scale for the Y
4781 *       axis
4782 
4783 *  Returned Value:
4784 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
4785 
4786 */
4787 
4788    *alpha = 1.0;
4789    *beta = 1.0;
4790    return 1;
4791 }
4792 
Plot3DText(AstKeyMap * grfconID,const char * text,float x,float y,const char * just,float upx,float upy)4793 static int Plot3DText( AstKeyMap *grfconID, const char *text, float x, float y,
4794                        const char *just, float upx, float upy ){
4795 /*
4796 *  Name:
4797 *     Plot3DText
4798 
4799 *  Purpose:
4800 *     Draw a text string.
4801 
4802 *  Type:
4803 *     Private function.
4804 
4805 *  Synopsis:
4806 *     #include "plot3d.h"
4807 *     int Plot3DText( AstKeyMap *grfconID, const char *text, float x, float y,
4808 *                     const char *just, float upx, float upy )
4809 
4810 *  Class Membership:
4811 *     Plot3D member function.
4812 
4813 *  Description:
4814 *     This function is called by one of the three encapsulated 2D Plots to
4815 *     draw a text string. It forwards the call to the grf3D module being
4816 *     used by this Plot3D. It should be registered with each of the 2D Plots
4817 *     using astGrfSet.
4818 
4819 *  Parameters:
4820 *     grfconID
4821 *        The Plot's GrfContext KeyMap. This is
4822 *        used to identify which of the three Plots is calling this function.
4823 *     text
4824 *        Pointer to a null-terminated character string to be displayed.
4825 *     x
4826 *        The reference x coordinate.
4827 *     y
4828 *        The reference y coordinate.
4829 *     just
4830 *        A character string which specifies the location within the
4831 *        text string which is to be placed at the reference position
4832 *        given by x and y.
4833 *     upx
4834 *        The x component of the up-vector for the text.
4835 *     upy
4836 *        The y component of the up-vector for the text.
4837 
4838 *  Returned Value:
4839 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
4840 
4841 */
4842 
4843 /* Local Variables: */
4844    AstKeyMap *grfcon;
4845    double gcon;
4846    float norm[ 3 ];
4847    float ref[ 3 ];
4848    float up[ 3 ];
4849    int plane;
4850    int rc;
4851    int result = 0;
4852    int *status;
4853 
4854 /* Get a pointer to the inherited status value. */
4855    status = astGetStatusPtr;
4856 
4857 /* Check the inherited status. */
4858    if( !astOK ) return result;
4859 
4860 /* Get a genuine pointer from the supplied grfcon identifier. */
4861    grfcon = astMakePointer( grfconID );
4862 
4863 /* Report an error if no grfcon object was supplied. */
4864    if( !grfcon ) {
4865       astError( AST__INTER, "astG3DText(Plot3D): No grfcon Object supplied "
4866                 "(internal AST programming error)." , status);
4867 
4868 /* If a grfcon Object was supplied, get the graphics box array out of it. */
4869    } else if( !astMapGet0D( grfcon, "Gcon", &gcon ) ) {
4870       astError( AST__INTER, "astG3DText(Plot3D): No \"Gcon\" key found "
4871                 "in the supplied grfcon Object (internal AST programming "
4872                 "error)." , status);
4873 
4874 /* If a grfcon Object was supplied, get the RootCorner value out of it. */
4875    } else if( !astMapGet0I( grfcon, "RootCorner", &rc ) ) {
4876       astError( AST__INTER, "astG3DLine(Plot3D): No \"RootCornern\" key found "
4877                 "in the supplied grfcon Object (internal AST programming "
4878                 "error)." , status);
4879 
4880 /* Also get the plane index out of it. */
4881    } else if( !astMapGet0I( grfcon, "Plane", &plane ) ) {
4882       astError( AST__INTER, "astG3DText(Plot3D): No \"Plane\" key found "
4883                 "in the supplied grfcon Object (internal AST programming "
4884                 "error)." , status);
4885 
4886 /* If OK, draw the text. */
4887    } else {
4888 
4889 /* Set up the reference, up and normal vectors so that the text appears
4890    on the required plane. */
4891       if( plane == XY ) {
4892          ref[ 0 ] = x;
4893          ref[ 1 ] = y;
4894          ref[ 2 ] = gcon;
4895          norm[ 0 ] = 0;
4896          norm[ 1 ] = 0;
4897          norm[ 2 ] = ( rc & 4 ) ? 1 : -1;
4898          up[ 0 ] = upx;
4899          up[ 1 ] = upy;
4900          up[ 2 ] = 0;
4901 
4902       } else if( plane == XZ ) {
4903          ref[ 0 ] = x;
4904          ref[ 1 ] = gcon;
4905          ref[ 2 ] = y;
4906          norm[ 0 ] = 0;
4907          norm[ 1 ] = ( rc & 2 ) ? 1 : -1;
4908          norm[ 2 ] = 0;
4909          up[ 0 ] = upx;
4910          up[ 1 ] = 0;
4911          up[ 2 ] = upy;
4912 
4913       } else if( plane == YZ ) {
4914          ref[ 0 ] = gcon;
4915          ref[ 1 ] = x;
4916          ref[ 2 ] = y;
4917          norm[ 0 ] = ( rc & 1 ) ? 1 : -1;
4918          norm[ 1 ] = 0;
4919          norm[ 2 ] = 0;
4920          up[ 0 ] = 0;
4921          up[ 1 ] = upx;
4922          up[ 2 ] = upy;
4923 
4924       } else {
4925          astError( AST__INTER, "astG3DText(Plot3D): Illegal plane "
4926                    "identifier %d supplied (internal AST programming "
4927                    "error).", status, plane );
4928       }
4929 
4930 /* Since we are about to call an external function which may not be
4931    thread safe, prevent any other thread from executing the following code
4932    until the current thread has finished executing it. */
4933       LOCK_MUTEX2;
4934 
4935 /* If ok, draw the markers in the 3D graphics coordinate space. */
4936       if( astOK ) result = astG3DText( text, ref, just, up, norm );
4937 
4938 /* Allow the next thread to proceed. */
4939       UNLOCK_MUTEX2;
4940    }
4941 
4942 /* Return the result. */
4943    return result;
4944 }
4945 
Plot3DTxExt(AstKeyMap * grfconID,const char * text,float x,float y,const char * just,float upx,float upy,float * xb,float * yb)4946 static int Plot3DTxExt( AstKeyMap *grfconID, const char *text, float x, float y,
4947                         const char *just, float upx, float upy, float *xb,
4948                         float *yb ){
4949 /*
4950 *  Name:
4951 *     Plot3DTxExt
4952 
4953 *  Purpose:
4954 *     Determine the plotted extent of a text string.
4955 
4956 *  Type:
4957 *     Private function.
4958 
4959 *  Synopsis:
4960 *     #include "plot3d.h"
4961 *     int Plot3DTxExt( AstKeyMap *grfconID, const char *text, float x,
4962 *                      float y, const char *just, float upx, float upy,
4963 *                      float *xb, float *yb )
4964 
4965 *  Class Membership:
4966 *     Plot3D member function.
4967 
4968 *  Description:
4969 *     This function is called by one of the three encapsulated 2D Plots to
4970 *     determine the extent a string would have if plotted using Plot3DText.
4971 *     It forwards the call to the grf3D module being used by this Plot3D. It
4972 *     should be registered with each of the 2D Plots using astGrfSet.
4973 
4974 *  Parameters:
4975 *     grfconID
4976 *        The Plot's GrfContext KeyMap. This is
4977 *        used to identify which of the three Plots is calling this function.
4978 *     text
4979 *        Pointer to a null-terminated character string to be displayed.
4980 *     x
4981 *        The reference x coordinate.
4982 *     y
4983 *        The reference y coordinate.
4984 *     just
4985 *        A character string which specifies the location within the
4986 *        text string which is to be placed at the reference position
4987 *        given by x and y.
4988 *     upx
4989 *        The x component of the up-vector for the text.
4990 *     upy
4991 *        The y component of the up-vector for the text.
4992 *     xb
4993 *        An array of 4 elements in which to return the x coordinate of
4994 *        each corner of the bounding box.
4995 *     yb
4996 *        An array of 4 elements in which to return the y coordinate of
4997 *        each corner of the bounding box.
4998 
4999 *  Returned Value:
5000 *     An integer value of 0 is returned if an error occurs, and 1 otherwise.
5001 
5002 */
5003 
5004 /* Local Variables: */
5005    AstKeyMap *grfcon;
5006    double gcon;
5007    float *xb3d = NULL;
5008    float *yb3d = NULL;
5009    float *zb3d = NULL;
5010    float bl[ 3 ];
5011    float norm[ 3 ];
5012    float ref[ 3 ];
5013    float unused[ 4 ];
5014    float up[ 3 ];
5015    int plane;
5016    int rc;
5017    int result = 0;
5018    int *status;
5019 
5020 /* Get a pointer to the inherited status value. */
5021    status = astGetStatusPtr;
5022 
5023 /* Check the inherited status. */
5024    if( !astOK ) return result;
5025 
5026 /* Get a genuine pointer from the supplied grfcon identifier. */
5027    grfcon = astMakePointer( grfconID );
5028 
5029 /* Report an error if no grfcon object was supplied. */
5030    if( !grfcon ) {
5031       astError( AST__INTER, "astG3DTxExt(Plot3D): No grfcon Object supplied "
5032                 "(internal AST programming error)." , status);
5033 
5034 /* If a grfcon Object was supplied, get the graphics box array out of it. */
5035    } else if( !astMapGet0D( grfcon, "Gcon", &gcon ) ) {
5036       astError( AST__INTER, "astG3DTxExt(Plot3D): No \"Gcon\" key found "
5037                 "in the supplied grfcon Object (internal AST programming "
5038                 "error)." , status);
5039 
5040 /* If a grfcon Object was supplied, get the RootCorner value out of it. */
5041    } else if( !astMapGet0I( grfcon, "RootCorner", &rc ) ) {
5042       astError( AST__INTER, "astG3DLine(Plot3D): No \"RootCornern\" key found "
5043                 "in the supplied grfcon Object (internal AST programming "
5044                 "error)." , status);
5045 
5046 /* Also get the plane index out of it. */
5047    } else if( !astMapGet0I( grfcon, "Plane", &plane ) ) {
5048       astError( AST__INTER, "astG3DTxExt(Plot3D): No \"Plane\" key found "
5049                 "in the supplied grfcon Object (internal AST programming "
5050                 "error)." , status);
5051 
5052 /* If OK, get the extent of the text. */
5053    } else {
5054 
5055 /* Set up the reference, up and normal vectors so that the text appears
5056    on the required plane. */
5057       if( plane == XY ) {
5058          ref[ 0 ] = x;
5059          ref[ 1 ] = y;
5060          ref[ 2 ] = gcon;
5061          norm[ 0 ] = 0;
5062          norm[ 1 ] = 0;
5063          norm[ 2 ] = ( rc & 4 ) ? 1 : -1;
5064          up[ 0 ] = upx;
5065          up[ 1 ] = upy;
5066          up[ 2 ] = 0;
5067          xb3d = xb;
5068          yb3d = yb;
5069          zb3d = unused;
5070 
5071       } else if( plane == XZ ) {
5072          ref[ 0 ] = x;
5073          ref[ 1 ] = gcon;
5074          ref[ 2 ] = y;
5075          norm[ 0 ] = 0;
5076          norm[ 1 ] = ( rc & 2 ) ? 1 : -1;
5077          norm[ 2 ] = 0;
5078          up[ 0 ] = upx;
5079          up[ 1 ] = 0;
5080          up[ 2 ] = upy;
5081          xb3d = xb;
5082          yb3d = unused;
5083          zb3d = yb;
5084 
5085       } else if( plane == YZ ) {
5086          ref[ 0 ] = gcon;
5087          ref[ 1 ] = x;
5088          ref[ 2 ] = y;
5089          norm[ 0 ] = ( rc & 1 ) ? 1 : -1;
5090          norm[ 1 ] = 0;
5091          norm[ 2 ] = 0;
5092          up[ 0 ] = 0;
5093          up[ 1 ] = upx;
5094          up[ 2 ] = upy;
5095          xb3d = unused;
5096          yb3d = xb;
5097          zb3d = yb;
5098 
5099       } else {
5100          astError( AST__INTER, "astG3DTxExt(Plot3D): Illegal plane "
5101                    "identifier %d supplied (internal AST programming "
5102                    "error).", status, plane );
5103       }
5104 
5105 /* Since we are about to call an external function which may not be
5106    thread safe, prevent any other thread from executing the following code
5107    until the current thread has finished executing it. */
5108       LOCK_MUTEX2;
5109 
5110 /* If ok, get the extent of the text. */
5111       if( astOK ) result = astG3DTxExt( text, ref, just, up, norm, xb3d, yb3d,
5112                                         zb3d, bl );
5113 /* Allow the next thread to proceed. */
5114       UNLOCK_MUTEX2;
5115    }
5116 
5117 /* Return the result. */
5118    return result;
5119 }
5120 
PolyCurve(AstPlot * this,int npoint,int ncoord,int indim,const double * in,int * status)5121 static void PolyCurve( AstPlot *this, int npoint, int ncoord, int indim,
5122                        const double *in, int *status ){
5123 /*
5124 *  Name:
5125 *     PolyCurve
5126 
5127 *  Purpose:
5128 *     Draw a series of connected geodesic curves.
5129 
5130 *  Type:
5131 *     Private member function.
5132 
5133 *  Synopsis:
5134 *     #include "plot3d.h"
5135 *     void PolyCurve( AstPlot *this, int npoint, int ncoord, int indim,
5136 *                     const double *in, int *status )
5137 
5138 *  Class Membership:
5139 *     Plot method (overrides the astPolyCurve method inherited form the
5140 *     Plot class)
5141 
5142 *  Description:
5143 *     This function joins a series of points specified in the physical
5144 *     coordinate system of a Plot by drawing a sequence of geodesic
5145 *     curves.  It is equivalent to making repeated use of the astCurve
5146 *     function (q.v.), except that astPolyCurve will generally be more
5147 *     efficient when drawing many geodesic curves end-to-end. A
5148 *     typical application of this might be in drawing contour lines.
5149 *
5150 *     As with astCurve, full account is taken of the Mapping between
5151 *     physical and graphical coordinate systems. This includes any
5152 *     discontinuities and clipping established using astClip.
5153 
5154 *  Parameters:
5155 *     this
5156 *        Pointer to the Plot.
5157 *     npoint
5158 *        The number of points between which geodesic curves are to be drawn.
5159 *     ncoord
5160 *        The number of coordinates being supplied for each point (i.e.
5161 *        the number of axes in the current Frame of the Plot, as given
5162 *        by its Naxes attribute).
5163 *     indim
5164 *        The number of elements along the second dimension of the "in"
5165 *        array (which contains the input coordinates). This value is
5166 *        required so that the coordinate values can be correctly
5167 *        located if they do not entirely fill this array. The value
5168 *        given should not be less than "npoint".
5169 *     in
5170 *        The address of the first element in a 2-dimensional array of shape
5171 *        "[ncoord][indim]" giving the
5172 *        physical coordinates of the points which are to be joined in
5173 *        sequence by geodesic curves. These should be stored such that
5174 *        the value of coordinate number "coord" for point number
5175 *        "point" is found in element "in[coord][point]".
5176 *     status
5177 *        Pointer to the inherited status variable.
5178 
5179 *  Notes:
5180 *     - No curve is drawn on either side of any point which has any
5181 *     coordinate equal to the value AST__BAD.
5182 *     - An error results if the base Frame of the Plot is not
5183 *     2-dimensional.
5184 *     - An error also results if the transformation between the
5185 *     current and base Frames of the Plot is not defined (i.e. the
5186 *     Plot's TranInverse attribute is zero).
5187 */
5188 
5189 /* Check the global error status. */
5190    if ( !astOK ) return;
5191 
5192    astError( AST__INTER, "astPolyCurve(%s): The astPolyCurve "
5193              "method cannot be used with a %s (programming error).", status,
5194              astGetClass( this ), astGetClass( this ) );
5195 }
5196 
RemoveFrame(AstFrameSet * this_fset,int iframe,int * status)5197 static void RemoveFrame( AstFrameSet *this_fset, int iframe, int *status ) {
5198 /*
5199 *  Name:
5200 *     RemoveFrame
5201 
5202 *  Purpose:
5203 *     Remove a Frame from a Plot3D.
5204 
5205 *  Type:
5206 *     Public virtual function.
5207 
5208 *  Synopsis:
5209 *     #include "plot.h"
5210 *     void RemoveFrame( AstFrameSet *this_fset, int iframe, int *status )
5211 
5212 *  Class Membership:
5213 *     Plot3D member function (over-rides the astRemoveFrame public
5214 *     method inherited from the Plot class).
5215 
5216 *  Description:
5217 *     This function removes a Frame from a Plot3D. All other Frames
5218 *     in the Plot3D have their indices re-numbered from one (if
5219 *     necessary), but are otherwise unchanged.
5220 *
5221 *     If the index of the original base Frame is changed, the index value
5222 *     stored in the Plot3D is updated. If the base Frame itself is
5223 *     removed, an error is reported.
5224 
5225 *  Parameters:
5226 *     this_fset
5227 *        Pointer to the FrameSet component of the Plot3D.
5228 *     iframe
5229 *        The index within the Plot3D of the Frame to be removed.
5230 *        This value should lie in the range from 1 to the number of
5231 *        Frames in the Plot3D (as given by its Nframe attribute).
5232 *     status
5233 *        Pointer to the inherited status variable.
5234 
5235 */
5236 
5237 /* Local Variables: */
5238    AstPlot3D *this;          /* Pointer to Plot3D structure */
5239    int ifrm;                 /* Validated frame index */
5240 
5241 /* Check the global error status. */
5242    if ( !astOK ) return;
5243 
5244 /* Obtain a pointer to the Plot3D structure. */
5245    this = (AstPlot3D *) this_fset;
5246 
5247 /* Validate the frame index. This translated AST__BASE and AST__CURRENT
5248    into actual Frame indices. */
5249    ifrm = astValidateFrameIndex( this_fset, iframe, "astRemoveFrame" );
5250 
5251 /* Report an error if an attempt is made to delete the Frame that defines
5252    the mapping onto the screen (the original base Frame in the FrameSet
5253    supplied when the Plot3D was constructed). */
5254    if( ifrm == this->pix_frame ){
5255       astError( AST__PXFRRM, "astRemoveFrame(%s): Cannot delete Frame "
5256                 "number %d from the supplied %s since it is the Frame "
5257                 "that defines the mapping onto the graphics plane.", status,
5258                  astGetClass( this ), iframe, astGetClass( this ) );
5259 
5260 /* Otherwise, invoke the parent astRemoveFrame method to remove the Frame. */
5261    } else {
5262       (*parent_removeframe)( this_fset, iframe, status );
5263 
5264 /* If the index of the removed Frame is smaller than the original base Frame
5265    index, then decrement the original base Frame index so that the same Frame
5266    will be used in future. */
5267       if( astOK ){
5268          if( ifrm < this->pix_frame ) (this->pix_frame)--;
5269       }
5270    }
5271 }
5272 
RootCornerInt(const char * rootcorner,int * status)5273 static int RootCornerInt( const char *rootcorner, int *status ){
5274 /*
5275 *  Name:
5276 *     RootCornerInt
5277 
5278 *  Purpose:
5279 *     Convert a RootCorner string to an integer.
5280 
5281 *  Type:
5282 *     Private function.
5283 
5284 *  Synopsis:
5285 *     #include "plot3d.h"
5286 *     int RootCornerInt( const char *rootcorner, int *status )
5287 
5288 *  Class Membership:
5289 *     Plot3D method.
5290 
5291 *  Description:
5292 *     This function converts a RootCorner string to an integer.
5293 
5294 *  Parameters:
5295 *     rootcorner
5296 *        The string value to convert. Should be 3 characters long
5297 *        and contain nothing but "U" or "L" (upper or lower case).
5298 *     status
5299 *        Pointer to the inherited status variable.
5300 
5301 *  Returned Value:
5302 *     The integer value that is is the protected equivalent of the
5303 *     supplied string. A negative value is returned if an error has
5304 *     already occurred, of the supplied string is not legal.
5305 
5306 */
5307 
5308 /* Local Variables: */
5309    int result;
5310 
5311 /* Initialise */
5312    result = -1;
5313 
5314 /* Check the inherited status. */
5315    if( !astOK ) return result;
5316 
5317 /* Compare thr supplied value with every legal value. */
5318    if( astChrMatch( rootcorner, "LLL" ) ) {
5319       result = LLL;
5320 
5321    } else if( astChrMatch( rootcorner, "ULL" ) ) {
5322       result = ULL;
5323 
5324    } else if( astChrMatch( rootcorner, "LUL" ) ) {
5325       result = LUL;
5326 
5327    } else if( astChrMatch( rootcorner, "UUL" ) ) {
5328       result = UUL;
5329 
5330    } else if( astChrMatch( rootcorner, "LLU" ) ) {
5331       result = LLU;
5332 
5333    } else if( astChrMatch( rootcorner, "ULU" ) ) {
5334       result = ULU;
5335 
5336    } else if( astChrMatch( rootcorner, "LUU" ) ) {
5337       result = LUU;
5338 
5339    } else if( astChrMatch( rootcorner, "UUU" ) ) {
5340       result = UUU;
5341 
5342    }
5343 
5344 /* Return the result. */
5345    return result;
5346 }
5347 
RootCornerString(int rootcorner,int * status)5348 static const char *RootCornerString( int rootcorner, int *status ){
5349 /*
5350 *  Name:
5351 *     RootCornerString
5352 
5353 *  Purpose:
5354 *     Convert a RootCorner integer to a string.
5355 
5356 *  Type:
5357 *     Private function.
5358 
5359 *  Synopsis:
5360 *     #include "plot3d.h"
5361 *     const char *RootCornerString( int rootcorner, int *status )
5362 
5363 *  Class Membership:
5364 *     Plot3D method.
5365 
5366 *  Description:
5367 *     This function converts a RootCorner integer to a string.
5368 
5369 *  Parameters:
5370 *     rootcorner
5371 *        The integer value to convert. Should be in the range 0 to 7.
5372 *     status
5373 *        Pointer to the inherited status variable.
5374 
5375 *  Returned Value:
5376 *     A pointer to a static string that is the public equivalent of the
5377 *     supplied integer. A NULL pointer is returned if an error has
5378 *     already occurred, of the supplied integer is not legal.
5379 
5380 */
5381 
5382 /* Local Variables: */
5383    char *result;
5384 
5385 /* Initialise */
5386    result = NULL;
5387 
5388 /* Check the inherited status. */
5389    if( !astOK ) return result;
5390 
5391 /* Compare thr supplied value with every legal value. */
5392    if( rootcorner == LLL ) {
5393       result = "LLL";
5394 
5395    } else if( rootcorner == ULL ) {
5396       result = "ULL";
5397 
5398    } else if( rootcorner == LUL ) {
5399       result = "LUL";
5400 
5401    } else if( rootcorner == UUL ) {
5402       result = "UUL";
5403 
5404    } else if( rootcorner == LLU ) {
5405       result = "LLU";
5406 
5407    } else if( rootcorner == ULU ) {
5408       result = "ULU";
5409 
5410    } else if( rootcorner == LUU ) {
5411       result = "LUU";
5412 
5413    } else if( rootcorner == UUU ) {
5414       result = "UUU";
5415 
5416    }
5417 
5418 /* Return the result. */
5419    return result;
5420 }
5421 
Set3DGrf(AstPlot3D * this,AstPlot * plot,int plane,int * status)5422 static void Set3DGrf( AstPlot3D *this, AstPlot *plot, int plane, int *status ){
5423 /*
5424 *  Name:
5425 *     Set3DGrf
5426 
5427 *  Purpose:
5428 *     Associate GRF functions with a Plot.
5429 
5430 *  Type:
5431 *     Private function.
5432 
5433 *  Synopsis:
5434 *     #include "plot3d.h"
5435 *     void Set3DGrf( AstPlot3D *this, AstPlot *plot, int plane, int *status )
5436 
5437 *  Class Membership:
5438 *     Plot3D method.
5439 
5440 *  Description:
5441 *     This function registers grf functions defined in this class with
5442 *     the supplied Plot, so that, whenever the Plot draws anything, the
5443 *     plotting request is caught by this class and converted into an
5444 *     appropriate grf3D call.
5445 
5446 *  Parameters:
5447 *     this
5448 *        Pointer to the Plot3D.
5449 *     plot
5450 *        Pointer to the Plot.
5451 *     plane
5452 *        An integer identifier for the plane within 3D GRAPHICS
5453 *        coordinates upon which the supplied Plot should draw.
5454 *     status
5455 *        Pointer to the inherited status variable.
5456 
5457 */
5458 
5459 /* Local Variables: */
5460    AstKeyMap *grfcon;
5461 
5462 /* Check the global error status. */
5463    if ( !astOK ) return;
5464 
5465 /* Register the plotting functions defined in this class, so that the
5466    plot will call these functions to do its 2D plotting. */
5467    astGrfSet( plot, "Attr", (AstGrfFun) Plot3DAttr );
5468    astGrfSet( plot, "Cap", (AstGrfFun) Plot3DCap );
5469    astGrfSet( plot, "Flush", (AstGrfFun) Plot3DFlush );
5470    astGrfSet( plot, "Line", (AstGrfFun) Plot3DLine );
5471    astGrfSet( plot, "Mark", (AstGrfFun) Plot3DMark );
5472    astGrfSet( plot, "Qch", (AstGrfFun) Plot3DQch );
5473    astGrfSet( plot, "Scales", (AstGrfFun) Plot3DScales );
5474    astGrfSet( plot, "Text", (AstGrfFun) Plot3DText );
5475    astGrfSet( plot, "TxExt", (AstGrfFun) Plot3DTxExt );
5476 
5477 /* Ensure that the Plot uses the grf interface registered using
5478    astGrfSet. */
5479    astSetGrf( plot, 1 );
5480 
5481 /* When the above functions are called, they need to know which plane
5482    they are drawing on. So we put this information into the GrfContext
5483    KeyMap stored in the Plot. This KeyMap will be passed to the above
5484    drawing functions when they are called from within the Plot class. */
5485    grfcon = astGetGrfContext( plot );
5486    astMapPut0I( grfcon, "Plane", plane, "The 2D plane being drawn on" );
5487    if( plane == XY ) {
5488       astMapPut0D( grfcon, "Gcon", this->gbox[2], "Constant Z value" );
5489    } else if( plane == XZ ) {
5490       astMapPut0D( grfcon, "Gcon", this->gbox[1], "Constant Y value" );
5491    } else {
5492       astMapPut0D( grfcon, "Gcon", this->gbox[0], "Constant X value" );
5493    }
5494    astMapPut0I( grfcon, "RootCorner", astGetRootCorner(this), "The labelled corner" );
5495    grfcon = astAnnul( grfcon );
5496 }
5497 
SetAttrib(AstObject * this_object,const char * setting,int * status)5498 static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
5499 /*
5500 *  Name:
5501 *     SetAttrib
5502 
5503 *  Purpose:
5504 *     Set an attribute value for a Plot3D.
5505 
5506 *  Type:
5507 *     Private function.
5508 
5509 *  Synopsis:
5510 *     #include "plot3d.h"
5511 *     void SetAttrib( AstObject *this, const char *setting, int *status )
5512 
5513 *  Class Membership:
5514 *     Plot3D member function (over-rides the astSetAttrib protected
5515 *     method inherited from the Plot class).
5516 
5517 *  Description:
5518 *     This function assigns an attribute value for a Plot3D, the
5519 *     attribute and its value being specified by means of a string of
5520 *     the form:
5521 *
5522 *        "attribute= value "
5523 *
5524 *     Here, "attribute" specifies the attribute name and should be in
5525 *     lower case with no white space present. The value to the right
5526 *     of the "=" should be a suitable textual representation of the
5527 *     value to be assigned and this will be interpreted according to
5528 *     the attribute's data type.  White space surrounding the value is
5529 *     only significant for string attributes.
5530 
5531 *  Parameters:
5532 *     this
5533 *        Pointer to the Plot3D.
5534 *     setting
5535 *        Pointer to a null terminated string specifying the new attribute
5536 *        value.
5537 *     status
5538 *        Pointer to the inherited status variable.
5539 */
5540 
5541 /* Local Variables: */
5542    AstPlot3D *this;              /* Pointer to the Plot3D structure */
5543    double dval;                  /* Floating point attribute value */
5544    int axis;                     /* Axis index */
5545    int ival;                     /* Int attribute value */
5546    int len;                      /* Length of setting string */
5547    int nc;                       /* Number of characters read by astSscanf */
5548 
5549 /* Check the global error status. */
5550    if ( !astOK ) return;
5551 
5552 /* Obtain a pointer to the Plot3D structure. */
5553    this = (AstPlot3D *) this_object;
5554 
5555 /* Obtain the length of the setting string. */
5556    len = (int) strlen( setting );
5557 
5558 /* Test for each recognised attribute in turn, using "astSscanf" to parse
5559    the setting string and extract the attribute value (or an offset to
5560    it in the case of string values). In each case, use the value set
5561    in "nc" to check that the entire string was matched. Once a value
5562    has been obtained, use the appropriate method to set it. */
5563 
5564 /* Norm(axis). */
5565 /* ----------- */
5566    if ( nc = 0,
5567         ( 2 == astSscanf( setting, "norm(%d)= %lg %n",
5568                           &axis, &dval, &nc ) )
5569                && ( nc >= len ) ) {
5570       astSetNorm( this, axis - 1, dval );
5571 
5572 /* RootCorner. */
5573 /* ----------- */
5574    } else if( nc = 0,
5575         ( 0 == astSscanf( setting, "rootcorner=%n%*[^\n]%n", &ival, &nc ) )
5576                && ( nc >= len ) ) {
5577       ival = RootCornerInt( setting + ival, status );
5578       if( astOK && ival < 0 ) {
5579          astError( AST__ATTIN, "astSetAttrib(Plot3D): Unusable value \"%s\" "
5580                    "given for attribute RootCorner.", status, setting + ival );
5581       } else {
5582          astSetRootCorner( this, ival );
5583       }
5584 
5585 /* If the attribute is still not recognised, pass it on to the parent
5586    method for further interpretation. */
5587    } else {
5588       (*parent_setattrib)( this_object, setting, status );
5589    }
5590 
5591 /* Undefine macros local to this function. */
5592 #undef MATCH
5593 }
5594 
SetCurrent(AstFrameSet * this_frameset,int iframe,int * status)5595 static void SetCurrent( AstFrameSet *this_frameset, int iframe, int *status ) {
5596 /*
5597 *  Name:
5598 *     SetCurrent
5599 
5600 *  Purpose:
5601 *     Set a value for the Current attribute of a Plot3D.
5602 
5603 *  Type:
5604 *     Private function.
5605 
5606 *  Synopsis:
5607 *     #include "plot3d.h"
5608 *     int astSetCurrent( AstFrameSet *this, int iframe, int *status )
5609 
5610 *  Class Membership:
5611 *     Plot3D member function (over-rides the public astSetCurrent method
5612 *     inherited from the FrameSet class).
5613 
5614 *  Description:
5615 *     This function sets a value for the Current attribute of a
5616 *     Plot3D. This attribute is an index that identifies the current
5617 *     Frame for the Plot3D.
5618 
5619 *  Parameters:
5620 *     this
5621 *        Pointer to the Plot3D.
5622 *     iframe
5623 *        Value to be set for the Current attribute.
5624 *     status
5625 *        Pointer to the inherited status variable.
5626 */
5627 
5628 /* Invoke the parent astSetCurrent method. */
5629    (*parent_setcurrent)( this_frameset, iframe, status );
5630 
5631 /* Update the three 2D Plots stored in the Plot3D structure so that they
5632    reflect this modified FrameSet. */
5633    UpdatePlots( (AstPlot3D *) this_frameset, status );
5634 }
5635 
SetPlotAttr(AstPlot * plot,int plane,int label[2],int * status)5636 static void SetPlotAttr( AstPlot *plot, int plane, int label[ 2 ], int *status ){
5637 /*
5638 *  Name:
5639 *     SetPlotAttr
5640 
5641 *  Purpose:
5642 *     Set the attributes ofr one of the encapsulated Plots.
5643 
5644 *  Type:
5645 *     Private function.
5646 
5647 *  Synopsis:
5648 *     #include "plot3d.h"
5649 *     void SetPlotAttr( AstPlot *plot, int plane, int label[ 2 ], int *status )
5650 
5651 *  Class Membership:
5652 *     Plot3D method.
5653 
5654 *  Description:
5655 *     This function sets the attributes of one of the encapsulated Plots.
5656 
5657 *  Parameters:
5658 *     plot
5659 *        Pointer to the Plot to modify.
5660 *     plane
5661 *        The 3D plane spanned by the 2D plot.
5662 *     label
5663 *        Array indicating if each WCS axis should be labelled or not.
5664 *     status
5665 *        Pointer to the inherited status variable.
5666 
5667 */
5668 
5669 /* Local Variables: */
5670    int axis;
5671 
5672 /* Check the inherited status. */
5673    if( !astOK ) return;
5674 
5675 /* Ensure that the Plot uses the grf interface registered using
5676    astGrfSet. */
5677    astSetGrf( plot, 1 );
5678 
5679 /* Ensure that no title is drawn. */
5680    astSetDrawTitle( plot, 0 );
5681 
5682 /* For each axis, ensure that no axis labels or ticks are produced unless
5683    the axis is indicated as a labelled axis in the supplied array. */
5684    for( axis = 0; axis < 2; axis++ ) {
5685       if( !label[ axis ] ) {
5686          astSetLabelUnits( plot, axis, 0 );
5687          astSetNumLab( plot, axis, 0 );
5688          astSetTextLab( plot, axis, 0 );
5689       }
5690    }
5691 }
5692 
SetRootCorner(AstPlot3D * this,int rootcorner,int * status)5693 static void SetRootCorner( AstPlot3D *this, int rootcorner, int *status ){
5694 /*
5695 *+
5696 *  Name:
5697 *     astSetRootCorner
5698 
5699 *  Purpose:
5700 *     Set a new value for the RootCorner attribute.
5701 
5702 *  Type:
5703 *     Protected virtual function.
5704 
5705 *  Synopsis:
5706 *     #include "plot3d.h"
5707 *     void astSetRootCorner( AstPlot3D *this, int rootcorner )
5708 
5709 *  Class Membership:
5710 *     Plot method.
5711 
5712 *  Description:
5713 *     This function sets a new value for the RootCorner attribute.
5714 
5715 *  Parameters:
5716 *     this
5717 *        Pointer to a Plot3D.
5718 *     rootcorner
5719 *        The new RootCorner value.
5720 
5721 *-
5722 */
5723 
5724 /* Check the global status. */
5725    if( !astOK ) return;
5726 
5727 /* Report an error if the new value is out of bounds. */
5728    if( rootcorner < 0 || rootcorner > 7 ){
5729       astError( AST__ATTIN, "astSetRootCorner(Plot3D): Invalid value %d "
5730                 "supplied for RootCorner attribute", status,rootcorner);
5731 
5732 /* If the new corner is OK, mirror any axes of the encapsulated Plots
5733    that need mirroring (this is done to ensure that Plots look right when
5734    viewed from the outside of the graphics cube), and modify the Edge
5735    attributes in the encapsulated Plots to ensure the labels appear on the
5736    requested edges of the 3D graphics cube. . */
5737    } else {
5738       ChangeRootCorner( this, astGetRootCorner(this), rootcorner, status );
5739 
5740 /* Store the new value. */
5741       this->rootcorner = rootcorner;
5742    }
5743 }
5744 
SetTickValues(AstPlot * this,int axis,int nmajor,double * major,int nminor,double * minor,int * status)5745 static void SetTickValues( AstPlot *this, int axis, int nmajor, double *major,
5746                            int nminor, double *minor, int *status ){
5747 /*
5748 *  Name:
5749 *     SetTickValues
5750 
5751 *  Purpose:
5752 *     Store the tick mark values to use for a given Plot axis.
5753 
5754 *  Type:
5755 *     Private member function.
5756 
5757 *  Synopsis:
5758 *     #include "plot3d.h"
5759 *     void SetTickValues( AstPlot *this, int axis, int nmajor,
5760 *                         double *major, int nminor, double *minor, int *status )
5761 
5762 *  Class Membership:
5763 *     Plot method (overrides the astSetTickValues method inherited form
5764 *     the Plot class)
5765 
5766 *  Description:
5767 *     This function stores a set of tick mark values that should be used by
5768 *     subsequent calls to astGrid.
5769 
5770 *  Parameters:
5771 *     this
5772 *        Pointer to a Plot.
5773 *     axis
5774 *        The zero-based index of the axis for which tick marks values
5775 *        have been supplied.
5776 *     nmajor
5777 *        The number of major tick mark values. If zero is supplied then
5778 *        the other parameters are ignored, and subsequent calls to
5779 *        astGrid will itself determine the tick values to be used.
5780 *     major
5781 *        Pointer to an array holding "nmajor" values for axis "axis" in
5782 *        the current Frame of the suppled Plot. Major tick marks will be
5783 *        drawn at these values.
5784 *     nminor
5785 *        The number of minor tick mark values.
5786 *     minor
5787 *        Pointer to an array holding "nminor" values for axis "axis" in
5788 *        the current Frame of the suppled Plot. Minor tick marks will be
5789 *        drawn at these values.
5790 *     status
5791 *        Pointer to the inherited status variable.
5792 */
5793 
5794 /* Check the global status. */
5795    if( !astOK ) return;
5796 
5797    astError( AST__INTER, "astSetTickValues(%s): The astSetTickValues "
5798              "method cannot be used with a %s (programming error).", status,
5799              astGetClass( this ), astGetClass( this ) );
5800 }
5801 
SplitFrameSet(AstFrameSet * fset,AstFrameSet ** fsetxy,int labelxy[2],int wcsxy[2],AstFrameSet ** fsetxz,int labelxz[2],int wcsxz[2],AstFrameSet ** fsetyz,int labelyz[2],int wcsyz[2],int * baseplane,int * status)5802 static void SplitFrameSet( AstFrameSet *fset,
5803                            AstFrameSet **fsetxy, int labelxy[2], int wcsxy[2],
5804                            AstFrameSet **fsetxz, int labelxz[2], int wcsxz[2],
5805                            AstFrameSet **fsetyz, int labelyz[2], int wcsyz[2],
5806                            int *baseplane, int *status ){
5807 /*
5808 *  Name:
5809 *     SplitFrameSet
5810 
5811 *  Purpose:
5812 *     Split a 3D FrameSet into three 2D FrameSets.
5813 
5814 *  Type:
5815 *     Private function.
5816 
5817 *  Synopsis:
5818 *     #include "plot3d.h"
5819 *     void SplitFrameSet( AstFrameSet *fset,
5820 *                         AstFrameSet **fsetxy, int labelxy[2], int wcsxy[2],
5821 *                         AstFrameSet **fsetxz, int labelxz[2], int wcsxz[2],
5822 *                         AstFrameSet **fsetyz, int labelyz[2], int wcsyz[2],
5823 *                         int *baseplane, int *status )
5824 
5825 *  Class Membership:
5826 *     Plot3D member function
5827 
5828 *  Description:
5829 *     This function returns 3 FrameSets, each of which has 2-dimensional
5830 *     base and current Frames. Each of the 2D base Frames span a single
5831 *     plane in the 3D base Frame of the supplied FrameSet. Likewise, each
5832 *     of the 2D current Frames span a single plane in the 3D current Frame
5833 *     of the supplied FrameSet. An error is reported if there is no
5834 *     one-to-one association between the three planes in the supplied
5835 *     current Frame and the 3 planes in the supplied base Frame.
5836 
5837 *  Parameters:
5838 *     fset
5839 *        Pointer to a FrameSet that has a 3D base Frame and a 3D current
5840 *        Frame.
5841 *     fsetxy
5842 *        Pointer to a location at which to return a pointer to a new FrameSet
5843 *        that has a 2D base Frame and a 2D current. The base Frame spans
5844 *        axes 1 and 2 of the 3D base Frame in "fset".
5845 *     labelxy
5846 *        Returned holding flags indicating if the two axes of the current
5847 *        Frame in *fsetxy should be labelled or not.
5848 *     wcsxy
5849 *        Returned holding the zero based axis index within the current Frame
5850 *        of the supplied FrameSet that corresponds to each of the two
5851 *        current Frame axes in the "fsetxy" FrameSet.
5852 *     fsetxz
5853 *        Pointer to a location at which to return a pointer to a new FrameSet
5854 *        that has a 2D base Frame and a 2D current. The base Frame spans
5855 *        axes 1 and 3 of the 3D base Frame in "fset".
5856 *     labelxz
5857 *        Returned holding flags indicating if the two axes of the current
5858 *        Frame in *fsetxz should be labelled or not.
5859 *     wcsxz
5860 *        Returned holding the zero based axis index within the current Frame
5861 *        of the supplied FrameSet that corresponds to each of the two
5862 *        current Frame axes in the "fsetxz" FrameSet.
5863 *     fsetyz
5864 *        Pointer to a location at which to return a pointer to a new FrameSet
5865 *        that has a 2D base Frame and a 2D current. The base Frame spans
5866 *        axes 2 and 3 of the 3D base Frame in "fset".
5867 *     labelyz
5868 *        Returned holding flags indicating if the two axes of the current
5869 *        Frame in *fsetyz should be labelled or not.
5870 *     wcsyz
5871 *        Returned holding the zero based axis index within the current Frame
5872 *        of the supplied FrameSet that corresponds to each of the two
5873 *        current Frame axes in the "fsetxy" FrameSet.
5874 *     baseplane
5875 *        Index of the plane that is spanned by two connected 3D axes.
5876 *     status
5877 *        Pointer to the inherited status variable.
5878 
5879 *  Notes:
5880 *     - Null pointers will be returned for the three new FrameSets if this
5881 *     function is invoked with the global status set, or if it should fail
5882 *     for any reason.
5883 *     - Each returned FrameSet has 2 Frames: Frame 1 is the base Frame
5884 *     and is spanned by 2 of the 3 axes in the base Frame of the supplied
5885 *     FrameSet; Frame 2 is the current Frame and is spanned by 2 of the 3
5886 *     axes in the current Frame of the supplied FrameSet. Any future changes
5887 *     to this function that alter this structure should reflected in
5888 *     equivalent changes to functions CreatePlots and UpdatePlots.
5889 */
5890 
5891 /* Local Variables: */
5892    AstFrame *bfrm2d;
5893    AstFrame *bfrm;
5894    AstFrame *cfrm1d;
5895    AstFrame *cfrm2d;
5896    AstFrame *cfrm;
5897    AstFrame *dummy;
5898    AstFrameSet *fset1;
5899    AstFrameSet *fset2;
5900    AstFrameSet *fset3;
5901    AstMapping *map1d;
5902    AstMapping *map2d;
5903    AstMapping *map;
5904    AstMapping *smap;
5905    AstUnitMap *unit1d;
5906    int *axout;
5907    int *other_axout;
5908    int axin2[ 2 ];
5909    int axin[ 2 ];
5910    int i;
5911    int label1[ 2 ];
5912    int label2[ 2 ];
5913    int label3[ 2 ];
5914    int other_axin;
5915    int wcsax1[ 2 ];
5916    int wcsax2[ 2 ];
5917    int wcsax3[ 2 ];
5918 
5919 /* Initialise. */
5920    *fsetxy = NULL;
5921    *fsetxz = NULL;
5922    *fsetyz = NULL;
5923    *baseplane = 0;
5924 
5925 /* Check the global error status. */
5926    if ( !astOK ) return;
5927 
5928 /* Get the simplified base -> current Mapping form the supplied FrameSet.
5929    Also get the base and current Frames themselves. */
5930    map = astGetMapping( fset, AST__BASE, AST__CURRENT );
5931    smap = astSimplify( map );
5932    map = astAnnul( map );
5933    cfrm = astGetFrame( fset, AST__CURRENT );
5934    bfrm = astGetFrame( fset, AST__BASE );
5935 
5936 /* Create a 1D UnitMap. */
5937    unit1d = astUnitMap( 1, "", status );
5938 
5939 /* First try to identify a pair of base Frame axes that map onto a pair
5940    of current Frame axes. This will be the case for instance if the 3D
5941    FrameSet describes a spectral cube in which two of the axes are spanned
5942    by a SkyFrame. We try all three possible pairs of axes in turn until a
5943    pair is found succesfully. */
5944    for( i = 0; i < 3  && ! *fsetxy; i++ ) {
5945       axin[ 0 ] = ( i < 2 ) ? 0 : 1;
5946       axin[ 1 ] = ( i == 0 ) ? 1 : 2;
5947 
5948 /* Try to get a Mapping that connects the inputs given by axin to a
5949    distinct subset of outputs. */
5950       axout = astMapSplit( smap, 2, axin, &map2d );
5951 
5952 /* If succesful, check that the 2 inputs correspond to exactly 2 outputs. */
5953       if( map2d ){
5954          if( astGetNout( map2d ) == 2 ) {
5955 
5956 /* Get the index of the other input axis (the one not included in the pair). */
5957             other_axin = 3 - axin[ 0 ] - axin[ 1 ];
5958 
5959 /* Try to get a Mapping that connects this remaining input to a distinct
5960    subset of outputs. */
5961             other_axout = astMapSplit( smap, 1, &other_axin, &map1d );
5962 
5963 /* If succesful, check that the 1 input correspond to exactly 1 output. */
5964             if( map1d ){
5965                if( astGetNout( map1d ) == 1 ) {
5966 
5967 /* Pick the two axes from the 3D base and current Frames that correspond to
5968    the paired axes found above. */
5969                   bfrm2d = astPickAxes( bfrm, 2, axin, NULL );
5970                   cfrm2d = astPickAxes( cfrm, 2, axout, NULL );
5971 
5972 /* Pick the axis from the 3D current Frame that correspond to
5973    the other axis. */
5974                   cfrm1d = astPickAxes( cfrm, 1, other_axout, NULL );
5975 
5976 /* Construct a FrameSet using these 2D Frames and Mapping. */
5977                   fset1 = astFrameSet( bfrm2d, "", status );
5978                   astAddFrame( fset1, AST__BASE, map2d, cfrm2d );
5979 
5980                   bfrm2d = astAnnul( bfrm2d );
5981                   cfrm2d = astAnnul( cfrm2d );
5982                   map2d = astAnnul( map2d );
5983 
5984 /* Indicate that both axes in the current Frame of this FrameSet should
5985    be labelled. */
5986                   label1[ 0 ] = 1;
5987                   label1[ 1 ] = 1;
5988 
5989 /* Store the index of the axis within the supplied current Frame that
5990    corresponds to each axis in the current Frame of the FrameSet created
5991    above. */
5992                   wcsax1[ 0 ] = axout[ 0 ];
5993                   wcsax1[ 1 ] = axout[ 1 ];
5994 
5995 /* Pick the two axes from the 3D base Frame that correspond to the first of
5996    the paired axes, and the unpaired axis. Order them so that we get the
5997    2 axes in the order xy, xz or yz. Also, store the index of the axis
5998    within the supplied  current Frame that corresponds to each axis in
5999    the current Frame of the FrameSet created below. */
6000                   if( i < 2 ) {
6001                      axin2[ 0 ] = axin[ 0 ];
6002                      axin2[ 1 ] = other_axin;
6003                      wcsax2[ 0 ] = axout[ 0 ];
6004                      wcsax2[ 1 ] = other_axout[ 0 ];
6005                   } else {
6006                      axin2[ 0 ] = other_axin;
6007                      axin2[ 1 ] = axin[ 0 ];
6008                      wcsax2[ 0 ] = other_axout[ 0 ];
6009                      wcsax2[ 1 ] = axout[ 0 ];
6010                   }
6011                   bfrm2d = astPickAxes( bfrm, 2, axin2, NULL );
6012 
6013 /* The corresponding current Frame in the new FrameSet will be a compound
6014    2D Frame holding the other current Frame axis and a copy of the input
6015    base Frame axis. Combine them so that we get the 2 axes in the order
6016    xy, xz or yz. */
6017                   dummy = astPickAxes( bfrm, 1, axin, NULL );
6018                   if( i < 2 ) {
6019                      cfrm2d = (AstFrame *) astCmpFrame( dummy, cfrm1d, "", status );
6020                   } else {
6021                      cfrm2d = (AstFrame *) astCmpFrame( cfrm1d, dummy, "", status );
6022                   }
6023                   dummy = astAnnul( dummy );
6024 
6025 /* The Mapping that joins this 2D base Frame to the 2D current Frame uses
6026    the above 1D mapping for the other axis, and a UnitMap for the copied
6027    base Frame axis. */
6028                   if( i < 2 ) {
6029                      map2d = (AstMapping *) astCmpMap( unit1d, map1d, 0, "", status );
6030                   } else {
6031                      map2d = (AstMapping *) astCmpMap( map1d, unit1d, 0, "", status );
6032                   }
6033 
6034 /* Construct a FrameSet using these 2D Frames and Mapping. */
6035                   fset2 = astFrameSet( bfrm2d, "", status );
6036                   astAddFrame( fset2, AST__BASE, map2d, cfrm2d );
6037 
6038                   bfrm2d = astAnnul( bfrm2d );
6039                   cfrm2d = astAnnul( cfrm2d );
6040                   map2d = astAnnul( map2d );
6041 
6042 /* Indicate that only one of the axes in the current Frame of this FrameSet
6043    should be labelled. */
6044                   if( i < 2 ) {
6045                      label2[ 0 ] = 0;
6046                      label2[ 1 ] = 1;
6047                   } else {
6048                      label2[ 0 ] = 1;
6049                      label2[ 1 ] = 0;
6050                   }
6051 
6052 /* Pick the two axes from the 3D base Frame that correspond to the second
6053    of the paired axes, and the unpaired axis. Order them so that we get the
6054    2 axes in the order xy, xz or yz. Also, store the index of the axis
6055    within the supplied  current Frame that corresponds to each axis in
6056    the current Frame of the FrameSet created below. */
6057                   if( i == 0 ) {
6058                      axin2[ 0 ] = axin[ 1 ];
6059                      axin2[ 1 ] = other_axin;
6060                      wcsax3[ 0 ] = axout[ 1 ];
6061                      wcsax3[ 1 ] = other_axout[ 0 ];
6062                   } else {
6063                      axin2[ 0 ] = other_axin;
6064                      axin2[ 1 ] = axin[ 1 ];
6065                      wcsax3[ 0 ] = other_axout[ 0 ];
6066                      wcsax3[ 1 ] = axout[ 1 ];
6067                   }
6068                   bfrm2d = astPickAxes( bfrm, 2, axin2, NULL );
6069 
6070 /* The corresponding current Frame in the new FrameSet will be a compound
6071    2D Frame holding the other current Frame axis and a copy of the input
6072    base Frame axis. Combine them so that we get the 2 axes in the order
6073    xy, xz or yz. */
6074                   dummy = astPickAxes( bfrm, 1, axin + 1, NULL );
6075                   if( i == 0 ) {
6076                      cfrm2d = (AstFrame *) astCmpFrame( dummy, cfrm1d, "", status );
6077                   } else {
6078                      cfrm2d = (AstFrame *) astCmpFrame( cfrm1d, dummy, "", status );
6079                   }
6080                   dummy = astAnnul( dummy );
6081 
6082 /* The Mapping that joins this 2D base Frame to the 2D current Frame uses
6083    the above 1D mapping for the other axis, and a UnitMap for the copied
6084    base Frame axis. */
6085                   if( i == 0 ) {
6086                      map2d = (AstMapping *) astCmpMap( unit1d, map1d, 0, "", status );
6087                   } else {
6088                      map2d = (AstMapping *) astCmpMap( map1d, unit1d, 0, "", status );
6089                   }
6090 
6091 /* Construct a FrameSet using these 2D Frames and Mapping. */
6092                   fset3 = astFrameSet( bfrm2d, "", status );
6093                   astAddFrame( fset3, AST__BASE, map2d, cfrm2d );
6094 
6095                   bfrm2d = astAnnul( bfrm2d );
6096                   cfrm2d = astAnnul( cfrm2d );
6097                   map2d = astAnnul( map2d );
6098 
6099 /* Indicate that neither axis in the current Frame of this FrameSet
6100    should be labelled. */
6101                   label3[ 0 ] = 0;
6102                   label3[ 1 ] = 0;
6103 
6104 /* Store each FrameSet in the correct returned pointer. */
6105                   if( i == 0 ) {
6106                      *baseplane = XY;
6107                      *fsetxy = fset1;
6108                      *fsetxz = fset2;
6109                      *fsetyz = fset3;
6110 
6111                      labelxy[ 0 ] = label1[ 0 ];
6112                      labelxy[ 1 ] = label1[ 1 ];
6113                      labelxz[ 0 ] = label2[ 0 ];
6114                      labelxz[ 1 ] = label2[ 1 ];
6115                      labelyz[ 0 ] = label3[ 0 ];
6116                      labelyz[ 1 ] = label3[ 1 ];
6117 
6118                      wcsxy[ 0 ] = wcsax1[ 0 ];
6119                      wcsxy[ 1 ] = wcsax1[ 1 ];
6120                      wcsxz[ 0 ] = wcsax2[ 0 ];
6121                      wcsxz[ 1 ] = wcsax2[ 1 ];
6122                      wcsyz[ 0 ] = wcsax3[ 0 ];
6123                      wcsyz[ 1 ] = wcsax3[ 1 ];
6124 
6125                   } else if( i == 1 ) {
6126                      *baseplane = XZ;
6127                      *fsetxy = fset2;
6128                      *fsetxz = fset1;
6129                      *fsetyz = fset3;
6130 
6131                      labelxy[ 0 ] = label2[ 0 ];
6132                      labelxy[ 1 ] = label2[ 1 ];
6133                      labelxz[ 0 ] = label1[ 0 ];
6134                      labelxz[ 1 ] = label1[ 1 ];
6135                      labelyz[ 0 ] = label3[ 0 ];
6136                      labelyz[ 1 ] = label3[ 1 ];
6137 
6138                      wcsxy[ 0 ] = wcsax2[ 0 ];
6139                      wcsxy[ 1 ] = wcsax2[ 1 ];
6140                      wcsxz[ 0 ] = wcsax1[ 0 ];
6141                      wcsxz[ 1 ] = wcsax1[ 1 ];
6142                      wcsyz[ 0 ] = wcsax3[ 0 ];
6143                      wcsyz[ 1 ] = wcsax3[ 1 ];
6144 
6145                   } else {
6146                      *baseplane = YZ;
6147                      *fsetxy = fset2;
6148                      *fsetxz = fset3;
6149                      *fsetyz = fset1;
6150 
6151                      labelxy[ 0 ] = label2[ 0 ];
6152                      labelxy[ 1 ] = label2[ 1 ];
6153                      labelxz[ 0 ] = label3[ 0 ];
6154                      labelxz[ 1 ] = label3[ 1 ];
6155                      labelyz[ 0 ] = label1[ 0 ];
6156                      labelyz[ 1 ] = label1[ 1 ];
6157 
6158                      wcsxy[ 0 ] = wcsax2[ 0 ];
6159                      wcsxy[ 1 ] = wcsax2[ 1 ];
6160                      wcsxz[ 0 ] = wcsax3[ 0 ];
6161                      wcsxz[ 1 ] = wcsax3[ 1 ];
6162                      wcsyz[ 0 ] = wcsax1[ 0 ];
6163                      wcsyz[ 1 ] = wcsax1[ 1 ];
6164 
6165                   }
6166 
6167 /*  Free resources */
6168                   cfrm1d = astAnnul( cfrm1d );
6169                }
6170 
6171 /*  Free resources */
6172                map1d = astAnnul( map1d );
6173                other_axout = astFree( other_axout );
6174             }
6175          }
6176 
6177 /*  Free resources */
6178          if( map2d ) map2d = astAnnul( map2d );
6179          axout = astFree( axout );
6180 
6181 /* Leave the loop if we now have the required FrameSets, or an error has
6182    occurred. */
6183          if( *fsetxy || !astOK ) break;
6184 
6185       }
6186    }
6187 
6188 /* Free resources */
6189    cfrm = astAnnul( cfrm );
6190    bfrm = astAnnul( bfrm );
6191    smap = astAnnul( smap );
6192    unit1d = astAnnul( unit1d );
6193 
6194 /* Return null pointers if an error has occurred. */
6195    if( !astOK ) {
6196       *fsetxy = astAnnul( *fsetxy );
6197       *fsetxz = astAnnul( *fsetxz );
6198       *fsetyz = astAnnul( *fsetyz );
6199 
6200 /* Report an error if the supplied FrameSet could not be split into 3
6201    independent 2D planes. */
6202    } if( ! *fsetxy ) {
6203       astError( AST__3DFSET, "astInitPlot3D(Plot3D): Supplied %s contains "
6204                              "no independent axes.", status, astGetClass( fset ) );
6205    }
6206 }
6207 
StoreAxisInfo(AstPlot3D * this,int labelxy[2],int wcsxy[2],int labelxz[2],int wcsxz[2],int labelyz[2],int wcsyz[2],int * status)6208 static void StoreAxisInfo( AstPlot3D *this, int labelxy[2], int wcsxy[2],
6209                            int labelxz[2], int wcsxz[2], int labelyz[2],
6210                            int wcsyz[2], int *status ) {
6211 /*
6212 *  Name:
6213 *     StoreAxisInfo
6214 
6215 *  Purpose:
6216 *     Store information connecting 3D axis with associuated 2D Plot axes.
6217 
6218 *  Type:
6219 *     Private function.
6220 
6221 *  Synopsis:
6222 *     #include "plot3d.h"
6223 *     void StoreAxisInfo( AstPlot3D *this, int labelxy[2], int wcsxy[2],
6224 *                         int labelxz[2], int wcsxz[2], int labelyz[2],
6225 *                         int wcsyz[2], int *status )
6226 
6227 *  Class Membership:
6228 *     Plot3D method.
6229 
6230 *  Description:
6231 *     This function stores information inside the Plot3D that allows each
6232 *     3D axis to be associated with the 2 Plots that share the 3D axis,
6233 *     and with the axis index within each of these two Plots.
6234 
6235 *  Parameters:
6236 *     this
6237 *        Pointer to the Plot3D.
6238 *     labelxy
6239 *        Flags indicating if the two axes of the current Frame in the XY
6240 *        Plot should be labelled or not.
6241 *     wcsxy
6242 *        The zero based axis index within the 3D current Frame that
6243 *        corresponds to each of the two current Frame axes in the XY Plot.
6244 *        A value of -1 should be used for 2D axes that do not correspond
6245 *        to any 3D axis.
6246 *     labelxz
6247 *        Flags indicating if the two axes of the current Frame in the XZ
6248 *        Plot should be labelled or not.
6249 *     wcsxz
6250 *        The zero based axis index within the 3D current Frame that
6251 *        corresponds to each of the two current Frame axes in the XZ Plot.
6252 *        A value of -1 should be used for 2D axes that do not correspond
6253 *        to any 3D axis.
6254 *     labelyz
6255 *        Flags indicating if the two axes of the current Frame in the YZ
6256 *        Plot should be labelled or not.
6257 *     wcsyz
6258 *        The zero based axis index within the 3D current Frame that
6259 *        corresponds to each of the two current Frame axes in the YZ Plot.
6260 *        A value of -1 should be used for 2D axes that do not correspond
6261 *        to any 3D axis.
6262 *     status
6263 *        Pointer to the inherited status variable.
6264 
6265 */
6266 
6267 /* Local Variables: */
6268    int axis2d;
6269    int axis3d;
6270    int gotfirst;
6271    int gotsecond;
6272    int temp;
6273 
6274 /* Check the inherited status. */
6275    if( !astOK ) return;
6276 
6277 /* Store information that allows each 3D WCS axis to be associated with
6278    a pair of Plots. Also store the WCS axis within each Plot that
6279    corresponds to the 3D WCS axis. Do each 3D WCS axis in turn. */
6280    for( axis3d = 0; axis3d < 3; axis3d++ ) {
6281 
6282 /* Indicate we have not yet found either of the two Plots that share the
6283    current 3D axis. */
6284       gotfirst = 0;
6285       gotsecond = 0;
6286 
6287 /* Check each of the 2 axes in the plot spanning the XY face of the 3D
6288    graphics cube. Break early if we have found both Plots for the current
6289    3D WCS axis. */
6290       for( axis2d = 0; axis2d < 2 && !gotsecond; axis2d++ ) {
6291 
6292 /* See if this 2D axis corresponds to the required 3D axis. If so, store
6293    the Plot identifier and the 2D axis index. */
6294          if( wcsxy[ axis2d ] == axis3d ) {
6295             if( gotfirst ) {
6296                this->axis_plot2[ axis3d ] = XY;
6297                this->axis_index2[ axis3d ] = axis2d;
6298                gotsecond = 1;
6299             } else {
6300                this->axis_plot1[ axis3d ] = XY;
6301                this->axis_index1[ axis3d ] = axis2d;
6302                gotfirst = 1;
6303             }
6304          }
6305       }
6306 
6307 /* Check the plot spanning the XZ face in the same way. */
6308       for( axis2d = 0; axis2d < 2 && !gotsecond; axis2d++ ) {
6309          if( wcsxz[ axis2d ] == axis3d ) {
6310             if( gotfirst ) {
6311                this->axis_plot2[ axis3d ] = XZ;
6312                this->axis_index2[ axis3d ] = axis2d;
6313                gotsecond = 1;
6314             } else {
6315                this->axis_plot1[ axis3d ] = XZ;
6316                this->axis_index1[ axis3d ] = axis2d;
6317                gotfirst = 1;
6318             }
6319          }
6320       }
6321 
6322 /* Check the plot spanning the YZ face in the same way. */
6323       for( axis2d = 0; axis2d < 2 && !gotsecond; axis2d++ ) {
6324          if( wcsyz[ axis2d ] == axis3d ) {
6325             if( gotfirst ) {
6326                this->axis_plot2[ axis3d ] = YZ;
6327                this->axis_index2[ axis3d ] = axis2d;
6328                gotsecond = 1;
6329             } else {
6330                this->axis_plot1[ axis3d ] = YZ;
6331                this->axis_index1[ axis3d ] = axis2d;
6332                gotfirst = 1;
6333             }
6334          }
6335       }
6336    }
6337 
6338 /* Ensure that the first Plot within each pair is the one that is used to
6339    generate labels for the 3D axis. */
6340    for( axis2d = 0; axis2d < 2; axis2d++ ) {
6341       if( labelxy[ axis2d ] ) {
6342          axis3d = wcsxy[ axis2d ];
6343          if( this->axis_plot1[ axis3d ] != XY ){
6344             temp = this->axis_plot1[ axis3d ];
6345             this->axis_plot1[ axis3d ] = this->axis_plot2[ axis3d ];
6346             this->axis_plot2[ axis3d ] = temp;
6347 
6348             temp = this->axis_index1[ axis3d ];
6349             this->axis_index1[ axis3d ] = this->axis_index2[ axis3d ];
6350             this->axis_index1[ axis3d ] = temp;
6351          }
6352       }
6353    }
6354 
6355    for( axis2d = 0; axis2d < 2; axis2d++ ) {
6356       if( labelxz[ axis2d ] ) {
6357          axis3d = wcsxz[ axis2d ];
6358          if( this->axis_plot1[ axis3d ] != XZ ){
6359             temp = this->axis_plot1[ axis3d ];
6360             this->axis_plot1[ axis3d ] = this->axis_plot2[ axis3d ];
6361             this->axis_plot2[ axis3d ] = temp;
6362 
6363             temp = this->axis_index1[ axis3d ];
6364             this->axis_index1[ axis3d ] = this->axis_index2[ axis3d ];
6365             this->axis_index1[ axis3d ] = temp;
6366          }
6367       }
6368    }
6369 
6370    for( axis2d = 0; axis2d < 2; axis2d++ ) {
6371       if( labelyz[ axis2d ] ) {
6372          axis3d = wcsyz[ axis2d ];
6373          if( this->axis_plot1[ axis3d ] != YZ ){
6374             temp = this->axis_plot1[ axis3d ];
6375             this->axis_plot1[ axis3d ] = this->axis_plot2[ axis3d ];
6376             this->axis_plot2[ axis3d ] = temp;
6377 
6378             temp = this->axis_index1[ axis3d ];
6379             this->axis_index1[ axis3d ] = this->axis_index2[ axis3d ];
6380             this->axis_index1[ axis3d ] = temp;
6381          }
6382       }
6383    }
6384 }
6385 
TestAttrib(AstObject * this_object,const char * attrib,int * status)6386 static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
6387 /*
6388 *  Name:
6389 *     TestAttrib
6390 
6391 *  Purpose:
6392 *     Test if a specified attribute value is set for a Plot3D.
6393 
6394 *  Type:
6395 *     Private function.
6396 
6397 *  Synopsis:
6398 *     #include "plot3d.h"
6399 *     int TestAttrib( AstObject *this, const char *attrib, int *status )
6400 
6401 *  Class Membership:
6402 *     Plot3D member function (over-rides the astTestAttrib protected
6403 *     method inherited from the Plot class).
6404 
6405 *  Description:
6406 *     This function returns a boolean result (0 or 1) to indicate whether
6407 *     a value has been set for one of a Plot3D's attributes.
6408 
6409 *  Parameters:
6410 *     this
6411 *        Pointer to the Plot3D.
6412 *     attrib
6413 *        Pointer to a null terminated string specifying the attribute
6414 *        name.  This should be in lower case with no surrounding white
6415 *        space.
6416 *     status
6417 *        Pointer to the inherited status variable.
6418 
6419 *  Returned Value:
6420 *     One if a value has been set, otherwise zero.
6421 
6422 *  Notes:
6423 *     - A value of zero will be returned if this function is invoked
6424 *     with the global status set, or if it should fail for any reason.
6425 */
6426 
6427 /* Local Variables: */
6428    AstPlot3D *this;              /* Pointer to the Plot3D structure */
6429    int axis;                     /* Axis index */
6430    int len;                      /* Length of attrib string */
6431    int nc;                       /* Number of character read */
6432    int result;                   /* Result value to return */
6433 
6434 /* Initialise. */
6435    result = 0;
6436 
6437 /* Check the global error status. */
6438    if ( !astOK ) return result;
6439 
6440 /* Obtain a pointer to the Plot3D structure. */
6441    this = (AstPlot3D *) this_object;
6442 
6443 /* Obtain the length of the attrib string. */
6444    len = strlen( attrib );
6445 
6446 /* Check the attribute name and test the appropriate attribute. */
6447 
6448 /* Norm. */
6449 /* ----- */
6450    if ( !strcmp( attrib, "norm" ) ) {
6451       result = astTestNorm( this, 0 ) ||
6452                astTestNorm( this, 1 ) ||
6453                astTestNorm( this, 2 );
6454 
6455 /* Norm(axis). */
6456 /* ----------- */
6457    } else if ( nc = 0,
6458                ( 1 == astSscanf( attrib, "norm(%d)%n", &axis, &nc ) )
6459                && ( nc >= len ) ) {
6460       result = astTestNorm( this, axis -  1 );
6461 
6462 /* RootCorner. */
6463 /* ----------- */
6464    } else if ( !strcmp( attrib, "rootcorner" ) ) {
6465       result = astTestRootCorner( this );
6466 
6467 /* If the attribute is still not recognised, pass it on to the parent
6468    method for further interpretation. */
6469    } else {
6470       result = (*parent_testattrib)( this_object, attrib, status );
6471    }
6472 
6473 /* Return the result, */
6474    return result;
6475 }
6476 
Text(AstPlot * this_plot,const char * text,const double pos[],const float up[],const char * just,int * status)6477 static void Text( AstPlot *this_plot, const char *text, const double pos[],
6478                   const float up[], const char *just, int *status ){
6479 /*
6480 *  Name:
6481 *     Text
6482 
6483 *  Purpose:
6484 *     Draw a text string for a Plot3D.
6485 
6486 *  Type:
6487 *     Private member function.
6488 
6489 *  Synopsis:
6490 *     #include "plot3d.h"
6491 *     void Text( AstPlot *this, const char *text, const double pos[],
6492 *                const float up[], const char *just, int *status )
6493 
6494 *  Class Membership:
6495 *     Plot3D method (overrides the Text method inherited form the Plot
6496 *     class).
6497 
6498 *  Description:
6499 *     This function draws a string of text at a position specified in
6500 *     the physical coordinate system of a Plot3D. The physical position
6501 *     is transformed into graphical coordinates to determine where the
6502 *     text should appear within the plotting area.
6503 *
6504 *     The text is drawn on a 2D plane that has a normal vector given by the
6505 *     current value of the Plot3D's "Norm" attribute.
6506 
6507 *  Parameters:
6508 *     this
6509 *        Pointer to the Plot3D.
6510 *     text
6511 *        Pointer to a null-terminated character string containing the
6512 *        text to be drawn. Trailing white space is ignored.
6513 *     pos
6514 *        An array, with one element for each axis of the Plot3D, giving
6515 *        the physical coordinates of the point where the reference
6516 *        position of the text string is to be placed.
6517 *     up
6518 *        An array holding the components of a vector in the "up"
6519 *        direction of the text (in graphical coordinates). For
6520 *        example, to get horizontal text, the vector {0.0f,1.0f} should
6521 *        be supplied. "Up" is taken to be the projection of the positive
6522 *        Z axis onto the plane specified by the current value of the
6523 *     just
6524 *        Pointer to a null-terminated character string identifying the
6525 *        reference point for the text being drawn. The first character in
6526 *        this string identifies the reference position in the "up" direction
6527 *        and may be "B" (baseline), "C" (centre), "T" (top) or "M" (bottom).
6528 *        The second character identifies the side-to-side reference position
6529 *        and may be "L" (left), "C" (centre) or "R" (right ). The string is
6530 *        case-insensitive, and only the first two characters are significant.
6531 *
6532 *        For example, a value of "BL" means that the left end of the
6533 *        baseline of the original (un-rotated) text is to be drawn at the
6534 *        position given by "pos".
6535 *     status
6536 *        Pointer to the inherited status variable.
6537 
6538 */
6539 
6540 /* Local Variables: */
6541    AstMapping *mapping;    /* Pointer to graphics->physical mapping */
6542    AstPlot3D *this;        /* Pointer to the Plot3D structure */
6543    AstPointSet *pset1;     /* PointSet holding physical positions */
6544    AstPointSet *pset2;     /* PointSet holding graphics positions */
6545    char *ltext;            /* Local copy of "text" excluding trailing spaces */
6546    char ljust[3];          /* Upper case copy of "just" */
6547    const char *class;      /* Object class */
6548    const char *method;     /* Current method */
6549    const double **ptr1;    /* Pointer to physical positions */
6550    double **ptr2;          /* Pointer to graphics positions */
6551    float norm[ 3 ];        /* Single precision normal vector */
6552    float ref[ 3 ];         /* Single precision ref position */
6553    int axis;               /* Axis index */
6554    int escs;               /* Original astEscapes value */
6555    int naxes;              /* No. of axes in the base Frame */
6556    int ncoord;             /* No. of axes in the current Frame */
6557    int ulen;               /* Length of "text" excluding trailing spaces */
6558 
6559 /* Check the global error status. */
6560    if ( !astOK || !text ) return;
6561 
6562 /* Store a pointer to the Plot3D structure. */
6563    this = (AstPlot3D *) this_plot;
6564 
6565 /* Store the current method and class for inclusion in error messages
6566    generated by lower level functions. */
6567    method = "astText";
6568    class = astClass( this );
6569 
6570 /* Check the base Frame of the Plot is 3-D. */
6571    naxes = astGetNin( this );
6572    if( naxes != 3 && astOK ){
6573       astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base "
6574                 "Frame of the supplied %s is invalid - this number should "
6575                 "be 3.", status, method, class, naxes, class );
6576    }
6577 
6578 /* Ensure AST functions do not included graphical escape sequences in any
6579    returned text strings. This is because the Plot3D implementation of
6580    this method cannot currently handle graphical escape sequences. */
6581    escs = astEscapes( 0 );
6582 
6583 /* Establish the correct graphical attributes as defined by attributes
6584    with the supplied Plot. */
6585    astGrfAttrs( this, AST__TEXT_ID, 1, GRF__TEXT, method, class );
6586 
6587 /* Get the number of coordinates in the physical coordinate frame. */
6588    ncoord = astGetNout( this );
6589 
6590 /* Create a PointSet to hold the supplied physical coordinates. */
6591    pset1 = astPointSet( 1, ncoord, "", status );
6592 
6593 /* Allocate memory to hold pointers to the first value on each axis. */
6594    ptr1 = (const double **) astMalloc( sizeof( const double * )*
6595                                        (size_t)( ncoord ));
6596 
6597 /* Check the pointer can be used, then store pointers to the first value
6598    on each axis. */
6599    if( astOK ){
6600       for( axis = 0; axis < ncoord; axis++ ){
6601          ptr1[ axis ] = pos + axis;
6602       }
6603    }
6604 
6605 /* Store these pointers in the PointSet. */
6606    astSetPoints( pset1, (double **) ptr1 );
6607 
6608 /* Transform the supplied data from the current frame (i.e. physical
6609    coordinates) to the base frame (i.e. graphics coordinates) using
6610    the inverse Mapping defined by the Plot. */
6611    mapping = astGetMapping( this, AST__BASE, AST__CURRENT );
6612    pset2 = astTransform( mapping, pset1, 0, NULL );
6613    mapping = astAnnul( mapping );
6614 
6615 /* Get pointers to the graphics coordinates. */
6616    ptr2 = astGetPoints( pset2 );
6617 
6618 /* Take a copy of the string excluding any trailing white space. */
6619    ulen = astChrLen( text );
6620    ltext = (char *) astStore( NULL, (void *) text, ulen + 1 );
6621 
6622 /* Check the pointers can be used. */
6623    if( astOK ){
6624 
6625 /* Terminate the local copy of the text string. */
6626       ltext[ ulen ] = 0;
6627 
6628 /* Produce an upper-case copy of the first two characters in "just". */
6629       ljust[0] = (char) toupper( (int) just[0] );
6630       ljust[1] = (char) toupper( (int) just[1] );
6631       ljust[2] = 0;
6632 
6633 /* Convert the double precision values to single precision, checking for
6634    bad positions. */
6635       if( ptr2[0][0] != AST__BAD && ptr2[1][0] != AST__BAD &&
6636           ptr2[2][0] != AST__BAD ){
6637          ref[ 0 ] = (float) ptr2[0][0];
6638          ref[ 1 ] = (float) ptr2[1][0];
6639          ref[ 2 ] = (float) ptr2[2][0];
6640 
6641 /* If the nornmal vector has non-zero length, draw the text. */
6642          norm[ 0 ] = (float) astGetNorm( this, 0 );
6643          norm[ 1 ] = (float) astGetNorm( this, 1 );
6644          norm[ 2 ] = (float) astGetNorm( this, 2 );
6645 
6646 /* Since we are about to call an external function which may not be
6647    thread safe, prevent any other thread from executing the following code
6648    until the current thread has finished executing it. */
6649          LOCK_MUTEX2;
6650 
6651          if( norm[ 0 ] != 0.0 || norm[ 1 ] != 0.0 || norm[ 2 ] != 0.0 ){
6652             if( !astG3DText( ltext, ref, ljust, (float *) up, norm ) ) {
6653                astError( AST__GRFER, "%s(%s): Graphics error in astG3DText. ", status,
6654                          method, class );
6655             }
6656          } else if( astOK ) {
6657             astError( AST__ATTIN, "%s(%s): The vector specified by the Norm "
6658                       "attribute has zero length.", status, method, class );
6659          }
6660 
6661 /* Allow the next thread to proceed. */
6662          UNLOCK_MUTEX2;
6663       }
6664 
6665 /* Free the local copy of the string. */
6666       ltext = (char *) astFree( (void *) ltext );
6667 
6668    }
6669 
6670 /* Annul the PointSets. */
6671    pset1 = astAnnul( pset1 );
6672    pset2 = astAnnul( pset2 );
6673 
6674 /* Free the memory holding the pointers to the first value on each axis. */
6675    ptr1 = (const double **) astFree( (void *) ptr1 );
6676 
6677 /* Re-establish the original graphical attributes. */
6678    astGrfAttrs( this, AST__TEXT_ID, 0, GRF__TEXT, method, class );
6679 
6680 /* Restore the original value of the flag which says whether graphical
6681    escape sequences should be incldued in any returned text strings. */
6682    astEscapes( escs );
6683 
6684 /* Return */
6685    return;
6686 }
6687 
Transform(AstMapping * this_mapping,AstPointSet * in,int forward,AstPointSet * out,int * status)6688 static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in,
6689                                int forward, AstPointSet *out, int *status ) {
6690 /*
6691 *  Name:
6692 *     Transform
6693 
6694 *  Purpose:
6695 *     Use a Plot to transform a set of points.
6696 
6697 *  Type:
6698 *     Private function.
6699 
6700 *  Synopsis:
6701 *     #include "plot3d.h"
6702 *     AstPointSet *Transform( AstMapping *this, AstPointSet *in,
6703 *                             int forward, AstPointSet *out, int *status )
6704 
6705 *  Class Membership:
6706 *     Plot3D member function (over-rides the astTransform protected
6707 *     method inherited from the Plot class).
6708 
6709 *  Description:
6710 *     This function takes a Plot3D and a set of points encapsulated in a
6711 *     PointSet and transforms the points from graphics coordinates to
6712 *     physical coordinates (in the forward direction). No clipping or
6713 *     normalisation is applied.
6714 
6715 *  Parameters:
6716 *     this
6717 *        Pointer to the Plot3D.
6718 *     in
6719 *        Pointer to the PointSet holding the input coordinate data.
6720 *     forward
6721 *        A non-zero value indicates that the forward coordinate
6722 *        transformation should be applied while a zero value requests the
6723 *        inverse transformation.
6724 *     out
6725 *        Pointer to a PointSet which will hold the transformed (output)
6726 *        coordinate values. A NULL value may also be given, in which case a
6727 *        new PointSet will be created by this function.
6728 *     status
6729 *        Pointer to the inherited status variable.
6730 
6731 *  Returned Value:
6732 *     Pointer to the output (possibly new) PointSet.
6733 
6734 *  Notes:
6735 *     -  A null pointer will be returned if this function is invoked with the
6736 *     global error status set, or if it should fail for any reason.
6737 *     -  The number of coordinate values per point in the input PointSet must
6738 *     match the number of coordinates for the Plot being applied.
6739 *     -  If an output PointSet is supplied, it must have space for sufficient
6740 *     number of points and coordinate values per point to accommodate the
6741 *     result. Any excess space will be ignored.
6742 */
6743 
6744 /* Local Variables: */
6745    AstMapping *map;              /* Pointer to the mapping */
6746    AstPointSet *result;          /* Positions in output Frame */
6747    AstPlot3D *this;              /* The Plot3D */
6748 
6749 /* Check the global error status. */
6750    if ( !astOK ) return NULL;
6751 
6752 /* Get a pointer to the Plot3D. */
6753    this = (AstPlot3D *) this_mapping;
6754 
6755 /* Get the Mapping from the base to the current Frame. */
6756    map = astGetMapping( this, AST__BASE, AST__CURRENT );
6757 
6758 /* Do the transformation. */
6759    result = astTransform( map, in, forward, out );
6760 
6761 /* Annul the mapping. */
6762    map = astAnnul( map );
6763 
6764 /* If an error has occurred, annul the result. */
6765    if( !astOK ) result = astAnnul( result );
6766 
6767 /* Return a pointer to the output PointSet. */
6768    return result;
6769 
6770 }
6771 
UpdatePlots(AstPlot3D * this,int * status)6772 static void UpdatePlots( AstPlot3D *this, int *status ) {
6773 /*
6774 *  Name:
6775 *     UpdatePlots
6776 
6777 *  Purpose:
6778 *     Update the three 2D plots stored in the Plot3D.
6779 
6780 *  Type:
6781 *     Private function.
6782 
6783 *  Synopsis:
6784 *     #include "plot3d.h"
6785 *     void UpdatePlots( AstPlot3D *this )
6786 
6787 *  Class Membership:
6788 *     Plot3D method.
6789 
6790 *  Description:
6791 *     This function splits the parent FrameSet up into 3 independent 2D
6792 *     FrameSets, each describing a 2D plane in the supplied 3D FrameSet.
6793 *     It then uses these 2D FrameSets to update the three Plots in the
6794 *     Plot3D, by removing the existing current Frame and adding in the
6795 *     new current Frame with the associated Mapping.
6796 
6797 *  Parameters:
6798 *     this
6799 *        Pointer to the Plot3D.
6800 
6801 *  Notes:
6802 *     - Each of the 3 plots has 3 Frames: Frame 1 is the base (GRAPHICS)
6803 *     Frame; Frame 2 is spanned by 2 of the 3 axes in the base Frame of
6804 *     the supplied FrameSet; Frame 3 is the current Frame and is spanned
6805 *     by 2 of the 3 axes in the current Frame of the supplied FrameSet.
6806 *     Any future changes to this function that alter this structure should
6807 *     reflected in equivalewnt changes to function CreatePlots.
6808 */
6809 
6810 /* Local Variables: */
6811    AstFrame *frm;
6812    AstFrameSet *fsetxy;
6813    AstFrameSet *fsetxz;
6814    AstFrameSet *fsetyz;
6815    AstFrameSet *fset;
6816    AstMapping *map;
6817    int baseplane;
6818    int labelxy[ 2 ];
6819    int labelxz[ 2 ];
6820    int labelyz[ 2 ];
6821    int wcsxy[ 2 ];
6822    int wcsxz[ 2 ];
6823    int wcsyz[ 2 ];
6824    int rootcorner;
6825 
6826 /* Check the inherited status. */
6827    if( !astOK ) return;
6828 
6829 /* Return without action if the Plot3D does not contain the three 2D
6830    Plots. This may be the case for instance if this function is called
6831    before the Plot3D is fully constructed. */
6832    if( this->plotxy && this->plotxz && this->plotyz ){
6833 
6834 /* We need a FrameSet that is equivalent to the one that was used to
6835    construct the Plot3D (i.e. a FrameSet that does not have the GRAPHICS
6836    Frame that was added by the Plot3D constructor). So take a copy of the
6837    parent FrameSet, remove the GRAPHICS Frame (Frame 1) and set the base
6838    Frame to be the Frame that was the base Frame when the Plot3D was
6839    constructed. */
6840       fset = (AstFrameSet *) astCast( this, dummy_frameset );
6841       astSetBase( fset, this->pix_frame );
6842       astRemoveFrame( fset, 1 );
6843 
6844 /* Split the supplied FrameSet up into 3 FrameSets, each with a 2D base
6845    and current Frame. Each of these FrameSets describes one plane of
6846    the 3D cube. */
6847       SplitFrameSet( fset, &fsetxy, labelxy, wcsxy, &fsetxz, labelxz, wcsxz,
6848                      &fsetyz, labelyz, wcsyz, &baseplane, status );
6849 
6850 /* First do the XY Plot. Extract the current Frame and base->current
6851    Mapping from the new FrameSet. It is assumed that he base Frame in the
6852    new FrameSet is equivalent to Frame 2 in the existing Plot. This
6853    assumption is based on the way the CreatePlots and SplitFrameSet
6854    functions work, and should be reviewed if either of these functions
6855    is changed. */
6856       frm = astGetFrame( fsetxy, 2 );
6857       map = astGetMapping( fsetxy, 1, 2 );
6858 
6859 /* Add the new Frame into the existing Plot using the Mapping to connect
6860    it to Frame 2 in the Plot. It becomes the current Frame in the Plot. */
6861       astAddFrame( this->plotxy, 2, map, frm );
6862 
6863 /* Delete the original current Frame in the Plot since it is not needed
6864    any more. */
6865       astRemoveFrame( this->plotxy, 3 );
6866 
6867 /* Set the Plot attributes. */
6868       SetPlotAttr( this->plotxy, XY, labelxy, status );
6869 
6870 /* Free resources */
6871       fsetxy = astAnnul( fsetxy );
6872       map = astAnnul( map );
6873       frm = astAnnul( frm );
6874 
6875 /* Do the same for the XZ plot. */
6876       frm = astGetFrame( fsetxz, 2 );
6877       map = astGetMapping( fsetxz, 1, 2 );
6878       astAddFrame( this->plotxz, 2, map, frm );
6879       astRemoveFrame( this->plotxz, 3 );
6880       SetPlotAttr( this->plotxz, XZ, labelxz, status );
6881       fsetxz = astAnnul( fsetxz );
6882       map = astAnnul( map );
6883       frm = astAnnul( frm );
6884 
6885 /* Do the same for the YZ plot. */
6886       frm = astGetFrame( fsetyz, 2 );
6887       map = astGetMapping( fsetyz, 1, 2 );
6888       astAddFrame( this->plotyz, 2, map, frm );
6889       astRemoveFrame( this->plotyz, 3 );
6890       SetPlotAttr( this->plotyz, YZ, labelyz, status );
6891       fsetyz = astAnnul( fsetyz );
6892       map = astAnnul( map );
6893       frm = astAnnul( frm );
6894 
6895 /* Store information that allows each 3D WCS axis to be associatedf with
6896    a pair of Plots. Also store the WCS axis within each Plot that
6897    corresponds to the 3D WCS axis. */
6898       StoreAxisInfo( this, labelxy, wcsxy, labelxz, wcsxz, labelyz, wcsyz, status );
6899 
6900 /* Set up the Edges attributes in the encapsulated Plots to produce labels
6901    on the required edges of the 3D graphics cube. */
6902       rootcorner = astGetRootCorner( this );
6903       ChangeRootCorner( this, rootcorner, rootcorner, status );
6904 
6905 /* Store the plane spanned by two connected 3D axes. */
6906       this->baseplot = baseplane;
6907 
6908 /* Free remaining resources */
6909       fset = astAnnul( fset );
6910    }
6911 }
6912 
VSet(AstObject * this_object,const char * settings,char ** text,va_list args,int * status)6913 static void VSet( AstObject *this_object, const char *settings,
6914                   char **text, va_list args, int *status ) {
6915 /*
6916 *  Name:
6917 *     VSet
6918 
6919 *  Purpose:
6920 *     Set values for a Plot3D's attributes.
6921 
6922 *  Type:
6923 *     Private function.
6924 
6925 *  Synopsis:
6926 *     #include "frameset.h"
6927 *     void VSet( AstObject *this, const char *settings, char **text,
6928 *                va_list args, int *status )
6929 
6930 *  Class Membership:
6931 *     Plot3D member function (over-rides the protected astVSet
6932 *     method inherited from the Object class).
6933 
6934 *  Description:
6935 *     This function assigns a set of attribute values for a Plot3D,
6936 *     the attributes and their values being specified by means of a
6937 *     string containing a comma-separated list of the form:
6938 *
6939 *        "attribute1 = value1, attribute2 = value2, ... "
6940 *
6941 *     Here, "attribute" specifies an attribute name and the value to
6942 *     the right of each "=" sign should be a suitable textual
6943 *     representation of the value to be assigned to that attribute. This
6944 *     will be interpreted according to the attribute's data type.
6945 *
6946 *     The string supplied may also contain "printf"-style format
6947 *     specifiers identified by a "%" sign in the usual way. If
6948 *     present, these will be substituted by values supplied as
6949 *     optional arguments (as a va_list variable argument list), using
6950 *     the normal "printf" rules, before the string is used.
6951 
6952 *  Parameters:
6953 *     this
6954 *        Pointer to the Plot3D.
6955 *     settings
6956 *        Pointer to a null-terminated string containing a
6957 *        comma-separated list of attribute settings.
6958 *     text
6959 *        Pointer to a location at which to return a pointer to dynamic
6960 *        memory holding a copy of the expanded setting string. This memory
6961 *        should be freed using astFree when no longer needed. If a NULL
6962 *        pointer is supplied, no string is created.
6963 *     args
6964 *        The variable argument list which contains values to be
6965 *        substituted for any "printf"-style format specifiers that
6966 *        appear in the "settings" string.
6967 *     status
6968 *        Pointer to the inherited status variable.
6969 
6970 *  Notes:
6971 *     - This function preserves the integrity of the Plot3D (if
6972 *     possible) by appropriately modifying the three encapsulated Plots.
6973 */
6974 
6975 /* Invoke the parent astVSet method to set the Plot3D's attribute values. */
6976    (*parent_vset)( this_object, settings, text, args, status );
6977 
6978 /* Update the three 2D Plots stored in the Plot3D structure so that they
6979    reflect this modified FrameSet. */
6980    UpdatePlots( (AstPlot3D *) this_object, status );
6981 }
6982 
6983 /* Functions which access Plot3D class attributes. */
6984 /* ----------------------------------------------- */
6985 
6986 /* RootCorner. */
6987 /* ----------- */
6988 /*
6989 *att++
6990 *  Name:
6991 *     RootCorner
6992 
6993 *  Purpose:
6994 *     Specifies which edges of the 3D box should be annotated.
6995 
6996 *  Type:
6997 *     Public attribute.
6998 
6999 *  Synopsis:
7000 *     String.
7001 
7002 *  Description:
7003 *     This attribute controls the appearance of an annotated
7004 c     coordinate grid (drawn with the astGrid function) by determining
7005 f     coordinate grid (drawn with the AST_GRID routine) by determining
7006 *     which edges of the cube enclosing the 3D graphics space are used
7007 *     for displaying numerical and descriptive axis labels. The attribute
7008 *     value identifies one of the eight corners of the cube within
7009 *     which graphics are being drawn (i.e. the cube specified by the
7010 c     "graphbox" parameter when astPlot3D
7011 f     GRAPHBOX argument when AST_PLOT3D
7012 *     was called tp create the Plot3D). Axis labels and tick marks will
7013 *     be placed on the three cube edges that meet at the given corner.
7014 *
7015 *     The attribute value should consist of three character, each of
7016 *     which must be either "U" or "L". The first character in the string
7017 *     specifies the position of the corner on the first graphics axis.
7018 *     If the character is "U" then the corner is at the upper bound on the
7019 *     first graphics axis. If it is "L", then the corner is at the lower
7020 *     bound on the first axis. Likewise, the second and third characters
7021 *     in the string specify the location of the corner on the second and
7022 *     third graphics axes.
7023 *
7024 *     For instance, corner "LLL" is the corner that is at the lower bound
7025 *     on all three graphics axes, and corner "ULU" is at the upper bound
7026 *     on axes 1 and 3 but at the lower bound on axis 2.
7027 *
7028 *     The default value is "LLL".
7029 
7030 *  Applicability:
7031 *     Plot3D
7032 *        All Plot3Ds have this attribute.
7033 
7034 *att--
7035 */
7036 
7037 /* Internally, the RootCorner is represented as an integer bit mask, with
7038    bit zero for the X axis, bit 1 for the Y axis and bit 2 for the Z axis.
7039    A bit is set if the corner is at the upper bound on the axis and unset
7040    if it is at the lower bound. A value of -1 indicates that the attribue
7041    has not been assigned a value. */
7042 astMAKE_GET(Plot3D,RootCorner,int,0,( this->rootcorner == -1 ? 0 : this->rootcorner))
7043 astMAKE_TEST(Plot3D,RootCorner,( this->rootcorner != -1 ))
7044 
7045 
7046 /* Norm(axis). */
7047 /* ----------- */
7048 /*
7049 *att++
7050 *  Name:
7051 *     Norm(axis)
7052 
7053 *  Purpose:
7054 *     Specifies the plane upon which a Plot3D draws text and markers.
7055 
7056 *  Type:
7057 *     Public attribute.
7058 
7059 *  Synopsis:
7060 *     Floating point.
7061 
7062 *  Description:
7063 *     This attribute controls the appearance of text and markers drawn
7064 *     by a Plot3D. It specifies the orientation of the plane upon which
7065 *     text and markers will be drawn by all subsequent invocations of the
7066 c     astText and astMark functions.
7067 f     AST_TEXT and AST_MARK functions.
7068 *
7069 *     When setting or getting the Norm attribute, the attribute name must
7070 *     be qualified by an axis index in the range 1 to 3. The 3 elements of
7071 *     the Norm attribute are together interpreted as a vector in 3D graphics
7072 *     coordinates that is normal to the plane upon which text and marks
7073 *     should be drawn. When testing or clearing the attribute, the axis
7074 *     index is optional. If no index is supplied, then clearing the Norm
7075 *     attribute will clear all three elements, and testing the Norm attribute
7076 *     will return a non-zero value if any of the three elements are set.
7077 *
7078 *     The default value is 1.0 for each of the 3 elements. The length of
7079 *     the vector is insignificant, but an error will be reported when
7080 *     attempting to draw text or markers if the vector has zero length.
7081 
7082 *  Applicability:
7083 *     Plot
7084 *        All Plot3Ds have this attribute.
7085 
7086 *att--
7087 */
7088 MAKE_CLEAR3(Norm,norm,AST__BAD,3)
7089 MAKE_SET3(Norm,double,norm,value,3)
7090 MAKE_TEST3(Norm,( this->norm[axis] != AST__BAD ),3)
7091 MAKE_GET3(Norm,double,AST__BAD,(this->norm[axis]!=AST__BAD?this->norm[axis]:1.0),3)
7092 
7093 
7094 
7095 /* Functions which access Plot class attributes. */
7096 /* --------------------------------------------- */
7097 
7098 /* First do axis specific attributes. */
7099 
7100 #define MAKE_ALL(attr,type,badval,whichplots) \
7101    MAKE_CLEAR(attr,whichplots) \
7102    MAKE_SET(attr,type,whichplots) \
7103    MAKE_GET(attr,type,badval )
7104 
7105 MAKE_ALL(MinTick,int,0,0)
7106 MAKE_ALL(Abbrev,int,0,1)
7107 MAKE_ALL(Gap,double,AST__BAD,1)
7108 MAKE_ALL(LogGap,double,AST__BAD,1)
7109 MAKE_ALL(LogPlot,int,0,0)
7110 MAKE_ALL(LogTicks,int,0,0)
7111 MAKE_ALL(LogLabel,int,0,1)
7112 MAKE_ALL(LabelUp,int,0,1)
7113 MAKE_ALL(DrawAxes,int,0,0)
7114 MAKE_ALL(LabelUnits,int,0,1)
7115 MAKE_ALL(MinTickLen,double,0.0,0)
7116 MAKE_ALL(MajTickLen,double,0.0,0)
7117 MAKE_ALL(NumLab,int,0,1)
7118 MAKE_ALL(NumLabGap,double,AST__BAD,1)
7119 MAKE_ALL(TextLab,int,0,1)
7120 MAKE_ALL(TextLabGap,double,AST__BAD,1)
7121 
7122 #undef MAKE_ALL
7123 
7124 
7125 /* Now do attributes that are not axis specific. */
7126 
7127 #define MAKE_ALL(attr,type) \
7128    MAKE_CLEAR1(attr) \
7129    MAKE_SET1(attr,type)
7130 
MAKE_ALL(Ink,int)7131 MAKE_ALL(Ink,int)
7132 MAKE_ALL(Tol,double)
7133 MAKE_ALL(Invisible,int)
7134 MAKE_ALL(TickAll,int)
7135 MAKE_ALL(ForceExterior,int)
7136 MAKE_ALL(Border,int)
7137 MAKE_ALL(Clip,int)
7138 MAKE_ALL(ClipOp,int)
7139 MAKE_ALL(Escape,int)
7140 MAKE_ALL(Grid,int)
7141 MAKE_ALL(Labelling,int)
7142 
7143 #undef MAKE_ALL
7144 
7145 
7146 
7147 /* First do element-specific attributes. */
7148 
7149 #define MAKE_ALL(attr,type) \
7150    MAKE_CLEAR2(attr) \
7151    MAKE_SET2(attr,type)
7152 
7153 MAKE_ALL(Style,int)
7154 MAKE_ALL(Font,int)
7155 MAKE_ALL(Colour,int)
7156 MAKE_ALL(Width,double)
7157 MAKE_ALL(Size,double)
7158 
7159 #undef MAKE_ALL
7160 
7161 
7162 
7163 
7164 
7165 /* Copy constructor. */
7166 /* ----------------- */
7167 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
7168 /*
7169 *  Name:
7170 *     Copy
7171 
7172 *  Purpose:
7173 *     Copy constructor for Plot3D objects.
7174 
7175 *  Type:
7176 *     Private function.
7177 
7178 *  Synopsis:
7179 *     void Copy( const AstObject *objin, AstObject *objout, int *status )
7180 
7181 *  Description:
7182 *     This function implements the copy constructor for Plot3D objects.
7183 
7184 *  Parameters:
7185 *     objin
7186 *        Pointer to the object to be copied.
7187 *     objout
7188 *        Pointer to the object being constructed.
7189 *     status
7190 *        Pointer to the inherited status variable.
7191 
7192 *  Notes:
7193 *     -  This constructor makes a deep copy.
7194 */
7195 
7196 /* Local Variables: */
7197    AstPlot3D *in;             /* Pointer to input Plot3D */
7198    AstPlot3D *out;            /* Pointer to output Plot3D */
7199 
7200 /* Check the global error status. */
7201    if ( !astOK ) return;
7202 
7203 /* Obtain pointers to the input and output Plot3Ds. */
7204    in = (AstPlot3D *) objin;
7205    out = (AstPlot3D *) objout;
7206 
7207 /* Nullify the pointers stored in the output object since these will
7208    currently be pointing at the input data (since the output is a simple
7209    byte-for-byte copy of the input). Otherwise, the input data could be
7210    freed by accidient if the output object is deleted due to an error
7211    occuring in this function. */
7212    out->plotxy = NULL;
7213    out->plotxz = NULL;
7214    out->plotyz = NULL;
7215 
7216 /* Copy the encapsulated Plots */
7217    if( in->plotxy ) out->plotxy = astCopy( in->plotxy );
7218    if( in->plotxz ) out->plotxz = astCopy( in->plotxz );
7219    if( in->plotyz ) out->plotyz = astCopy( in->plotyz );
7220 
7221 /* If an error has occurred, free the output resources. */
7222    if( !astOK ) Delete( (AstObject *) out, status );
7223 
7224 }
7225 
7226 /* Destructor. */
7227 /* ----------- */
Delete(AstObject * obj,int * status)7228 static void Delete( AstObject *obj, int *status ) {
7229 /*
7230 *  Name:
7231 *     Delete
7232 
7233 *  Purpose:
7234 *     Destructor for Plot3D objects.
7235 
7236 *  Type:
7237 *     Private function.
7238 
7239 *  Synopsis:
7240 *     void Delete( AstObject *obj, int *status )
7241 
7242 *  Description:
7243 *     This function implements the destructor for Plot3D objects.
7244 
7245 *  Parameters:
7246 *     obj
7247 *        Pointer to the object to be deleted.
7248 *     status
7249 *        Pointer to the inherited status variable.
7250 
7251 *  Notes:
7252 *     This function attempts to execute even if the global error status is
7253 *     set.
7254 */
7255 
7256 /* Local Variables: */
7257    AstPlot3D *this;
7258 
7259 /* Release the memory referred to in the Plot3D structure. */
7260    this = (AstPlot3D *) obj;
7261    if( this ) {
7262       this->plotxy = astDelete( this->plotxy );
7263       this->plotxz = astDelete( this->plotxz );
7264       this->plotyz = astDelete( this->plotyz );
7265    }
7266 }
7267 
7268 /* Dump function. */
7269 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)7270 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
7271 /*
7272 *  Name:
7273 *     Dump
7274 
7275 *  Purpose:
7276 *     Dump function for Plot3D objects.
7277 
7278 *  Type:
7279 *     Private function.
7280 
7281 *  Synopsis:
7282 *     void Dump( AstObject *this, AstChannel *channel, int *status )
7283 
7284 *  Description:
7285 *     This function implements the Dump function which writes out data
7286 *     for the Plot3D class to an output Channel.
7287 
7288 *  Parameters:
7289 *     this
7290 *        Pointer to the Plot3D whose data are being written.
7291 *     channel
7292 *        Pointer to the Channel to which the data are being written.
7293 *     status
7294 *        Pointer to the inherited status variable.
7295 */
7296 
7297 /* Local Constants: */
7298 #define KEY_LEN 50               /* Maximum length of a keyword */
7299 
7300 /* Local Variables: */
7301    AstPlot3D *this;
7302    double dval;
7303    char key[ KEY_LEN + 1 ];
7304    int axis;
7305    int helpful;
7306    int ival;
7307    int set;
7308    const char *text;
7309 
7310 /* Check the global error status. */
7311    if ( !astOK ) return;
7312 
7313 /* Obtain a pointer to the Plot3D structure. */
7314    this = (AstPlot3D *) this_object;
7315 
7316 /* Write out values representing the instance variables for the
7317    Plot3D class.  Accompany these with appropriate comment strings,
7318    possibly depending on the values being written.*/
7319 
7320 /* In the case of attributes, we first use the appropriate (private)
7321    Test...  member function to see if they are set. If so, we then use
7322    the (private) Get... function to obtain the value to be written
7323    out.
7324 
7325    For attributes which are not set, we use the astGet... method to
7326    obtain the value instead. This will supply a default value
7327    (possibly provided by a derived class which over-rides this method)
7328    which is more useful to a human reader as it corresponds to the
7329    actual default attribute value.  Since "set" will be zero, these
7330    values are for information only and will not be read back. */
7331 
7332 
7333 /* Norm. */
7334 /* ----- */
7335    for ( axis = 0; axis < 3; axis++ ) {
7336       dval = astGetNorm( this, axis );
7337       helpful = ( dval != -DBL_MAX );
7338       (void) sprintf( key, "Norm%d", axis + 1 );
7339       astWriteDouble( channel, key, 0, helpful, dval, "Text plane normal vector");
7340    }
7341 
7342 /* RootCorner. */
7343 /* ----------- */
7344    set = TestRootCorner( this, status );
7345    ival = set ? GetRootCorner( this, status ) : astGetRootCorner( this );
7346    text = RootCornerString( ival, status );
7347    if( text ) {
7348       astWriteString( channel, "RootCn", set, 1, text, "Corner where labelled axes meet" );
7349    } else if( astOK ) {
7350       astError( AST__INTER, "astDump(Plot3D): Illegal value %d found for "
7351                 "RootCorner attribute (interbal AST programming error).", status,
7352                 ival );
7353    }
7354 
7355 /* Labelled axes */
7356    astWriteInt( channel, "AxPlX1", 1, 1, this->axis_plot1[0],
7357                 "Plot used to label the 3D X axis" );
7358    astWriteInt( channel, "AxPlY1", 1, 1, this->axis_plot1[1],
7359                 "Plot used to label the 3D Y axis" );
7360    astWriteInt( channel, "AxPlZ1", 1, 1, this->axis_plot1[2],
7361                 "Plot used to label the 3D Z axis" );
7362    astWriteInt( channel, "AxInX1", 1, 1, this->axis_index1[0],
7363                 "Plot axis index used to label the 3D X axis" );
7364    astWriteInt( channel, "AxInY1", 1, 1, this->axis_index1[1],
7365                 "Plot axis index used to label the 3D Y axis" );
7366    astWriteInt( channel, "AxInZ1", 1, 1, this->axis_index1[2],
7367                 "Plot axis index used to label the 3D Z axis" );
7368 
7369 /* Unlabelled axes */
7370    astWriteInt( channel, "AxPlX2", 1, 1, this->axis_plot2[0],
7371                 "Other Plot touching the 3D X axis" );
7372    astWriteInt( channel, "AxPlY2", 1, 1, this->axis_plot2[1],
7373                 "Other Plot touching the 3D Y axis" );
7374    astWriteInt( channel, "AxPlZ2", 1, 1, this->axis_plot2[2],
7375                 "Other Plot touching the 3D Z axis" );
7376    astWriteInt( channel, "AxInX2", 1, 1, this->axis_index2[0],
7377                 "Other Plot axis index touching the 3D X axis" );
7378    astWriteInt( channel, "AxInY2", 1, 1, this->axis_index2[1],
7379                 "Other Plot axis index touching the 3D Y axis" );
7380    astWriteInt( channel, "AxInZ2", 1, 1, this->axis_index2[2],
7381                 "Other Plot axis index touching the 3D Z axis" );
7382 
7383 /* The Plot that spans the two connected axes. */
7384    astWriteInt( channel, "BasePl", 1, 1, this->baseplot,
7385                 "Plot spanning two connected 3D axes" );
7386 
7387 /* XY Plot */
7388    astWriteObject( channel, "PlotXY", 1, 1, this->plotxy,
7389                    "Plot describing the XY plane" );
7390 
7391 /* XZ Plot */
7392    astWriteObject( channel, "PlotXZ", 1, 1, this->plotxz,
7393                    "Plot describing the XZ plane" );
7394 
7395 /* YZ Plot */
7396    astWriteObject( channel, "PlotYZ", 1, 1, this->plotyz,
7397                    "Plot describing the YZ plane" );
7398 
7399 /* The index within the Plot3D FrameSet, of the original base Frame in
7400    the FrameSet supplied when the Plot3D was constructed. */
7401    astWriteInt( channel, "PixFrm", 1, 0, this->pix_frame,
7402                 "Index of original base Frame" );
7403 
7404 /* Undefine macros local to this function. */
7405 #undef KEY_LEN
7406 }
7407 
7408 /* Standard class functions. */
7409 /* ========================= */
7410 /* Implement the astIsAPlot3D and astCheckPlot3D functions using the
7411    macros defined for this purpose in the "object.h" header file. */
astMAKE_ISA(Plot3D,Plot)7412 astMAKE_ISA(Plot3D,Plot)
7413 astMAKE_CHECK(Plot3D)
7414 
7415 
7416 AstPlot3D *astPlot3D_( void *frame_void, const float *graphbox,
7417                        const double *basebox, const char *options, int *status, ...) {
7418 /*
7419 *+
7420 *  Name:
7421 *     astPlot3D
7422 
7423 *  Purpose:
7424 *     Create a Plot3D.
7425 
7426 *  Type:
7427 *     Protected function.
7428 
7429 *  Synopsis:
7430 *     #include "plot3d.h"
7431 *     AstPlot3D *astPlot3D( AstFrame *frame, const float *graphbox,
7432 *                           const double *basebox, const char *options, ..., int *status )
7433 
7434 *  Class Membership:
7435 *     Plot3D constructor.
7436 
7437 *  Description:
7438 *     This function creates a new Plot3D and optionally initialises its
7439 *     attributes.
7440 *
7441 *     The supplied Frame (or the base frame if a FrameSet was supplied) is
7442 *     assumed to be related to the graphics world coordinate system by a
7443 *     simple shift and scale along each axis. The mapping between graphics
7444 *     world coordinates and this Frame is specified by supplying the
7445 *     coordinates in both systems at the lower bounds and upper bounds corners
7446 *     of a box on the graphics device. By default, no graphics will be
7447 *     produced outside the supplied box, but this default behaviour can be
7448 *     changed by setting explicit values for the various clipping attributes.
7449 
7450 *  Parameters:
7451 *     frame
7452 *        A pointer to a Frame or FrameSet to be annotated. If a NULL pointer
7453 *        is supplied, then a default 3-D Frame will be created to which labels,
7454 *        etc, can be attached by setting the relevant Frame attributes.
7455 *     graphbox
7456 *        A pointer to an array of 6 values giving the graphics world
7457 *        coordinates of the lower bounds and upper bound corners of a box on
7458 *        the graphics output device. The first triple of values should be the
7459 *        coordinates of the lower bounds corner of the box and the second
7460 *        triple of values should be the coordinates of the upper bounds corner.
7461 *     basebox
7462 *        A pointer to an array of 6 values giving the coordinates in the
7463 *        supplied Frame, or base frame of the supplied FrameSet, at the
7464 *        lower bounds corner and upper bounds corners of the box specified
7465 *        by parameter graphbox. These should be supplied in the same order as
7466 *        for parameter "graphbox".
7467 *     options
7468 *        Pointer to a null terminated string containing an optional
7469 *        comma-separated list of attribute assignments to be used for
7470 *        initialising the new Plot3D. The syntax used is the same as for the
7471 *        astSet method and may include "printf" format specifiers identified
7472 *        by "%" symbols in the normal way.
7473 *     status
7474 *        Pointer to the inherited status variable.
7475 *     ...
7476 *        If the "options" string contains "%" format specifiers, then an
7477 *        optional list of arguments may follow it in order to supply values to
7478 *        be substituted for these specifiers. The rules for supplying these
7479 *        are identical to those for the astSet method (and for the C "printf"
7480 *        function).
7481 
7482 *  Returned Value:
7483 *     A pointer to the new Plot3D.
7484 
7485 *  Notes:
7486 *     -  A NULL pointer will be returned if this function is invoked with the
7487 *     global error status set, or if it should fail for any reason.
7488 *-
7489 
7490 *  Implementation Notes:
7491 *     - This function implements the basic Plot3D constructor which
7492 *     is available via the protected interface to the Plot3D class.
7493 *     A public interface is provided by the astPlot3DId_ function.
7494 */
7495 
7496 /* Local Variables: */
7497    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
7498    AstFrame *frame;              /* Pointer to Frame structure */
7499    AstPlot3D *new;               /* Pointer to new Plot3D */
7500    va_list args;                 /* Variable argument list */
7501 
7502 /* Get a pointer to the thread specific global data structure. */
7503    astGET_GLOBALS(NULL);
7504 
7505 /* Check the global status. */
7506    if ( !astOK ) return NULL;
7507 
7508 /* Initialise variables to avoid "used of uninitialised variable"
7509    messages from dumb compilers. */
7510    new = NULL;
7511 
7512 /* Obtain and validate a pointer to any supplied Frame structure. */
7513    if( frame_void ){
7514       frame = astCheckFrame( frame_void );
7515    } else {
7516       frame = NULL;
7517    }
7518 
7519 /* Check the pointer can be used. */
7520    if ( astOK ) {
7521 
7522 /* Initialise the Plot3D, allocating memory and initialising the
7523    virtual function table as well if necessary. */
7524       new = astInitPlot3D( NULL, sizeof( AstPlot3D ), !class_init,
7525                            &class_vtab, "Plot3D", frame, graphbox,
7526                            basebox );
7527 
7528 /* If successful, note that the virtual function table has been
7529    initialised. */
7530       if ( astOK ) {
7531          class_init = 1;
7532 
7533 /* Obtain the variable argument list and pass it along with the
7534    options string to the astVSet method to initialise the new
7535    Plot's attributes. */
7536          va_start( args, status );
7537          astVSet( new, options, NULL, args );
7538          va_end( args );
7539 
7540 /* If an error occurred, clean up by deleting the new object. */
7541          if ( !astOK ) new = astDelete( new );
7542       }
7543    }
7544 
7545 /* Return a pointer to the new Plot. */
7546    return new;
7547 }
7548 
astInitPlot3D_(void * mem,size_t size,int init,AstPlot3DVtab * vtab,const char * name,AstFrame * frame,const float * graphbox,const double * basebox,int * status)7549 AstPlot3D *astInitPlot3D_( void *mem, size_t size, int init,
7550                            AstPlot3DVtab *vtab, const char *name,
7551                            AstFrame *frame, const float *graphbox,
7552                            const double *basebox, int *status ) {
7553 /*
7554 *+
7555 *  Name:
7556 *     astInitPlot3D
7557 
7558 *  Purpose:
7559 *     Initialise a Plot3D.
7560 
7561 *  Type:
7562 *     Protected function.
7563 
7564 *  Synopsis:
7565 *     #include "plot3d.h"
7566 *     AstPlot3D *astInitPlot3D( void *mem, size_t size, int init,
7567 *                               AstPlotVtab *vtab, const char *name,
7568 *                               AstFrame *frame, const float *graphbox,
7569 *                               const double *basebox )
7570 
7571 *  Class Membership:
7572 *     Plot3D initialiser.
7573 
7574 *  Description:
7575 *     This function is provided for use by class implementations to
7576 *     initialise a new Plot3D object. It allocates memory (if
7577 *     necessary) to accommodate the Plot3D plus any additional data
7578 *     associated with the derived class. It then initialises a
7579 *     Plot3D structure at the start of this memory. If the "init"
7580 *     flag is set, it also initialises the contents of a virtual function
7581 *     table for a Plot3D at the start of the memory passed via the
7582 *     "vtab" parameter.
7583 
7584 *  Parameters:
7585 *     mem
7586 *        A pointer to the memory in which the Plot3D is to be
7587 *        created. This must be of sufficient size to accommodate the
7588 * 	 Plot3D data (sizeof(Plot3D)) plus any data used by
7589 * 	 the derived class. If a value of NULL is given, this function
7590 *	 will allocate the memory itself using the "size" parameter to
7591 *	 determine its size.
7592 *     size
7593 *        The amount of memory used by the Plot3D (plus derived
7594 *	 class data). This will be used to allocate memory if a value of
7595 *	 NULL is given for the "mem" parameter. This value is also stored
7596 *	 in the Plot3D structure, so a valid value must be supplied
7597 *	 even if not required for allocating memory.
7598 *     init
7599 *        A logical flag indicating if the Plot3D's virtual function
7600 *	 table is to be initialised. If this value is non-zero, the
7601 *	 virtual function table will be initialised by this function.
7602 *     vtab
7603 *        Pointer to the start of the virtual function table to be
7604 *	 associated with the new Plot3D.
7605 *     name
7606 *        Pointer to a constant null-terminated character string which
7607 *	 contains the name of the class to which the new object belongs
7608 *	 (it is this pointer value that will subsequently be returned by
7609 *	 the astGetClass method).
7610 *     fset
7611 *        A pointer to the Frame or Frameset to be annotated.
7612 *     graphbox
7613 *        A pointer to an array of 6 values giving the graphics coordinates
7614 *        of the bottom left and top right corners of a box on the graphics
7615 *        output device. The first triple of values should be the graphics
7616 *        coordinates of the bottom left corner of the box and the second
7617 *        triple of values are the graphics coordinates of the top right corner.
7618 *     basebox
7619 *        A pointer to an array of 6 values giving the coordinates in the
7620 *        supplied Frame or base Frame of the supplied FrameSet at the bottom
7621 *        left and top right corners of the box specified by parameter graphbox.
7622 *        These should be supplied in the same order as for parameter "graphbox".
7623 
7624 *  Returned Value:
7625 *     A pointer to the new Plot3D.
7626 
7627 *  Notes:
7628 *     -  A null pointer will be returned if this function is invoked with the
7629 *     global error status set, or if it should fail for any reason.
7630 *-
7631 */
7632 
7633 /* Local Variables: */
7634    AstFrame *baseframe = NULL;  /* Pointer to base frame */
7635    AstFrame *graphicsframe = NULL; /* Pointer to graphics frame */
7636    AstFrameSet *fset0 = NULL;   /* The n-D FrameSet to be annotated */
7637    AstFrameSet *fset = NULL;    /* The 2-D FrameSet to be annotated */
7638    AstMapping *map = NULL;      /* Mapping for converting bbox -> gbox */
7639    AstPlot3D *new = NULL;       /* Pointer to new Plot3D */
7640    char *mess = NULL;           /* Pointer to a descriptive message */
7641    double djunkbox[ 4 ] = { 0.0, 0.0, 1.0, 1.0 }; /* Dummy 2D basebox */
7642    float fjunkbox[ 4 ] = { 0.0, 0.0, 1.0, 1.0 }; /* Dummy 2D graphbox */
7643    int bi;                      /* Index of base frame */
7644    int ci;                      /* Index of current frame */
7645    int i;                       /* Loop count */
7646    int ii;                      /* Loop count */
7647    int naxes;                   /* No. of axes in frame */
7648    int nfrm;                    /* Number of Frames in frameset */
7649 
7650 /* Check the global status. */
7651    if ( !astOK ) return NULL;
7652 
7653 /* If necessary, initialise the virtual function table. */
7654    if ( init ) astInitPlot3DVtab( vtab, name );
7655 
7656 /* First of all we need to ensure that we have a FrameSet and a base
7657    Frame on which to base the new Plot3D. If a NULL Frame pointer was
7658    supplied, create a default 3-D Frame, and then create a FrameSet
7659    containing just this default Frame. Also store a pointer to a
7660    message which can be used to describe the object within error
7661    messages. */
7662    if( !frame ){
7663       baseframe = astFrame( 3, "", status );
7664       fset = astFrameSet( baseframe, "", status );
7665       mess = "default 3-d Frame";
7666 
7667 /* If an object was supplied, report an error if it is not a Frame or
7668    an object derived from a Frame (such as a FrameSet). */
7669    } else if( !astIsAFrame( frame ) ){
7670       if( astOK ){
7671          astError( AST__BDOBJ, "astInitPlot3D(%s): Supplied Object (class '%s') "
7672                    "is not a Frame.", status, name, astGetClass( frame ) );
7673       }
7674 
7675 /* If the supplied object is a Plot3D or an object derived from a Plot3D
7676    (a Plot3D is a sort of Frame and so will pass the above test), extract a
7677    FrameSet from the Plot3D, and clear the Domain attribute for any existing
7678    Frames which have Domain GRAPHICS. */
7679    } else if( astIsAPlot3D( frame ) ){
7680       fset0 = astFrameSet( frame, "", status );
7681       fset = astCopy( fset0 );
7682       fset0 = astAnnul( fset0 );
7683 
7684       for( i = 0; i < astGetNframe( fset ); i++ ) {
7685          graphicsframe = astGetFrame( fset, i );
7686          if( !strcmp( astGetDomain( graphicsframe ), "GRAPHICS" ) ) {
7687             astClearDomain( graphicsframe );
7688          }
7689          graphicsframe = astAnnul( graphicsframe );
7690       }
7691 
7692       baseframe = astGetFrame( fset, astGetBase( fset ) );
7693       mess = "base Frame of the supplied Plot3D";
7694 
7695 /* If the object is not a FrameSet, create a FrameSet holding the
7696    supplied Frame. If the Frame is not 3D, an extra 3D Frame is
7697    included in the FrameSet derived from axes 1, 2 and 3 of the supplied
7698    Frame. This new Frame becomes the base Frame. */
7699    } else if( !astIsAFrameSet( frame ) ){
7700       fset0 = astFrameSet( frame, "", status );
7701       mess = "supplied Frame";
7702       fset = Fset3D( fset0, AST__BASE, status );
7703       fset0 = astAnnul( fset0 );
7704       baseframe = astGetFrame( fset, astGetBase( fset ) );
7705 
7706 /* If a FrameSet was supplied, ensure it has a 3D base Frame.
7707    If the supplied FrameSet is not 3D, then a new base Frame is
7708    inserted into it which is derived from axes 1, 2 and 3 of the
7709    original base Frame. */
7710    } else {
7711       fset = Fset3D( (AstFrameSet *) frame, AST__BASE, status );
7712       baseframe = astGetFrame( fset, astGetBase( fset ) );
7713       mess = "base Frame of the supplied FrameSet";
7714    }
7715 
7716 /* Check that there are 3 axes in the base frame of the FrameSet. */
7717    naxes = astGetNaxes( baseframe );
7718    if ( naxes != 3 && astOK ) {
7719       astError( AST__NAXIN, "astInitPlot3D(%s): Number of axes (%d) in the %s "
7720                 "is invalid - this number should be 3.", status, name, naxes, mess );
7721    }
7722 
7723 /* Check that no dimension of the graphbox is bad. */
7724    if( astISBAD(graphbox[0]) || astISBAD(graphbox[1]) ||
7725        astISBAD(graphbox[2]) || astISBAD(graphbox[3]) ||
7726        astISBAD(graphbox[4]) || astISBAD(graphbox[5]) ) {
7727       astError( AST__BADBX, "astInitPlot3D(%s): The plotting volume has undefined limits "
7728                 "in the graphics world coordinate system.", status, name );
7729    }
7730 
7731 /* Check that no dimension of the graphbox is zero. */
7732    if( ( graphbox[ 3 ] == graphbox[ 0 ] ||
7733          graphbox[ 4 ] == graphbox[ 1 ] ||
7734          graphbox[ 5 ] == graphbox[ 2 ] ) && astOK ){
7735       astError( AST__BADBX, "astInitPlot3D(%s): The plotting volume has zero size "
7736                 "in the graphics world coordinate system.", status, name );
7737    }
7738 
7739 /* Check that no dimension of the basebox is bad. */
7740    if( astISBAD(basebox[0]) || astISBAD(basebox[1]) ||
7741        astISBAD(basebox[2]) || astISBAD(basebox[3]) ||
7742        astISBAD(basebox[4]) || astISBAD(basebox[5]) ) {
7743       astError( AST__BADBX, "astInitPlot3D(%s): The limits of "
7744                 "the %s are undefined or bad.", status, name, name );
7745    }
7746 
7747 /* Create a Frame which describes the graphics world coordinate system. */
7748    graphicsframe = astFrame( 3, "Domain=GRAPHICS,Title=Graphical Coordinates", status );
7749 
7750 /* Initialise a 2D Plot structure (the parent class) as the first component
7751    within the Plot3D structure, allocating memory if necessary. We supply
7752    dummy arguments since we will not be using the parent Plot class to
7753    draw anything. We supply a NULL vtab pointer so that methods defined by
7754    the Plot class will be used during the construction of the Plot3D. Once
7755    the Plot3D is fully constructed, we will use astSetVtab to establish
7756    the correct vtab. */
7757    new = (AstPlot3D *) astInitPlot( mem, size, 0, NULL, name, NULL, fjunkbox,
7758                                     djunkbox );
7759    if ( astOK ) {
7760 
7761 /* Initialise the Plot3D data. */
7762 /* ----------------------------- */
7763 
7764 /* Remove all Frames from the parent FrameSet except for the base (2D graphics)
7765    Frame (we leave this last Frame since an error is reported if the last
7766    Frame is removed from a FrameSet). We do this by repeatedly removing the
7767    first Frame, causing all remaining Frames to have their index reduced by 1.
7768    When the base Frame arrives at index 1, we skip it and start removing the
7769    second frame instead. */
7770       nfrm = astGetNframe( new );
7771       i = 1;
7772       for( ii = 0; ii < nfrm; ii++ ) {
7773          if( i > 1 || astGetBase( new ) != 1 ) {
7774             astRemoveFrame( new, i );
7775          } else {
7776             i = 2;
7777          }
7778       }
7779 
7780 /* Add in the 3D graphics Frame, using a PermMap to connect it to the
7781    2D graphics Frame. */
7782       map = (AstMapping *) astPermMap( 2, NULL, 3, NULL, NULL, "", status );
7783       astAddFrame( new, 1, map, graphicsframe );
7784       map = astAnnul( map );
7785 
7786 /* And remove the 2D GRAPHICS Frame, leaving just the 3D GRAPHICS Frame
7787    in the FrameSet, with index 1. */
7788       astRemoveFrame( new, 1 );
7789 
7790 /* Get the index of the current (physical) and base (pixel) Frames in
7791    the supplied FrameSet. */
7792       bi = astGetBase( fset );
7793       ci = astGetCurrent( fset );
7794 
7795 /* Temporarily set the current Frame to be the pixel frame. */
7796       astSetCurrent( fset, bi );
7797 
7798 /* Get a double precision version of "graphbox", and store it in the
7799    Plot3D structure. */
7800       new->gbox[ 0 ] = (double) graphbox[ 0 ];
7801       new->gbox[ 1 ] = (double) graphbox[ 1 ];
7802       new->gbox[ 2 ] = (double) graphbox[ 2 ];
7803       new->gbox[ 3 ] = (double) graphbox[ 3 ];
7804       new->gbox[ 4 ] = (double) graphbox[ 4 ];
7805       new->gbox[ 5 ] = (double) graphbox[ 5 ];
7806 
7807 /* The base Frame of the supplied FrameSet is mapped linearly onto the
7808    graphics frame. Create a WinMap that maps the base box (within the
7809    base Frame of the supplied FrameSet) onto the graphics box. */
7810       map = (AstMapping *) astWinMap( 3, new->gbox, new->gbox + 3, basebox,
7811                                       basebox + 3, "", status );
7812 
7813 /* Add the supplied FrameSet into the Plot3D (i.e. FrameSet) created
7814    earlier. This leaves the graphics frame with index 1 in the
7815    returned  Plot3D. */
7816       astAddFrame( (AstFrameSet *) new, 1, map, fset );
7817       map = astAnnul( map );
7818 
7819 /* Set the current Frame in the Plot to be the physical coordinate Frame
7820    (with index incremented by one because the graphics Frame has been added). */
7821       astSetCurrent( (AstFrameSet *) new, ci + 1 );
7822 
7823 /* Note the index of the original base Frame in the Plot3D FrameSet */
7824       new->pix_frame = bi + 1;
7825 
7826 /* Re-establish the original current Frame in the supplied FrameSet. */
7827       astSetCurrent( fset, ci );
7828 
7829 /* Initialise the Plot pointers. */
7830       new->plotxy = NULL;
7831       new->plotxz = NULL;
7832       new->plotyz = NULL;
7833 
7834 /* Initialise other attributes */
7835       new->rootcorner = -1;
7836 
7837 /* Initialise the normal vector to the plane used by astText and astMark. */
7838       new->norm[ 0 ] = AST__BAD;
7839       new->norm[ 1 ] = AST__BAD;
7840       new->norm[ 2 ] = AST__BAD;
7841 
7842 /* Create three 2D Plots to describe the three planes in the cube. */
7843       CreatePlots( new, fset, graphbox, basebox, status );
7844 
7845 /* Ensure that attempts to use the graphics interface of the parent
7846    Plot structure get forwarded to the relevant 3D routines defined in
7847    this class. */
7848       astGrfSet( new, "Attr", (AstGrfFun) Attr3D );
7849       astSetGrf( new, 1 );
7850 
7851 /* Change the virtual function table stored in the new Plot3D, from the Plot
7852    vtab (established when astINitPlot was called above), to the supplied
7853    vtab. */
7854       if( vtab ) astSetVtab( new, vtab );
7855 
7856 /* Ensure that these Plots use the grf functions defined by this class
7857    (Plot3D). This means that whenever a Plot draws anything, it will use
7858    the appropriate grf function defined in this class to do the drawing.
7859    The grf functions defined in this class, convert the grf call into a
7860    grf3D call apprpriate the plane spanned by the Plot. */
7861       Set3DGrf( new, new->plotxy, XY, status );
7862       Set3DGrf( new, new->plotxz, XZ, status );
7863       Set3DGrf( new, new->plotyz, YZ, status );
7864 
7865 /* Set up the Edges attributes in the encapsulated Plots so that labels
7866    appear on the requited edges. Initially, the root corner is "LLL"
7867    (i.e. the lower bound on every axis). */
7868       ChangeRootCorner( new, 0, 0, status );
7869    }
7870 
7871 /* Annul the frame. */
7872    graphicsframe = astAnnul( graphicsframe );
7873 
7874 /* If an error occurred, clean up by deleting the new object. */
7875    if ( !astOK ) new = astDelete( new );
7876 
7877 /* Annul the pointer to the base Frame and FrameSet. */
7878    baseframe = astAnnul( baseframe );
7879    fset = astAnnul( fset );
7880 
7881 /* Return a pointer to the new object. */
7882    return new;
7883 }
7884 
7885 
astLoadPlot3D_(void * mem,size_t size,AstPlot3DVtab * vtab,const char * name,AstChannel * channel,int * status)7886 AstPlot3D *astLoadPlot3D_( void *mem, size_t size, AstPlot3DVtab *vtab,
7887                            const char *name, AstChannel *channel, int *status ) {
7888 /*
7889 *+
7890 *  Name:
7891 *     astLoadPlot3D
7892 
7893 *  Purpose:
7894 *     Load a Plot3D.
7895 
7896 *  Type:
7897 *     Protected function.
7898 
7899 *  Synopsis:
7900 *     #include "plot3d.h"
7901 *     AstPlot3D *astLoadPlot3D( void *mem, size_t size,
7902 *                               AstPlot3DVtab *vtab,
7903 *                               const char *name, AstChannel *channel )
7904 
7905 *  Class Membership:
7906 *     Plot3D loader.
7907 
7908 *  Description:
7909 *     This function is provided to load a new Plot3D using data read
7910 *     from a Channel. It first loads the data used by the parent class
7911 *     (which allocates memory if necessary) and then initialises a
7912 *     Plot3D structure in this memory, using data read from the
7913 *     input Channel.
7914 
7915 *  Parameters:
7916 *     mem
7917 *        A pointer to the memory into which the Plot3D is to be
7918 *        loaded.  This must be of sufficient size to accommodate the
7919 *        Plot3D data (sizeof(Plot3D)) plus any data used by
7920 *        derived classes. If a value of NULL is given, this function
7921 *        will allocate the memory itself using the "size" parameter to
7922 *        determine its size.
7923 *     size
7924 *        The amount of memory used by the Plot3D (plus derived class
7925 *        data).  This will be used to allocate memory if a value of
7926 *        NULL is given for the "mem" parameter. This value is also
7927 *        stored in the Plot3D structure, so a valid value must be
7928 *        supplied even if not required for allocating memory.
7929 *
7930 *        If the "vtab" parameter is NULL, the "size" value is ignored
7931 *        and sizeof(AstPlot3D) is used instead.
7932 *     vtab
7933 *        Pointer to the start of the virtual function table to be
7934 *        associated with the new Plot3D. If this is NULL, a pointer
7935 *        to the (static) virtual function table for the Plot3D class
7936 *        is used instead.
7937 *     name
7938 *        Pointer to a constant null-terminated character string which
7939 *        contains the name of the class to which the new object
7940 *        belongs (it is this pointer value that will subsequently be
7941 *        returned by the astGetClass method).
7942 *
7943 *        If the "vtab" parameter is NULL, the "name" value is ignored
7944 *        and a pointer to the string "Plot3D" is used instead.
7945 
7946 *  Returned Value:
7947 *     A pointer to the new Plot3D.
7948 
7949 *  Notes:
7950 *     - A null pointer will be returned if this function is invoked
7951 *     with the global error status set, or if it should fail for any
7952 *     reason.
7953 *-
7954 */
7955 
7956 /* Local Constants: */
7957 #define KEY_LEN 50               /* Maximum length of a keyword */
7958 
7959 /* Local Variables: */
7960    astDECLARE_GLOBALS
7961    AstPlot3D *new;
7962    char key[ KEY_LEN + 1 ];
7963    char *text;
7964    int axis;
7965    int i;
7966 
7967 /* Initialise. */
7968    new = NULL;
7969 
7970 /* Check the global error status. */
7971    if( !astOK ) return new;
7972 
7973 /* Get a pointer to the thread specific global data structure. */
7974    astGET_GLOBALS(channel);
7975 
7976 /* If a NULL virtual function table has been supplied, then this is
7977    the first loader to be invoked for this Plot3D. In this case the
7978    Plot3D belongs to this class, so supply appropriate values to be
7979    passed to the parent class loader (and its parent, etc.). */
7980    if ( !vtab ) {
7981       size = sizeof( AstPlot3D );
7982       vtab = &class_vtab;
7983       name = "Plot3D";
7984 
7985 /* If required, initialise the virtual function table for this class. */
7986       if ( !class_init ) {
7987          astInitPlot3DVtab( vtab, name );
7988          class_init = 1;
7989       }
7990    }
7991 
7992 /* Allocate memory to hold the new Object. We allocate it now rather than
7993    waiting for astInitObject to allocate it so that we can pass a NULL
7994    vtab pointer to the Plot loader, thus causing the Plot loader to use the
7995    function implementations provided by the Plot class rather than those
7996    provided by the class being instantiated. */
7997    if( !mem ) mem = astMalloc( size );
7998 
7999 /* Invoke the parent class loader to load data for all the ancestral
8000    classes of the current one, returning a pointer to the resulting
8001    partly-built Plot3D. Pass a NULL vtab pointer so that the "new" object
8002    will be loaded using Plot methods rather than than Plot3D methods.
8003    This is important because the implementations provided by the Plot3D
8004    class for the Plot attribute accessors require the existence of the
8005    encapsulated Plots held within the Plot3D, but these have not yet been
8006    created. */
8007    new = astLoadPlot( mem, size, NULL, name, channel );
8008    if ( astOK ) {
8009 
8010 /* Now modify the new object to use the supplied vtab. */
8011       astSetVtab( new, vtab );
8012 
8013 /* Read input data. */
8014 /* ================ */
8015 /* Request the input Channel to read all the input data appropriate to
8016    this class into the internal "values list". */
8017       astReadClassData( channel, "Plot3D" );
8018 
8019 /* Now read each individual data item from this list and use it to
8020    initialise the appropriate instance variable(s) for this class. */
8021 
8022 /* In the case of attributes, we first read the "raw" input value,
8023    supplying the "unset" value as the default. If a "set" value is
8024    obtained, we then use the appropriate (private) Set... member
8025    function to validate and set the value properly. */
8026 
8027 /* Norm. */
8028 /* ----- */
8029       for( axis = 0; axis < 3; axis++ ) {
8030          (void) sprintf( key, "norm%d", axis + 1 );
8031          new->norm[ axis ] = astReadDouble( channel, key, AST__BAD );
8032          if( TestNorm( new, axis, status ) ) SetNorm( new, axis, new->norm[ axis ], status );
8033       }
8034 
8035 /* RootCorner. */
8036 /* ----------- */
8037       text = astReadString( channel, "rootcn", " " );
8038       if( astOK && strcmp( text, " " ) ) {
8039          new->rootcorner = RootCornerInt( text, status );
8040          if( new->rootcorner < 0 && astOK ) {
8041             astError( AST__INTER, "astRead(Plot3D): Corrupt Plot3D contains "
8042                       "invalid RootCorner attribute value (%s).", status, text );
8043          }
8044       } else {
8045          new->rootcorner = -1;
8046       }
8047       text = astFree( text );
8048 
8049 /* Labelled axes */
8050       new->axis_plot1[0] = astReadInt( channel, "axplx1", -1 );
8051       new->axis_plot1[1] = astReadInt( channel, "axply1", -1 );
8052       new->axis_plot1[2] = astReadInt( channel, "axplz1", -1 );
8053 
8054       new->axis_index1[0] = astReadInt( channel, "axinx1", -1 );
8055       new->axis_index1[1] = astReadInt( channel, "axiny1", -1 );
8056       new->axis_index1[2] = astReadInt( channel, "axinz1", -1 );
8057 
8058 /* Unlabelled axes */
8059       new->axis_plot2[0] = astReadInt( channel, "axplx2", -1 );
8060       new->axis_plot2[1] = astReadInt( channel, "axply2", -1 );
8061       new->axis_plot2[2] = astReadInt( channel, "axplz2", -1 );
8062 
8063       new->axis_index2[0] = astReadInt( channel, "axinx2", -1 );
8064       new->axis_index2[1] = astReadInt( channel, "axiny2", -1 );
8065       new->axis_index2[2] = astReadInt( channel, "axinz2", -1 );
8066 
8067 /* Plot that spans two connected 3D axes. */
8068       new->baseplot = astReadInt( channel, "basepl", -1 );
8069 
8070 /* XY Plot */
8071       new->plotxy = astReadObject( channel, "plotxy", NULL );
8072 
8073 /* XZ Plot */
8074       new->plotxz = astReadObject( channel, "plotxz", NULL );
8075 
8076 /* YZ Plot */
8077       new->plotyz = astReadObject( channel, "plotyz", NULL );
8078 
8079 /* The index within the Plot3D FrameSet, of the original base Frame in
8080    the FrameSet supplied when the Plot3D was constructed. */
8081       new->pix_frame = astReadInt( channel, "pixfrm", AST__NOFRAME );
8082 
8083 /* Ensure that these Plots use the grf functions defined by this class
8084    (Plot3D). This means that whener a Plot draws anything, it will use
8085    the appropriate grf function defined in this class to do the drawing.
8086    The grf functions defined in this class, convert the grf call into a
8087    grf3D call apprpriate the plane spanned by the Plot. */
8088       Set3DGrf( new, new->plotxy, XY, status );
8089       Set3DGrf( new, new->plotxz, XZ, status );
8090       Set3DGrf( new, new->plotyz, YZ, status );
8091 
8092 /* For attributes of the parent Plot class will have been loaded
8093    each attribute that has a set value in the parent Plot structure,
8094    re-set the value so that it gets copied to the copy the  to the
8095    encapsulated Plots. First do axis specific attributes. */
8096 
8097 #define COPY_ATTR(attr,nval) \
8098    for( i = 0; i < nval; i++ ) { \
8099       if( astTest##attr(new,i) ) astSet##attr(new,i,astGet##attr(new,i)); \
8100    }
8101 
8102    COPY_ATTR(MinTick,3)
8103    COPY_ATTR(Abbrev,3)
8104    COPY_ATTR(Gap,3)
8105    COPY_ATTR(LogGap,3)
8106    COPY_ATTR(LogPlot,3)
8107    COPY_ATTR(LogTicks,3)
8108    COPY_ATTR(LogLabel,3)
8109    COPY_ATTR(LabelUp,3)
8110    COPY_ATTR(DrawAxes,3)
8111    COPY_ATTR(LabelUnits,3)
8112    COPY_ATTR(MinTickLen,3)
8113    COPY_ATTR(MajTickLen,3)
8114    COPY_ATTR(NumLab,3)
8115    COPY_ATTR(NumLabGap,3)
8116    COPY_ATTR(TextLab,3)
8117    COPY_ATTR(TextLabGap,3)
8118 
8119    COPY_ATTR(Style,AST__NPID)
8120    COPY_ATTR(Font,AST__NPID)
8121    COPY_ATTR(Colour,AST__NPID)
8122    COPY_ATTR(Width,AST__NPID)
8123    COPY_ATTR(Size,AST__NPID)
8124 
8125 #undef COPY_ATTR
8126 
8127 /* Now do attributes that are not axis specific. */
8128 
8129 #define COPY_ATTR(attr) \
8130    if( astTest##attr(new) ) astSet##attr(new,astGet##attr(new));
8131 
8132    COPY_ATTR(Ink)
8133    COPY_ATTR(Tol)
8134    COPY_ATTR(Invisible)
8135    COPY_ATTR(TickAll)
8136    COPY_ATTR(ForceExterior)
8137    COPY_ATTR(Border)
8138    COPY_ATTR(Clip)
8139    COPY_ATTR(ClipOp)
8140    COPY_ATTR(Escape)
8141    COPY_ATTR(Grid)
8142    COPY_ATTR(Labelling)
8143 
8144 #undef COPY_ATTR
8145 
8146 /* If an error occurred, clean up by deleting the new Plot3D. */
8147       if ( !astOK ) new = astDelete( new );
8148    }
8149 
8150 /* Return the new Plot3D pointer. */
8151    return new;
8152 
8153 /* Undefine macros local to this function. */
8154 #undef KEY_LEN
8155 }
8156 
8157 /* Virtual function interfaces. */
8158 /* ============================ */
8159 /* These provide the external interface to the virtual functions defined by
8160    this class. Each simply checks the global error status and then locates and
8161    executes the appropriate member function, using the function pointer stored
8162    in the object's virtual function table (this pointer is located using the
8163    astMEMBER macro defined in "object.h").
8164 
8165    Note that the member function may not be the one defined here, as it may
8166    have been over-ridden by a derived class. However, it should still have the
8167    same interface. */
8168 
astClearRootCorner_(AstPlot3D * this,int * status)8169 void astClearRootCorner_( AstPlot3D *this, int *status ) {
8170    if ( !astOK ) return;
8171    (**astMEMBER(this,Plot3D,ClearRootCorner))( this, status );
8172 }
8173 
astSetRootCorner_(AstPlot3D * this,int value,int * status)8174 void astSetRootCorner_( AstPlot3D *this, int value, int *status ) {
8175    if ( !astOK ) return;
8176    (**astMEMBER(this,Plot3D,SetRootCorner))( this, value, status );
8177 }
8178 
8179 
8180 
8181 
8182 /* Special public interface functions. */
8183 /* =================================== */
8184 /* These provide the public interface to certain special functions
8185    whose public interface cannot be handled using macros (such as
8186    astINVOKE) alone. In general, they are named after the
8187    corresponding protected version of the function, but with "Id"
8188    appended to the name. */
8189 
8190 /* Public Interface Function Prototypes. */
8191 /* ------------------------------------- */
8192 /* The following functions have public prototypes only (i.e. no
8193    protected prototypes), so we must provide local prototypes for use
8194    within this module. */
8195 AstPlot3D *astPlot3DId_( void *frame_void, const float graphbox[6],
8196                          const double basebox[6], const char *, ... );
8197 
8198 /* Special interface function implementations. */
8199 /* ------------------------------------------- */
astPlot3DId_(void * frame_void,const float graphbox[6],const double basebox[6],const char * options,...)8200 AstPlot3D *astPlot3DId_( void *frame_void, const float graphbox[6],
8201                          const double basebox[6], const char *options, ... ) {
8202 /*
8203 *++
8204 *  Name:
8205 c     astPlot3D
8206 f     AST_PLOT3D
8207 
8208 *  Purpose:
8209 *     Create a Plot3D.
8210 
8211 *  Type:
8212 *     Public function.
8213 
8214 *  Synopsis:
8215 c     #include "plot3d.h"
8216 c     AstPlot3D *astPlot3D( AstFrame *frame, const float graphbox[ 6 ],
8217 c                           const double basebox[ 6 ], const char *options, ... )
8218 f     RESULT = AST_PLOT3D( FRAME, GRAPHBOX, BASEBOX, OPTIONS, STATUS )
8219 
8220 *  Class Membership:
8221 *     Plot3D constructor.
8222 
8223 *  Description:
8224 *     This function creates a new Plot3D and optionally initialises
8225 *     its attributes.
8226 *
8227 *     A Plot3D is a specialised form of Plot that provides facilities
8228 *     for producing 3D graphical output.
8229 
8230 *  Parameters:
8231 c     frame
8232 f     FRAME = INTEGER (Given)
8233 *        Pointer to a Frame describing the physical coordinate system
8234 *        in which to plot. A pointer to a FrameSet may also be given,
8235 *        in which case its current Frame will be used to define the
8236 *        physical coordinate system and its base Frame will be mapped
8237 *        on to graphical coordinates (see below).
8238 *
8239 *        If a null Object pointer (AST__NULL) is given, a default
8240 *        3-dimensional Frame will be used to describe the physical
8241 *        coordinate system. Labels, etc. may then be attached to this
8242 *        by setting the appropriate Frame attributes
8243 *        (e.g. Label(axis)) for the Plot.
8244 c     graphbox
8245 f     GRAPHBOX( 6 ) = REAL (Given)
8246 *        An array giving the position and extent of the plotting volume
8247 *        (within the plotting space of the underlying graphics system)
8248 *        in which graphical output is to appear. This must be
8249 *        specified using graphical coordinates appropriate to the
8250 *        underlying graphics system.
8251 *
8252 *        The first triple of values should give the coordinates of the
8253 *        bottom left corner of the plotting volume and the second triple
8254 *        should give the coordinates of the top right corner. The
8255 *        coordinate on the horizontal axis should be given first in
8256 *        each pair. Note that the order in which these points are
8257 *        given is important because it defines up, down, left and
8258 *        right for subsequent graphical operations.
8259 c     basebox
8260 f     BASEBOX( 6 ) = DOUBLE PRECISION (Given)
8261 *        An array giving the coordinates of two points in the supplied
8262 *        Frame (or in the base Frame if a FrameSet was supplied) which
8263 *        correspond to the bottom left and top right corners of the
8264 *        plotting volume, as specified above. This range of coordinates
8265 *        will be mapped linearly on to the plotting area. The
8266 *        coordinates should be given in the same order as above.
8267 c     options
8268 f     OPTIONS = CHARACTER * ( * ) (Given)
8269 c        Pointer to a null-terminated string containing an optional
8270 c        comma-separated list of attribute assignments to be used for
8271 c        initialising the new Plot3D. The syntax used is identical to
8272 c        that for the astSet function and may include "printf" format
8273 c        specifiers identified by "%" symbols in the normal way.
8274 c        If no initialisation is required, a zero-length string may be
8275 c        supplied.
8276 f        A character string containing an optional comma-separated
8277 f        list of attribute assignments to be used for initialising the
8278 f        new Plot3D. The syntax used is identical to that for the
8279 f        AST_SET routine. If no initialisation is required, a blank
8280 f        value may be supplied.
8281 c     ...
8282 c        If the "options" string contains "%" format specifiers, then
8283 c        an optional list of additional arguments may follow it in
8284 c        order to supply values to be substituted for these
8285 c        specifiers. The rules for supplying these are identical to
8286 c        those for the astSet function (and for the C "printf"
8287 c        function).
8288 f     STATUS = INTEGER (Given and Returned)
8289 f        The global status.
8290 
8291 *  Returned Value:
8292 c     astPlot3D()
8293 f     AST_PLOT3D = INTEGER
8294 *        A pointer to the new Plot3D.
8295 
8296 *  Notes:
8297 *     - The base Frame of the returned Plot3D will be a new Frame which
8298 *     is created by this function to represent the coordinate system
8299 *     of the underlying graphics system (graphical coordinates). It is
8300 *     given a Frame index of 1 within the Plot3D. The choice of base
8301 *     Frame (Base attribute) should not, in general, be changed once a
8302 *     Plot3D has been created (although you could use this as a way of
8303 *     moving the plotting area around on the plotting surface).
8304 c     - If a Frame is supplied (via the "frame" pointer), then it
8305 f     - If a Frame is supplied (via the FRAME pointer), then it
8306 *     becomes the current Frame of the new Plot3D and is given a Frame
8307 *     index of 2.
8308 c     - If a FrameSet is supplied (via the "frame" pointer), then
8309 f     - If a FrameSet is supplied (via the FRAME pointer), then
8310 *     all the Frames within this FrameSet become part of the new Plot3D
8311 *     (where their Frame indices are increased by 1), with the
8312 *     FrameSet's current Frame becoming the current Frame of the Plot3D.
8313 *     - At least one of the three axes of the current Frame must be
8314 *     independent of the other two current Frame axes.
8315 *     - If a null Object pointer (AST__NULL) is supplied (via the
8316 c     "frame" pointer), then the returned Plot3D will contain two
8317 f     FRAME pointer), then the returned Plot3D will contain two
8318 *     Frames, both created by this function. The base Frame will
8319 *     describe graphics coordinates (as above) and the current Frame
8320 *     will be a basic Frame with no attributes set (this will
8321 *     therefore give default values for such things as the Plot3D Title
8322 *     and the Label on each axis). Physical coordinates will be mapped
8323 *     linearly on to graphical coordinates.
8324 *     - An error will result if the Frame supplied (or the base Frame
8325 *     if a FrameSet was supplied) is not 3-dimensional.
8326 *     - A null Object pointer (AST__NULL) will be returned if this
8327 c     function is invoked with the AST error status set, or if it
8328 f     function is invoked with STATUS set to an error value, or if it
8329 *     should fail for any reason.
8330 *--
8331 
8332 *  Implementation Notes:
8333 *     - This function implements the external (public) interface to
8334 *     the astPlot3D constructor function. It returns an ID value
8335 *     (instead of a true C pointer) to external users, and must be
8336 *     provided because astPlot3D_ has a variable argument list which
8337 *     cannot be encapsulated in a macro (where this conversion would
8338 *     otherwise occur).
8339 *     - Because no checking or casting of arguments is performed
8340 *     before the function is invoked, the "frame" parameter is of type
8341 *     (void *) and is converted from an ID value to a pointer and
8342 *     validated within the function itself.
8343 *     - The variable argument list also prevents this function from
8344 *     invoking astPlot3D_ directly, so it must be a
8345 *     re-implementation of it in all respects, except for the final
8346 *     conversion of the result to an ID value.
8347 */
8348 
8349 /* Local Variables: */
8350    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
8351    AstFrame *frame;              /* Pointer to Frame structure */
8352    AstPlot3D *new;               /* Pointer to new Plot3D */
8353    va_list args;                 /* Variable argument list */
8354    int *status;                  /* Pointer to inherited status value */
8355 
8356 /* Get a pointer to the thread specific global data structure. */
8357    astGET_GLOBALS(NULL);
8358 
8359 /* Get a pointer to the inherited status value. */
8360    status = astGetStatusPtr;
8361 
8362 /* Check the global status. */
8363    if ( !astOK ) return NULL;
8364 
8365 /* Initialise variables to avoid "used of uninitialised variable"
8366    messages from dumb compilers. */
8367    new = NULL;
8368 
8369 /* Obtain a Frame pointer from any ID supplied and validate the
8370    pointer to ensure it identifies a valid Frame. */
8371    if( frame_void ){
8372       frame = astVerifyFrame( astMakePointer( frame_void ) );
8373    } else {
8374       frame = NULL;
8375    }
8376 
8377 /* Check the pointer can be used. */
8378    if ( astOK ) {
8379 
8380 /* Initialise the Plot3D, allocating memory and initialising the
8381    virtual function table as well if necessary. */
8382       new = astInitPlot3D( NULL, sizeof( AstPlot3D ), !class_init,
8383                            &class_vtab, "Plot3D", frame, graphbox,
8384                            basebox );
8385 
8386 /* If successful, note that the virtual function table has been
8387    initialised. */
8388       if ( astOK ) {
8389          class_init = 1;
8390 
8391 /* Obtain the variable argument list and pass it along with the
8392    options string to the astVSet method to initialise the new
8393    Plot3D's attributes. */
8394          va_start( args, options );
8395          astVSet( new, options, NULL, args );
8396          va_end( args );
8397 
8398 /* If an error occurred, clean up by deleting the new object. */
8399          if ( !astOK ) new = astDelete( new );
8400       }
8401    }
8402 
8403 /* Return an ID value for the new Plot3D. */
8404    return astMakeId( new );
8405 
8406 }
8407 
8408 
8409 
8410 /* Macros that define method to override the methods of the Plot class
8411    that are not currently implemented by this class. They just report an
8412    error if called. */
8413 
8414 #define METHOD1(name) \
8415 static void name(ARGLIST,int *status){ \
8416    if( !astOK ) return; \
8417    astError( AST__INTER, "ast##name(%s): The ast##name " \
8418              "method cannot be used with a %s (programming error).", status,  \
8419              astGetClass( this ), astGetClass( this ) ); \
8420 }
8421 
8422 #define METHOD2(name,rettype,retval) \
8423 static rettype name(ARGLIST,int *status){ \
8424    if( !astOK ) return retval; \
8425    astError( AST__INTER, "ast##name(%s): The ast##name " \
8426              "method cannot be used with a %s (programming error).", status,  \
8427              astGetClass( this ), astGetClass( this ) ); \
8428    return retval; \
8429 }
8430 
8431 
8432 #define ARGLIST AstPlot *this
8433 METHOD2(GetGrfContext,AstKeyMap *,NULL)
8434 #undef ARGLIST
8435 
8436 #define ARGLIST AstPlot *this
8437 METHOD1(GrfPop)
8438 #undef ARGLIST
8439 
8440 #define ARGLIST AstPlot *this
8441 METHOD1(GrfPush)
8442 #undef ARGLIST
8443 
8444 #define ARGLIST AstPlot *this, const char *name, AstGrfFun fun
8445 METHOD1(GrfSet)
8446 #undef ARGLIST
8447 
8448 #define ARGLIST AstPlot *this, int axis, const double start[], double length
8449 METHOD1(GridLine)
8450 #undef ARGLIST
8451 
8452 #define ARGLIST AstPlot *this, float lbnd[2], float ubnd[2]
8453 METHOD1(BoundingBox)
8454 #undef ARGLIST
8455 
8456 #define ARGLIST AstPlot *this, int iframe, const double lbnd[], const double ubnd[]
8457 METHOD1(Clip)
8458 #undef ARGLIST
8459 
8460 #define ARGLIST AstPlot *this, const double start[], const double finish[]
8461 METHOD1(Curve)
8462 #undef ARGLIST
8463 
8464 #define ARGLIST AstPlot *this, AstMapping *map
8465 METHOD1(GenCurve)
8466 #undef ARGLIST
8467 
8468 
8469 
8470 
8471 
8472 
8473 
8474 
8475