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