1 /*
2 *class++
3 *  Name:
4 *     CmpRegion
5 
6 *  Purpose:
7 *     A combination of two regions within a single Frame
8 
9 *  Constructor Function:
10 c     astCmpRegion
11 f     AST_CMPREGION
12 
13 *  Description:
14 *     A CmpRegion is a Region which allows two component
15 *     Regions (of any class) to be combined to form a more complex
16 *     Region. This combination may be performed a boolean AND, OR
17 *     or XOR (exclusive OR) operator. If the AND operator is
18 *     used, then a position is inside the CmpRegion only if it is
19 *     inside both of its two component Regions. If the OR operator is
20 *     used, then a position is inside the CmpRegion if it is inside
21 *     either (or both) of its two component Regions. If the XOR operator
22 *     is used, then a position is inside the CmpRegion if it is inside
23 *     one but not both of its two component Regions. Other operators can
24 *     be formed by negating one or both component Regions before using
25 *     them to construct a new CmpRegion.
26 *
27 *     The two component Region need not refer to the same coordinate
28 *     Frame, but it must be possible for the
29 c     astConvert
30 f     AST_CONVERT
31 *     function to determine a Mapping between them (an error will be
32 *     reported otherwise when the CmpRegion is created). For instance,
33 *     a CmpRegion may combine a Region defined within an ICRS SkyFrame
34 *     with a Region defined within a Galactic SkyFrame. This is
35 *     acceptable because the SkyFrame class knows how to convert between
36 *     these two systems, and consequently the
37 c     astConvert
38 f     AST_CONVERT
39 *     function will also be able to convert between them. In such cases,
40 *     the second component Region will be mapped into the coordinate Frame
41 *     of the first component Region, and the Frame represented by the
42 *     CmpRegion as a whole will be the Frame of the first component Region.
43 *
44 *     Since a CmpRegion is itself a Region, it can be used as a
45 *     component in forming further CmpRegions. Regions of arbitrary
46 *     complexity may be built from simple individual Regions in this
47 *     way.
48 
49 *  Inheritance:
50 *     The CmpRegion class inherits from the Region class.
51 
52 *  Attributes:
53 *     The CmpRegion class does not define any new attributes beyond those
54 *     which are applicable to all Regions.
55 
56 *  Functions:
57 c     The CmpRegion class does not define any new functions beyond those
58 f     The CmpRegion class does not define any new routines beyond those
59 *     which are applicable to all Regions.
60 
61 *  Copyright:
62 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
63 *     Research Councils
64 *     Copyright (C) 2009 Science & Technology Facilities Council.
65 *     All Rights Reserved.
66 
67 *  Licence:
68 *     This program is free software: you can redistribute it and/or
69 *     modify it under the terms of the GNU Lesser General Public
70 *     License as published by the Free Software Foundation, either
71 *     version 3 of the License, or (at your option) any later
72 *     version.
73 *
74 *     This program is distributed in the hope that it will be useful,
75 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
76 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
77 *     GNU Lesser General Public License for more details.
78 *
79 *     You should have received a copy of the GNU Lesser General
80 *     License along with this program.  If not, see
81 *     <http://www.gnu.org/licenses/>.
82 
83 *  Authors:
84 *     DSB: David S. Berry (Starlink)
85 
86 *  History:
87 *     7-OCT-2004 (DSB):
88 *        Original version.
89 *     28-MAY-2007 (DSB):
90 *        - Corrected RegBaseMesh.
91 *        - In RegBaseBox, if the CmpRegion is bounded find the box by
92 *        finding the extreme position sin a mesh covering the boundary.
93 *     20-JAN-2009 (DSB):
94 *        Over-ride astRegBasePick.
95 *     19-MAR-2009 (DSB):
96 *        Over-ride the astDecompose method.
97 *     8-SEP-2009 (DSB):
98 *        Fix logic in RegTrace.
99 *     9-SEP-2009 (DSB):
100 *        - Added astCmpRegionList
101 *        - Added support for XOR
102 *        - Override astGetObjSize.
103 *     27-APR-2012 (DSB):
104 *        - Cache the bounded property.
105 *        - Speed up plotting of CmpRegions by using the cached negation
106 *        of a Region instead of setting the Regions's Negated flag (which
107 *        causes the Region's cache to be cleared).
108 *     30-APR-2012 (DSB):
109 *        Use geodesic distance to measure distances around the two component
110 *        Regions when tracing the border. Previously, a distance normalised
111 *        from zero to one was used for both component Regions, but this gives
112 *        greater priority to Regions higher in the CmpRegion nesting order,
113 *        resulting in a high chance that lower Regions will not be seen.
114 *     7-JUN-2012 (DSB):
115 *        Override astRegSplit method.
116 *     21-NOV-2012 (DSB):
117 *        Map the regions returned by RegSplit into the current Frame of the
118 *        CmpRegion.
119 *class--
120 */
121 
122 /* Module Macros. */
123 /* ============== */
124 /* Set the name of the class we are implementing. This indicates to
125    the header files that define class interfaces that they should make
126    "protected" symbols available. */
127 #define astCLASS CmpRegion
128 
129 /* Macros which return the maximum and minimum of two values. */
130 #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb))
131 #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb))
132 
133 /* Include files. */
134 /* ============== */
135 /* Interface definitions. */
136 /* ---------------------- */
137 
138 #include "globals.h"             /* Thread-safe global data access */
139 #include "error.h"               /* Error reporting facilities */
140 #include "memory.h"              /* Memory allocation facilities */
141 #include "object.h"              /* Base Object class */
142 #include "pointset.h"            /* Sets of points/coordinates */
143 #include "region.h"              /* Regions (parent class) */
144 #include "channel.h"             /* I/O channels */
145 #include "nullregion.h"          /* Boundless Regions */
146 #include "cmpregion.h"           /* Interface definition for this class */
147 #include "unitmap.h"             /* Unit Mapings */
148 
149 /* Error code definitions. */
150 /* ----------------------- */
151 #include "ast_err.h"             /* AST error codes */
152 
153 /* C header files. */
154 /* --------------- */
155 #include <stdarg.h>
156 #include <stddef.h>
157 #include <string.h>
158 #include <stdio.h>
159 #include <limits.h>
160 
161 /* Module Variables. */
162 /* ================= */
163 
164 /* Address of this static variable is used as a unique identifier for
165    member of this class. */
166 static int class_check;
167 
168 /* Pointers to parent class methods which are extended by this class. */
169 static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
170 static AstRegion *(* parent_getdefunc)( AstRegion *, int * );
171 static void (* parent_setregfs)( AstRegion *, AstFrame *, int * );
172 static AstMapping *(* parent_simplify)( AstMapping *, int * );
173 static int (* parent_equal)( AstObject *, AstObject *, int * );
174 static void (* parent_setclosed)( AstRegion *, int, int * );
175 static void (* parent_setmeshsize)( AstRegion *, int, int * );
176 static void (* parent_clearclosed)( AstRegion *, int * );
177 static void (* parent_clearmeshsize)( AstRegion *, int * );
178 static double (*parent_getfillfactor)( AstRegion *, int * );
179 static void (*parent_regsetattrib)( AstRegion *, const char *, char **, int * );
180 static void (*parent_regclearattrib)( AstRegion *, const char *, char **, int * );
181 static void (* parent_resetcache)( AstRegion *, int * );
182 static int (* parent_getobjsize)( AstObject *, int * );
183 
184 #if defined(THREAD_SAFE)
185 static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
186 #endif
187 
188 
189 #ifdef THREAD_SAFE
190 /* Define how to initialise thread-specific globals. */
191 #define GLOBAL_inits \
192    globals->Class_Init = 0;
193 
194 /* Create the function that initialises global data for this module. */
195 astMAKE_INITGLOBALS(CmpRegion)
196 
197 /* Define macros for accessing each item of thread specific global data. */
198 #define class_init astGLOBAL(CmpRegion,Class_Init)
199 #define class_vtab astGLOBAL(CmpRegion,Class_Vtab)
200 
201 
202 #include <pthread.h>
203 
204 
205 #else
206 
207 
208 /* Define the class virtual function table and its initialisation flag
209    as static variables. */
210 static AstCmpRegionVtab class_vtab;   /* Virtual function table */
211 static int class_init = 0;       /* Virtual function table initialised? */
212 
213 #endif
214 
215 /* External Interface Function Prototypes. */
216 /* ======================================= */
217 /* The following functions have public prototypes only (i.e. no
218    protected prototypes), so we must provide local prototypes for use
219    within this module. */
220 AstCmpRegion *astCmpRegionId_( void *, void *, int, const char *, ... );
221 
222 /* Prototypes for Private Member Functions. */
223 /* ======================================== */
224 static AstMapping *Simplify( AstMapping *, int * );
225 static AstPointSet *RegBaseMesh( AstRegion *, int * );
226 static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
227 static AstRegion *GetDefUnc( AstRegion *, int * );
228 static AstRegion *MatchRegion( AstRegion *, int, AstRegion *, const char *, int * );
229 static AstRegion *RegBasePick( AstRegion *this, int, const int *, int * );
230 static AstRegion **RegSplit( AstRegion *, int *, int * );
231 static double GetFillFactor( AstRegion *, int * );
232 static int CmpRegionList( AstCmpRegion *, int *, AstRegion ***, int * );
233 static int Equal( AstObject *, AstObject *, int * );
234 static int GetBounded( AstRegion *, int * );
235 static int GetObjSize( AstObject *, int * );
236 static int RegPins( AstRegion *, AstPointSet *, AstRegion *, int **, int * );
237 static int RegTrace( AstRegion *, int, double *, double **, int * );
238 static void ClearClosed( AstRegion *, int * );
239 static void ClearMeshSize( AstRegion *, int * );
240 static void Copy( const AstObject *, AstObject *, int * );
241 static void Decompose( AstMapping *, AstMapping **, AstMapping **, int *, int *, int *, int * );
242 static void Delete( AstObject *, int * );
243 static void Dump( AstObject *, AstChannel *, int * );
244 static void GetRegions( AstCmpRegion *, AstRegion **, AstRegion **, int *, int *, int *, int * );
245 static void RegBaseBox( AstRegion *, double *, double *, int * );
246 static void RegBaseBox2( AstRegion *, double *, double *, int * );
247 static void RegClearAttrib( AstRegion *, const char *, char **, int * );
248 static void RegSetAttrib( AstRegion *, const char *, char **, int * );
249 static void ResetCache( AstRegion *this, int * );
250 static void SetBreakInfo( AstCmpRegion *, int, int * );
251 static void SetClosed( AstRegion *, int, int * );
252 static void SetMeshSize( AstRegion *, int, int * );
253 static void SetRegFS( AstRegion *, AstFrame *, int * );
254 static void XORCheck( AstCmpRegion *, int * );
255 
256 #if defined(THREAD_SAFE)
257 static int ManageLock( AstObject *, int, int, AstObject **, int * );
258 #endif
259 
260 
261 /* Member functions. */
262 /* ================= */
CmpRegionList(AstCmpRegion * this,int * nreg,AstRegion *** reg_list,int * status)263 int CmpRegionList( AstCmpRegion *this, int *nreg, AstRegion ***reg_list,
264                    int *status ) {
265 /*
266 *+
267 *  Name:
268 *     astCmpRegionList
269 
270 *  Purpose:
271 *     Decompose a CmpRegion into a sequence of simpler Regions.
272 
273 *  Type:
274 *     Protected virtual function.
275 
276 *  Synopsis:
277 *     #include "cmpregion.h"
278 *     int astCmpRegionList( AstCmpRegion *this, int *nreg,
279 *                           AstRegion ***reg_list, int *status )
280 
281 *  Class Membership:
282 *     CmpRegion method.
283 
284 *  Description:
285 *     This function decomposes a CmpRegion into a sequence of simpler
286 *     Regions which may be applied in sequence to achieve the same
287 *     effect.
288 
289 *  Parameters:
290 *     this
291 *        Pointer to the CmpRegion to be decomposed (the CmpRegion is not
292 *        actually modified by this function).
293 *     nreg
294 *        The address of an int which holds a count of the number of
295 *        individual Regions in the decomposition. On entry, this
296 *        should count the number of Regions already in the
297 *        "*reg_list" array (below). On exit, it is updated to include
298 *        any new Regions appended by this function.
299 *     reg_list
300 *        Address of a pointer to an array of Region pointers. On
301 *        entry, this array pointer should either be NULL (if no
302 *        Regions have yet been obtained) or should point at a
303 *        dynamically allocated array containing Region pointers
304 *        ("*nreg" in number) which have been obtained from a previous
305 *        invocation of this function.
306 *
307 *        On exit, the dynamic array will be enlarged to contain any
308 *        new Region pointers that result from the decomposition
309 *        requested. These pointers will be appended to any previously
310 *        present, and the array pointer will be updated as necessary
311 *        to refer to the enlarged array (any space released by the
312 *        original array will be freed automatically).
313 *
314 *        The new Region pointers returned will identify a sequence of
315 *        Region which, when applied in order, will represent an area
316 *        equivalent to that of the original Region.
317 *
318 *        All the Region pointers returned by this function should be
319 *        annulled by the caller, using astAnnul, when no longer
320 *        required. The dynamic array holding these pointers should
321 *        also be freed, using astFree.
322 
323 *  Returned Value:
324 *     An integer identifying the boolean operation that should be used to
325 *     combine the Regions returned in "reg_list". This will be AST__AND
326 *     or AST__OR.
327 
328 *-
329 */
330 
331 /* Local Variables: */
332    AstCmpRegion *cmpreg;
333    int add;
334    int result;
335 
336 /* Check the global error status. */
337    if ( !astOK ) return AST__AND;
338 
339 /* Check if this CmpRegion has an equivalent XOR representation. Is so,
340    store details of the XOR representation in the CmpRegion. */
341    XORCheck( this, status );
342 
343 /* The CmpRegion class only has full support for AND and OR operators.
344    However, it can also represent XOR operators, but it does this by
345    an equivalent set of AND and OR operators. When an XOR CmpRegion is
346    created, the original supplied argument regions are stored in
347    "this->xor1" and "this->xor2", and the component Regions placed in the
348    new CmpRegion are actually CmpRegions that implement the equivalent
349    of an XOR operation, using AND and OR operators. We want to hide this
350    to the outside world, so if the supplied CmpRegion represents an XOR
351    operation, add the XOR regions to the returned list, and return an
352    XOR operator. */
353    if( this->xor1 ) {
354       *reg_list = astGrow( *reg_list, *nreg + 2, sizeof( AstRegion * ) );
355       if( astOK ) {
356          ( *reg_list )[ (*nreg)++ ] = astClone( this->xor1 );
357          ( *reg_list )[ (*nreg)++ ] = astClone( this->xor2 );
358       }
359       result = AST__XOR;
360 
361 /* For AND and OR operators, we deal with the component Regions directly. */
362    } else {
363 
364 /* If the first component of the supplied CmpRegion is itself a CmpRegion
365    that uses the same boolean operator as "this", call this function
366    recursively to add its component Regions to the returned list. */
367       add = 1;
368       if( astIsACmpRegion( this->region1 ) ) {
369          cmpreg = (AstCmpRegion *) this->region1;
370          if( cmpreg->oper == this->oper ) {
371             (void) CmpRegionList( cmpreg, nreg, reg_list, status );
372             add = 0;
373          }
374       }
375 
376 /* Otherwise, add the component Region directly into the returned list of
377    Regions. */
378       if( add ) {
379          *reg_list = astGrow( *reg_list, *nreg + 1, sizeof( AstRegion * ) );
380          if( astOK ) {
381             ( *reg_list )[ *nreg ] = astClone( this->region1 );
382             ( *nreg )++;
383          }
384       }
385 
386 /* Do the same for the second component region */
387       add = 1;
388       if( astIsACmpRegion( this->region2 ) ) {
389          cmpreg = (AstCmpRegion *) this->region2;
390          if( cmpreg->oper == this->oper ) {
391             (void) CmpRegionList( cmpreg, nreg, reg_list, status );
392             add = 0;
393          }
394       }
395 
396       if( add ) {
397          *reg_list = astGrow( *reg_list, *nreg + 1, sizeof( AstRegion * ) );
398          if( astOK ) {
399             ( *reg_list )[ *nreg ] = astClone( this->region2 );
400             ( *nreg )++;
401          }
402       }
403 
404       result = this->oper;
405    }
406 
407 /* Return the boolean operator used to combine the regions in the
408    returned array. */
409    return result;
410 }
411 
Decompose(AstMapping * this_mapping,AstMapping ** map1,AstMapping ** map2,int * series,int * invert1,int * invert2,int * status)412 static void Decompose( AstMapping *this_mapping, AstMapping **map1,
413                        AstMapping **map2, int *series, int *invert1,
414                        int *invert2, int *status ) {
415 /*
416 *
417 *  Name:
418 *     Decompose
419 
420 *  Purpose:
421 *     Decompose a CmpRegion into two component Regions.
422 
423 *  Type:
424 *     Private function.
425 
426 *  Synopsis:
427 *     #include "cmpregion.h"
428 *     void Decompose( AstMapping *this, AstMapping **map1,
429 *                     AstMapping **map2, int *series,
430 *                     int *invert1, int *invert2, int *status )
431 
432 *  Class Membership:
433 *     CmpRegion member function (over-rides the protected astDecompose
434 *     method inherited from the Mapping class).
435 
436 *  Description:
437 *     This function returns pointers to two Mappings which, when applied
438 *     either in series or parallel, are equivalent to the supplied Mapping.
439 *
440 *     Since the Frame class inherits from the Mapping class, Frames can
441 *     be considered as special types of Mappings and so this method can
442 *     be used to decompose either CmpMaps, CmpFrames, CmpRegions or Prisms.
443 
444 *  Parameters:
445 *     this
446 *        Pointer to the Mapping.
447 *     map1
448 *        Address of a location to receive a pointer to first component
449 *        Mapping.
450 *     map2
451 *        Address of a location to receive a pointer to second component
452 *        Mapping.
453 *     series
454 *        Address of a location to receive a value indicating if the
455 *        component Mappings are applied in series or parallel. A non-zero
456 *        value means that the supplied Mapping is equivalent to applying map1
457 *        followed by map2 in series. A zero value means that the supplied
458 *        Mapping is equivalent to applying map1 to the lower numbered axes
459 *        and map2 to the higher numbered axes, in parallel.
460 *     invert1
461 *        The value of the Invert attribute to be used with map1.
462 *     invert2
463 *        The value of the Invert attribute to be used with map2.
464 *     status
465 *        Pointer to the inherited status variable.
466 
467 *  Notes:
468 *     - Any changes made to the component rames using the returned
469 *     pointers will be reflected in the supplied CmpFrame.
470 
471 *-
472 */
473 
474 
475 /* Local Variables: */
476    AstCmpRegion *this;              /* Pointer to CmpRegion structure */
477 
478 /* Check the global error status. */
479    if ( !astOK ) return;
480 
481 /* Obtain a pointer to the CmpMap structure. */
482    this = (AstCmpRegion *) this_mapping;
483 
484 /* The components Frames of a CmpRegion are considered to be series
485    Mappings. */
486    if( series ) *series = 1;
487 
488 /* The Frames are returned in their original order whether or not the
489    CmpRegion has been inverted. */
490    if( map1 ) *map1 = astClone( this->region1 );
491    if( map2 ) *map2 = astClone( this->region2 );
492 
493 /* The invert flags dont mean anything for a Region, but we return them
494    anyway. If the CmpRegion has been inverted, return inverted Invert flags. */
495    if( astGetInvert( this ) ) {
496       if( invert1 ) *invert1 = astGetInvert( this->region1 ) ? 0 : 1;
497       if( invert2 ) *invert2 = astGetInvert( this->region2 ) ? 0 : 1;
498 
499 /* If the CmpRegion has not been inverted, return the current Invert flags. */
500    } else {
501       if( invert1 ) *invert1 = astGetInvert( this->region1 );
502       if( invert2 ) *invert2 = astGetInvert( this->region2 );
503    }
504 }
505 
Equal(AstObject * this_object,AstObject * that_object,int * status)506 static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
507 /*
508 *  Name:
509 *     Equal
510 
511 *  Purpose:
512 *     Test if two Objects are equivalent.
513 
514 *  Type:
515 *     Private function.
516 
517 *  Synopsis:
518 *     #include "cmpregion.h"
519 *     int Equal( AstObject *this_object, AstObject *that_object, int *status )
520 
521 *  Class Membership:
522 *     CmpRegion member function (over-rides the astEqual protected
523 *     method inherited from the Region class).
524 
525 *  Description:
526 *     This function returns a boolean result (0 or 1) to indicate whether
527 *     two CmpRegions are equivalent.
528 
529 *  Parameters:
530 *     this
531 *        Pointer to the first CmpRegion.
532 *     that
533 *        Pointer to the second CmpRegion.
534 *     status
535 *        Pointer to the inherited status variable.
536 
537 *  Returned Value:
538 *     One if the CmpRegions are equivalent, zero otherwise.
539 
540 *  Notes:
541 *     - The CmpRegions are equivalent if their component Regions are
542 *     equivalent and if they have the same boolean operation, negation
543 *     and closed flags.
544 *     - A value of zero will be returned if this function is invoked
545 *     with the global status set, or if it should fail for any reason.
546 */
547 
548 /* Local Variables: */
549    AstCmpRegion *that;
550    AstCmpRegion *this;
551    int result;
552 
553 /* Initialise. */
554    result = 0;
555 
556 /* Check the global error status. */
557    if ( !astOK ) return result;
558 
559 /* Invoke the Equal method inherited from the parent Region class. This checks
560    that the Objects are both of the same class, and have the same Negated
561    and Closed flags (amongst other things). */
562    if( (*parent_equal)( this_object, that_object, status ) ) {
563 
564 /* Obtain pointers to the two CmpRegion structures. */
565       this = (AstCmpRegion *) this_object;
566       that = (AstCmpRegion *) that_object;
567 
568 /* Test their first component Regions for equality. */
569       if( astEqual( this->region1, that->region1 ) ) {
570 
571 /* Test their second component Regions for equality. */
572          if( astEqual( this->region2, that->region2 ) ) {
573 
574 /* Test their boolean operator for equality. */
575             if( this->oper == that->oper ) result = 1;
576          }
577       }
578    }
579 
580 /* If an error occurred, clear the result value. */
581    if ( !astOK ) result = 0;
582 
583 /* Return the result, */
584    return result;
585 }
586 
587 /*
588 *  Name:
589 *     MAKE_SET
590 
591 *  Purpose:
592 *     Define a function to set an attribute value for a CmpRegion.
593 
594 *  Type:
595 *     Private macro.
596 
597 *  Synopsis:
598 *     #include "cmpregion.h"
599 *     MAKE_SET(attribute,lattribute,type)
600 
601 *  Class Membership:
602 *     Defined by the CmpRegion class.
603 
604 *  Description:
605 *     This macro expands to an implementation of a private member function
606 *     of the form:
607 *
608 *        static void Set<Attribute>( AstRegion *this, <Type> value )
609 *
610 *     that sets the value of a specified Region attribute in the parent
611 *     Region structure and also in the component Regions.
612 
613 *  Parameters:
614 *     attribute
615 *        Name of the attribute, as it appears in the function name.
616 *     lattribute
617 *        Name of the attribute, all in lower case.
618 *     type
619 *        The C type of the attribute.
620 */
621 
622 /* Define the macro. */
623 #define MAKE_SET(attribute,lattribute,type) \
624 static void Set##attribute( AstRegion *this_region, type value, int *status ) { \
625 \
626 /* Local Variables: */ \
627    AstCmpRegion *this;         /* Pointer to the CmpRegion structure */ \
628 \
629 /* Check the global error status. */ \
630    if ( !astOK ) return; \
631 \
632 /* Use the parent method to set the value in the parent Region structure. */ \
633    (*parent_set##lattribute)( this_region, value, status ); \
634 \
635 /* Also set the value in the two component Regions. */ \
636    this = (AstCmpRegion *) this_region; \
637    astSet##attribute( this->region1, value ); \
638    astSet##attribute( this->region2, value ); \
639 }
640 
641 /* Use the above macro to create accessors for the MeshSize and Closed attributes. */
MAKE_SET(MeshSize,meshsize,int)642 MAKE_SET(MeshSize,meshsize,int)
643 MAKE_SET(Closed,closed,int)
644 
645 /* Undefine the macro. */
646 #undef MAKE_SET
647 
648 /*
649 *  Name:
650 *     MAKE_CLEAR
651 
652 *  Purpose:
653 *     Define a function to clear an attribute value for a CmpRegion.
654 
655 *  Type:
656 *     Private macro.
657 
658 *  Synopsis:
659 *     #include "cmpregion.h"
660 *     MAKE_CLEAR(attribute,lattribute)
661 
662 *  Class Membership:
663 *     Defined by the CmpRegion class.
664 
665 *  Description:
666 *     This macro expands to an implementation of a private member function
667 *     of the form:
668 *
669 *        static void Clear<Attribute>( AstRegion *this )
670 *
671 *     that sets the value of a specified Region attribute in the parent
672 *     Region structure and also in the component Regions.
673 
674 *  Parameters:
675 *     attribute
676 *        Name of the attribute, as it appears in the function name.
677 *     lattribute
678 *        Name of the attribute, all in lower case.
679 */
680 
681 /* Define the macro. */
682 #define MAKE_CLEAR(attribute,lattribute) \
683 static void Clear##attribute( AstRegion *this_region, int *status ) { \
684 \
685 /* Local Variables: */ \
686    AstCmpRegion *this;         /* Pointer to the CmpRegion structure */ \
687 \
688 /* Check the global error status. */ \
689    if ( !astOK ) return; \
690 \
691 /* Use the parent method to clear the value in the parent Region structure. */ \
692    (*parent_clear##lattribute)( this_region, status ); \
693 \
694 /* Also clear the value in the two component Regions. */ \
695    this = (AstCmpRegion *) this_region; \
696    astClear##attribute( this->region1 ); \
697    astClear##attribute( this->region2 ); \
698 }
699 
700 /* Use the above macro to create accessors for the MeshSize and Closed attributes. */
701 MAKE_CLEAR(MeshSize,meshsize)
702 MAKE_CLEAR(Closed,closed)
703 
704 /* Undefine the macro. */
705 #undef MAKE_CLEAR
706 
707 static int GetBounded( AstRegion *this_region, int *status ) {
708 /*
709 *  Name:
710 *     GetBounded
711 
712 *  Purpose:
713 *     Is the Region bounded?
714 
715 *  Type:
716 *     Private function.
717 
718 *  Synopsis:
719 *     #include "cmpregion.h"
720 *     int GetBounded( AstRegion *this, int *status )
721 
722 *  Class Membership:
723 *     CmpRegion method (over-rides the astGetBounded method inherited from
724 *     the Region class).
725 
726 *  Description:
727 *     This function returns a flag indicating if the Region is bounded.
728 *     The implementation provided by the base Region class is suitable
729 *     for Region sub-classes representing the inside of a single closed
730 *     curve (e.g. Circle, Ellipse, Box, etc). Other sub-classes (such as
731 *     CmpRegion, PointList, etc ) may need to provide their own
732 *     implementations.
733 
734 *  Parameters:
735 *     this
736 *        Pointer to the Region.
737 *     status
738 *        Pointer to the inherited status variable.
739 
740 *  Returned Value:
741 *     Non-zero if the Region is bounded. Zero otherwise.
742 
743 */
744 
745 /* Local Variables: */
746    AstCmpRegion *this;        /* Pointer to CmpRegion structure */
747    AstRegion *reg1;           /* Pointer to first component Region */
748    AstRegion *reg2;           /* Pointer to second component Region */
749    int neg1;                  /* Negated flag to use with first component */
750    int neg2;                  /* Negated flag to use with second component */
751    int oper;                  /* Combination operator */
752    int overlap;               /* Nature of overlap between components */
753    int reg1b;                 /* Is the first component Region bounded?*/
754    int reg2b;                 /* Is the second component Region bounded?*/
755    int result;                /* Returned result */
756 
757 /* Initialise */
758    result = 0;
759 
760 /* Check the global error status. */
761    if ( !astOK ) return result;
762 
763 /* Get a pointer to the CmpRegion structure. */
764    this = (AstCmpRegion *) this_region;
765 
766 /* Only calculated a new value if there is no cached value in the Region. */
767    if( this->bounded == -INT_MAX ) {
768 
769 /* Get the component Regions, how they should be combined, and the
770    Negated values which should be used with them. The returned values
771    take account of whether the supplied CmpRegion has itself been Negated
772    or not. The returned Regions represent regions within the base Frame
773    of the FrameSet encapsulated by the parent Region structure. */
774       GetRegions( this, &reg1, &reg2, &oper, &neg1, &neg2, status );
775 
776 /* If the first component Region does not have the required value for
777    its "Negated" attribute, use the negation of "reg1" in place of "reg1"
778    itself. */
779       if( neg1 != astGetNegated( reg1 ) ) {
780          AstRegion *tmp = astGetNegation( reg1 );
781          (void) astAnnul( reg1 );
782          reg1 = tmp;
783       }
784 
785 /* If the second component Region does not have the required value for
786    its "Negated" attribute, use the negation of "reg2" in place of "reg2"
787    itself. */
788       if( neg2 != astGetNegated( reg2 ) ) {
789          AstRegion *tmp = astGetNegation( reg2 );
790          (void) astAnnul( reg2 );
791          reg2 = tmp;
792       }
793 
794 /* See if either of the component Regions is bounded. */
795       reg1b = astGetBounded( reg1 );
796       reg2b = astGetBounded( reg2 );
797 
798 /* If the regions are ANDed... */
799       if( oper == AST__AND ) {
800 
801 /* If either one of the two components are bounded, then the AND region is
802    bounded. */
803          if( reg1b || reg2b ) {
804             result = 1;
805 
806 /* If neither of the two components is bounded, then the AND region is
807    unbounded if there is partial or no overlap between them and is bounded
808    otherwise. */
809          } else {
810             overlap = astOverlap( reg1, reg2 );
811             if( overlap == 1 || overlap == 4 || overlap == 6 ) {
812                result = 0;
813             } else {
814                result = 1;
815             }
816          }
817 
818 /* If the regions are ORed... */
819       } else {
820 
821 /* If either one of the two components is unbounded, then the OR region is
822    unbounded. */
823          if( !reg1b || !reg2b ) {
824             result = 0;
825 
826 /* If both of the two components are bounded, then the OR region is also
827    bounded. */
828          } else {
829             result = 1;
830          }
831       }
832 
833 /* Free resources. */
834       reg1 = astAnnul( reg1 );
835       reg2 = astAnnul( reg2 );
836 
837 /* Cache the value in the CmpRegion. */
838       this->bounded = astOK ? result : -INT_MAX;
839    }
840 
841 /* Return zero if an error occurred. Otherwise, return the cached value. */
842    if( astOK ) {
843       result = ( this->bounded == -INT_MAX ) ? 0 : this->bounded;
844    } else {
845       result = 0;
846    }
847 
848 /* Return the required pointer. */
849    return result;
850 }
851 
GetFillFactor(AstRegion * this_region,int * status)852 static double GetFillFactor( AstRegion *this_region, int *status ) {
853 /*
854 *  Name:
855 *     GetFillFactor
856 
857 *  Purpose:
858 *     Obtain the value of the FillFactor attribute for a CmpRegion.
859 
860 *  Type:
861 *     Private function.
862 
863 *  Synopsis:
864 *     #include "cmpregion.h"
865 *     double GetFillFactor( AstRegion *this, int *status )
866 
867 *  Class Membership:
868 *     CmpRegion member function (over-rides the astGetFillFactor method inherited
869 *     from the Region class).
870 
871 *  Description:
872 *     This function returns the value of the FillFactor attribute for a
873 *     CmpRegion.  A suitable default value is returned if no value has
874 *     previously been set.
875 
876 *  Parameters:
877 *     this
878 *        Pointer to the CmpRegion.
879 *     status
880 *        Pointer to the inherited status variable.
881 
882 *  Returned Value:
883 *     The FillFactor value to use.
884 
885 */
886 
887 /* Local Variables: */
888    AstCmpRegion *this;
889    double result;
890 
891 /* Check the global error status. */
892    if ( !astOK ) return AST__BAD;
893 
894 /* Initialise. */
895    result = AST__BAD;
896 
897 /* Obtain a pointer to the CmpRegion structure. */
898    this = (AstCmpRegion *) this_region;
899 
900 /* See if a FillFactor value has been set. If so, use the parent
901    astGetFillFactor  method to obtain it. */
902    if ( astTestFillFactor( this ) ) {
903       result = (*parent_getfillfactor)( this_region, status );
904 
905 /* Otherwise, we will generate a default value equal to the FillFactor values
906    of the first component Region. */
907    } else {
908       result = astGetFillFactor( this->region1 );
909    }
910 
911 /* If an error occurred, clear the returned value. */
912    if ( !astOK ) result = AST__BAD;
913 
914 /* Return the result. */
915    return result;
916 }
917 
GetObjSize(AstObject * this_object,int * status)918 static int GetObjSize( AstObject *this_object, int *status ) {
919 /*
920 *  Name:
921 *     GetObjSize
922 
923 *  Purpose:
924 *     Return the in-memory size of an Object.
925 
926 *  Type:
927 *     Private function.
928 
929 *  Synopsis:
930 *     #include "cmpregion.h"
931 *     int GetObjSize( AstObject *this, int *status )
932 
933 *  Class Membership:
934 *     CmpRegion member function (over-rides the astGetObjSize protected
935 *     method inherited from the parent class).
936 
937 *  Description:
938 *     This function returns the in-memory size of the supplied CmpRegion,
939 *     in bytes.
940 
941 *  Parameters:
942 *     this
943 *        Pointer to the CmpRegion.
944 *     status
945 *        Pointer to the inherited status variable.
946 
947 *  Returned Value:
948 *     The Object size, in bytes.
949 
950 *  Notes:
951 *     - A value of zero will be returned if this function is invoked
952 *     with the global status set, or if it should fail for any reason.
953 */
954 
955 /* Local Variables: */
956    AstCmpRegion *this;        /* Pointer to CmpRegion structure */
957    int result;                /* Result value to return */
958 
959 /* Initialise. */
960    result = 0;
961 
962 /* Check the global error status. */
963    if ( !astOK ) return result;
964 
965 /* Obtain a pointers to the CmpRegion structure. */
966    this = (AstCmpRegion *) this_object;
967 
968 /* Invoke the GetObjSize method inherited from the parent class, and then
969    add on any components of the class structure defined by this class
970    which are stored in dynamically allocated memory. */
971    result = (*parent_getobjsize)( this_object, status );
972 
973    result += astGetObjSize( this->region1 );
974    result += astGetObjSize( this->region2 );
975    if( this->xor1 ) result += astGetObjSize( this->xor1 );
976    if( this->xor2 ) result += astGetObjSize( this->xor2 );
977 
978 /* If an error occurred, clear the result value. */
979    if ( !astOK ) result = 0;
980 
981 /* Return the result, */
982    return result;
983 }
984 
GetRegions(AstCmpRegion * this,AstRegion ** reg1,AstRegion ** reg2,int * oper,int * neg1,int * neg2,int * status)985 static void GetRegions( AstCmpRegion *this, AstRegion **reg1, AstRegion **reg2,
986                         int *oper, int *neg1, int *neg2, int *status ) {
987 /*
988 *
989 *  Name:
990 *     GetRegions
991 
992 *  Purpose:
993 *     Get the component Regions of a CmpRegion.
994 
995 *  Type:
996 *     Private function.
997 
998 *  Synopsis:
999 *     #include "region.h"
1000 *     void GetRegions( AstCmpRegion *this, AstRegion **reg1, AstRegion **reg2,
1001 *                      int *oper, int *neg1, int *neg2, int *status )
1002 
1003 *  Class Membership:
1004 *     CmpRegion member function
1005 
1006 *  Description:
1007 *     This function returns pointers to two Regions which, when applied
1008 *     using the returned boolean operator, are equivalent to the supplied
1009 *     Region. If the CmpRegion has been negated, then the returned operator
1010 *     and "negated" flags will be set such that they represent the
1011 *     negated CmpRegion.
1012 *
1013 *     The current Frames in both the returned component Regions will be
1014 *     equivalent to the base Frame in the FrameSet encapsulated by the
1015 *     parent Region structure.
1016 
1017 *  Parameters:
1018 *     this
1019 *        Pointer to the CmpRegion.
1020 *     reg1
1021 *        Address of a location to receive a pointer to first component
1022 *        Region. The current Frame in this region will be equivalent to
1023 *        the base Frame in the FrameSet
1024 *     reg2
1025 *        Address of a location to receive a pointer to second component
1026 *        Region.
1027 *     oper
1028 *        Address of a location to receive a value indicating how the
1029 *        component Regions are combined together. This will be one of
1030 *        AST__AND or AST__OR
1031 *     neg1
1032 *        The value of the Negated attribute to be used with reg1.
1033 *     neg2
1034 *        The value of the Negated attribute to be used with reg2.
1035 *     status
1036 *        Pointer to the inherited status variable.
1037 
1038 *  Notes:
1039 *     - Any changes made to the component Regions using the returned
1040 *     pointers will be reflected in the supplied CmpRegion.
1041 
1042 *-
1043 */
1044 
1045 /* Initialise */
1046    if( reg1 ) *reg1 = NULL;
1047    if( reg2 ) *reg2 = NULL;
1048 
1049 /* Check the global error status. */
1050    if ( !astOK ) return;
1051 
1052 /* Return the component Region pointers. */
1053    if( reg1 ) *reg1 = astClone( this->region1 );
1054    if( reg2 ) *reg2 = astClone( this->region2 );
1055 
1056 /* Initialise the other returned items. Note, the CmpRegion initialiser
1057    stored a deep copy of the supplied component Regions, and so we do not
1058    need to worry about attributes of the components having been changed
1059    after the creation of the CmpRegion. This is different to the CmpMap
1060    class which merely clones its supplied component pointers and so has
1061    to save copies of the original Invert settings within the CmpMap
1062    structure. */
1063    if( oper ) *oper = this->oper;
1064    if( neg1 ) *neg1 = astGetNegated( this->region1 );
1065    if( neg2 ) *neg2 = astGetNegated( this->region2 );
1066 
1067 /* If the CmpRegion has been inverted, we modify the boolean operator and
1068    negation flags so that they reflect the inverted CmpRegion. */
1069    if( astGetNegated( this ) ) {
1070 
1071 /* If the component Regions are combined using AND, then the negated
1072    CmpRegion combines its negated components using  OR. */
1073       if( this->oper == AST__AND ){
1074          if( oper ) *oper = AST__OR;
1075          if( neg1 ) *neg1 = *neg1 ? 0 : 1;
1076          if( neg2 ) *neg2 = *neg2 ? 0 : 1;
1077 
1078 /* If the component Regions are combined using OR, then the negated CmpRegion
1079    combines its negated components using  AND. */
1080       } else if( this->oper == AST__OR ){
1081          if( oper ) *oper = AST__AND;
1082          if( neg1 ) *neg1 = *neg1 ? 0 : 1;
1083          if( neg2 ) *neg2 = *neg2 ? 0 : 1;
1084 
1085       } else if( astOK ) {
1086          astError( AST__INTER, "GetRegions(%s): The %s refers to an unknown "
1087                    "boolean operator with identifier %d (internal AST "
1088                    "programming error).", status, astGetClass( this ),
1089                    astGetClass( this ), this->oper );
1090       }
1091    }
1092 }
1093 
GetDefUnc(AstRegion * this_region,int * status)1094 static AstRegion *GetDefUnc( AstRegion *this_region, int *status ) {
1095 /*
1096 *  Name:
1097 *     GetDefUnc
1098 
1099 *  Purpose:
1100 *     Obtain a pointer to the default uncertainty Region for a given Region.
1101 
1102 *  Type:
1103 *     Private function.
1104 
1105 *  Synopsis:
1106 *     #include "cmpregion.h"
1107 *     AstRegion *GetDefUnc( AstRegion *this )
1108 
1109 *  Class Membership:
1110 *     CmpRegion method (over-rides the astGetDefUnc method inherited from
1111 *     the Region class).
1112 
1113 *     This function returns a pointer to a Region which represents the
1114 *     default uncertainty associated with a position on the boundary of the
1115 *     given  Region. The returned Region refers to the base Frame within the
1116 *     FrameSet encapsulated by the supplied Region.
1117 
1118 *  Parameters:
1119 *     this
1120 *        Pointer to the Region.
1121 
1122 *  Returned Value:
1123 *     A pointer to the Region. This should be annulled (using astAnnul)
1124 *     when no longer needed.
1125 
1126 *  Notes:
1127 *     - A NULL pointer will be returned if this function is invoked
1128 *     with the global error status set, or if it should fail for any
1129 *     reason.
1130 */
1131 
1132 /* Local Variables: */
1133    AstCmpRegion *this;        /* Pointer to CmpRegion structure */
1134    AstRegion *result;         /* Returned pointer */
1135 
1136 /* Initialise */
1137    result = NULL;
1138 
1139 /* Check the global error status. */
1140    if ( !astOK ) return result;
1141 
1142 /* Get a pointer to the CmpRegion structure. */
1143    this = (AstCmpRegion *) this_region;
1144 
1145 /* If the first component region has non-default uncertainty, use it as
1146    the default uncertainty for the CmpRegion. Note, the current Frame of
1147    an uncertainty Region is assumed to be the same as the base Frame in the
1148    CmpRegion. */
1149    if( astTestUnc( this->region1 ) ) {
1150       result = astGetUncFrm( this->region1, AST__CURRENT );
1151 
1152 /* Otherwise, if the second component region has non-default uncertainty,
1153    use it as the default uncertainty for the CmpRegion. */
1154    } else if( astTestUnc( this->region2 ) ) {
1155       result = astGetUncFrm( this->region2, AST__CURRENT );
1156 
1157 /* Otherwise, use the parent method to determine the default uncertainty. */
1158    } else {
1159       result = (* parent_getdefunc)( this_region, status );
1160    }
1161 
1162 /* Return NULL if an error occurred. */
1163    if( !astOK ) result = astAnnul( result );
1164 
1165 /* Return the required pointer. */
1166    return result;
1167 }
1168 
astInitCmpRegionVtab_(AstCmpRegionVtab * vtab,const char * name,int * status)1169 void astInitCmpRegionVtab_(  AstCmpRegionVtab *vtab, const char *name, int *status ) {
1170 /*
1171 *+
1172 *  Name:
1173 *     astInitCmpRegionVtab
1174 
1175 *  Purpose:
1176 *     Initialise a virtual function table for a CmpRegion.
1177 
1178 *  Type:
1179 *     Protected function.
1180 
1181 *  Synopsis:
1182 *     #include "cmpregion.h"
1183 *     void astInitCmpRegionVtab( AstCmpRegionVtab *vtab, const char *name )
1184 
1185 *  Class Membership:
1186 *     CmpRegion vtab initialiser.
1187 
1188 *  Description:
1189 *     This function initialises the component of a virtual function
1190 *     table which is used by the CmpRegion class.
1191 
1192 *  Parameters:
1193 *     vtab
1194 *        Pointer to the virtual function table. The components used by
1195 *        all ancestral classes will be initialised if they have not already
1196 *        been initialised.
1197 *     name
1198 *        Pointer to a constant null-terminated character string which contains
1199 *        the name of the class to which the virtual function table belongs (it
1200 *        is this pointer value that will subsequently be returned by the Object
1201 *        astClass function).
1202 *-
1203 */
1204 
1205 /* Local Variables: */
1206    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1207    AstMappingVtab *mapping;      /* Pointer to Mapping component of Vtab */
1208    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
1209    AstRegionVtab *region;        /* Pointer to Region component of Vtab */
1210 
1211 /* Check the local error status. */
1212    if ( !astOK ) return;
1213 
1214 
1215 /* Get a pointer to the thread specific global data structure. */
1216    astGET_GLOBALS(NULL);
1217 
1218 /* Initialize the component of the virtual function table used by the
1219    parent class. */
1220    astInitRegionVtab( (AstRegionVtab *) vtab, name );
1221 
1222 /* Store a unique "magic" value in the virtual function table. This
1223    will be used (by astIsACmpRegion) to determine if an object belongs to
1224    this class.  We can conveniently use the address of the (static)
1225    class_check variable to generate this unique value. */
1226    vtab->id.check = &class_check;
1227    vtab->id.parent = &(((AstRegionVtab *) vtab)->id);
1228 
1229 /* Initialise member function pointers. */
1230 /* ------------------------------------ */
1231 /* Store pointers to the member functions (implemented here) that
1232    provide virtual methods for this class. */
1233 
1234    vtab->CmpRegionList = CmpRegionList;
1235 
1236 /* Save the inherited pointers to methods that will be extended, and
1237    replace them with pointers to the new member functions. */
1238    object = (AstObjectVtab *) vtab;
1239    mapping = (AstMappingVtab *) vtab;
1240    region = (AstRegionVtab *) vtab;
1241 
1242    parent_transform = mapping->Transform;
1243    mapping->Transform = Transform;
1244 
1245    parent_simplify = mapping->Simplify;
1246    mapping->Simplify = Simplify;
1247 
1248    parent_getdefunc = region->GetDefUnc;
1249    region->GetDefUnc = GetDefUnc;
1250 
1251    parent_setregfs = region->SetRegFS;
1252    region->SetRegFS = SetRegFS;
1253 
1254    parent_resetcache = region->ResetCache;
1255    region->ResetCache = ResetCache;
1256 
1257    parent_equal = object->Equal;
1258    object->Equal = Equal;
1259 
1260    parent_getobjsize = object->GetObjSize;
1261    object->GetObjSize = GetObjSize;
1262 
1263 #if defined(THREAD_SAFE)
1264    parent_managelock = object->ManageLock;
1265    object->ManageLock = ManageLock;
1266 #endif
1267 
1268    parent_clearclosed = region->ClearClosed;
1269    region->ClearClosed = ClearClosed;
1270 
1271    parent_clearmeshsize = region->ClearMeshSize;
1272    region->ClearMeshSize = ClearMeshSize;
1273 
1274    parent_setclosed = region->SetClosed;
1275    region->SetClosed = SetClosed;
1276 
1277    parent_setmeshsize = region->SetMeshSize;
1278    region->SetMeshSize = SetMeshSize;
1279 
1280    parent_getfillfactor = region->GetFillFactor;
1281    region->GetFillFactor = GetFillFactor;
1282 
1283    parent_regsetattrib = region->RegSetAttrib;
1284    region->RegSetAttrib = RegSetAttrib;
1285 
1286    parent_regclearattrib = region->RegClearAttrib;
1287    region->RegClearAttrib = RegClearAttrib;
1288 
1289 /* Store replacement pointers for methods which will be over-ridden by
1290    new member functions implemented here. */
1291    mapping->Decompose = Decompose;
1292    region->RegBaseBox = RegBaseBox;
1293    region->RegBaseBox2 = RegBaseBox2;
1294    region->RegBaseMesh = RegBaseMesh;
1295    region->RegSplit = RegSplit;
1296    region->RegPins = RegPins;
1297    region->RegTrace = RegTrace;
1298    region->GetBounded = GetBounded;
1299    region->RegBasePick = RegBasePick;
1300 
1301 /* Declare the copy constructor, destructor and class dump function. */
1302    astSetCopy( vtab, Copy );
1303    astSetDelete( vtab, Delete );
1304    astSetDump( vtab, Dump, "CmpRegion", "Combination of two Regions" );
1305 
1306 /* If we have just initialised the vtab for the current class, indicate
1307    that the vtab is now initialised, and store a pointer to the class
1308    identifier in the base "object" level of the vtab. */
1309    if( vtab == &class_vtab ) {
1310       class_init = 1;
1311       astSetVtabClassIdentifier( vtab, &(vtab->id) );
1312    }
1313 }
1314 
1315 #if defined(THREAD_SAFE)
ManageLock(AstObject * this_object,int mode,int extra,AstObject ** fail,int * status)1316 static int ManageLock( AstObject *this_object, int mode, int extra,
1317                        AstObject **fail, int *status ) {
1318 /*
1319 *  Name:
1320 *     ManageLock
1321 
1322 *  Purpose:
1323 *     Manage the thread lock on an Object.
1324 
1325 *  Type:
1326 *     Private function.
1327 
1328 *  Synopsis:
1329 *     #include "object.h"
1330 *     AstObject *ManageLock( AstObject *this, int mode, int extra,
1331 *                            AstObject **fail, int *status )
1332 
1333 *  Class Membership:
1334 *     CmpRegion member function (over-rides the astManageLock protected
1335 *     method inherited from the parent class).
1336 
1337 *  Description:
1338 *     This function manages the thread lock on the supplied Object. The
1339 *     lock can be locked, unlocked or checked by this function as
1340 *     deteremined by parameter "mode". See astLock for details of the way
1341 *     these locks are used.
1342 
1343 *  Parameters:
1344 *     this
1345 *        Pointer to the Object.
1346 *     mode
1347 *        An integer flag indicating what the function should do:
1348 *
1349 *        AST__LOCK: Lock the Object for exclusive use by the calling
1350 *        thread. The "extra" value indicates what should be done if the
1351 *        Object is already locked (wait or report an error - see astLock).
1352 *
1353 *        AST__UNLOCK: Unlock the Object for use by other threads.
1354 *
1355 *        AST__CHECKLOCK: Check that the object is locked for use by the
1356 *        calling thread (report an error if not).
1357 *     extra
1358 *        Extra mode-specific information.
1359 *     fail
1360 *        If a non-zero function value is returned, a pointer to the
1361 *        Object that caused the failure is returned at "*fail". This may
1362 *        be "this" or it may be an Object contained within "this". Note,
1363 *        the Object's reference count is not incremented, and so the
1364 *        returned pointer should not be annulled. A NULL pointer is
1365 *        returned if this function returns a value of zero.
1366 *     status
1367 *        Pointer to the inherited status variable.
1368 
1369 *  Returned Value:
1370 *    A local status value:
1371 *        0 - Success
1372 *        1 - Could not lock or unlock the object because it was already
1373 *            locked by another thread.
1374 *        2 - Failed to lock a POSIX mutex
1375 *        3 - Failed to unlock a POSIX mutex
1376 *        4 - Bad "mode" value supplied.
1377 
1378 *  Notes:
1379 *     - This function attempts to execute even if an error has already
1380 *     occurred.
1381 */
1382 
1383 /* Local Variables: */
1384    AstCmpRegion *this;       /* Pointer to CmpRegion structure */
1385    int result;               /* Returned status value */
1386 
1387 /* Initialise */
1388    result = 0;
1389 
1390 /* Check the supplied pointer is not NULL. */
1391    if( !this_object ) return result;
1392 
1393 /* Obtain a pointers to the CmpRegion structure. */
1394    this = (AstCmpRegion *) this_object;
1395 
1396 /* Invoke the ManageLock method inherited from the parent class. */
1397    if( !result ) result = (*parent_managelock)( this_object, mode, extra,
1398                                                 fail, status );
1399 
1400 /* Invoke the astManageLock method on any Objects contained within
1401    the supplied Object. */
1402    if( !result ) result = astManageLock( this->region1, mode, extra, fail );
1403    if( !result ) result = astManageLock( this->region2, mode, extra, fail );
1404 
1405    return result;
1406 
1407 }
1408 #endif
1409 
MatchRegion(AstRegion * this,int ifrm,AstRegion * that,const char * method,int * status)1410 static AstRegion *MatchRegion( AstRegion *this, int ifrm, AstRegion *that,
1411                                const char *method, int *status ) {
1412 /*
1413 *  Name:
1414 *     MatchRegion
1415 
1416 *  Purpose:
1417 *     Map a Region into the Frame of another Region.
1418 
1419 *  Type:
1420 *     Private function.
1421 
1422 *  Synopsis:
1423 *     #include "cmpregion.h"
1424 *     AstRegion *MatchRegion( AstRegion *this, int ifrm, AstRegion *that,
1425 *                             const char *method, int *status )
1426 
1427 *  Class Membership:
1428 *     CmpRegion method.
1429 
1430 *  Description:
1431 *     This function returns a pointer to a new Region which is a copy of
1432 *     "that" mapped into either the base or current Frame of "this".
1433 
1434 *  Parameters:
1435 *     this
1436 *        Pointer to a Region defining the Frame of the returned Region.
1437 *     ifrm
1438 *        The index of a Frame within the FrameSet encapsulated by "this".
1439 *        The returned Region will refer to the requested Frame. It should
1440 *        be either AST__CURRENT or AST__BASE.
1441 *     that
1442 *        Pointer to a Region defining the shape and extent of the
1443 *        returned Region.
1444 *     method
1445 *        Pointer to a string holding the calling method.This is only used
1446 *        in error messages.
1447 *     status
1448 *        Pointer to the inherited status variable.
1449 
1450 *  Returned Value:
1451 *     A pointer to a new Region. This should be annulled (using astAnnul)
1452 *     when no longer needed.
1453 
1454 *  Notes:
1455 *     - A NULL pointer will be returned if this function is invoked
1456 *     with the global error status set, or if it should fail for any
1457 *     reason.
1458 */
1459 
1460 /* Local Variables: */
1461    AstFrame *frm;             /* Current Frame from "fs" */
1462    AstFrameSet *fs;           /* FrameSet connecting that to this */
1463    AstMapping *map;           /* Base->Current Mapping from "fs" */
1464    AstRegion *result;         /* Returned pointer */
1465 
1466 /* Initialise */
1467    result = NULL;
1468 
1469 /* Check the global error status. Also return NULL if no Regions were
1470    supplied. */
1471    if ( !astOK || !this || !that ) return result;
1472 
1473 /* Temporarily invert "this" if we are matching its base Frame (since the
1474    astConvert method matches current Frames). */
1475    if( ifrm == AST__BASE ) astInvert( this );
1476 
1477 /* Find a FrameSet connecting the current Frames of the two Regions */
1478    fs = astConvert( that, this, "" );
1479 
1480 /* Re-instate the original Frame indices in "this" if required. */
1481    if( ifrm == AST__BASE ) astInvert( this );
1482 
1483 /* Check a conversion path was found. */
1484    if( fs ) {
1485 
1486 /* Get the Frame and Mapping form the FrameSet. */
1487       frm = astGetFrame( fs, AST__CURRENT );
1488       map = astGetMapping( fs, AST__BASE, AST__CURRENT );
1489 
1490 /* Re-map the Region. */
1491       result = astMapRegion( that, map, frm );
1492 
1493 /* Free resources. */
1494       frm = astAnnul( frm );
1495       map = astAnnul( map );
1496       fs = astAnnul( fs );
1497 
1498 /* Report an error if there is no conversion between the two Frames. */
1499    } else {
1500       astError( AST__INTER, "%s(%s): MatchRegion cannot convert between "
1501                 "the two supplied coordinate Frames (internal AST "
1502                 "programming error).", status, method, astGetClass( this ) );
1503    }
1504 
1505 /* Annul the returned pointer if an error has occurred. */
1506    if( !astOK ) result = astAnnul( result );
1507 
1508 /* Return the result. */
1509    return result;
1510 }
1511 
RegBaseBox(AstRegion * this_region,double * lbnd,double * ubnd,int * status)1512 static void RegBaseBox( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){
1513 /*
1514 *  Name:
1515 *     RegBaseBox
1516 
1517 *  Purpose:
1518 *     Returns the bounding box of an un-negated Region in the base Frame of
1519 *     the encapsulated FrameSet.
1520 
1521 *  Type:
1522 *     Private function.
1523 
1524 *  Synopsis:
1525 *     #include "cmpregion.h"
1526 *     void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status )
1527 
1528 *  Class Membership:
1529 *     CmpRegion member function (over-rides the astRegBaseBox protected
1530 *     method inherited from the Region class).
1531 
1532 *  Description:
1533 *     This function returns the upper and lower axis bounds of a Region in
1534 *     the base Frame of the encapsulated FrameSet, assuming the Region
1535 *     has not been negated. That is, the value of the Negated attribute
1536 *     is ignored.
1537 
1538 *  Parameters:
1539 *     this
1540 *        Pointer to the Region.
1541 *     lbnd
1542 *        Pointer to an array in which to return the lower axis bounds
1543 *        covered by the Region in the base Frame of the encapsulated
1544 *        FrameSet. It should have at least as many elements as there are
1545 *        axes in the base Frame.
1546 *     ubnd
1547 *        Pointer to an array in which to return the upper axis bounds
1548 *        covered by the Region in the base Frame of the encapsulated
1549 *        FrameSet. It should have at least as many elements as there are
1550 *        axes in the base Frame.
1551 *     status
1552 *        Pointer to the inherited status variable.
1553 
1554 */
1555 
1556 /* Local Variables: */
1557    AstCmpRegion *this;          /* Pointer to CmpRegion structure */
1558    AstPointSet *ps;             /* Mesh pointset */
1559    AstRegion *reg1;             /* Pointer to first component Region */
1560    AstRegion *reg2;             /* Pointer to second component Region */
1561    double **ptr;                /* Pointer to mesh data */
1562    double *clbnd1;              /* Point to 1st comp lower bounds array */
1563    double *clbnd2;              /* Point to 2nd comp lower bounds array */
1564    double *cubnd1;              /* Point to 1st comp upper bounds array */
1565    double *cubnd2;              /* Point to 2nd comp upper bounds array */
1566    double *p;                   /* Pointer to next coordinate value */
1567    double lb;                   /* Lower limit */
1568    double ub;                   /* Upper limit */
1569    int i;                       /* Axis index */
1570    int icoord;                  /* Coordinate index */
1571    int inc1;                    /* First component interval is included? */
1572    int inc2;                    /* Second component interval is included? */
1573    int ipoint;                  /* Point index */
1574    int nax;                     /* Number of axes in Frame */
1575    int ncoord;                  /* Number of coords */
1576    int neg1;                    /* First component negated? */
1577    int neg2;                    /* Second component negated? */
1578    int npoint;                  /* Number of points */
1579 
1580 /* Check the global error status. */
1581    if ( !astOK ) return;
1582 
1583 /* Get a pointer to the CmpRegion structure */
1584    this = (AstCmpRegion *) this_region;
1585 
1586 /* If the CmpRegion is bounded, we find the bounding box using a mesh of
1587    points spread evenly over the boundary of the CmpRegion. */
1588    if( astGetBounded( this ) ) {
1589       ps = astRegBaseMesh( this_region );
1590       ptr = astGetPoints( ps );
1591       ncoord = astGetNcoord( ps );
1592       npoint = astGetNpoint( ps );
1593 
1594       if( astOK ) {
1595          for( icoord = 0; icoord < ncoord; icoord++ ) {
1596             lbnd[ icoord ] = DBL_MAX;
1597             ubnd[ icoord ] = -DBL_MAX;
1598             p = ptr[ icoord ];
1599             for( ipoint = 0; ipoint < npoint; ipoint++, p++ ) {
1600                if( *p != AST__BAD ) {
1601                   if( *p < lbnd[ icoord ] )  lbnd[ icoord ] = *p;
1602                   if( *p > ubnd[ icoord ] )  ubnd[ icoord ] = *p;
1603                }
1604             }
1605          }
1606       }
1607       ps = astAnnul( ps );
1608 
1609 /* If the CmpRegion is not bounded we look at each axis individually. */
1610    } else {
1611 
1612 /* Get pointers to the component Regions. */
1613       reg1 = this->region1;
1614       reg2 = this->region2;
1615 
1616 /* Get their negated flags */
1617       neg1 = astGetNegated( reg1 );
1618       neg2 = astGetNegated( reg2 );
1619 
1620 /* The base Frame of the parent Region structure is the current Frame of
1621    the component Regions. Get the no. of axes in this Frame. */
1622       nax = astGetNaxes( reg1 );
1623 
1624 /* Get the bounding boxes of the component Regions in this Frame. */
1625       clbnd1 = astMalloc( sizeof( double )*(size_t) nax );
1626       cubnd1 = astMalloc( sizeof( double )*(size_t) nax );
1627       clbnd2 = astMalloc( sizeof( double )*(size_t) nax );
1628       cubnd2 = astMalloc( sizeof( double )*(size_t) nax );
1629       if( astOK ) {
1630          astGetRegionBounds( reg1, clbnd1, cubnd1 );
1631          astGetRegionBounds( reg2, clbnd2, cubnd2 );
1632 
1633 /* Loop round every axis. */
1634          for( i = 0; i < nax; i++ ) {
1635 
1636 /* If the first component Region has been negated, the lower and upper
1637    bounds from the first component are the bounds of an *excluded* axis
1638    interval, not an included interval. If either of the bounds are
1639    infinite, we can swap it to an included interval. If both bounds are
1640    finite, we cannot convert to an included interval. In this case, we
1641    assume that the gap will be filled at some point on another axis, if
1642    there is more than 1 axis, and convert it to an unbouded included
1643    interval. */
1644             inc1 = 1;
1645             if( neg1 ) {
1646                lb = clbnd1[ i ];
1647                ub = cubnd1[ i ];
1648                if( lb == -DBL_MAX ) clbnd1[ i ] = ub;
1649                if( ub == DBL_MAX ) cubnd1[ i ] = lb;
1650                if( lb != -DBL_MAX && ub != DBL_MAX ) {
1651                   if( nax == 1 ) {
1652                      inc1 = 0;
1653                   } else {
1654                      clbnd1[ i ] = -DBL_MAX;
1655                      cubnd1[ i ] = DBL_MAX;
1656                   }
1657                }
1658             }
1659 
1660 /* Likewise attempt to convert an excluded interval into an included
1661    interval for the second component Region. */
1662             inc2 = 1;
1663             if( neg2 ) {
1664                lb = clbnd2[ i ];
1665                ub = cubnd2[ i ];
1666                if( lb == -DBL_MAX ) clbnd2[ i ] = ub;
1667                if( ub == DBL_MAX ) cubnd2[ i ] = lb;
1668                if( lb != -DBL_MAX && ub != DBL_MAX ) {
1669                   if( nax == 1 ) {
1670                      inc2 = 0;
1671                   } else {
1672                      clbnd2[ i ] = -DBL_MAX;
1673                      cubnd2[ i ] = DBL_MAX;
1674                   }
1675                }
1676             }
1677 
1678 /* If the component Regions are combined using AND, find the overlap of
1679    the axis intervals. This depends on whether the intervals are included
1680    or excluded. */
1681             if( this->oper == AST__AND ) {
1682 
1683                if( inc1 ) {
1684                   if( inc2 ) {
1685                      lbnd[ i ] = MAX( clbnd1[ i ], clbnd2[ i ] );
1686                      ubnd[ i ] = MIN( cubnd1[ i ], cubnd2[ i ] );
1687                   } else {
1688                      lbnd[ i ] = clbnd1[ i ] < clbnd2[ i ] ? clbnd1[ i ] : cubnd2[ i ];
1689                      ubnd[ i ] = cubnd1[ i ] > cubnd2[ i ] ? cubnd1[ i ] : clbnd2[ i ];
1690                   }
1691                } else {
1692                   if( inc2 ) {
1693                      lbnd[ i ] = clbnd2[ i ] < clbnd1[ i ] ? clbnd2[ i ] : cubnd1[ i ];
1694                      ubnd[ i ] = cubnd2[ i ] > cubnd1[ i ] ? cubnd2[ i ] : clbnd1[ i ];
1695                   } else {
1696                      lbnd[ i ] = clbnd1[ i ] < clbnd2[ i ] ? clbnd1[ i ] : cubnd2[ i ];
1697                      ubnd[ i ] = cubnd1[ i ] > cubnd2[ i ] ? cubnd1[ i ] : clbnd2[ i ];
1698                   }
1699                }
1700 
1701 /* If the component Regions are not combined using AND, find the union of
1702    the axis intervals. */
1703             } else {
1704                if( inc1 && inc2 ) {
1705                   lbnd[ i ] = MIN( clbnd1[ i ], clbnd2[ i ] );
1706                   ubnd[ i ] = MAX( cubnd1[ i ], cubnd2[ i ] );
1707                } else {
1708                   lbnd[ i ] = -DBL_MAX;
1709                   ubnd[ i ] = DBL_MAX;
1710                }
1711             }
1712          }
1713       }
1714 
1715 /* Free resources. */
1716       clbnd1 = astFree( clbnd1 );
1717       cubnd1 = astFree( cubnd1 );
1718       clbnd2 = astFree( clbnd2 );
1719       cubnd2 = astFree( cubnd2 );
1720    }
1721 }
1722 
RegBaseBox2(AstRegion * this_region,double * lbnd,double * ubnd,int * status)1723 static void RegBaseBox2( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){
1724 /*
1725 *  Name:
1726 *     RegBaseBox2
1727 
1728 *  Purpose:
1729 *     Returns the bounding box of an un-negated Region in the base Frame of
1730 *     the encapsulated FrameSet.
1731 
1732 *  Type:
1733 *     Private function.
1734 
1735 *  Synopsis:
1736 *     #include "cmpregion.h"
1737 *     void RegBaseBox2( AstRegion *this, double *lbnd, double *ubnd, int *status )
1738 
1739 *  Class Membership:
1740 *     CmpRegion member function (over-rides the astRegBaseBox2 protected
1741 *     method inherited from the Region class).
1742 
1743 *  Description:
1744 *     This function is similar to astRegBaseBox in that it returns the
1745 *     upper and lower axis bounds of a Region in the base Frame of the
1746 *     encapsulated FrameSet. But, in addition to assuming that the
1747 *     supplied Region has not been negated, it also assumes that any
1748 *     component Regions contained within the supplied Region have not been
1749 *     negated.
1750 
1751 *  Parameters:
1752 *     this
1753 *        Pointer to the Region.
1754 *     lbnd
1755 *        Pointer to an array in which to return the lower axis bounds
1756 *        covered by the Region in the base Frame of the encapsulated
1757 *        FrameSet. It should have at least as many elements as there are
1758 *        axes in the base Frame.
1759 *     ubnd
1760 *        Pointer to an array in which to return the upper axis bounds
1761 *        covered by the Region in the base Frame of the encapsulated
1762 *        FrameSet. It should have at least as many elements as there are
1763 *        axes in the base Frame.
1764 *     status
1765 *        Pointer to the inherited status variable.
1766 
1767 */
1768 
1769 /* Local Variables: */
1770    AstCmpRegion *this;          /* Pointer to CmpRegion structure */
1771    AstRegion *reg1;             /* Pointer to first component Region */
1772    AstRegion *reg2;             /* Pointer to second component Region */
1773    double *clbnd1;              /* Point to 1st comp lower bounds array */
1774    double *clbnd2;              /* Point to 2nd comp lower bounds array */
1775    double *cubnd1;              /* Point to 1st comp upper bounds array */
1776    double *cubnd2;              /* Point to 2nd comp upper bounds array */
1777    int i;                       /* Axis index */
1778    int nax;                     /* Number of axes in Frame */
1779 
1780 /* Check the global error status. */
1781    if ( !astOK ) return;
1782 
1783 /* Get a pointer to the CmpRegion structure */
1784    this = (AstCmpRegion *) this_region;
1785 
1786 /* Get pointers to the component Regions. */
1787    reg1 = this->region1;
1788    reg2 = this->region2;
1789 
1790 /* The base Frame of the parent Region structure is the current Frame of
1791    the component Regions. Get the no. of axes in this Frame. */
1792    nax = astGetNaxes( reg1 );
1793 
1794 /* Get the bounding boxes of the component Regions in this Frame. */
1795    clbnd1 = astMalloc( sizeof( double )*(size_t) nax );
1796    cubnd1 = astMalloc( sizeof( double )*(size_t) nax );
1797    clbnd2 = astMalloc( sizeof( double )*(size_t) nax );
1798    cubnd2 = astMalloc( sizeof( double )*(size_t) nax );
1799    if( astOK ) {
1800       astGetRegionBounds2( reg1, clbnd1, cubnd1 );
1801       astGetRegionBounds2( reg2, clbnd2, cubnd2 );
1802 
1803 /* How we combine the two bounding boxes depends on the boolean operator
1804    associated with this CmpRegion.  For AND find the overlap of the two
1805    bounding boxes. For other operators find the union. */
1806       if( this->oper == AST__AND ) {
1807          for( i = 0; i < nax; i++ ) {
1808             lbnd[ i ]= MAX( clbnd1[ i ], clbnd2[ i ] );
1809             ubnd[ i ]= MIN( cubnd1[ i ], cubnd2[ i ] );
1810          }
1811 
1812       } else {
1813          for( i = 0; i < nax; i++ ) {
1814             lbnd[ i ]= MIN( clbnd1[ i ], clbnd2[ i ] );
1815             ubnd[ i ]= MAX( cubnd1[ i ], cubnd2[ i ] );
1816          }
1817       }
1818    }
1819 
1820 /* Free resources. */
1821    clbnd1 = astFree( clbnd1 );
1822    cubnd1 = astFree( cubnd1 );
1823    clbnd2 = astFree( clbnd2 );
1824    cubnd2 = astFree( cubnd2 );
1825 
1826 }
1827 
RegBaseMesh(AstRegion * this_region,int * status)1828 static AstPointSet *RegBaseMesh( AstRegion *this_region, int *status ){
1829 /*
1830 *  Name:
1831 *     RegBaseMesh
1832 
1833 *  Purpose:
1834 *     Return a PointSet containing a mesh of points on the boundary of a
1835 *     Region in its base Frame.
1836 
1837 *  Type:
1838 *     Private function.
1839 
1840 *  Synopsis:
1841 *     #include "cmpregion.h"
1842 *     AstPointSet *astRegBaseMesh( AstRegion *this, int *status )
1843 
1844 *  Class Membership:
1845 *     CmpRegion member function (over-rides the astRegBaseMesh protected
1846 *     method inherited from the Region class).
1847 
1848 *  Description:
1849 *     This function returns a PointSet containing a mesh of points on the
1850 *     boundary of the Region. The points refer to the base Frame of
1851 *     the encapsulated FrameSet.
1852 
1853 *  Parameters:
1854 *     this
1855 *        Pointer to the Region.
1856 *     status
1857 *        Pointer to the inherited status variable.
1858 
1859 *  Returned Value:
1860 *     Pointer to the PointSet. Annul the pointer using astAnnul when it
1861 *     is no longer needed.
1862 
1863 *  Notes:
1864 *    - A NULL pointer is returned if an error has already occurred, or if
1865 *    this function should fail for any reason.
1866 
1867 */
1868 
1869 
1870 /* Local Variables: */
1871    AstCmpRegion *this;            /* The CmpRegion structure */
1872    AstPointSet *mesh1;            /* PointSet holding mesh for 1st component */
1873    AstPointSet *mesh1b;           /* Mesh for 1st component mapped by 2nd comp. */
1874    AstPointSet *mesh2;            /* PointSet holding mesh for 2nd component */
1875    AstPointSet *mesh2b;           /* Mesh for 2nd component mapped by 1st comp. */
1876    AstPointSet *result;           /* Returned pointer */
1877    AstRegion *reg1;               /* Pointer to first component Region */
1878    AstRegion *reg2;               /* Pointer to second component Region */
1879    double **ptr1;                 /* Pointer to array of mesh1b axis value pointers */
1880    double **ptr2;                 /* Pointer to array of mesh2b axis value pointers */
1881    double **ptr;                  /* Pointer to array of total axis value pointers */
1882    double *lbnd;                  /* Pointer to array of bounding box lower bounds */
1883    double *ubnd;                  /* Pointer to array of bounding box upper bounds */
1884    double v;                      /* Axis value */
1885    int hasMesh1;                  /* Does 1st component Region have a mesh? */
1886    int hasMesh2;                  /* Does 2nd component Region have a mesh? */
1887    int ic;                        /* Axis index */
1888    int ip;                        /* Input point index */
1889    int jp;                        /* Output point index */
1890    int nc;                        /* No. of axis values per point */
1891    int np1;                       /* No. of points in mesh1b */
1892    int np2;                       /* No. of points in mesh2b */
1893    int np;                        /* No. of points in returned PointSet */
1894    int ok;                        /* Were all axis values good at this point? */
1895 
1896 /* Initialise */
1897    result= NULL;
1898 
1899 /* Check the global error status. */
1900    if ( !astOK ) return result;
1901 
1902 /* Get a pointer to the CmpRegion structure. */
1903    this = (AstCmpRegion *) this_region;
1904 
1905 /* If the Region structure contains a pointer to a PointSet holding
1906    a previously created mesh, return it. */
1907    if( this_region->basemesh ) {
1908       result = astClone( this_region->basemesh );
1909 
1910 /* Otherwise, create a new mesh. */
1911    } else {
1912 
1913 /* Get pointers to the component regions. */
1914       reg1 = this->region1;
1915       reg2 = this->region2;
1916 
1917 /* A mesh can only be produced for a Region if it is bounded when either
1918    negated or un-negated. See if meshes can be produced for the component
1919    Regions. */
1920       hasMesh1 = astGetBounded( reg1 );
1921       if( !hasMesh1 ){
1922          astNegate( reg1 );
1923          hasMesh1 = astGetBounded( reg1 );
1924          astNegate( reg1 );
1925       }
1926 
1927       hasMesh2 = astGetBounded( reg2 );
1928       if( !hasMesh2 ){
1929          astNegate( reg2 );
1930          hasMesh2 = astGetBounded( reg2 );
1931          astNegate( reg2 );
1932       }
1933 
1934 /* If neither Region has a mesh we cannot produce a mesh. */
1935       if( !hasMesh1 && !hasMesh2 && astOK ) {
1936          astError( AST__INTER, "astRegBaseMesh(%s): No mesh can be "
1937                    "produced for the %s bacause neither of its component "
1938                    "Regions has a mesh (internal AST programming error).", status,
1939                    astGetClass( this ), astGetClass( this ) );
1940 
1941 /* If only one Region has a mesh, we can produce a mesh so long as the
1942     boolean operator is not OR. */
1943       } else if( ( !hasMesh1 || !hasMesh2 ) && this->oper == AST__OR && astOK ) {
1944          astError( AST__INTER, "astRegBaseMesh(%s): No mesh can be produced "
1945                    "for the %s bacause one its component Regions has no "
1946                    "mesh and the union of the Regions is required (internal "
1947                    "AST programming error).", status, astGetClass( this ), astGetClass( this ) );
1948       }
1949 
1950 /* Allocate memory to hold a bounding box in the base Frame of the CmpRegion. */
1951       nc = astGetNin( this_region->frameset );
1952       lbnd = astMalloc( sizeof( double )*(size_t) nc );
1953       ubnd = astMalloc( sizeof( double )*(size_t) nc );
1954 
1955 /* Get current Frame meshes covering the two component Regions (the current
1956    Frame of the component Regions is the same as the base Frame of the parent
1957    Region). We now know that at least one Region has a mesh. If the other
1958    one does not have a mesh we may be able to create a mesh by taking the
1959    intersection of the Region with the bounding box of the bounded Region. */
1960       if( hasMesh1 ) {
1961          mesh1 = astRegMesh( reg1 );
1962          if( hasMesh2 ) {
1963             mesh2 = astRegMesh( reg2 );
1964          } else {
1965             astGetRegionBounds( reg1, lbnd, ubnd );
1966             mesh2 = astBndMesh( reg2, lbnd, ubnd );
1967          }
1968 
1969       } else {
1970          mesh2 = astRegMesh( reg2 );
1971          astGetRegionBounds( reg2, lbnd, ubnd );
1972          mesh1 = astBndMesh( reg1, lbnd, ubnd );
1973       }
1974 
1975 /* If the CmpRegion represents the intersection of the two component Regions
1976    (AND operator), the total mesh is the sum of the component mesh points
1977    which are inside the other component region. If the CmpRegion represents
1978    the union of the two component Regions (OR operator), the total mesh is
1979    the sum of the component mesh points which are outside the other component
1980    region. So temporarily negate the component Regions if they are
1981    combined using OR. */
1982       if( this->oper == AST__OR ) {
1983          astNegate( reg1 );
1984          astNegate( reg2 );
1985       }
1986 
1987 /* Transform the mesh for the first component using the second component
1988    as a Mapping. Mesh points outside (or inside if "oper" is OR) the bounds
1989    of the second component will be set bad. */
1990       mesh1b = astTransform( reg2, mesh1, 1, NULL );
1991 
1992 /* Transform the mesh for the second component using the first component
1993    as a Mapping. Mesh points outside (or inside if "oper" is OR) the bounds
1994    of the first component will be set bad. */
1995       mesh2b = astTransform( reg1, mesh2, 1, NULL );
1996 
1997 /* If required, negate them again to bring them back to their original state.*/
1998       if( this->oper == AST__OR ) {
1999          astNegate( reg1 );
2000          astNegate( reg2 );
2001       }
2002 
2003 /* The required mesh contains all the good points form both mesh1b and
2004    mesh2b (i.e. all boundary points which are inside -or inside if "oper"
2005    is OR- the other component Region). Create a PointSet assuming that all
2006    points are good. First allocate an array to hold pointers to the arrays
2007    holding coordinate values for each axis. */
2008       nc = astGetNcoord( mesh1b );
2009       np1 = astGetNpoint( mesh1b );
2010       np2 = astGetNpoint( mesh2b );
2011       np = np1 + np2;
2012       result = astPointSet( np, nc, "", status );
2013       ptr = astGetPoints( result );
2014 
2015 /* Get points to the axis values of the mapped meshes. */
2016       ptr1 = astGetPoints( mesh1b );
2017       ptr2 = astGetPoints( mesh2b );
2018 
2019 /* Check pointers can be used safely. */
2020       if( astOK ) {
2021 
2022 /* Initialise the index of the next point in the total mesh. */
2023          jp = 0;
2024 
2025 /* Loop round all the points in the transformed mesh for the first
2026    component. */
2027          for( ip = 0; ip < np1; ip++ ) {
2028 
2029 /* Assume this point has good axis values */
2030             ok = 1;
2031 
2032 /* Copy the axis values into the total mesh. Break if a bad axis value is
2033    found. */
2034             for( ic = 0; ic < nc; ic++ ) {
2035                v = ptr1[ ic ][ ip ];
2036                if( v != AST__BAD ) {
2037                   ptr[ ic ][ jp ] = v;
2038                } else {
2039                   ok = 0;
2040                   break;
2041                }
2042             }
2043 
2044 /* If no bad axis values were found, increment the index of the next
2045    point in the total mesh. */
2046             if( ok ) jp++;
2047          }
2048 
2049 /* Now similarly copy the good values from the second transformed mesh onto
2050    the end of the total mesh array. */
2051          for( ip = 0; ip < np2; ip++ ) {
2052             ok = 1;
2053             for( ic = 0; ic < nc; ic++ ) {
2054                v = ptr2[ ic ][ ip ];
2055                if( v != AST__BAD ) {
2056                   ptr[ ic ][ jp ] = v;
2057                } else {
2058                   ok = 0;
2059                   break;
2060                }
2061             }
2062             if( ok ) jp++;
2063          }
2064 
2065 /* If the total mesh contains no good points, we will create a PointSet
2066    holding a single bad position. */
2067          if( jp == 0 ) {
2068             np = 1;
2069             for( ic = 0; ic < nc; ic++ ) ptr[ ic ][ 0 ] = AST__BAD;
2070          } else {
2071             np = jp;
2072          }
2073 
2074 /* Adjust the size of the returned PointSet to exclude the extra space
2075    caused by any axis values being bad in the transformed meshes. */
2076          astSetNpoint( result, np );
2077 
2078       }
2079 
2080 /* Free resources. */
2081       mesh1 = astAnnul( mesh1 );
2082       mesh2 = astAnnul( mesh2 );
2083       mesh1b = astAnnul( mesh1b );
2084       mesh2b = astAnnul( mesh2b );
2085       lbnd = astFree( lbnd );
2086       ubnd = astFree( ubnd );
2087 
2088 /* Save the returned pointer in the Region structure so that it does not
2089    need to be created again next time this function is called. */
2090       if( astOK && result ) this_region->basemesh = astClone( result );
2091    }
2092 
2093 /* Annul the result if an error has occurred. */
2094    if( !astOK ) result = astAnnul( result );
2095 
2096 /* Return a pointer to the output PointSet. */
2097    return result;
2098 }
2099 
RegBasePick(AstRegion * this_region,int naxes,const int * axes,int * status)2100 static AstRegion *RegBasePick( AstRegion *this_region, int naxes,
2101                                const int *axes, int *status ){
2102 /*
2103 *  Name:
2104 *     RegBasePick
2105 
2106 *  Purpose:
2107 *     Return a Region formed by picking selected base Frame axes from the
2108 *     supplied Region.
2109 
2110 *  Type:
2111 *     Private function.
2112 
2113 *  Synopsis:
2114 *     #include "cmpregion.h"
2115 *     AstRegion *RegBasePick( AstRegion *this, int naxes, const int *axes,
2116 *                             int *status )
2117 
2118 *  Class Membership:
2119 *     CmpRegion member function (over-rides the astRegBasePick protected
2120 *     method inherited from the Region class).
2121 
2122 *  Description:
2123 *     This function attempts to return a Region that is spanned by selected
2124 *     axes from the base Frame of the encapsulated FrameSet of the supplied
2125 *     Region. This may or may not be possible, depending on the class of
2126 *     Region. If it is not possible a NULL pointer is returned.
2127 
2128 *  Parameters:
2129 *     this
2130 *        Pointer to the Region.
2131 *     naxes
2132 *        The number of base Frame axes to select.
2133 *     axes
2134 *        An array holding the zero-based indices of the base Frame axes
2135 *        that are to be selected.
2136 *     status
2137 *        Pointer to the inherited status variable.
2138 
2139 *  Returned Value:
2140 *     Pointer to the Region, or NULL if no region can be formed.
2141 
2142 *  Notes:
2143 *    - A NULL pointer is returned if an error has already occurred, or if
2144 *    this function should fail for any reason.
2145 */
2146 
2147 /* Local Variables: */
2148    AstCmpRegion *this;     /* Pointer to CmpRegion structure */
2149    AstFrame *frm1;         /* Axes picked from the 1st encapsulated Region */
2150    AstFrame *frm2;         /* Axes picked from the 2nd encapsulated Region */
2151    AstRegion *result;      /* Returned Region */
2152 
2153 /* Initialise */
2154    result = NULL;
2155 
2156 /* Check the global error status. */
2157    if ( !astOK ) return result;
2158 
2159 /* Get a pointer to the CmpRegion information. */
2160    this = (AstCmpRegion *) this_region;
2161 
2162 /* Both encapsulated regions refer to the same Frame (the base Frame of
2163    the parent Region), so attempt to pick the requested axs from them.
2164    If the resulting Frames are not Regions, we cannot pick the requested
2165    axes so return the NULL Frame pointer initialised above. */
2166    frm1 = astPickAxes( this->region1, naxes, axes, NULL );
2167    if( astIsARegion( frm1 ) ) {
2168       frm2 = astPickAxes( this->region2, naxes, axes, NULL );
2169       if( astIsARegion( frm2 ) ) {
2170 
2171 /* Create the new CmpRegion. */
2172          result = (AstRegion *) astCmpRegion( (AstRegion *) frm1,
2173                                               (AstRegion *) frm2,
2174                                               this->oper, "", status );
2175       }
2176 
2177 /* Free resources */
2178       frm2 = astAnnul( frm2 );
2179    }
2180    frm1 = astAnnul( frm1 );
2181 
2182 /* Return a NULL pointer if an error has occurred. */
2183    if( !astOK ) result = astAnnul( result );
2184 
2185 /* Return the result. */
2186    return result;
2187 }
2188 
RegPins(AstRegion * this_region,AstPointSet * pset,AstRegion * unc,int ** mask,int * status)2189 static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
2190                     int **mask, int *status ){
2191 /*
2192 *  Name:
2193 *     RegPins
2194 
2195 *  Purpose:
2196 *     Check if a set of points fall on the boundary of a given CmpRegion.
2197 
2198 *  Type:
2199 *     Private function.
2200 
2201 *  Synopsis:
2202 *     #include "cmpregion.h"
2203 *     int RegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc,
2204 *                  int **mask, int *status )
2205 
2206 *  Class Membership:
2207 *     CmpRegion member function (over-rides the astRegPins protected
2208 *     method inherited from the Region class).
2209 
2210 *  Description:
2211 *     This function returns a flag indicating if the supplied set of
2212 *     points all fall on the boundary of the given CmpRegion.
2213 *
2214 *     Some tolerance is allowed, as specified by the uncertainty Region
2215 *     stored in the supplied CmpRegion "this", and the supplied uncertainty
2216 *     Region "unc" which describes the uncertainty of the supplied points.
2217 
2218 *  Parameters:
2219 *     this
2220 *        Pointer to the CmpRegion.
2221 *     pset
2222 *        Pointer to the PointSet. The points are assumed to refer to the
2223 *        base Frame of the FrameSet encapsulated by "this".
2224 *     unc
2225 *        Pointer to a Region representing the uncertainties in the points
2226 *        given by "pset". The Region is assumed to represent the base Frame
2227 *        of the FrameSet encapsulated by "this". Zero uncertainity is assumed
2228 *        if NULL is supplied.
2229 *     mask
2230 *        Pointer to location at which to return a pointer to a newly
2231 *        allocated dynamic array of ints. The number of elements in this
2232 *        array is equal to the value of the Npoint attribute of "pset".
2233 *        Each element in the returned array is set to 1 if the
2234 *        corresponding position in "pset" is on the boundary of the Region
2235 *        and is set to zero otherwise. A NULL value may be supplied
2236 *        in which case no array is created. If created, the array should
2237 *        be freed using astFree when no longer needed.
2238 *     status
2239 *        Pointer to the inherited status variable.
2240 
2241 *  Returned Value:
2242 *     Non-zero if the points all fall on the boundary of the given
2243 *     Region, to within the tolerance specified. Zero otherwise.
2244 
2245 */
2246 
2247 /* Local variables: */
2248    AstCmpRegion *this;          /* Pointer to the CmpRegion structure. */
2249    AstPointSet *pset1;          /* Points masked by 1st component Region */
2250    AstPointSet *pset2;          /* Points masked by 2nd component Region */
2251    AstPointSet *psetb1;         /* Points in base Frame of 1st component Region */
2252    AstPointSet *psetb2;         /* Points in base Frame of 2nd component Region */
2253    AstRegion *reg1;             /* Pointer to first component Region */
2254    AstRegion *reg2;             /* Pointer to second component Region */
2255    AstRegion *unc1;             /* Base Frame uncertainty in 1st component Region */
2256    AstRegion *unc2;             /* Base Frame uncertainty in 2nd component Region */
2257    double **ptr1;               /* Pointer to axis values in "pset1" */
2258    double **ptr2;               /* Pointer to axis values in "pset2" */
2259    double *p1;                  /* Pointer to next axis zero value for pset1 */
2260    double *p2;                  /* Pointer to next axis zero value for pset2 */
2261    int *mask1;                  /* Mask for first component boundary */
2262    int *mask2;                  /* Mask for second component boundary */
2263    int ip;                      /* Point index */
2264    int np;                      /* Number of points */
2265    int result;                  /* Returned flag */
2266 
2267 /* Initialise */
2268    result = 0;
2269    if( mask ) *mask = NULL;
2270 
2271 /* Check the inherited status. */
2272    if( !astOK ) return result;
2273 
2274 /* Get a pointer to the CmpRegion structure. */
2275    this = (AstCmpRegion *) this_region;
2276 
2277 /* Get pointers to the two component Regions. */
2278    reg1 = this->region1;
2279    reg2 = this->region2;
2280 
2281 /* Get a mask which indicates if each supplied point is on or off the
2282    boundary of the first component Region. astRegPins expects its "pset"
2283    argument to contain positions in the base Frame of the Region, so
2284    we must first transform the supplied points into the base Frame of
2285    "reg1". We must also map the uncertainty into the base Frame of the
2286    component Region. */
2287    psetb1 = astRegTransform( reg1, pset, 0, NULL, NULL );
2288    unc1 = MatchRegion( reg1, AST__BASE, unc, "astRegPins", status );
2289    astRegPins( reg1, psetb1, unc1, &mask1 );
2290 
2291 /* Likewise, get a mask which indicates if each supplied point is on or off
2292    the boundary of the second component Region. */
2293    psetb2 = astRegTransform( reg2, pset, 0, NULL, NULL );
2294    unc2 = MatchRegion( reg2, AST__BASE, unc, "astRegPins", status );
2295    astRegPins( reg2, psetb2, unc2, &mask2 );
2296 
2297 /* The criteria for a point to be on the boundary of the CmpRegion depend
2298    on the boolean operator being used. If component regions A and B are
2299    ANDed together, then a point is on the boundary of the CmpRegion if
2300    either 1) it is on the boundary of A and inside B, or 2) it is on the
2301    boundary of B and inside A. If the component regions are ORed together,
2302    then a point is on the boundary of the CmpRegion if either 1) it is on
2303    the boundary of A and outside B, or 2) it is on the boundary of B and
2304    outside A. Either we need to transform the supplied PointSet using each
2305    component Region as a Mapping. But if using OR we temporarily negate
2306    the Regions. */
2307    if( this->oper == AST__OR ) {
2308       astNegate( reg1 );
2309       astNegate( reg2 );
2310    }
2311    pset1 = astTransform( reg1, pset, 1, NULL );
2312    pset2 = astTransform( reg2, pset, 1, NULL );
2313    if( this->oper == AST__OR ) {
2314       astNegate( reg1 );
2315       astNegate( reg2 );
2316    }
2317 
2318 /* Get pointers to the axis values in these PointSets */
2319    ptr1 = astGetPoints( pset1 );
2320    ptr2 = astGetPoints( pset2 );
2321 
2322 /* If required, create an output mask array */
2323    np = astGetNpoint( pset );
2324    if( mask ) *mask = astMalloc( sizeof(int)*(size_t) np );
2325 
2326 /* Check pointers can be used safely. */
2327    if( astOK ) {
2328 
2329 /* We can use the values for the first axis to indicate if a point is
2330    inside or outside a Region. So store pointers to the first axis arrays. */
2331       p1 = ptr1[ 0 ];
2332       p2 = ptr2[ 0 ];
2333 
2334 /* Assume all points are on the boundary of the CmpRegion. */
2335       result = 1;
2336 
2337 /* If we are creating an output mask, we must check every point. Otherwise
2338    we can stop checking when we find the first point which is not on the
2339    boundary of the CmpRegion. */
2340       if( mask ) {
2341 
2342          for( ip = 0; ip < np; ip++ ) {
2343             if( ( mask1[ ip ] && p2[ ip ] != AST__BAD ) ||
2344                 ( mask2[ ip ] && p1[ ip ] != AST__BAD ) ){
2345                (*mask)[ ip ] = 1;
2346             } else {
2347                (*mask)[ ip ] = 0;
2348                result = 0;
2349             }
2350          }
2351 
2352       } else {
2353 
2354          for( ip = 0; ip < np; ip++ ) {
2355             if( ( !mask1[ ip ] || p2[ ip ] == AST__BAD ) &&
2356                 ( !mask2[ ip ] || p1[ ip ] == AST__BAD ) ){
2357                result = 0;
2358                break;
2359             }
2360          }
2361       }
2362    }
2363 
2364 /* Free resources */
2365    mask1 = astFree( mask1 );
2366    mask2 = astFree( mask2 );
2367    pset1 = astAnnul( pset1 );
2368    pset2 = astAnnul( pset2 );
2369    psetb1 = astAnnul( psetb1 );
2370    psetb2 = astAnnul( psetb2 );
2371    if( unc1 ) unc1 = astAnnul( unc1 );
2372    if( unc2 ) unc2 = astAnnul( unc2 );
2373 
2374 /* If an error has occurred, return zero. */
2375    if( !astOK ) {
2376       result = 0;
2377       if( mask ) *mask = astAnnul( *mask );
2378    }
2379 
2380 /* Return the result. */
2381    return result;
2382 }
2383 
RegSetAttrib(AstRegion * this_region,const char * setting,char ** base_setting,int * status)2384 static void RegSetAttrib( AstRegion *this_region, const char *setting,
2385                           char **base_setting, int *status ) {
2386 /*
2387 *  Name:
2388 *     RegSetAttrib
2389 
2390 *  Purpose:
2391 *     Set an attribute value for a Region.
2392 
2393 *  Type:
2394 *     Private function.
2395 
2396 *  Synopsis:
2397 *     #include "cmpregion.h"
2398 *     void RegSetAttrib( AstRegion *this, const char *setting,
2399 *                        char **base_setting, int *status )
2400 
2401 *  Class Membership:
2402 *     CmpRegion method (over-rides the astRegSetAttrib method inherited from
2403 *     the Region class).
2404 
2405 *  Description:
2406 *     This function assigns an attribute value to both the base and
2407 *     current Frame in the FrameSet encapsulated within a Region, without
2408 *     remapping either Frame.
2409 *
2410 *     No error is reported if the attribute is not recognised by the base
2411 *     Frame.
2412 
2413 *  Parameters:
2414 *     this
2415 *        Pointer to the Region.
2416 *     setting
2417 *        Pointer to a null terminated attribute setting string. NOTE, IT
2418 *        SHOULD BE ENTIRELY LOWER CASE. The supplied string will be
2419 *        interpreted using the public interpretation implemented by
2420 *        astSetAttrib. This can be different to the interpretation of the
2421 *        protected accessor functions. For instance, the public
2422 *        interpretation of an unqualified floating point value for the
2423 *        Epoch attribute is to interpet the value as a gregorian year,
2424 *        but the protected interpretation is to interpret the value as an
2425 *        MJD.
2426 *     base_setting
2427 *        Address of a location at which to return a pointer to the null
2428 *        terminated attribute setting string which was applied to the
2429 *        base Frame of the encapsulated FrameSet. This may differ from
2430 *        the supplied setting if the supplied setting contains an axis
2431 *        index and the current->base Mapping in the FrameSet produces an
2432 *        axis permutation. The returned pointer should be freed using
2433 *        astFree when no longer needed. A NULL pointer may be supplied in
2434 *        which case no pointer is returned.
2435 *     status
2436 *        Pointer to the inherited status variable.
2437 
2438 */
2439 
2440 /* Local Variables: */
2441    AstCmpRegion *this;
2442    char *bset;
2443    int rep;
2444 
2445 /* Check the global error status. */
2446    if ( !astOK ) return;
2447 
2448 /* Get a pointer to the CmpRegion structure. */
2449    this = (AstCmpRegion *) this_region;
2450 
2451 /* Use the RegSetAttrib method inherited from the parent class to apply the
2452    setting to the current and base Frames in the FrameSet encapsulated by the
2453    parent Region structure. */
2454    (*parent_regsetattrib)( this_region, setting, &bset, status );
2455 
2456 /* Now apply the base Frame setting to the component Regions (the current
2457    Frame within the component Regions is equivalent to the base Frame in the
2458    parent Region structure). Annul any "attribute unknown" error that results
2459    from attempting to do this. */
2460    if( astOK ) {
2461       rep = astReporting( 0 );
2462       astRegSetAttrib( this->region1, bset, NULL );
2463       astRegSetAttrib( this->region2, bset, NULL );
2464       if( astStatus == AST__BADAT ) astClearStatus;
2465       astReporting( rep );
2466    }
2467 
2468 /* If required, return the base Frame setting string, otherwise free it. */
2469    if( base_setting ) {
2470       *base_setting = bset;
2471    } else {
2472       bset = astFree( bset );
2473    }
2474 }
2475 
RegSplit(AstRegion * this_region,int * nlist,int * status)2476 static AstRegion **RegSplit( AstRegion *this_region, int *nlist, int *status ){
2477 /*
2478 *+
2479 *  Name:
2480 *     RegSplit
2481 
2482 *  Purpose:
2483 *     Split a Region into a list of disjoint component Regions.
2484 
2485 *  Type:
2486 *     Private function.
2487 
2488 *  Synopsis:
2489 *     #include "region.h"
2490 *     AstRegion **astRegSplit( AstRegion *this, int *nlist )
2491 
2492 *  Class Membership:
2493 *     CmpRegion member function (overrides the astRegSplit method
2494 *     inherited from the parent Region class).
2495 
2496 *  Description:
2497 *     This function splits the supplied Region into a set of disjoint
2498 *     component Regions. If the Region cannot be split, then the returned
2499 *     array contains only one pointer - a clone of the supplied Region
2500 *     pointer.
2501 
2502 *  Parameters:
2503 *     this
2504 *        Pointer to the Region.
2505 *     nlist
2506 *        Pointer to an int in which to return the number of elements in
2507 *        the returned array.
2508 
2509 *  Returned Value:
2510 *     Pointer to dynamically alloctaed memory holding an array of Region
2511 *     pointers. The length of this array is given by the value returned
2512 *     in "*nlist". The pointers in the returned array should be annulled
2513 *     using astAnnul when no longer needed, and the memory used to hold
2514 *     the array should be freed using astFree.
2515 
2516 *  Notes:
2517 *    - A NULL pointer is returned if an error has already occurred, or if
2518 *    this function should fail for any reason.
2519 *-
2520 */
2521 
2522 /* Local Variables; */
2523    AstCmpRegion *new;
2524    AstCmpRegion *this;
2525    AstFrame *frm;
2526    AstFrameSet *fs;
2527    AstMapping *map;
2528    AstRegion **cmplist;
2529    AstRegion **result;
2530    AstRegion *cmpreg;
2531    AstRegion *new_reg;
2532    int icomp;
2533    int ifirst;
2534    int ilist;
2535    int iw;
2536    int jcomp;
2537    int ncomp;
2538    int nn;
2539    int unbounded;
2540 
2541 /* Initialise. */
2542    result = NULL;
2543    *nlist = 0;
2544 
2545 /* Check the local error status. */
2546    if ( !astOK ) return result;
2547 
2548 /* Get a pointer to the CmpRegion structure. */
2549    this = (AstCmpRegion *) this_region;
2550 
2551 /* Can only split non-inverted CmpRegions that combine their components
2552    using the OR operator. */
2553    if( this->oper == AST__OR && !astGetNegated( this->region1 ) &&
2554                                 !astGetNegated( this->region2 ) ) {
2555 
2556 /* Indicate we have not yet found any unbounded component regions. */
2557       unbounded = 0;
2558 
2559 /* Process each of the two component Regions in turn. */
2560       for( icomp = 0; icomp < 2 && !unbounded; icomp++ ) {
2561          cmpreg = icomp ? this->region2 : this->region1;
2562 
2563 /* Create a set of disjoint Regions that are equivalent to the current
2564    component Region, and loop round them. */
2565          cmplist = astRegSplit( cmpreg, &ncomp );
2566          for( jcomp = 0; jcomp < ncomp; jcomp++ ) {
2567 
2568 /* If any of the components are unbounds, we cannot split the supplied
2569    Region. */
2570             unbounded = unbounded || !astGetBounded( cmplist[ jcomp ] );
2571             if( ! unbounded ) {
2572 
2573 /* Initialise the index within the returned list of the first Region that
2574    overlaps the current disjoint component Region. */
2575                ifirst = -1;
2576 
2577 /* Loop round all the Regions currently in the returned list. */
2578                for( ilist = 0; ilist < *nlist; ilist++ ) {
2579                   if( result[ ilist ] ) {
2580 
2581 /* See if the current disjoint component overlaps the current entry in
2582    the returned list. */
2583                      if( astOverlap( cmplist[ jcomp ], result[ ilist ] ) > 1 ) {
2584 
2585 /* If this is the first overlap found for the current disjoint component,
2586    form a CmpRegion that combines the two overlapping Regions, and use it
2587    to replace the current entry in the returned list. */
2588                         if( ifirst == -1 ) {
2589                            new = astCmpRegion( cmplist[ jcomp ], result[ ilist ],
2590                                                AST__OR, " ", status );
2591                            (void) astAnnul( result[ ilist ] );
2592                            result[ ilist ] = (AstRegion *) new;
2593 
2594 /* Note the index within the returned list of the first Region that overlaps
2595    the current disjoint component Region. */
2596                            ifirst = ilist;
2597 
2598 /* If this is the second or later overlap, add the overlapping returned Region
2599    into the CmpRegion that it is stored at index "ifirsT" in the returned
2600    list. */
2601                         } else {
2602                            new = astCmpRegion( result[ ilist ], result[ ifirst ],
2603                                                AST__OR, " ", status );
2604                            result[ ilist ] = astAnnul( result[ ilist ] );
2605                            (void) astAnnul( result[ ifirst ] );
2606                            result[ ifirst ] = (AstRegion *) new;
2607                         }
2608                      }
2609                   }
2610                }
2611 
2612 /* If the current disjoint component does not overlap any of the Regions
2613    already in the returned list, append the current disjoint component to
2614    the end of the returned list. */
2615                if( ifirst == -1 ) {
2616                   ilist = (*nlist)++;
2617                   result = astGrow( result, *nlist, sizeof( *result ) );
2618                   if( astOK ) result[ ilist ] = astClone( cmplist[ jcomp ] );
2619                }
2620             }
2621 
2622 /* Annul the pointer to the disjoint component Region. */
2623             cmplist[ jcomp ] = astAnnul( cmplist[ jcomp ] );
2624          }
2625 
2626 /* Free the mnemory holding the list of disjoint components. */
2627          cmplist = astFree( cmplist );
2628       }
2629    }
2630 
2631 /* If any unbounded components were found, ensure the returned list is
2632    empty. */
2633    if( unbounded && result ) {
2634       for( ilist = 0; ilist < *nlist; ilist++ ) {
2635          if( result[ ilist ] ) result[ ilist ] = astAnnul( result[ ilist ] );
2636       }
2637       result = astFree( result );
2638       *nlist = 0;
2639 
2640 /* Otherwise, shuffle later entries down to fill any NULL slots in the returned
2641    list. */
2642    } else if( result ){
2643       nn = *nlist;
2644       iw = 0;
2645       for( ilist = 0; ilist < nn; ilist++ ) {
2646          if( result[ ilist ] ) result[ iw++ ] = result[ ilist ];
2647       }
2648       *nlist = iw;
2649    }
2650 
2651 /* If this CmpRegion cannot be split, the returned list just holds a
2652    clone of the Region pointer. */
2653    if( !result ) {
2654       result = astMalloc( sizeof( *result ) );
2655       if( astOK ) {
2656          result[ 0 ] = astClone( this );
2657          *nlist = 1;
2658       }
2659    }
2660 
2661 /* Remap any returned Regions so that they are defined within the same
2662    coordinate system as the supplied Region. */
2663    if( result && *nlist > 0 )  {
2664       fs = this_region->frameset;
2665       map = astGetMapping( fs, AST__BASE, AST__CURRENT );
2666       frm = astGetFrame( fs, AST__CURRENT );
2667       for( ilist = 0; ilist < *nlist; ilist++ ) {
2668          new_reg = astMapRegion( result[ ilist ], map, frm );
2669          (void) astAnnul( result[ ilist ] );
2670          result[ ilist ] = new_reg;
2671       }
2672       map = astAnnul( map );
2673       frm = astAnnul( frm );
2674    }
2675 
2676 /* Free all returned pointers if an error has occurred. */
2677    if( !astOK && result ) {
2678       for( ilist = 0; ilist < *nlist; ilist++ ) {
2679          result[ ilist ] = astAnnul( result[ ilist ] );
2680       }
2681       result = astFree( result );
2682       *nlist = 0;
2683    }
2684 
2685 /* Return the result. */
2686    return result;
2687 }
2688 
RegTrace(AstRegion * this_region,int n,double * dist,double ** ptr,int * status)2689 static int RegTrace( AstRegion *this_region, int n, double *dist, double **ptr,
2690                      int *status ){
2691 /*
2692 *+
2693 *  Name:
2694 *     RegTrace
2695 
2696 *  Purpose:
2697 *     Return requested positions on the boundary of a 2D Region.
2698 
2699 *  Type:
2700 *     Private function.
2701 
2702 *  Synopsis:
2703 *     #include "cmpregion.h"
2704 *     int astRegTrace( AstRegion *this, int n, double *dist, double **ptr );
2705 
2706 *  Class Membership:
2707 *     CmpRegion member function (overrides the astRegTrace method
2708 *     inherited from the parent Region class).
2709 
2710 *  Description:
2711 *     This function returns positions on the boundary of the supplied
2712 *     Region, if possible. The required positions are indicated by a
2713 *     supplied list of scalar parameter values in the range zero to one.
2714 *     Zero corresponds to some arbitrary starting point on the boundary,
2715 *     and one corresponds to the end (which for a closed region will be
2716 *     the same place as the start).
2717 
2718 *  Parameters:
2719 *     this
2720 *        Pointer to the Region.
2721 *     n
2722 *        The number of positions to return. If this is zero, the function
2723 *        returns without action (but the returned function value still
2724 *        indicates if the method is supported or not).
2725 *     dist
2726 *        Pointer to an array of "n" scalar parameter values in the range
2727 *        0 to 1.0.
2728 *     ptr
2729 *        A pointer to an array of pointers. The number of elements in
2730 *        this array should equal tthe number of axes in the Frame spanned
2731 *        by the Region. Each element of the array should be a pointer to
2732 *        an array of "n" doubles, in which to return the "n" values for
2733 *        the corresponding axis. The contents of the arrays are unchanged
2734 *        if the supplied Region belongs to a class that does not
2735 *        implement this method.
2736 
2737 *  Returned Value:
2738 *     Non-zero if the astRegTrace method is implemented by the class
2739 *     of Region supplied, and zero if not.
2740 
2741 *  Notes:
2742 *    - The current algorithm results in the boundary of the CmpRegion
2743 *    being dis-contiguous - supplied distance values from zero up to some
2744 *    mid-value correspond to positions on the first component Region, and
2745 *    higher distance (up to 1.0) correspond to points on the second
2746 *    component Region.
2747 
2748 *-
2749 */
2750 
2751 /* Local Variables; */
2752    AstCmpRegion *this;
2753    AstFrame *frm;
2754    AstMapping *map;
2755    AstPointSet *bpset;
2756    AstPointSet *cpset;
2757    AstRegion *ureg1;
2758    AstRegion *ureg2;
2759    double **bptr;
2760    int i;
2761    int j;
2762    int ncur;
2763    int result;
2764    double *rval;
2765    double *off;
2766    double *r1d;
2767    double *r2d;
2768    double *r1ptr[ 2 ];
2769    double *r2ptr[ 2 ];
2770    double **r1ptrb;
2771    double **r2ptrb;
2772    double dbreak;
2773    double dtot;
2774    double x;
2775    double x0;
2776    int r1n;
2777    int r2n;
2778    AstPointSet *r1pset;
2779    AstPointSet *r2pset;
2780    AstPointSet *r1psetb;
2781    AstPointSet *r2psetb;
2782 
2783 /* Initialise */
2784    result = 0;
2785 
2786 /* Check inherited status. */
2787    if( ! astOK ) return result;
2788 
2789 /* Get a pointer to the CmpRegion structure. */
2790    this = (AstCmpRegion *) this_region;
2791 
2792 /* Get a pointer to the base Frame in the encapsulated FrameSet. */
2793    frm = astGetFrame( this_region->frameset, AST__BASE );
2794 
2795 /* Check it is 2-dimensional. */
2796    result = 1;
2797    if( astGetNaxes( frm ) != 2 ) result = 0;
2798 
2799 /* Check the component Regions can be traced. */
2800    if( !astRegTrace( this->region1, 0, NULL, NULL ) ||
2801        !astRegTrace( this->region1, 0, NULL, NULL ) ) result = 0;
2802 
2803 /* Check we have some points to find. */
2804    if( result && n > 0 ) {
2805 
2806 /* We first determine the required positions in the base Frame of the
2807    Region, and then transform them into the current Frame. Get the
2808    base->current Mapping, and the number of current Frame axes. */
2809       map = astGetMapping( this_region->frameset, AST__BASE, AST__CURRENT );
2810 
2811 /* If it's a UnitMap we do not need to do the transformation, so put the
2812    base Frame positions directly into the supplied arrays. */
2813       if( astIsAUnitMap( map ) ) {
2814          bpset = NULL;
2815          bptr = ptr;
2816          ncur = 2;
2817 
2818 /* Otherwise, create a PointSet to hold the base Frame positions. */
2819       } else {
2820          bpset = astPointSet( n, 2, " ", status );
2821          bptr = astGetPoints( bpset );
2822          ncur = astGetNout( map );
2823       }
2824 
2825       r1d = astMalloc( sizeof( double )*n );
2826       r2d = astMalloc( sizeof( double )*n );
2827 
2828 /* Ensure information about the breaks in the boundary of each component
2829    region is available within the CmpRegion structure. These breaks are
2830    the points at which the two boundaries cross. */
2831       SetBreakInfo( this, 0, status );
2832       SetBreakInfo( this, 1, status );
2833 
2834 /* Get the constants needed to convert the supplied distances (normalised
2835    so that the border of the entire CmpRegion has a length of 1.0), into
2836    geodesic distances around the border of each component Region. */
2837       dtot = this->d0[ 0 ] + this->d0[ 1 ];
2838       dbreak = this->d0[ 0 ]/dtot;
2839 
2840 /* Initialise here to avoid compiler warnings. */
2841       r1n = 0;
2842       r2n = 0;
2843 
2844 /* Check the pointers can be used safely. */
2845       if( astOK ) {
2846 
2847 /* Loop round all supplied distances, determining if they represent a
2848    position on the first or second component Region. */
2849          for( i = 0; i < n; i++ ) {
2850 
2851 /* If the current distance represents a point in the second component
2852    Region... */
2853             if( dist[ i ] > dbreak ) {
2854 
2855 /* Find the correspond distance around the used sections of the second
2856    component region (normalised so that the entire border of the
2857    component region has a length of "this->d0[1]"). */
2858                x0 = ( dist[ i ] - dbreak )*dtot;
2859                x = x0;
2860 
2861 /* Convert this into the correspond distance around the entire border of
2862    the second component region (normalised so that the entire border of the
2863    component region has unit length). */
2864                rval = this->rvals[ 1 ];
2865                off = this->offs[ 1 ];
2866 
2867                for( j = 0; j < this->nbreak[ 1 ]; j++,rval++,off++ ) {
2868                   if( *rval >= x0 ) break;
2869                   x += *off;
2870                }
2871 
2872 /* Store this as the next distance to move around the second component
2873    Region, normalising it to the range 0 to 1 as required by astRegTrace. */
2874                r2d[ r2n++ ] = x/this->dtot[ 1 ];
2875 
2876 /* Now we do the same if the current distance corresponds to a position
2877    in the first component Region. */
2878             } else {
2879 
2880                x0 = dist[ i ]*dtot;
2881                x = x0;
2882 
2883                rval = this->rvals[ 0 ];
2884                off = this->offs[ 0 ];
2885 
2886                for( j = 0; j < this->nbreak[ 0 ]; j++,rval++,off++ ) {
2887                   if( *rval >= x0 ) break;
2888                   x += *off;
2889                }
2890 
2891                r1d[ r1n++ ] = x/this->dtot[ 0 ];
2892 
2893             }
2894 
2895          }
2896       }
2897 
2898 /* Allocate memory to hold the axis values at the corresponding positions
2899    in the first component Region. */
2900       r1ptr[ 0 ] = astMalloc( sizeof( double )*r1n );
2901       r1ptr[ 1 ] = astMalloc( sizeof( double )*r1n );
2902 
2903 /* Allocate memory to hold the axis values at the corresponding positions
2904    in the second component Region. */
2905       r2ptr[ 0 ] = astMalloc( sizeof( double )*r2n );
2906       r2ptr[ 1 ] = astMalloc( sizeof( double )*r2n );
2907 
2908 /* Check the pointers can be used safely. */
2909       if( astOK ) {
2910 
2911 /* Find the axis values at each of the required positions that fall in
2912    the first component Region. Negate it first if needed to ensure the
2913    Region is bounded (not guaranteed, but likely). */
2914          if( astGetBounded( this->region1 ) ) {
2915             (void) astRegTrace( this->region1, r1n, r1d, r1ptr );
2916          } else {
2917             AstRegion *negation = astGetNegation( this->region1 );
2918             (void) astRegTrace( negation, r1n, r1d, r1ptr );
2919             negation = astAnnul( negation );
2920          }
2921 
2922 /* Do the same for the second component Region. */
2923          if( astGetBounded( this->region2 ) ) {
2924             (void) astRegTrace( this->region2, r2n, r2d, r2ptr );
2925          } else {
2926             AstRegion *negation = astGetNegation( this->region2 );
2927             (void) astRegTrace( negation, r2n, r2d, r2ptr );
2928             negation = astAnnul( negation );
2929          }
2930 
2931 /* The arrays of positions returned by the above calls to astRegTrace may
2932    include points that should not be there (e.g. points on the boundary
2933    of one component region that should have been blanked due to being inside
2934    the second component region - if the regions are ORed together). This
2935    is a consequence of the relatively low value of the "NP" local constant
2936    in function SetBreakInfo. So we now refine the positions to exclude
2937    any such unwanted positions.
2938 
2939    If the two component Regions are ANDed together, we want to remove the
2940    positions from the boundary of the required component Region that fall
2941    outside the other region. We can do this by simply using the other Region
2942    as a Mapping. If the two component Regions are ORed together, we want to
2943    remove the position that fall within (rather than outside) the other
2944    Region. To do this we need to negate the other region  first. */
2945          if( this->oper == AST__OR ) {
2946             ureg1 = astGetNegation( this->region1 );
2947             ureg2 = astGetNegation( this->region2 );
2948          } else {
2949             ureg1 = astClone( this->region1 );
2950             ureg2 = astClone( this->region2 );
2951          }
2952 
2953 /* Now transform the points on the boundary of the first Region in order
2954    to set invalid those positions which are not on the boundary of the
2955    supplied CmpRegion. */
2956          if( r1n > 0 ) {
2957             r1pset = astPointSet( r1n, 2, " ", status );
2958             astSetPoints( r1pset, r1ptr );
2959             r1psetb = astTransform( ureg2, r1pset, 1, NULL );
2960             r1ptrb = astGetPoints( r1psetb );
2961          } else {
2962             r1pset = NULL;
2963             r1psetb = NULL;
2964             r1ptrb = NULL;
2965          }
2966 
2967 /* Now transform the points on the boundary of the second Region in order
2968    to set invalid those positions which are not on the boundary of the
2969    supplied CmpRegion. */
2970          if( r2n > 0 ) {
2971             r2pset = astPointSet( r2n, 2, " ", status );
2972             astSetPoints( r2pset, r2ptr );
2973             r2psetb = astTransform( ureg1, r2pset, 1, NULL );
2974             r2ptrb = astGetPoints( r2psetb );
2975          } else {
2976             r2pset = NULL;
2977             r2psetb = NULL;
2978             r2ptrb = NULL;
2979          }
2980 
2981 /* Free the begation pointers. */
2982          ureg1 = astAnnul( ureg1 );
2983          ureg2 = astAnnul( ureg2 );
2984 
2985 /* Check pointer can be used safely. */
2986          if( astOK ) {
2987 
2988 /* Copy the boundary positions from each component Region into a single
2989    PointSet. These positions are in the base Frame of the CmpRegion. */
2990             r1n = 0;
2991             r2n = 0;
2992             for( i = 0; i < n; i++ ) {
2993                if( dist[ i ] > dbreak ) {
2994                   bptr[ 0 ][ i ] = r2ptrb[ 0 ][ r2n ];
2995                   bptr[ 1 ][ i ] = r2ptrb[ 1 ][ r2n++ ];
2996                } else {
2997                   bptr[ 0 ][ i ] = r1ptrb[ 0 ][ r1n ];
2998                   bptr[ 1 ][ i ] = r1ptrb[ 1 ][ r1n++ ];
2999                }
3000             }
3001 
3002          }
3003 
3004 /* Free resources. */
3005          if( r1pset ) r1pset = astAnnul( r1pset );
3006          if( r2pset ) r2pset = astAnnul( r2pset );
3007          if( r1psetb ) r1psetb = astAnnul( r1psetb );
3008          if( r2psetb ) r2psetb = astAnnul( r2psetb );
3009 
3010       }
3011 
3012 /* If required, transform the base frame positions into the current
3013    Frame of the CmpRegion, storing them in the supplied array. Then
3014    free resources. */
3015       if( bpset ) {
3016          cpset = astPointSet( n, ncur, " ", status );
3017          astSetPoints( cpset, ptr );
3018 
3019          (void) astTransform( map, bpset, 1, cpset );
3020 
3021          cpset = astAnnul( cpset );
3022          bpset = astAnnul( bpset );
3023       }
3024 
3025 /* Free remaining resources. */
3026       map = astAnnul( map );
3027    }
3028    frm = astAnnul( frm );
3029 
3030 /* Return the result. */
3031    return result;
3032 }
3033 
RegClearAttrib(AstRegion * this_region,const char * attrib,char ** base_attrib,int * status)3034 static void RegClearAttrib( AstRegion *this_region, const char *attrib,
3035                             char **base_attrib, int *status ) {
3036 /*
3037 *  Name:
3038 *     RegClearAttrib
3039 
3040 *  Purpose:
3041 *     Clear an attribute value for a Region.
3042 
3043 *  Type:
3044 *     Private function.
3045 
3046 *  Synopsis:
3047 *     #include "cmpregion.h"
3048 *     void RegClearAttrib( AstRegion *this, const char *attrib,
3049 *                          char **base_attrib, int *status )
3050 
3051 *  Class Membership:
3052 *     CmpRegion member function (over-rides the astRegClearAttrib method
3053 *     inherited from the Region class).
3054 
3055 *  Description:
3056 *     This function clears the value of a named attribute in both the base
3057 *     and current Frame in the FrameSet encapsulated within a Region, without
3058 *     remapping either Frame.
3059 *
3060 *     No error is reported if the attribute is not recognised by the base
3061 *     Frame.
3062 
3063 *  Parameters:
3064 *     this
3065 *        Pointer to the Region.
3066 *     attrib
3067 *        Pointer to a null terminated string holding the attribute name.
3068 *        NOTE, IT SHOULD BE ENTIRELY LOWER CASE.
3069 *     base_attrib
3070 *        Address of a location at which to return a pointer to the null
3071 *        terminated string holding the attribute name which was cleared in
3072 *        the base Frame of the encapsulated FrameSet. This may differ from
3073 *        the supplied attribute if the supplied attribute contains an axis
3074 *        index and the current->base Mapping in the FrameSet produces an
3075 *        axis permutation. The returned pointer should be freed using
3076 *        astFree when no longer needed. A NULL pointer may be supplied in
3077 *        which case no pointer is returned.
3078 *     status
3079 *        Pointer to the inherited status variable.
3080 
3081 */
3082 
3083 /* Local Variables: */
3084    AstCmpRegion *this;
3085    char *batt;
3086    int rep;
3087 
3088 /* Check the global error status. */
3089    if ( !astOK ) return;
3090 
3091 /* Get a pointer to the CmpRegion structure. */
3092    this = (AstCmpRegion *) this_region;
3093 
3094 /* Use the RegClearAttrib method inherited from the parent class to clear the
3095    attribute in the current and base Frames in the FrameSet encapsulated by
3096    the parent Region structure. */
3097    (*parent_regclearattrib)( this_region, attrib, &batt, status );
3098 
3099 /* Now clear the base Frame attribute to the component Regions (the current
3100    Frame within the component Regions is equivalent to the base Frame in the
3101    parent Region structure). Annul any "attribute unknown" error that results
3102    from attempting to do this. */
3103    if( astOK ) {
3104       rep = astReporting( 0 );
3105       astRegClearAttrib( this->region1, batt, NULL );
3106       astRegClearAttrib( this->region2, batt, NULL );
3107       if( astStatus == AST__BADAT ) astClearStatus;
3108       astReporting( rep );
3109    }
3110 
3111 /* If required, return the base Frame attribute name, otherwise free it. */
3112    if( base_attrib ) {
3113       *base_attrib = batt;
3114    } else {
3115       batt = astFree( batt );
3116    }
3117 }
3118 
ResetCache(AstRegion * this_region,int * status)3119 static void ResetCache( AstRegion *this_region, int *status ){
3120 /*
3121 *  Name:
3122 *     ResetCache
3123 
3124 *  Purpose:
3125 *     Clear cached information within the supplied Region.
3126 
3127 *  Type:
3128 *     Private function.
3129 
3130 *  Synopsis:
3131 *     #include "cmpregion.h"
3132 *     void ResetCache( AstRegion *this, int *status )
3133 
3134 *  Class Membership:
3135 *     Region member function (overrides the astResetCache method
3136 *     inherited from the parent Region class).
3137 
3138 *  Description:
3139 *     This function clears cached information from the supplied Region
3140 *     structure.
3141 
3142 *  Parameters:
3143 *     this
3144 *        Pointer to the Region.
3145 *     status
3146 *        Pointer to the inherited status variable.
3147 */
3148 
3149 /* Local Variables *: */
3150    AstCmpRegion *this;
3151    int i;
3152 
3153 /* Check a Region was supplied. */
3154    if( this_region ) {
3155 
3156 /* Get a pointer to the CmpRegion structure. */
3157       this = (AstCmpRegion *) this_region;
3158 
3159 /* Clear information cached in the CmpRegion structure. */
3160       for( i = 0; i < 2; i++ ) {
3161          this->rvals[ i ] = astFree(  this->rvals[ i ] );
3162          this->offs[ i ] = astFree(  this->offs[ i ] );
3163          this->nbreak[ i ] = 0;
3164          this->d0[ i ] = AST__BAD;
3165          this->dtot[ i ] = AST__BAD;
3166       }
3167 
3168       this->bounded = -INT_MAX;
3169 
3170 /* Clear information cached in the component regions. */
3171       if( this->region1 ) astResetCache( this->region1 );
3172       if( this->region2 ) astResetCache( this->region2 );
3173 
3174 /* Clear information cached in the parent Region structure. */
3175       (*parent_resetcache)( this_region, status );
3176    }
3177 }
3178 
SetBreakInfo(AstCmpRegion * this,int comp,int * status)3179 static void SetBreakInfo( AstCmpRegion *this, int comp, int *status ){
3180 /*
3181 *  Name:
3182 *     SetBreakInfo
3183 
3184 *  Purpose:
3185 *     Ensure that a CmpRegion has information about the breaks in the
3186 *     boundaries of one of the two component Regions.
3187 
3188 *  Type:
3189 *     Private function.
3190 
3191 *  Synopsis:
3192 *     #include "cmpregion.h"
3193 *     void SetBreakInfo( AstCmpRegion *this, int comp, int *status )
3194 
3195 *  Class Membership:
3196 *     CmpRegion method.
3197 
3198 *  Description:
3199 *     This function returns without action if the supplied CmpRegion
3200 *     already contains break information for the specified component Region.
3201 *     Otherwise, it creates the required information and stores it in the
3202 *     CmpRegion.
3203 *
3204 *     Each component Region in the CmpRegion has a boundary. But in
3205 *     general only part of the boundary of a component Region will also
3206 *     be included in the CmpRegion boundary. Thus the component Region
3207 *     boundary can be broken up into sections; sections that form part
3208 *     of the CmpRegion boundary, and sections that do not. This function
3209 *     stores information about the breaks between these sections.
3210 *
3211 *     The complete boundary of a component Region is parameterised by a
3212 *     geodesic distance that goes from 0.0 to the value found by this
3213 *     function and stored in this->dtot (the total geodesic distance
3214 *     around the border). This function find the ranges of this parameter
3215 *     that correspond to the sections of the boundary that are also on the
3216 *     CmpRegion boundary, and thus finds the total length that the component
3217 *     boundary contributes to the CmpRegion boundary. This length is stored
3218 *     in "this->d0" (a two element array, one for each component Region).
3219 *
3220 *     It also find two arrays "this->rvals" and "this->offs" that allow a
3221 *     distance value in the range 0.0 to "this->d0" (i.e. a distance
3222 *     measured by skipping over the parts of the component boundary that
3223 *     are not on the CmpRegion boundary), to be converted into the
3224 *     corresponding distance value in the range 0.0 to "this->dtot" (i.e. a
3225 *     distance measured round the complete component boundary, including the
3226 *     parts not on the CmpRegion boundary).
3227 
3228 *  Parameters:
3229 *     this
3230 *        Pointer to a CmpRegion.
3231 *     comp
3232 *        Zero or one, indicating which component Region is to be checked.
3233 *     status
3234 *        Pointer to the inherited status variable.
3235 
3236 */
3237 
3238 /* The number of points to be spread evenly over the entire boundary of the
3239    component Region. */
3240 #define NP 101
3241 
3242 /* Local Variables: */
3243    AstFrame *frm;
3244    AstPointSet *pset1;
3245    AstPointSet *pset2;
3246    AstRegion *other;
3247    AstRegion *reg;
3248    AstRegion *uother;
3249    double **ptr2;
3250    double **ptr1;
3251    double *d;
3252    double *offs;
3253    double *p0;
3254    double *p1;
3255    double *p;
3256    double *q;
3257    double *rvals;
3258    double delta;
3259    double dist;
3260    double pnt1[ 2 ];
3261    double pnt2[ 2 ];
3262    double rbad;
3263    double rval;
3264    double totdist;
3265    int i;
3266    int j;
3267    int nn;
3268    int prevgood;
3269 
3270 /* Check inherited status */
3271    if( !astOK ) return;
3272 
3273 /* If the information describing breaks in the component boundary has not
3274    yet been set up, do so now. */
3275    if( this->d0[ comp ] == AST__BAD ) {
3276 
3277 /* Get a pointer to the component Region for which break information is
3278    required. */
3279       reg = comp ? this->region2 : this->region1;
3280 
3281 /* Check the component class implements the astRegTrace method. */
3282       if( astRegTrace( reg, 0, NULL, NULL ) ) {
3283 
3284 /* Create a pointSet to hold axis values at evenly spaced positions along
3285    the entire boundary of the selected component region. */
3286          pset1 = astPointSet( NP, 2, " ", status );
3287          ptr1 = astGetPoints( pset1 );
3288 
3289 /* Allocate memory to hold an array of corresponding scalar distances around
3290    the boundary. */
3291          d = astMalloc( NP*sizeof( double ) );
3292 
3293 /* Check pointers can be used safely. */
3294          if( astOK ) {
3295 
3296 /* Get the distance increment between points (at this point the distances
3297    are normalised so that the entire boundary has unit length, as
3298    required by astRegTrace). */
3299             delta = 1.0/( NP - 1 );
3300 
3301 /* Set up the array of evenly spaced distances around the boundary of the
3302    component region. */
3303             for( i = 0; i < NP; i++ ) d[ i ] = i*delta;
3304 
3305 /* Get the corresponding Frame positions. If the Region is unbounded
3306    (e.g. a negated circle, etc), then negate it first in the hope that
3307    this may produced a bounded Region. */
3308             if( astGetBounded( reg ) ) {
3309                (void) astRegTrace( reg, NP, d, ptr1 );
3310             } else {
3311                AstRegion *negation = astGetNegation( reg );
3312                (void) astRegTrace( negation, NP, d, ptr1 );
3313                negation = astAnnul( negation );
3314             }
3315 
3316 /* Get a pointer to the other component Region. */
3317             other = comp ? this->region1 : this->region2;
3318 
3319 /* If the two component Regions are ANDed together, we want to remove the
3320    positions from the boundary of the required component Region that fall
3321    outside the other region. We can do this by simply using the other Region
3322    as a Mapping. If the two component Regions are ORed together, we want to
3323    remove the position that fall within (rather than outside) the other
3324    Region. To do this we need to negate the other region  first. */
3325             if( this->oper == AST__OR ) {
3326                uother = astGetNegation( other );
3327             } else {
3328                uother = astClone( other );
3329             }
3330 
3331 /* Now transform the points on the boundary of the selected Region in
3332    order to set invalid those positions which are not on the boundary of
3333    the supplied CmpRegion. */
3334             pset2 = astTransform( uother, pset1, 1, NULL );
3335 
3336 /* Annul the negation pointer */
3337             uother = astAnnul( uother );
3338 
3339 /* Modify the distance array by setting invalid each element that is not
3340    on the boundary of the CmpRegion. */
3341             ptr2 = astGetPoints( pset2 );
3342             if( astOK ) {
3343                p = ptr2[ 0 ];
3344                q = ptr2[ 1 ];
3345                for( i = 0; i < NP; i++,p++,q++ ) {
3346                   if( *p == AST__BAD || *q == AST__BAD ) d[ i ] = AST__BAD;
3347                }
3348 
3349 /* At each good/bad junction in this list, extend the good section by one
3350    point. This ensures that the good sections of the curve do in fact
3351    touch each other (they may in fact overlap a little but that does not
3352    matter). */
3353                prevgood = ( d[ 0 ] != AST__BAD );
3354                for( i = 1; i < NP; i++,p++,q++ ) {
3355                   if( d[ i ] == AST__BAD ) {
3356                      if( prevgood ) d[ i ] = i*delta;
3357                      prevgood = 0;
3358 
3359                   } else {
3360                      if( !prevgood ) d[ i - 1 ] = ( i - 1 )*delta;
3361                      prevgood = 1;
3362                   }
3363                }
3364 
3365 /* Find the total geodesic distance around the border. This is only an
3366    approximation but it is only used to give a relative weight to this
3367    component within the CmpFrame, and so does not need to be very accurate. */
3368                frm = astGetFrame( reg->frameset, AST__CURRENT );
3369                p0 = ptr1[ 0 ];
3370                p1 = ptr1[ 1 ];
3371                totdist = 0;
3372                pnt1[ 0 ] = *(p0++);
3373                pnt1[ 1 ] = *(p1++);
3374                for( i = 1; i < NP; i++ ) {
3375                   pnt2[ 0 ] = *(p0++);
3376                   pnt2[ 1 ] = *(p1++);
3377                   dist = astDistance( frm, pnt1, pnt2 );
3378                   if( dist != AST__BAD ) totdist += dist;
3379                   pnt1[ 0 ] = pnt2[ 0 ];
3380                   pnt1[ 1 ] = pnt2[ 1 ];
3381                }
3382 
3383 /* Change delta so that it represents a geodesic distance, rather than a
3384    normalised distance in the range zero to one. Working in geodesic distance
3385    (e.g. Radians on a SkyFrame) prevents Regions higher up in a complex nested
3386    CmpRegion being given higher priority than a lower Region. */
3387                delta *= totdist;
3388 
3389 /* Now create two arrays - "rvals" holds the distance travelled around
3390    the used parts of the border at which breaks occur, "offs" holds the jump
3391    in distance around the complete border at each break. The distance
3392    around the complete border is normalised to the range [0.0,1.0].
3393    Therefore the total distance around the used parts of the border will in
3394    general be less than 1.0 */
3395                if( d[ 0 ] == AST__BAD ) {
3396                   nn = 1;
3397                   j = 0;
3398                   rvals = astMalloc( sizeof( double ) );
3399                   offs = astMalloc( sizeof( double ) );
3400                   if( astOK ) rvals[ 0 ] = -0.5*delta;
3401                   rbad = 0.5;
3402                   prevgood = 0;
3403                   rval = -0.5*delta;
3404 
3405                } else {
3406                   nn = 0;
3407                   rvals = NULL;
3408                   offs = NULL;
3409                   prevgood = 1;
3410                   rbad = 0.0;
3411                   rval = 0.0;
3412                }
3413 
3414                for( i = 1; i < NP; i++,p++,q++ ) {
3415 
3416                   if( d[ i ] == AST__BAD ) {
3417                      if( prevgood ) {
3418                         j = nn++;
3419                         rvals = astGrow( rvals, nn, sizeof( double ) );
3420                         offs = astGrow( offs, nn, sizeof( double ) );
3421                         if( astOK ) {
3422                            rvals[ j ] = rval + 0.5*delta;
3423                            rbad = 0.0;
3424                         } else {
3425                            break;
3426                         }
3427                         prevgood = 0;
3428                      }
3429 
3430                      rbad += 1.0;
3431 
3432                   } else {
3433                      if( !prevgood ) {
3434                         offs[ j ] = rbad*delta;
3435                         prevgood = 1;
3436                      }
3437                      rval += delta;
3438                   }
3439                }
3440 
3441                if( !prevgood ) {
3442                   rval += 0.5*delta;
3443                   offs[ j ] = rbad*delta;
3444                }
3445 
3446 /* Record the information in the CmpRegion structure. */
3447                this->rvals[ comp ] = rvals;
3448                this->offs[ comp ] = offs;
3449                this->nbreak[ comp ] = nn;
3450                this->d0[ comp ] = rval;
3451                this->dtot[ comp ] = totdist;
3452             }
3453 
3454 /* Free resources. */
3455             pset2 = astAnnul( pset2 );
3456          }
3457 
3458          pset1 = astAnnul( pset1 );
3459          d = astFree( d );
3460 
3461       }
3462    }
3463 }
3464 
3465 #undef NP
3466 
SetRegFS(AstRegion * this_region,AstFrame * frm,int * status)3467 static void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) {
3468 /*
3469 *  Name:
3470 *     SetRegFS
3471 
3472 *  Purpose:
3473 *     Stores a new FrameSet in a Region
3474 
3475 *  Type:
3476 *     Private function.
3477 
3478 *  Synopsis:
3479 *     #include "cmpregion.h"
3480 *     void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status )
3481 
3482 *  Class Membership:
3483 *     CmpRegion method (over-rides the astSetRegFS method inherited from
3484 *     the Region class).
3485 
3486 *  Description:
3487 *     This function creates a new FrameSet and stores it in the supplied
3488 *     Region. The new FrameSet contains two copies of the supplied
3489 *     Frame, connected by a UnitMap.
3490 
3491 *  Parameters:
3492 *     this
3493 *        Pointer to the Region.
3494 *     frm
3495 *        The Frame to use.
3496 *     status
3497 *        Pointer to the inherited status variable.
3498 
3499 */
3500 
3501 /* Local Variables: */
3502    AstRegion *creg;        /* Pointer to component Region structure */
3503 
3504 /* Check the global error status. */
3505    if ( !astOK ) return;
3506 
3507 /* Invoke the parent method to store the FrameSet in the parent Region
3508    structure. */
3509    (* parent_setregfs)( this_region, frm, status );
3510 
3511 /* If either component Region has a dummy FrameSet use this method
3512    recursively to give them the same FrameSet. */
3513    creg = ((AstCmpRegion *) this_region )->region1;
3514    if( creg && !astGetRegionFS( creg ) ) astSetRegFS( creg, frm );
3515 
3516    creg = ((AstCmpRegion *) this_region )->region2;
3517    if( creg && !astGetRegionFS( creg ) ) astSetRegFS( creg, frm );
3518 
3519 }
3520 
Simplify(AstMapping * this_mapping,int * status)3521 static AstMapping *Simplify( AstMapping *this_mapping, int *status ) {
3522 /*
3523 *  Name:
3524 *     Simplify
3525 
3526 *  Purpose:
3527 *     Simplify a Region.
3528 
3529 *  Type:
3530 *     Private function.
3531 
3532 *  Synopsis:
3533 *     #include "region.h"
3534 *     AstMapping *Simplify( AstMapping *this, int *status )
3535 
3536 *  Class Membership:
3537 *     CmpRegion method (over-rides the astSimplify method inherited from
3538 *     the Region class).
3539 
3540 *  Description:
3541 *     This function simplifies a CmpRegion to eliminate redundant
3542 *     computational steps, or to merge separate steps which can be
3543 *     performed more efficiently in a single operation.
3544 
3545 *  Parameters:
3546 *     this
3547 *        Pointer to the original Region.
3548 *     status
3549 *        Pointer to the inherited status variable.
3550 
3551 *  Returned Value:
3552 *     A new pointer to the (possibly simplified) Region.
3553 
3554 *  Notes:
3555 *     - A NULL pointer value will be returned if this function is
3556 *     invoked with the AST error status set, or if it should fail for
3557 *     any reason.
3558 
3559 *  Deficiencies:
3560 *     - Currently, this function does not attempt to map the component
3561 *     Regions into the current Frame of the parent Region structure.
3562 *     Both components should be mapped into the current Frame, and if the
3563 *     resulting base->current Mappings in *both* remapped component Regions are
3564 *     UnitMaps, then a new CmpRegion should be created from the re-mapped
3565 *     Regions.
3566 */
3567 
3568 /* Local Variables: */
3569    AstCmpRegion *newb;           /* New CmpRegion defined in base Frame */
3570    AstCmpRegion *newc;           /* New CmpRegion defined in current Frame */
3571    AstFrame *frm;                /* Current Frame */
3572    AstMapping *map;              /* Base->current Mapping */
3573    AstMapping *result;           /* Result pointer to return */
3574    AstRegion *csreg1;            /* Copy of simplified first component Region */
3575    AstRegion *csreg2;            /* Copy of simplified second component Region */
3576    AstRegion *nullreg;           /* Null or infinfite Region */
3577    AstRegion *othereg;           /* Non-Null and non-infinfite Region */
3578    AstRegion *reg1;              /* First component Region */
3579    AstRegion *reg2;              /* Second component Region */
3580    AstRegion *sreg1;             /* Simplified first component Region */
3581    AstRegion *sreg2;             /* Simplified second component Region */
3582    int neg1;                     /* Negated flag to use with first component */
3583    int neg2;                     /* Negated flag to use with second component */
3584    int oper;                     /* Boolean operator used to combine components */
3585    int overlap;                  /* Nature of overlap between components */
3586    int simpler;                  /* Has any simplification taken place? */
3587 
3588 /* Initialise. */
3589    result = NULL;
3590 
3591 /* Check the global error status. */
3592    if ( !astOK ) return result;
3593 
3594 /* Invoke the parent Simplify method inherited from the Region class. This
3595    will simplify the encapsulated FrameSet and uncertainty Region. The
3596    returned pointer identifies a region within the current Frame of the
3597    FrameSet encapsulated by the parent Region structure. Note this by
3598    storing the pointer in the "newc" ("c" for "current") variable. */
3599    newc = (AstCmpRegion *) (*parent_simplify)( this_mapping, status );
3600 
3601 /* Note if any simplification took place. This is assumed to be the case
3602    if the pointer returned by the above call is different to the supplied
3603    pointer. */
3604    simpler = ( (AstMapping *) newc != this_mapping );
3605 
3606 /* Below we may create a new simplified region which identifies a region
3607    within the base Frame of the FrameSet encapsulated by the parent Region
3608    structure. Such a result will need to be mapped into the current Frame
3609    before being returned. The "newb" variable ("b" for "base") will be
3610    used to store a pointer to such a result. Initialise this variable to
3611    indicate that we do not yet have a base Frame result. */
3612    newb = NULL;
3613 
3614 /* Get the component Regions, how they should be combined, and the
3615    Negated values which should be used with them. The returned values
3616    take account of whether the supplied CmpRegion has itself been Negated
3617    or not. The returned Regions represent regions within the base Frame
3618    of the FrameSet encapsulated by the parent Region structure. */
3619    GetRegions( newc, &reg1, &reg2, &oper, &neg1, &neg2, status );
3620 
3621 /* If the first component Region does not have the required value for
3622    its "Negated" attribute, use the negation of "reg1" in place of "reg1"
3623    itself. */
3624    if( neg1 != astGetNegated( reg1 ) ) {
3625       AstRegion *tmp = astGetNegation( reg1 );
3626       (void) astAnnul( reg1 );
3627       reg1 = tmp;
3628    }
3629 
3630 /* If the second component Region does not have the required value for
3631    its "Negated" attribute, use the negation of "reg2" in place of "reg2"
3632    itself. */
3633    if( neg2 != astGetNegated( reg2 ) ) {
3634       AstRegion *tmp = astGetNegation( reg2 );
3635       (void) astAnnul( reg2 );
3636       reg2 = tmp;
3637    }
3638 
3639 /* Simplify each of the two components. */
3640    sreg1 = astSimplify( reg1 );
3641    sreg2 = astSimplify( reg2 );
3642 
3643 /* Note if any simplification took place. */
3644    simpler = simpler || ( sreg1 != reg1 || sreg2 != reg2 );
3645 
3646 /* If either component is null or infinite we can exclude it from the
3647    returned Region. */
3648    if( astIsANullRegion( sreg1 ) || astIsANullRegion( sreg2 ) ) {
3649 
3650 /* Get a pointer to the non-null Region. The following is still valid
3651    even if both regions are null or infinite. */
3652       if( astIsANullRegion( sreg1 ) ){
3653          nullreg = sreg1;
3654          othereg = sreg2;
3655       } else {
3656          nullreg = sreg2;
3657          othereg = sreg1;
3658       }
3659 
3660 /* If null.. */
3661       if( !astGetNegated( nullreg ) ){
3662          if( oper == AST__AND ) {
3663             newb = (AstCmpRegion *) astNullRegion( othereg,
3664                                              astGetUnc( othereg, 0 ), "", status );
3665 
3666          } else if( oper == AST__OR ) {
3667             newb = astCopy( othereg );
3668 
3669          } else {
3670             astError( AST__INTER, "astSimplify(%s): The %s refers to an "
3671                       "unknown boolean operator with identifier %d (internal "
3672                       "AST programming error).", status, astGetClass( newc ),
3673                       astGetClass( newc ), oper );
3674          }
3675 
3676 /* If infinite.. */
3677       } else {
3678          if( oper == AST__AND ) {
3679             newb = astCopy( othereg );
3680 
3681          } else if( oper == AST__OR ) {
3682             newb = (AstCmpRegion *) astNullRegion( othereg,
3683                                       astGetUnc( othereg, 0 ), "negated=1", status );
3684 
3685          } else {
3686             astError( AST__INTER, "astSimplify(%s): The %s refers to an "
3687                       "unknown boolean operator with identifier %d (internal "
3688                       "AST programming error).", status, astGetClass( newc ),
3689                       astGetClass( newc ), oper );
3690          }
3691       }
3692 
3693 /* Flag that we have done some simplication.*/
3694       simpler = 1;
3695 
3696 /* If neither component is null or infinite, see if it is possible to
3697    remove one or both of the components on the basis of the overlap
3698    between them. */
3699    } else {
3700       overlap = astOverlap( sreg1, sreg2 );
3701 
3702 /* If the components have no overlap, and they are combined using AND, then
3703    the CmpRegion is null. */
3704       if( ( overlap == 1 || overlap == 6 ) && oper == AST__AND ) {
3705          newb = (AstCmpRegion *) astNullRegion( sreg1, astGetUnc( sreg1, 0 ),
3706                                                 "", status );
3707          simpler = 1;
3708 
3709 /* If one component is the negation of the other component, and they are
3710    combined using OR, then the CmpRegion is infinite. This is represented
3711    by a negated null region.*/
3712       } else if( overlap == 6 && oper == AST__OR ) {
3713          newb = (AstCmpRegion  *) astNullRegion( sreg1, astGetUnc( sreg1, 0 ),
3714                                                  "negated=1", status );
3715          simpler = 1;
3716 
3717 /* If the two components are identical... */
3718       } else if( overlap == 5 ) {
3719          simpler = 1;
3720 
3721 /* If combined with AND or OR, the CmpRegion can be replaced by the first
3722    (or second) component Region. */
3723          if( oper == AST__AND || oper == AST__OR ) {
3724             newb = astCopy( sreg1 );
3725          } else {
3726             astError( AST__INTER, "astSimplify(%s): The %s refers to an "
3727                       "unknown boolean operator with identifier %d (internal "
3728                       "AST programming error).", status, astGetClass( newc ),
3729                       astGetClass( newc ), oper );
3730          }
3731 
3732 /* If the first component is entirely contained within the second
3733    component, and they are combined using AND or OR, then the CmpRegion
3734    can be replaced by the first or second component. */
3735       } else if( overlap == 2 && ( oper == AST__AND || oper == AST__OR ) ){
3736          newb = astCopy( ( oper == AST__AND ) ? sreg1 : sreg2 );
3737          simpler = 1;
3738 
3739 /* If the second component is entirely contained within the first
3740    component, and they are combined using AND or OR, then the CmpRegion
3741    can be replaced by the second or first component. */
3742       } else if( overlap == 3 && ( oper == AST__AND || oper == AST__OR ) ){
3743          newb = astCopy( ( oper == AST__AND ) ? sreg2 : sreg1 );
3744          simpler = 1;
3745 
3746 /* Otherwise, no further simplication is possible, so either create a new
3747    CmpRegion or leave the "newb" pointer NULL (which will cause "newc" to
3748    be used), depending on whether the components were simplified. */
3749       } else if( simpler ){
3750          csreg1 = astCopy( sreg1 );
3751          csreg2 = astCopy( sreg2 );
3752          newb = astCmpRegion( csreg1, csreg2, oper, "", status );
3753          csreg1 = astAnnul( csreg1 );
3754          csreg2 = astAnnul( csreg2 );
3755 
3756       }
3757    }
3758 
3759 /* If any simplification took place, decide whether to use the "newc" or
3760    "newb" pointer for the returned Mapping. If "newb" is non-NULL we use
3761    it, otherwise we use "newc". If "newb" is used we must first map the
3762    result Region from the base Frame of the FrameSet encapsulated
3763    by the parent Region structure, to the current Frame. */
3764    if( simpler ) {
3765       if( newb ){
3766          frm = astGetFrame( ((AstRegion *) newc)->frameset, AST__CURRENT );
3767          map = astGetMapping( ((AstRegion *) newc)->frameset, AST__BASE, AST__CURRENT );
3768          result = astMapRegion( newb, map, frm );
3769          frm = astAnnul( frm );
3770          map = astAnnul( map );
3771          newb = astAnnul( newb );
3772       } else {
3773          result = astClone( newc );
3774       }
3775 
3776 /* If no simplification took place, return a clone of the supplied pointer. */
3777    } else {
3778       result = astClone( this_mapping );
3779    }
3780 
3781 /* Free resources. */
3782    reg1 = astAnnul( reg1 );
3783    reg2 = astAnnul( reg2 );
3784    sreg1 = astAnnul( sreg1 );
3785    sreg2 = astAnnul( sreg2 );
3786    newc = astAnnul( newc );
3787 
3788 /* If an error occurred, annul the returned Mapping. */
3789    if ( !astOK ) result = astAnnul( result );
3790 
3791 /* Return the result. */
3792    return result;
3793 }
3794 
Transform(AstMapping * this_mapping,AstPointSet * in,int forward,AstPointSet * out,int * status)3795 static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in,
3796                                int forward, AstPointSet *out, int *status ) {
3797 /*
3798 *  Name:
3799 *     Transform
3800 
3801 *  Purpose:
3802 *     Apply a CmpRegion to transform a set of points.
3803 
3804 *  Type:
3805 *     Private function.
3806 
3807 *  Synopsis:
3808 *     #include "cmpregion.h"
3809 *     AstPointSet *Transform( AstMapping *this, AstPointSet *in,
3810 *                             int forward, AstPointSet *out, int *status )
3811 
3812 *  Class Membership:
3813 *     CmpRegion member function (over-rides the astTransform method inherited
3814 *     from the Region class).
3815 
3816 *  Description:
3817 *     This function takes a CmpRegion and a set of points encapsulated in a
3818 *     PointSet and transforms the points so as to apply the required Region.
3819 *     This implies applying each of the CmpRegion's component Regions in turn,
3820 *     either in series or in parallel.
3821 
3822 *  Parameters:
3823 *     this
3824 *        Pointer to the CmpRegion.
3825 *     in
3826 *        Pointer to the PointSet associated with the input coordinate values.
3827 *     forward
3828 *        A non-zero value indicates that the forward coordinate transformation
3829 *        should be applied, while a zero value requests the inverse
3830 *        transformation.
3831 *     out
3832 *        Pointer to a PointSet which will hold the transformed (output)
3833 *        coordinate values. A NULL value may also be given, in which case a
3834 *        new PointSet will be created by this function.
3835 *     status
3836 *        Pointer to the inherited status variable.
3837 
3838 *  Returned Value:
3839 *     Pointer to the output (possibly new) PointSet.
3840 
3841 *  Notes:
3842 *     -  A null pointer will be returned if this function is invoked with the
3843 *     global error status set, or if it should fail for any reason.
3844 *     -  The number of coordinate values per point in the input PointSet must
3845 *     match the number of coordinates for the CmpRegion being applied.
3846 *     -  If an output PointSet is supplied, it must have space for sufficient
3847 *     number of points and coordinate values per point to accommodate the
3848 *     result. Any excess space will be ignored.
3849 */
3850 
3851 /* Local Variables: */
3852    AstCmpRegion *this;           /* Pointer to the CmpRegion structure */
3853    AstPointSet *ps1;             /* Pointer to PointSet for first component */
3854    AstPointSet *ps2;             /* Pointer to PointSet for second component */
3855    AstPointSet *pset_tmp;        /* Pointer to PointSet holding base Frame positions*/
3856    AstPointSet *result;          /* Pointer to output PointSet */
3857    AstRegion *reg1;              /* Pointer to first component Region */
3858    AstRegion *reg2;              /* Pointer to second component Region */
3859    double **ptr1;                /* Pointer to first component axis values */
3860    double **ptr2;                /* Pointer to second component axis values */
3861    double **ptr_out;             /* Pointer to output coordinate data */
3862    int coord;                    /* Zero-based index for coordinates */
3863    int good;                     /* Is the point inside the CmpRegion? */
3864    int ncoord_out;               /* No. of coordinates per output point */
3865    int ncoord_tmp;               /* No. of coordinates per base Frame point */
3866    int neg1;                     /* Negated value for first component Region */
3867    int neg2;                     /* Negated value for second component Region */
3868    int npoint;                   /* No. of points */
3869    int oper;                     /* Boolean operator to use */
3870    int point;                    /* Loop counter for points */
3871 
3872 /* Initialise. */
3873    result = NULL;
3874 
3875 /* Check the global error status. */
3876    if ( !astOK ) return result;
3877 
3878 /* Get a Pointer to the CmpRegion structure */
3879    this = (AstCmpRegion *) this_mapping;
3880 
3881 /* Get the component Regions, how they should be combined, and the
3882    Negated values which should be used with them. The returned values
3883    take account of whether the supplied CmpRegion has itself been Negated
3884    or not. The returned Regions represent regions within the base Frame
3885    of the FrameSet encapsulated by the parent Region structure. */
3886    GetRegions( this, &reg1, &reg2, &oper, &neg1, &neg2, status );
3887 
3888 /* If the first component Region does not have the required value for
3889    its "Negated" attribute, use the negation of "reg1" in place of "reg1"
3890    itself. */
3891    if( neg1 != astGetNegated( reg1 ) ) {
3892       AstRegion *tmp = astGetNegation( reg1 );
3893       (void) astAnnul( reg1 );
3894       reg1 = tmp;
3895    }
3896 
3897 /* If the second component Region does not have the required value for
3898    its "Negated" attribute, use the negation of "reg2" in place of "reg2"
3899    itself. */
3900    if( neg2 != astGetNegated( reg2 ) ) {
3901       AstRegion *tmp = astGetNegation( reg2 );
3902       (void) astAnnul( reg2 );
3903       reg2 = tmp;
3904    }
3905 
3906 /* Apply the parent mapping using the stored pointer to the Transform member
3907    function inherited from the parent Region class. This function validates
3908    all arguments and generates an output PointSet if necessary, containing
3909    a copy of the input PointSet. */
3910    result = (*parent_transform)( this_mapping, in, forward, out, status );
3911 
3912 /* We will now extend the parent astTransform method by performing the
3913    calculations needed to generate the output coordinate values. */
3914 
3915 /* First use the encapsulated FrameSet in the parent Region structure to
3916    transform the supplied positions from the current Frame in the
3917    encapsulated FrameSet (the Frame represented by the CmpRegion), to the
3918    base Frame (the Frame in which the component Regions are defined). Note,
3919    the returned pointer may be a clone of the "in" pointer, and so we
3920    must be carefull not to modify the contents of the returned PointSet. */
3921    pset_tmp = astRegTransform( this, in, 0, NULL, NULL );
3922 
3923 /* Now transform this PointSet using each of the two component Regions in
3924    turn. */
3925    ps1 = astTransform( reg1, pset_tmp, 0, NULL );
3926    ps2 = astTransform( reg2, pset_tmp, 0, NULL );
3927 
3928 /* Determine the numbers of points and coordinates per point for these base
3929    Frame PointSets and obtain pointers for accessing the base Frame and output
3930    coordinate values. */
3931    npoint = astGetNpoint( pset_tmp );
3932    ncoord_tmp = astGetNcoord( pset_tmp );
3933    ptr1 = astGetPoints( ps1 );
3934    ptr2 = astGetPoints( ps2 );
3935    ncoord_out = astGetNcoord( result );
3936    ptr_out = astGetPoints( result );
3937 
3938 /* Perform coordinate arithmetic. */
3939 /* ------------------------------ */
3940    if ( astOK ) {
3941 
3942 /* First deal with ANDed Regions */
3943       if( oper == AST__AND ) {
3944          for ( point = 0; point < npoint; point++ ) {
3945             good = 0;
3946 
3947             for ( coord = 0; coord < ncoord_tmp; coord++ ) {
3948                if( ptr1[ coord ][ point ] != AST__BAD &&
3949                    ptr2[ coord ][ point ] != AST__BAD ) {
3950                   good = 1;
3951                   break;
3952                }
3953             }
3954 
3955             if( !good ) {
3956                for ( coord = 0; coord < ncoord_out; coord++ ) {
3957                   ptr_out[ coord ][ point ] = AST__BAD;
3958                }
3959             }
3960          }
3961 
3962 /* Now deal with ORed Regions */
3963       } else if( oper == AST__OR ) {
3964          for ( point = 0; point < npoint; point++ ) {
3965             good = 0;
3966 
3967             for ( coord = 0; coord < ncoord_tmp; coord++ ) {
3968                if( ptr1[ coord ][ point ] != AST__BAD ||
3969                    ptr2[ coord ][ point ] != AST__BAD ) {
3970                   good = 1;
3971                   break;
3972                }
3973             }
3974 
3975             if( !good ) {
3976                for ( coord = 0; coord < ncoord_out; coord++ ) {
3977                   ptr_out[ coord ][ point ] = AST__BAD;
3978                }
3979             }
3980          }
3981 
3982 /* Report error for any unknown operator. */
3983       } else if( astOK ) {
3984          astError( AST__INTER, "astTransform(%s): The %s refers to an unknown "
3985                    "boolean operator with identifier %d (internal AST "
3986                    "programming error).", status, astGetClass( this ),
3987                     astGetClass( this ), oper );
3988       }
3989    }
3990 
3991 /* Free resources. */
3992    reg1 = astAnnul( reg1 );
3993    reg2 = astAnnul( reg2 );
3994    ps1 = astAnnul( ps1 );
3995    ps2 = astAnnul( ps2 );
3996    pset_tmp = astAnnul( pset_tmp );
3997 
3998 /* If an error occurred, clean up by deleting the output PointSet (if
3999    allocated by this function) and setting a NULL result pointer. */
4000    if ( !astOK ) {
4001       if ( !out ) result = astDelete( result );
4002       result = NULL;
4003    }
4004 
4005 /* Return a pointer to the output PointSet. */
4006    return result;
4007 }
4008 
XORCheck(AstCmpRegion * this,int * status)4009 static void XORCheck( AstCmpRegion *this, int *status ) {
4010 /*
4011 *  Name:
4012 *     XORCheck
4013 
4014 *  Purpose:
4015 *     Check if the supplied CmpRegion represents an XOR operation.
4016 
4017 *  Type:
4018 *     Private function.
4019 
4020 *  Synopsis:
4021 *     #include "cmpregion.h"
4022 *      void XORCheck( AstCmpRegion *this, int *status )
4023 
4024 *  Class Membership:
4025 *     CmpRegion method
4026 
4027 *  Decription:
4028 *     This function analyses the component Regions within the supplied
4029 *     CmpRegion to see if the CmpRegion is equivalent to an XOR operation
4030 *     on two other Regions. If it is, teh Regions that are XORed are
4031 *     stored in the supplied CmpRegion.
4032 
4033 *  Parameters:
4034 *     this
4035 *        Pointer to the CmpRegion.
4036 
4037 */
4038 
4039 /* Local Variables: */
4040    AstCmpRegion *cmpreg1;
4041    AstCmpRegion *cmpreg2;
4042    int xor;
4043 
4044 /* Check the global error status. */
4045    if ( !astOK ) return;
4046 
4047 /* If the CmpRegion is already known to be an XOR operation, return
4048    without action. */
4049    if( this->xor1 ) return;
4050 
4051 /* To be equivalent to an XOR operation, the supplied CmpRegion must be an
4052    OR operation and each component Region must be a CmpRegion. */
4053    if( this->oper == AST__OR && astIsACmpRegion( this->region1 )
4054                              && astIsACmpRegion( this->region2 ) ) {
4055       cmpreg1 = (AstCmpRegion *) this->region1;
4056       cmpreg2 = (AstCmpRegion *) this->region2;
4057 
4058 /* Each component CmpRegion must be an AND operation. */
4059       if( cmpreg1->oper == AST__AND && cmpreg2->oper == AST__AND ) {
4060 
4061 /* Temporarily negate the first component of the first CmpRegion. */
4062          astNegate( cmpreg1->region1 );
4063 
4064 /* Initially, assume the supplied CmpRegion is not equivalent to an XOR
4065    operation. */
4066          xor = 0;
4067 
4068 /* This negated region must be equal to one of the two component Regions
4069    in the second component CmpRegion. Check the first. */
4070          if( astEqual( cmpreg1->region1, cmpreg2->region1 ) ) {
4071 
4072 /* We now check that the other two Regions are equal (after negating the
4073    first). If so, set "xor" non-zero. */
4074             astNegate( cmpreg1->region2 );
4075             if( astEqual( cmpreg1->region2, cmpreg2->region2 ) ) xor = 1;
4076             astNegate( cmpreg1->region2 );
4077 
4078 /* Do equiovalent checks the other way round. */
4079          } else if( astEqual( cmpreg1->region1, cmpreg2->region2 ) ) {
4080             astNegate( cmpreg1->region2 );
4081             if( astEqual( cmpreg1->region2, cmpreg2->region1 ) ) xor = 1;
4082             astNegate( cmpreg1->region2 );
4083          }
4084 
4085 /* Re-instate the original state of the Negated attribute in the first
4086    component of the first CmpRegion. */
4087          astNegate( cmpreg1->region1 );
4088 
4089 /* If the supplied CmpRegion is equivalent to an XOR operation, store
4090    copies of the components in the supplied CmpRegion. */
4091          if( xor ) {
4092             this->xor1 = astCopy( cmpreg1->region1 );
4093             this->xor2 = astCopy( cmpreg1->region2 );
4094 
4095 /* We need to negate one of these two Region (it doesn't matter which),
4096    and we choose to negate which ever of them is already negated (so that
4097    it becomes un-negated). */
4098             if( astGetNegated( this->xor1 ) ) {
4099                astNegate( this->xor1 );
4100             } else {
4101                astNegate( this->xor2 );
4102             }
4103          }
4104       }
4105    }
4106 }
4107 
4108 /* Copy constructor. */
4109 /* ----------------- */
Copy(const AstObject * objin,AstObject * objout,int * status)4110 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
4111 /*
4112 *  Name:
4113 *     Copy
4114 
4115 *  Purpose:
4116 *     Copy constructor for CmpRegion objects.
4117 
4118 *  Type:
4119 *     Private function.
4120 
4121 *  Synopsis:
4122 *     void Copy( const AstObject *objin, AstObject *objout, int *status )
4123 
4124 *  Description:
4125 *     This function implements the copy constructor for CmpRegion objects.
4126 
4127 *  Parameters:
4128 *     objin
4129 *        Pointer to the object to be copied.
4130 *     objout
4131 *        Pointer to the object being constructed.
4132 *     status
4133 *        Pointer to the inherited status variable.
4134 
4135 *  Returned Value:
4136 *     void
4137 
4138 *  Notes:
4139 *     -  This constructor makes a deep copy, including a copy of the component
4140 *     Regions within the CmpRegion.
4141 */
4142 
4143 /* Local Variables: */
4144    AstCmpRegion *in;                /* Pointer to input CmpRegion */
4145    AstCmpRegion *out;               /* Pointer to output CmpRegion */
4146    int i;                           /* Loop count */
4147 
4148 /* Check the global error status. */
4149    if ( !astOK ) return;
4150 
4151 /* Obtain pointers to the input and output CmpRegions. */
4152    in = (AstCmpRegion *) objin;
4153    out = (AstCmpRegion *) objout;
4154 
4155 /* For safety, start by clearing any memory references in the output
4156    Region that were copied from the input Region. */
4157    out->region1 = NULL;
4158    out->region2 = NULL;
4159    out->xor1 = NULL;
4160    out->xor2 = NULL;
4161 
4162    for( i = 0; i < 2; i++ ) {
4163       out->rvals[ i ] = NULL;
4164       out->offs[ i ] = NULL;
4165    }
4166 
4167 /* Make copies of these Regions and store pointers to them in the output
4168    CmpRegion structure. */
4169    out->region1 = astCopy( in->region1 );
4170    out->region2 = astCopy( in->region2 );
4171    if( in->xor1 ) out->xor1 = astCopy( in->xor1 );
4172    if( in->xor2 ) out->xor2 = astCopy( in->xor2 );
4173 
4174 /* Copy cached arrays. */
4175    for( i = 0; i < 2; i++ ) {
4176       out->rvals[ i ] = astStore( NULL, in->rvals[ i ], in->nbreak[ i ]*sizeof( **in->rvals ) );
4177       out->offs[ i ] = astStore( NULL, in->offs[ i ], in->nbreak[ i ]*sizeof( **in->offs ) );
4178    }
4179 }
4180 
4181 /* Destructor. */
4182 /* ----------- */
Delete(AstObject * obj,int * status)4183 static void Delete( AstObject *obj, int *status ) {
4184 /*
4185 *  Name:
4186 *     Delete
4187 
4188 *  Purpose:
4189 *     Destructor for CmpRegion objects.
4190 
4191 *  Type:
4192 *     Private function.
4193 
4194 *  Synopsis:
4195 *     void Delete( AstObject *obj, int *status )
4196 
4197 *  Description:
4198 *     This function implements the destructor for CmpRegion objects.
4199 
4200 *  Parameters:
4201 *     obj
4202 *        Pointer to the object to be deleted.
4203 *     status
4204 *        Pointer to the inherited status variable.
4205 
4206 *  Returned Value:
4207 *     void
4208 
4209 *  Notes:
4210 *     This function attempts to execute even if the global error status is
4211 *     set.
4212 */
4213 
4214 /* Local Variables: */
4215    AstCmpRegion *this;              /* Pointer to CmpRegion */
4216    int i;
4217 
4218 /* Obtain a pointer to the CmpRegion structure. */
4219    this = (AstCmpRegion *) obj;
4220 
4221 /* Free arrays holding cached information. */
4222    for( i = 0; i < 2; i++ ) {
4223       this->rvals[ i ] = astFree( this->rvals[ i ] );
4224       this->offs[ i ] = astFree( this->offs[ i ] );
4225    }
4226 
4227 /* Annul the pointers to the component Regions. */
4228    this->region1 = astAnnul( this->region1 );
4229    this->region2 = astAnnul( this->region2 );
4230    if( this->xor1 ) this->xor1 = astAnnul( this->xor1 );
4231    if( this->xor2 ) this->xor2 = astAnnul( this->xor2 );
4232 }
4233 
4234 /* Dump function. */
4235 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)4236 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
4237 /*
4238 *  Name:
4239 *     Dump
4240 
4241 *  Purpose:
4242 *     Dump function for CmpRegion objects.
4243 
4244 *  Type:
4245 *     Private function.
4246 
4247 *  Synopsis:
4248 *     void Dump( AstObject *this, AstChannel *channel, int *status )
4249 
4250 *  Description:
4251 *     This function implements the Dump function which writes out data
4252 *     for the CmpRegion class to an output Channel.
4253 
4254 *  Parameters:
4255 *     this
4256 *        Pointer to the CmpRegion whose data are being written.
4257 *     channel
4258 *        Pointer to the Channel to which the data are being written.
4259 *     status
4260 *        Pointer to the inherited status variable.
4261 */
4262 
4263 /* Local Variables: */
4264    AstRegion *reg1;              /* First Region to include in dump */
4265    AstRegion *reg2;              /* Second Region to include in dump */
4266    AstCmpRegion *this;           /* Pointer to the CmpRegion structure */
4267    const char *comment;          /* Pointer to comment string */
4268    int ival;                     /* Integer value */
4269    int oper;                     /* The operator to include in the dump */
4270 
4271 /* Check the global error status. */
4272    if ( !astOK ) return;
4273 
4274 /* Obtain a pointer to the CmpRegion structure. */
4275    this = (AstCmpRegion *) this_object;
4276 
4277 /* Check if this CmpRegion has an equivalent XOR representation. Is so,
4278    store details of the XOR representation in the CmpRegion. */
4279    XORCheck( this, status );
4280 
4281 /* Choose the operator and component regions to include in the dump. If
4282    the CmpRegion originally used an XOR operator, then save the XORed
4283    regions. Otherwise, store the real component Regions. */
4284    if( this->xor1 ) {
4285       oper = AST__XOR;
4286       reg1 = this->xor1;
4287       reg2 = this->xor2;
4288    } else {
4289       oper = this->oper;
4290       reg1 = this->region1;
4291       reg2 = this->region2;
4292    }
4293 
4294 /* Write out values representing the instance variables for the CmpRegion
4295    class.  Accompany these with appropriate comment strings, possibly
4296    depending on the values being written.*/
4297 
4298 /* In the case of attributes, we first use the appropriate (private)
4299    Test...  member function to see if they are set. If so, we then use
4300    the (private) Get... function to obtain the value to be written
4301    out.
4302 
4303    For attributes which are not set, we use the astGet... method to
4304    obtain the value instead. This will supply a default value
4305    (possibly provided by a derived class which over-rides this method)
4306    which is more useful to a human reader as it corresponds to the
4307    actual default attribute value.  Since "set" will be zero, these
4308    values are for information only and will not be read back. */
4309 
4310 /* Oper */
4311 /* ------- */
4312    ival = oper;
4313    if( ival == AST__AND ) {
4314       comment = "Regions combined using Boolean AND";
4315    } else if( ival == AST__OR ) {
4316       comment = "Regions combined using Boolean OR";
4317    } else if( ival == AST__XOR ) {
4318       comment = "Regions combined using Boolean XOR";
4319    } else {
4320       comment = "Regions combined using unknown operator";
4321    }
4322    astWriteInt( channel, "Operator", 1, 0, ival, comment );
4323 
4324 /* First Region. */
4325 /* -------------- */
4326    astWriteObject( channel, "RegionA", 1, 1, reg1,
4327                    "First component Region" );
4328 
4329 /* Second Region. */
4330 /* --------------- */
4331    astWriteObject( channel, "RegionB", 1, 1, reg2,
4332                    "Second component Region" );
4333 }
4334 
4335 /* Standard class functions. */
4336 /* ========================= */
4337 /* Implement the astIsACmpRegion and astCheckCmpRegion functions using the
4338    macros defined for this purpose in the "object.h" header file. */
astMAKE_ISA(CmpRegion,Region)4339 astMAKE_ISA(CmpRegion,Region)
4340 astMAKE_CHECK(CmpRegion)
4341 
4342 AstCmpRegion *astCmpRegion_( void *region1_void, void *region2_void, int oper,
4343                              const char *options, int *status, ...) {
4344 /*
4345 *+
4346 *  Name:
4347 *     astCmpRegion
4348 
4349 *  Purpose:
4350 *     Create a CmpRegion.
4351 
4352 *  Type:
4353 *     Protected function.
4354 
4355 *  Synopsis:
4356 *     #include "cmpregion.h"
4357 *     AstCmpRegion *astCmpRegion( AstRegion *region1, AstRegion *region2,
4358 *                                 int oper, const char *options, ..., int *status )
4359 
4360 *  Class Membership:
4361 *     CmpRegion constructor.
4362 
4363 *  Description:
4364 *     This function creates a new CmpRegion and optionally initialises its
4365 *     attributes.
4366 
4367 *  Parameters:
4368 *     region1
4369 *        Pointer to the first Region.
4370 *     region2
4371 *        Pointer to the second Region.
4372 *     oper
4373 *        The boolean operator with which to combine the two Regions. Either
4374 *        AST__AND or AST__OR.
4375 *     options
4376 *        Pointer to a null terminated string containing an optional
4377 *        comma-separated list of attribute assignments to be used for
4378 *        initialising the new CmpRegion. The syntax used is the same as for the
4379 *        astSet method and may include "printf" format specifiers identified
4380 *        by "%" symbols in the normal way.
4381 *     status
4382 *        Pointer to the inherited status variable.
4383 *     ...
4384 *        If the "options" string contains "%" format specifiers, then an
4385 *        optional list of arguments may follow it in order to supply values to
4386 *        be substituted for these specifiers. The rules for supplying these
4387 *        are identical to those for the astSet method (and for the C "printf"
4388 *        function).
4389 
4390 *  Returned Value:
4391 *     A pointer to the new CmpRegion.
4392 
4393 *  Notes:
4394 *     - A null pointer will be returned if this function is invoked
4395 *     with the global error status set, or if it should fail for any
4396 *     reason.
4397 *-
4398 
4399 *  Implementation Notes:
4400 *     - This function implements the basic CmpRegion constructor which is
4401 *     available via the protected interface to the CmpRegion class.  A
4402 *     public interface is provided by the astCmpRegionId_ function.
4403 *     - Because this function has a variable argument list, it is
4404 *     invoked by a macro that evaluates to a function pointer (not a
4405 *     function invocation) and no checking or casting of arguments is
4406 *     performed before the function is invoked. Because of this, the
4407 *     "region1" and "region2" parameters are of type (void *) and are
4408 *     converted and validated within the function itself.
4409 */
4410 
4411 /* Local Variables: */
4412    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
4413    AstCmpRegion *new;              /* Pointer to new CmpRegion */
4414    AstRegion *region1;             /* Pointer to first Region structure */
4415    AstRegion *region2;             /* Pointer to second Region structure */
4416    va_list args;                   /* Variable argument list */
4417 
4418 /* Initialise. */
4419    new = NULL;
4420 
4421 /* Get a pointer to the thread specific global data structure. */
4422    astGET_GLOBALS(NULL);
4423 
4424 /* Check the global status. */
4425    if ( !astOK ) return new;
4426 
4427 /* Obtain and validate pointers to the Region structures provided. */
4428    region1 = astCheckRegion( region1_void );
4429    region2 = astCheckRegion( region2_void );
4430    if ( astOK ) {
4431 
4432 /* Initialise the CmpRegion, allocating memory and initialising the
4433    virtual function table as well if necessary. */
4434       new = astInitCmpRegion( NULL, sizeof( AstCmpRegion ), !class_init,
4435                               &class_vtab, "CmpRegion", region1, region2,
4436                               oper );
4437 
4438 /* If successful, note that the virtual function table has been
4439    initialised. */
4440       if ( astOK ) {
4441          class_init = 1;
4442 
4443 /* Obtain the variable argument list and pass it along with the
4444    options string to the astVSet method to initialise the new CmpRegion's
4445    attributes. */
4446          va_start( args, status );
4447          astVSet( new, options, NULL, args );
4448          va_end( args );
4449 
4450 /* If an error occurred, clean up by deleting the new object. */
4451          if ( !astOK ) new = astDelete( new );
4452       }
4453    }
4454 
4455 /* Return a pointer to the new CmpRegion. */
4456    return new;
4457 }
4458 
astCmpRegionId_(void * region1_void,void * region2_void,int oper,const char * options,...)4459 AstCmpRegion *astCmpRegionId_( void *region1_void, void *region2_void,
4460                                int oper, const char *options, ... ) {
4461 /*
4462 *++
4463 *  Name:
4464 c     astCmpRegion
4465 f     AST_CMPREGION
4466 
4467 *  Purpose:
4468 *     Create a CmpRegion.
4469 
4470 *  Type:
4471 *     Public function.
4472 
4473 *  Synopsis:
4474 c     #include "cmpregion.h"
4475 c     AstCmpRegion *astCmpRegion( AstRegion *region1, AstRegion *region2,
4476 c                                 int oper, const char *options, ... )
4477 f     RESULT = AST_CMPREGION( REGION1, REGION2, OPER, OPTIONS, STATUS )
4478 
4479 *  Class Membership:
4480 *     CmpRegion constructor.
4481 
4482 *  Description:
4483 *     This function creates a new CmpRegion and optionally initialises
4484 *     its attributes.
4485 *
4486 *     A CmpRegion is a Region which allows two component
4487 *     Regions (of any class) to be combined to form a more complex
4488 *     Region. This combination may be performed a boolean AND, OR
4489 *     or XOR (exclusive OR) operator. If the AND operator is
4490 *     used, then a position is inside the CmpRegion only if it is
4491 *     inside both of its two component Regions. If the OR operator is
4492 *     used, then a position is inside the CmpRegion if it is inside
4493 *     either (or both) of its two component Regions. If the XOR operator
4494 *     is used, then a position is inside the CmpRegion if it is inside
4495 *     one but not both of its two component Regions. Other operators can
4496 *     be formed by negating one or both component Regions before using
4497 *     them to construct a new CmpRegion.
4498 *
4499 *     The two component Region need not refer to the same coordinate
4500 *     Frame, but it must be possible for the
4501 c     astConvert
4502 f     AST_CONVERT
4503 *     function to determine a Mapping between them (an error will be
4504 *     reported otherwise when the CmpRegion is created). For instance,
4505 *     a CmpRegion may combine a Region defined within an ICRS SkyFrame
4506 *     with a Region defined within a Galactic SkyFrame. This is
4507 *     acceptable because the SkyFrame class knows how to convert between
4508 *     these two systems, and consequently the
4509 c     astConvert
4510 f     AST_CONVERT
4511 *     function will also be able to convert between them. In such cases,
4512 *     the second component Region will be mapped into the coordinate Frame
4513 *     of the first component Region, and the Frame represented by the
4514 *     CmpRegion as a whole will be the Frame of the first component Region.
4515 *
4516 *     Since a CmpRegion is itself a Region, it can be used as a
4517 *     component in forming further CmpRegions. Regions of arbitrary
4518 *     complexity may be built from simple individual Regions in this
4519 *     way.
4520 
4521 *  Parameters:
4522 c     region1
4523 f     REGION1 = INTEGER (Given)
4524 *        Pointer to the first component Region.
4525 c     region2
4526 f     REGION2 = INTEGER (Given)
4527 *        Pointer to the second component Region. This Region will be
4528 *        transformed into the coordinate Frame of the first region before
4529 *        use. An error will be reported if this is not possible.
4530 c     oper
4531 f     OPER = INTEGER (Given)
4532 *        The boolean operator with which to combine the two Regions. This
4533 *        must be one of the symbolic constants AST__AND, AST__OR or AST__XOR.
4534 c     options
4535 f     OPTIONS = CHARACTER * ( * ) (Given)
4536 c        Pointer to a null-terminated string containing an optional
4537 c        comma-separated list of attribute assignments to be used for
4538 c        initialising the new CmpRegion. The syntax used is identical to
4539 c        that for the astSet function and may include "printf" format
4540 c        specifiers identified by "%" symbols in the normal way.
4541 f        A character string containing an optional comma-separated
4542 f        list of attribute assignments to be used for initialising the
4543 f        new CmpRegion. The syntax used is identical to that for the
4544 f        AST_SET routine.
4545 c     ...
4546 c        If the "options" string contains "%" format specifiers, then
4547 c        an optional list of additional arguments may follow it in
4548 c        order to supply values to be substituted for these
4549 c        specifiers. The rules for supplying these are identical to
4550 c        those for the astSet function (and for the C "printf"
4551 c        function).
4552 f     STATUS = INTEGER (Given and Returned)
4553 f        The global status.
4554 
4555 *  Returned Value:
4556 c     astCmpRegion()
4557 f     AST_CMPREGION = INTEGER
4558 *        A pointer to the new CmpRegion.
4559 
4560 *  Notes:
4561 *     - If one of the supplied Regions has an associated uncertainty,
4562 *     that uncertainty will also be used for the returned CmpRegion.
4563 *     If both supplied Regions have associated uncertainties, the
4564 *     uncertainty associated with the first Region will be used for the
4565 *     returned CmpRegion.
4566 *     - Deep copies are taken of the supplied Regions. This means that
4567 *     any subsequent changes made to the component Regions using the
4568 *     supplied pointers will have no effect on the CmpRegion.
4569 *     - A null Object pointer (AST__NULL) will be returned if this
4570 c     function is invoked with the AST error status set, or if it
4571 f     function is invoked with STATUS set to an error value, or if it
4572 *     should fail for any reason.
4573 *--
4574 
4575 *  Implementation Notes:
4576 *     - This function implements the external (public) interface to
4577 *     the astCmpRegion constructor function. It returns an ID value
4578 *     (instead of a true C pointer) to external users, and must be
4579 *     provided because astCmpRegion_ has a variable argument list which
4580 *     cannot be encapsulated in a macro (where this conversion would
4581 *     otherwise occur).
4582 *     - Because no checking or casting of arguments is performed
4583 *     before the function is invoked, the "region1" and "region2" parameters
4584 *     are of type (void *) and are converted from an ID value to a
4585 *     pointer and validated within the function itself.
4586 *     - The variable argument list also prevents this function from
4587 *     invoking astCmpRegion_ directly, so it must be a re-implementation
4588 *     of it in all respects, except for the conversions between IDs
4589 *     and pointers on input/output of Objects.
4590 */
4591 
4592 /* Local Variables: */
4593    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
4594    AstCmpRegion *new;              /* Pointer to new CmpRegion */
4595    AstRegion *region1;             /* Pointer to first Region structure */
4596    AstRegion *region2;             /* Pointer to second Region structure */
4597    va_list args;                   /* Variable argument list */
4598 
4599    int *status;                  /* Pointer to inherited status value */
4600 
4601 /* Get a pointer to the thread specific global data structure. */
4602    astGET_GLOBALS(NULL);
4603 
4604 /* Initialise. */
4605    new = NULL;
4606 
4607 /* Get a pointer to the inherited status value. */
4608    status = astGetStatusPtr;
4609 
4610 /* Check the global status. */
4611    if ( !astOK ) return new;
4612 
4613 /* Obtain the Region pointers from the ID's supplied and validate the
4614    pointers to ensure they identify valid Regions. */
4615    region1 = astVerifyRegion( astMakePointer( region1_void ) );
4616    region2 = astVerifyRegion( astMakePointer( region2_void ) );
4617    if ( astOK ) {
4618 
4619 /* Initialise the CmpRegion, allocating memory and initialising the
4620    virtual function table as well if necessary. */
4621       new = astInitCmpRegion( NULL, sizeof( AstCmpRegion ), !class_init,
4622                               &class_vtab, "CmpRegion", region1, region2,
4623                               oper );
4624 
4625 /* If successful, note that the virtual function table has been initialised. */
4626       if ( astOK ) {
4627          class_init = 1;
4628 
4629 /* Obtain the variable argument list and pass it along with the
4630    options string to the astVSet method to initialise the new CmpRegion's
4631    attributes. */
4632          va_start( args, options );
4633          astVSet( new, options, NULL, args );
4634          va_end( args );
4635 
4636 /* If an error occurred, clean up by deleting the new object. */
4637          if ( !astOK ) new = astDelete( new );
4638       }
4639    }
4640 
4641 /* Return an ID value for the new CmpRegion. */
4642    return astMakeId( new );
4643 }
4644 
astInitCmpRegion_(void * mem,size_t size,int init,AstCmpRegionVtab * vtab,const char * name,AstRegion * region1,AstRegion * region2,int oper,int * status)4645 AstCmpRegion *astInitCmpRegion_( void *mem, size_t size, int init,
4646                                  AstCmpRegionVtab *vtab, const char *name,
4647                                  AstRegion *region1, AstRegion *region2,
4648                                  int oper, int *status ) {
4649 /*
4650 *+
4651 *  Name:
4652 *     astInitCmpRegion
4653 
4654 *  Purpose:
4655 *     Initialise a CmpRegion.
4656 
4657 *  Type:
4658 *     Protected function.
4659 
4660 *  Synopsis:
4661 *     #include "cmpregion.h"
4662 *     AstCmpRegion *astInitCmpRegion_( void *mem, size_t size, int init,
4663 *                                      AstCmpRegionVtab *vtab, const char *name,
4664 *                                      AstRegion *region1, AstRegion *region2,
4665 *                                      int oper )
4666 
4667 *  Class Membership:
4668 *     CmpRegion initialiser.
4669 
4670 *  Description:
4671 *     This function is provided for use by class implementations to initialise
4672 *     a new CmpRegion object. It allocates memory (if necessary) to
4673 *     accommodate the CmpRegion plus any additional data associated with the
4674 *     derived class. It then initialises a CmpRegion structure at the start
4675 *     of this memory. If the "init" flag is set, it also initialises the
4676 *     contents of a virtual function table for a CmpRegion at the start of
4677 *     the memory passed via the "vtab" parameter.
4678 
4679 *  Parameters:
4680 *     mem
4681 *        A pointer to the memory in which the CmpRegion is to be initialised.
4682 *        This must be of sufficient size to accommodate the CmpRegion data
4683 *        (sizeof(CmpRegion)) plus any data used by the derived class. If a
4684 *        value of NULL is given, this function will allocate the memory itself
4685 *        using the "size" parameter to determine its size.
4686 *     size
4687 *        The amount of memory used by the CmpRegion (plus derived class
4688 *        data). This will be used to allocate memory if a value of NULL is
4689 *        given for the "mem" parameter. This value is also stored in the
4690 *        CmpRegion structure, so a valid value must be supplied even if not
4691 *        required for allocating memory.
4692 *     init
4693 *        A logical flag indicating if the CmpRegion's virtual function table
4694 *        is to be initialised. If this value is non-zero, the virtual function
4695 *        table will be initialised by this function.
4696 *     vtab
4697 *        Pointer to the start of the virtual function table to be associated
4698 *        with the new CmpRegion.
4699 *     name
4700 *        Pointer to a constant null-terminated character string which contains
4701 *        the name of the class to which the new object belongs (it is this
4702 *        pointer value that will subsequently be returned by the Object
4703 *        astClass function).
4704 *     region1
4705 *        Pointer to the first Region.
4706 *     region2
4707 *        Pointer to the second Region.
4708 *     oper
4709 *        The boolean operator to use. Must be one of AST__AND, AST__OR or
4710 *        AST__XOR.
4711 
4712 *  Returned Value:
4713 *     A pointer to the new CmpRegion.
4714 
4715 *  Notes:
4716 *     -  A null pointer will be returned if this function is invoked with the
4717 *     global error status set, or if it should fail for any reason.
4718 *-
4719 */
4720 
4721 /* Local Variables: */
4722    AstCmpRegion *new;            /* Pointer to new CmpRegion */
4723    AstFrame *frm;                /* Frame encapsulated by first Region */
4724    AstFrameSet *fs;              /* FrameSet connecting supplied Regions */
4725    AstMapping *map;              /* Mapping between two supplied Regions */
4726    AstMapping *smap;             /* Simplified Mapping between two supplied Regions */
4727    AstRegion *new_reg1;          /* Replacement for first region */
4728    AstRegion *new_reg2;          /* Replacement for second region */
4729    AstRegion *reg1;              /* First Region to store in the CmpRegion */
4730    AstRegion *reg2;              /* Second Region to store in the CmpRegion */
4731    AstRegion *xor1;              /* Copy of first supplied Region or NULL */
4732    AstRegion *xor2;              /* Copy of second supplied Region or NULL */
4733    int i;                        /* Loop count */
4734    int used_oper;                /* The boolean operation actually used */
4735 
4736 /* Check the global status. */
4737    if ( !astOK ) return NULL;
4738 
4739 /* If necessary, initialise the virtual function table. */
4740    if ( init ) astInitCmpRegionVtab( vtab, name );
4741 
4742 /* Initialise. */
4743    new = NULL;
4744 
4745 /* Check the supplied oper value. */
4746    if( oper != AST__AND && oper != AST__OR && oper != AST__XOR && astOK ) {
4747       astError( AST__INTRD, "astInitCmpRegion(%s): Illegal "
4748                 "boolean operator value (%d) supplied.", status, name, oper );
4749    }
4750 
4751 /* Take copies of the supplied Regions. */
4752    reg1 = astCopy( region1 );
4753    reg2 = astCopy( region2 );
4754 
4755 /* Get the Mapping from the second to the first Region. */
4756    fs = astConvert( reg2, reg1, "" );
4757 
4758 /* Report an error if not possible. */
4759    if( fs == NULL ) {
4760       frm = NULL;
4761       if( astOK ) astError( AST__INTRD, "astInitCmpRegion(%s): No Mapping can "
4762                             "be found between the two supplied Regions.", status, name );
4763 
4764 /* Otherwise, map the second Region into the Frame of the first (unless
4765    they are already in the same Frame). This results in both component
4766    Frames having the same current Frame. This current Frame is used as the
4767    encapsulated Frame within the parent Region structure. */
4768    } else {
4769       frm = astGetFrame( fs, AST__CURRENT );
4770       map = astGetMapping( fs, AST__BASE, AST__CURRENT );
4771       smap = astSimplify( map );
4772       if( !astIsAUnitMap( smap ) ) {
4773          new_reg2 = astMapRegion( reg2, smap, frm );
4774          (void) astAnnul( reg2 );
4775          reg2 = new_reg2;
4776       }
4777       smap = astAnnul( smap );
4778       map = astAnnul( map );
4779       fs = astAnnul( fs );
4780    }
4781 
4782 /* The CmpRegion class does not implement XOR directly (as it does for
4783    AND and OR). Instead, when requested to create an XOR CmpRegion, it
4784    creates a CmpRegion that uses AND and OR to simulate XOR. The top
4785    level XOR CmpRegion actually uses AST__OR and the two component
4786    regions within it are CmpRegions formed by combing the two supplied
4787    Regions (one being negated first) using AND. Create the required
4788    component Regions. */
4789    if( oper == AST__XOR ) {
4790       astNegate( reg1 );
4791       new_reg1 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND, " ",
4792                                              status );
4793       astNegate( reg1 );
4794 
4795       astNegate( reg2 );
4796       new_reg2 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND, " ",
4797                                              status );
4798       astNegate( reg2 );
4799 
4800       xor1 = reg1;
4801       xor2 = reg2;
4802 
4803       reg1 = new_reg1;
4804       reg2 = new_reg2;
4805 
4806       used_oper = AST__OR;
4807 
4808 /* For AND and OR, use the supplied operator. */
4809    } else {
4810       xor1 = NULL;
4811       xor2 = NULL;
4812       used_oper = oper;
4813    }
4814 
4815 /* Initialise a Region structure (the parent class) as the first component
4816    within the CmpRegion structure, allocating memory if necessary. A NULL
4817    PointSet is suppled as the two component Regions will perform the function
4818    of defining the Region shape. The base Frame of the FrameSet in the
4819    parent Region structure will be the same as the current Frames of the
4820    FrameSets in the two component Regions. */
4821    if ( astOK ) {
4822       new = (AstCmpRegion *) astInitRegion( mem, size, 0,
4823                                           (AstRegionVtab *) vtab, name,
4824                                           frm, NULL, NULL );
4825 
4826 /* Initialise the CmpRegion data. */
4827 /* --------------------------- */
4828 /* Store pointers to the component Regions. */
4829       new->region1 = astClone( reg1 );
4830       new->region2 = astClone( reg2 );
4831 
4832 /* Note the operator used to combine the somponent Regions. */
4833       new->oper = used_oper;
4834 
4835 /* If we are creating an XOR CmpRegion, save copies of the supplied
4836    Regions (i.e. the supplied Regions which are XORed). These will not
4837    be the same as "reg1" and "reg2" since each of those two regions will
4838    be CmpRegions that combine the supplied Regions using AST__AND. */
4839       if( oper == AST__XOR ) {
4840          new->xor1 = xor1;
4841          new->xor2 = xor2;
4842       } else {
4843          new->xor1 = NULL;
4844          new->xor2 = NULL;
4845       }
4846 
4847 /* Initialised cached values to show they have not yet been found. */
4848       for( i = 0; i < 2; i++ ) {
4849          new->rvals[ i ] = NULL;
4850          new->offs[ i ] = NULL;
4851          new->nbreak[ i ] = 0;
4852          new->d0[ i ] = AST__BAD;
4853          new->dtot[ i ] = AST__BAD;
4854       }
4855       new->bounded = -INT_MAX;
4856 
4857 /* If the base->current Mapping in the FrameSet within each component Region
4858    is a UnitMap, then the FrameSet does not need to be included in the
4859    Dump of the new CmpRegion. Set the RegionFS attribute of the component
4860    Region to zero to flag this. */
4861       map = astGetMapping( reg1->frameset, AST__BASE, AST__CURRENT );
4862       if( astIsAUnitMap( map ) ) astSetRegionFS( reg1, 0 );
4863       map = astAnnul( map );
4864 
4865       map = astGetMapping( reg2->frameset, AST__BASE, AST__CURRENT );
4866       if( astIsAUnitMap( map ) ) astSetRegionFS( reg2, 0 );
4867       map = astAnnul( map );
4868 
4869 /* Copy attribute values from the first component Region to the parent
4870    Region. */
4871       if( astTestMeshSize( new->region1 ) ) {
4872          astSetMeshSize( new,  astGetMeshSize( new->region1 ) );
4873       }
4874       if( astTestClosed( new->region1 ) ) {
4875          astSetClosed( new,  astGetClosed( new->region1 ) );
4876       }
4877 
4878 /* If an error occurred, clean up by annulling the Region pointers and
4879    deleting the new object. */
4880       if ( !astOK ) {
4881          new->region1 = astAnnul( new->region1 );
4882          new->region2 = astAnnul( new->region2 );
4883          new = astDelete( new );
4884       }
4885    }
4886 
4887 /* Free resources */
4888    reg1 = astAnnul( reg1 );
4889    reg2 = astAnnul( reg2 );
4890    if( frm ) frm = astAnnul( frm );
4891 
4892 /* Return a pointer to the new object. */
4893    return new;
4894 }
4895 
astLoadCmpRegion_(void * mem,size_t size,AstCmpRegionVtab * vtab,const char * name,AstChannel * channel,int * status)4896 AstCmpRegion *astLoadCmpRegion_( void *mem, size_t size,
4897                                  AstCmpRegionVtab *vtab, const char *name,
4898                                  AstChannel *channel, int *status ) {
4899 /*
4900 *+
4901 *  Name:
4902 *     astLoadCmpRegion
4903 
4904 *  Purpose:
4905 *     Load a CmpRegion.
4906 
4907 *  Type:
4908 *     Protected function.
4909 
4910 *  Synopsis:
4911 *     #include "cmpregion.h"
4912 *     AstCmpRegion *astLoadCmpRegion( void *mem, size_t size,
4913 *                                     AstCmpRegionVtab *vtab, const char *name,
4914 *                                     AstChannel *channel )
4915 
4916 *  Class Membership:
4917 *     CmpRegion loader.
4918 
4919 *  Description:
4920 *     This function is provided to load a new CmpRegion using data read
4921 *     from a Channel. It first loads the data used by the parent class
4922 *     (which allocates memory if necessary) and then initialises a
4923 *     CmpRegion structure in this memory, using data read from the input
4924 *     Channel.
4925 *
4926 *     If the "init" flag is set, it also initialises the contents of a
4927 *     virtual function table for a CmpRegion at the start of the memory
4928 *     passed via the "vtab" parameter.
4929 
4930 
4931 *  Parameters:
4932 *     mem
4933 *        A pointer to the memory into which the CmpRegion is to be
4934 *        loaded.  This must be of sufficient size to accommodate the
4935 *        CmpRegion data (sizeof(CmpRegion)) plus any data used by derived
4936 *        classes. If a value of NULL is given, this function will
4937 *        allocate the memory itself using the "size" parameter to
4938 *        determine its size.
4939 *     size
4940 *        The amount of memory used by the CmpRegion (plus derived class
4941 *        data).  This will be used to allocate memory if a value of
4942 *        NULL is given for the "mem" parameter. This value is also
4943 *        stored in the CmpRegion structure, so a valid value must be
4944 *        supplied even if not required for allocating memory.
4945 *
4946 *        If the "vtab" parameter is NULL, the "size" value is ignored
4947 *        and sizeof(AstCmpRegion) is used instead.
4948 *     vtab
4949 *        Pointer to the start of the virtual function table to be
4950 *        associated with the new CmpRegion. If this is NULL, a pointer to
4951 *        the (static) virtual function table for the CmpRegion class is
4952 *        used instead.
4953 *     name
4954 *        Pointer to a constant null-terminated character string which
4955 *        contains the name of the class to which the new object
4956 *        belongs (it is this pointer value that will subsequently be
4957 *        returned by the astGetClass method).
4958 *
4959 *        If the "vtab" parameter is NULL, the "name" value is ignored
4960 *        and a pointer to the string "CmpRegion" is used instead.
4961 
4962 *  Returned Value:
4963 *     A pointer to the new CmpRegion.
4964 
4965 *  Notes:
4966 *     - A null pointer will be returned if this function is invoked
4967 *     with the global error status set, or if it should fail for any
4968 *     reason.
4969 *-
4970 */
4971 
4972 /* Local Variables: */
4973    AstCmpRegion *new;            /* Pointer to the new CmpRegion */
4974    AstRegion *reg1;              /* First Region read from dump */
4975    AstRegion *reg2;              /* Second Region read from dump */
4976    AstFrame *f1;                 /* Base Frame in parent Region */
4977    AstRegion *creg;              /* Pointer to component Region */
4978    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
4979    int i;                        /* Loop count */
4980    int oper;                     /* The operator to include in the dump */
4981 
4982 /* Initialise. */
4983    new = NULL;
4984 
4985 /* Get a pointer to the thread specific global data structure. */
4986    astGET_GLOBALS(channel);
4987 
4988 /* Check the global error status. */
4989    if ( !astOK ) return new;
4990 
4991 /* If a NULL virtual function table has been supplied, then this is
4992    the first loader to be invoked for this CmpRegion. In this case the
4993    CmpRegion belongs to this class, so supply appropriate values to be
4994    passed to the parent class loader (and its parent, etc.). */
4995    if ( !vtab ) {
4996       size = sizeof( AstCmpRegion );
4997       vtab = &class_vtab;
4998       name = "CmpRegion";
4999 
5000 /* If required, initialise the virtual function table for this class. */
5001       if ( !class_init ) {
5002          astInitCmpRegionVtab( vtab, name );
5003          class_init = 1;
5004       }
5005    }
5006 
5007 /* Invoke the parent class loader to load data for all the ancestral
5008    classes of the current one, returning a pointer to the resulting
5009    partly-built CmpRegion. */
5010    new = astLoadRegion( mem, size, (AstRegionVtab *) vtab, name,
5011                          channel );
5012 
5013    if ( astOK ) {
5014 
5015 /* Read input data. */
5016 /* ================ */
5017 /* Request the input Channel to read all the input data appropriate to
5018    this class into the internal "values list". */
5019       astReadClassData( channel, "CmpRegion" );
5020 
5021 /* Now read each individual data item from this list and use it to
5022    initialise the appropriate instance variable(s) for this class. */
5023 
5024 /* In the case of attributes, we first read the "raw" input value,
5025    supplying the "unset" value as the default. If a "set" value is
5026    obtained, we then use the appropriate (private) Set... member
5027    function to validate and set the value properly. */
5028 
5029 /* Operator */
5030 /* -------- */
5031       oper = astReadInt( channel, "operator", AST__AND );
5032 
5033 /* First Region. */
5034 /* -------------- */
5035       reg1 = astReadObject( channel, "regiona", NULL );
5036 
5037 /* Second Region. */
5038 /* --------------- */
5039       reg2 = astReadObject( channel, "regionb", NULL );
5040 
5041 /* Initialised cached values to show they have not yet been found. */
5042       for( i = 0; i < 2; i++ ) {
5043          new->rvals[ i ] = NULL;
5044          new->offs[ i ] = NULL;
5045          new->nbreak[ i ] = 0;
5046          new->d0[ i ] = AST__BAD;
5047          new->dtot[ i ] = AST__BAD;
5048       }
5049       new->bounded = -INT_MAX;
5050 
5051 /* The CmpRegion class does not implement XOR directly (as it does for
5052    AND and OR). Instead, when requested to create an XOR CmpRegion, it
5053    creates a CmpRegion that uses AND and OR to simulate XOR. The top
5054    level XOR CmpRegion actually uses AST__OR and the two component
5055    regions within it are CmpRegions formed by combing the two supplied
5056    Regions (one being negated first) using AND. Create the required
5057    component Regions. */
5058       if( oper == AST__XOR ) {
5059          astNegate( reg1 );
5060          new->region1 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND,
5061                                                     " ", status );
5062          astNegate( reg1 );
5063 
5064          astNegate( reg2 );
5065          new->region2 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND,
5066                                                     " ", status );
5067          astNegate( reg2 );
5068 
5069          new->xor1 = reg1;
5070          new->xor2 = reg2;
5071 
5072          new->oper = AST__OR;
5073 
5074 /* For AND and OR, use the supplied Regions and operator. */
5075       } else {
5076          new->region1 = reg1;
5077          new->region2 = reg2;
5078          new->xor1 = NULL;
5079          new->xor2 = NULL;
5080          new->oper = oper;
5081       }
5082 
5083 /* If either component Region has a dummy FrameSet rather than the correct
5084    FrameSet, the correct FrameSet will have copies of the base Frame of the
5085    new CmpRegion as both its current and base Frames, connected by a UnitMap
5086    (this is equivalent to a FrameSet containing a single Frame). However if
5087    the new CmpRegion being loaded has itself got a dummy FrameSet, then we do
5088    not do this since we do not yet know what the correct FrameSet is. In this
5089    case we wait until the parent Region invokes the astSetRegFS method on the
5090    new CmpRegion. */
5091       if( !astRegDummyFS( new ) ) {
5092          f1 = astGetFrame( ((AstRegion *) new)->frameset, AST__BASE );
5093          creg = new->region1;
5094          if( astRegDummyFS( creg ) ) astSetRegFS( creg, f1 );
5095          creg = new->region2;
5096          if( astRegDummyFS( creg ) ) astSetRegFS( creg, f1 );
5097          f1 = astAnnul( f1 );
5098       }
5099 
5100 /* If an error occurred, clean up by deleting the new CmpRegion. */
5101       if ( !astOK ) new = astDelete( new );
5102    }
5103 
5104 /* Return the new CmpRegion pointer. */
5105    return new;
5106 }
5107 
5108 /* Virtual function interfaces. */
5109 /* ============================ */
5110 /* These provide the external interface to the virtual functions defined by
5111    this class. Each simply checks the global error status and then locates and
5112    executes the appropriate member function, using the function pointer stored
5113    in the object's virtual function table (this pointer is located using the
5114    astMEMBER macro defined in "object.h").
5115 
5116    Note that the member function may not be the one defined here, as it may
5117    have been over-ridden by a derived class. However, it should still have the
5118    same interface. */
5119 
astCmpRegionList_(AstCmpRegion * this,int * nreg,AstRegion *** reg_list,int * status)5120 int astCmpRegionList_( AstCmpRegion *this, int *nreg, AstRegion ***reg_list,
5121                        int *status ) {
5122    if ( !astOK ) return AST__AND;
5123    return (**astMEMBER(this,CmpRegion,CmpRegionList))( this, nreg, reg_list,
5124                                                        status );
5125 }
5126 
5127 
5128 
5129 
5130 
5131 
5132