summaryrefslogtreecommitdiffstats
path: root/ast/cmpregion.c
diff options
context:
space:
mode:
Diffstat (limited to 'ast/cmpregion.c')
-rw-r--r--ast/cmpregion.c5127
1 files changed, 5127 insertions, 0 deletions
diff --git a/ast/cmpregion.c b/ast/cmpregion.c
new file mode 100644
index 0000000..94f581d
--- /dev/null
+++ b/ast/cmpregion.c
@@ -0,0 +1,5127 @@
+/*
+*class++
+* Name:
+* CmpRegion
+
+* Purpose:
+* A combination of two regions within a single Frame
+
+* Constructor Function:
+c astCmpRegion
+f AST_CMPREGION
+
+* Description:
+* A CmpRegion is a Region which allows two component
+* Regions (of any class) to be combined to form a more complex
+* Region. This combination may be performed a boolean AND, OR
+* or XOR (exclusive OR) operator. If the AND operator is
+* used, then a position is inside the CmpRegion only if it is
+* inside both of its two component Regions. If the OR operator is
+* used, then a position is inside the CmpRegion if it is inside
+* either (or both) of its two component Regions. If the XOR operator
+* is used, then a position is inside the CmpRegion if it is inside
+* one but not both of its two component Regions. Other operators can
+* be formed by negating one or both component Regions before using
+* them to construct a new CmpRegion.
+*
+* The two component Region need not refer to the same coordinate
+* Frame, but it must be possible for the
+c astConvert
+f AST_CONVERT
+* function to determine a Mapping between them (an error will be
+* reported otherwise when the CmpRegion is created). For instance,
+* a CmpRegion may combine a Region defined within an ICRS SkyFrame
+* with a Region defined within a Galactic SkyFrame. This is
+* acceptable because the SkyFrame class knows how to convert between
+* these two systems, and consequently the
+c astConvert
+f AST_CONVERT
+* function will also be able to convert between them. In such cases,
+* the second component Region will be mapped into the coordinate Frame
+* of the first component Region, and the Frame represented by the
+* CmpRegion as a whole will be the Frame of the first component Region.
+*
+* Since a CmpRegion is itself a Region, it can be used as a
+* component in forming further CmpRegions. Regions of arbitrary
+* complexity may be built from simple individual Regions in this
+* way.
+
+* Inheritance:
+* The CmpRegion class inherits from the Region class.
+
+* Attributes:
+* The CmpRegion class does not define any new attributes beyond those
+* which are applicable to all Regions.
+
+* Functions:
+c The CmpRegion class does not define any new functions beyond those
+f The CmpRegion class does not define any new routines beyond those
+* which are applicable to all Regions.
+
+* Copyright:
+* Copyright (C) 1997-2006 Council for the Central Laboratory of the
+* Research Councils
+* Copyright (C) 2009 Science & Technology Facilities Council.
+* All Rights Reserved.
+
+* Licence:
+* This program is free software: you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation, either
+* version 3 of the License, or (at your option) any later
+* version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General
+* License along with this program. If not, see
+* <http://www.gnu.org/licenses/>.
+
+* Authors:
+* DSB: David S. Berry (Starlink)
+
+* History:
+* 7-OCT-2004 (DSB):
+* Original version.
+* 28-MAY-2007 (DSB):
+* - Corrected RegBaseMesh.
+* - In RegBaseBox, if the CmpRegion is bounded find the box by
+* finding the extreme position sin a mesh covering the boundary.
+* 20-JAN-2009 (DSB):
+* Over-ride astRegBasePick.
+* 19-MAR-2009 (DSB):
+* Over-ride the astDecompose method.
+* 8-SEP-2009 (DSB):
+* Fix logic in RegTrace.
+* 9-SEP-2009 (DSB):
+* - Added astCmpRegionList
+* - Added support for XOR
+* - Override astGetObjSize.
+* 27-APR-2012 (DSB):
+* - Cache the bounded property.
+* - Speed up plotting of CmpRegions by using the cached negation
+* of a Region instead of setting the Regions's Negated flag (which
+* causes the Region's cache to be cleared).
+* 30-APR-2012 (DSB):
+* Use geodesic distance to measure distances around the two component
+* Regions when tracing the border. Previously, a distance normalised
+* from zero to one was used for both component Regions, but this gives
+* greater priority to Regions higher in the CmpRegion nesting order,
+* resulting in a high chance that lower Regions will not be seen.
+* 7-JUN-2012 (DSB):
+* Override astRegSplit method.
+* 21-NOV-2012 (DSB):
+* Map the regions returned by RegSplit into the current Frame of the
+* CmpRegion.
+*class--
+*/
+
+/* Module Macros. */
+/* ============== */
+/* Set the name of the class we are implementing. This indicates to
+ the header files that define class interfaces that they should make
+ "protected" symbols available. */
+#define astCLASS CmpRegion
+
+/* Include files. */
+/* ============== */
+/* Interface definitions. */
+/* ---------------------- */
+
+#include "globals.h" /* Thread-safe global data access */
+#include "error.h" /* Error reporting facilities */
+#include "memory.h" /* Memory allocation facilities */
+#include "object.h" /* Base Object class */
+#include "pointset.h" /* Sets of points/coordinates */
+#include "region.h" /* Regions (parent class) */
+#include "channel.h" /* I/O channels */
+#include "nullregion.h" /* Boundless Regions */
+#include "cmpregion.h" /* Interface definition for this class */
+#include "unitmap.h" /* Unit Mapings */
+
+/* Error code definitions. */
+/* ----------------------- */
+#include "ast_err.h" /* AST error codes */
+
+/* C header files. */
+/* --------------- */
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+/* Module Variables. */
+/* ================= */
+
+/* Address of this static variable is used as a unique identifier for
+ member of this class. */
+static int class_check;
+
+/* Pointers to parent class methods which are extended by this class. */
+static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
+static AstRegion *(* parent_getdefunc)( AstRegion *, int * );
+static void (* parent_setregfs)( AstRegion *, AstFrame *, int * );
+static AstMapping *(* parent_simplify)( AstMapping *, int * );
+static int (* parent_equal)( AstObject *, AstObject *, int * );
+static void (* parent_setclosed)( AstRegion *, int, int * );
+static void (* parent_setmeshsize)( AstRegion *, int, int * );
+static void (* parent_clearclosed)( AstRegion *, int * );
+static void (* parent_clearmeshsize)( AstRegion *, int * );
+static double (*parent_getfillfactor)( AstRegion *, int * );
+static void (*parent_regsetattrib)( AstRegion *, const char *, char **, int * );
+static void (*parent_regclearattrib)( AstRegion *, const char *, char **, int * );
+static void (* parent_resetcache)( AstRegion *, int * );
+static int (* parent_getobjsize)( AstObject *, int * );
+
+#if defined(THREAD_SAFE)
+static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
+#endif
+
+
+#ifdef THREAD_SAFE
+/* Define how to initialise thread-specific globals. */
+#define GLOBAL_inits \
+ globals->Class_Init = 0;
+
+/* Create the function that initialises global data for this module. */
+astMAKE_INITGLOBALS(CmpRegion)
+
+/* Define macros for accessing each item of thread specific global data. */
+#define class_init astGLOBAL(CmpRegion,Class_Init)
+#define class_vtab astGLOBAL(CmpRegion,Class_Vtab)
+
+
+#include <pthread.h>
+
+
+#else
+
+
+/* Define the class virtual function table and its initialisation flag
+ as static variables. */
+static AstCmpRegionVtab class_vtab; /* Virtual function table */
+static int class_init = 0; /* Virtual function table initialised? */
+
+#endif
+
+/* External Interface Function Prototypes. */
+/* ======================================= */
+/* The following functions have public prototypes only (i.e. no
+ protected prototypes), so we must provide local prototypes for use
+ within this module. */
+AstCmpRegion *astCmpRegionId_( void *, void *, int, const char *, ... );
+
+/* Prototypes for Private Member Functions. */
+/* ======================================== */
+static AstMapping *Simplify( AstMapping *, int * );
+static AstPointSet *RegBaseMesh( AstRegion *, int * );
+static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
+static AstRegion *GetDefUnc( AstRegion *, int * );
+static AstRegion *MatchRegion( AstRegion *, int, AstRegion *, const char *, int * );
+static AstRegion *RegBasePick( AstRegion *this, int, const int *, int * );
+static AstRegion **RegSplit( AstRegion *, int *, int * );
+static double GetFillFactor( AstRegion *, int * );
+static int CmpRegionList( AstCmpRegion *, int *, AstRegion ***, int * );
+static int Equal( AstObject *, AstObject *, int * );
+static int GetBounded( AstRegion *, int * );
+static int GetObjSize( AstObject *, int * );
+static int RegPins( AstRegion *, AstPointSet *, AstRegion *, int **, int * );
+static int RegTrace( AstRegion *, int, double *, double **, int * );
+static void ClearClosed( AstRegion *, int * );
+static void ClearMeshSize( AstRegion *, int * );
+static void Copy( const AstObject *, AstObject *, int * );
+static void Decompose( AstMapping *, AstMapping **, AstMapping **, int *, int *, int *, int * );
+static void Delete( AstObject *, int * );
+static void Dump( AstObject *, AstChannel *, int * );
+static void GetRegions( AstCmpRegion *, AstRegion **, AstRegion **, int *, int *, int *, int * );
+static void RegBaseBox( AstRegion *, double *, double *, int * );
+static void RegBaseBox2( AstRegion *, double *, double *, int * );
+static void RegClearAttrib( AstRegion *, const char *, char **, int * );
+static void RegSetAttrib( AstRegion *, const char *, char **, int * );
+static void ResetCache( AstRegion *this, int * );
+static void SetBreakInfo( AstCmpRegion *, int, int * );
+static void SetClosed( AstRegion *, int, int * );
+static void SetMeshSize( AstRegion *, int, int * );
+static void SetRegFS( AstRegion *, AstFrame *, int * );
+static void XORCheck( AstCmpRegion *, int * );
+
+#if defined(THREAD_SAFE)
+static int ManageLock( AstObject *, int, int, AstObject **, int * );
+#endif
+
+
+/* Member functions. */
+/* ================= */
+int CmpRegionList( AstCmpRegion *this, int *nreg, AstRegion ***reg_list,
+ int *status ) {
+/*
+*+
+* Name:
+* astCmpRegionList
+
+* Purpose:
+* Decompose a CmpRegion into a sequence of simpler Regions.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* int astCmpRegionList( AstCmpRegion *this, int *nreg,
+* AstRegion ***reg_list, int *status )
+
+* Class Membership:
+* CmpRegion method.
+
+* Description:
+* This function decomposes a CmpRegion into a sequence of simpler
+* Regions which may be applied in sequence to achieve the same
+* effect.
+
+* Parameters:
+* this
+* Pointer to the CmpRegion to be decomposed (the CmpRegion is not
+* actually modified by this function).
+* nreg
+* The address of an int which holds a count of the number of
+* individual Regions in the decomposition. On entry, this
+* should count the number of Regions already in the
+* "*reg_list" array (below). On exit, it is updated to include
+* any new Regions appended by this function.
+* reg_list
+* Address of a pointer to an array of Region pointers. On
+* entry, this array pointer should either be NULL (if no
+* Regions have yet been obtained) or should point at a
+* dynamically allocated array containing Region pointers
+* ("*nreg" in number) which have been obtained from a previous
+* invocation of this function.
+*
+* On exit, the dynamic array will be enlarged to contain any
+* new Region pointers that result from the decomposition
+* requested. These pointers will be appended to any previously
+* present, and the array pointer will be updated as necessary
+* to refer to the enlarged array (any space released by the
+* original array will be freed automatically).
+*
+* The new Region pointers returned will identify a sequence of
+* Region which, when applied in order, will represent an area
+* equivalent to that of the original Region.
+*
+* All the Region pointers returned by this function should be
+* annulled by the caller, using astAnnul, when no longer
+* required. The dynamic array holding these pointers should
+* also be freed, using astFree.
+
+* Returned Value:
+* An integer identifying the boolean operation that should be used to
+* combine the Regions returned in "reg_list". This will be AST__AND
+* or AST__OR.
+
+*-
+*/
+
+/* Local Variables: */
+ AstCmpRegion *cmpreg;
+ int add;
+ int result;
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__AND;
+
+/* Check if this CmpRegion has an equivalent XOR representation. Is so,
+ store details of the XOR representation in the CmpRegion. */
+ XORCheck( this, status );
+
+/* The CmpRegion class only has full support for AND and OR operators.
+ However, it can also represent XOR operators, but it does this by
+ an equivalent set of AND and OR operators. When an XOR CmpRegion is
+ created, the original supplied argument regions are stored in
+ "this->xor1" and "this->xor2", and the component Regions placed in the
+ new CmpRegion are actually CmpRegions that implement the equivalent
+ of an XOR operation, using AND and OR operators. We want to hide this
+ to the outside world, so if the supplied CmpRegion represents an XOR
+ operation, add the XOR regions to the returned list, and return an
+ XOR operator. */
+ if( this->xor1 ) {
+ *reg_list = astGrow( *reg_list, *nreg + 2, sizeof( AstRegion * ) );
+ if( astOK ) {
+ ( *reg_list )[ (*nreg)++ ] = astClone( this->xor1 );
+ ( *reg_list )[ (*nreg)++ ] = astClone( this->xor2 );
+ }
+ result = AST__XOR;
+
+/* For AND and OR operators, we deal with the component Regions directly. */
+ } else {
+
+/* If the first component of the supplied CmpRegion is itself a CmpRegion
+ that uses the same boolean operator as "this", call this function
+ recursively to add its component Regions to the returned list. */
+ add = 1;
+ if( astIsACmpRegion( this->region1 ) ) {
+ cmpreg = (AstCmpRegion *) this->region1;
+ if( cmpreg->oper == this->oper ) {
+ (void) CmpRegionList( cmpreg, nreg, reg_list, status );
+ add = 0;
+ }
+ }
+
+/* Otherwise, add the component Region directly into the returned list of
+ Regions. */
+ if( add ) {
+ *reg_list = astGrow( *reg_list, *nreg + 1, sizeof( AstRegion * ) );
+ if( astOK ) {
+ ( *reg_list )[ *nreg ] = astClone( this->region1 );
+ ( *nreg )++;
+ }
+ }
+
+/* Do the same for the second component region */
+ add = 1;
+ if( astIsACmpRegion( this->region2 ) ) {
+ cmpreg = (AstCmpRegion *) this->region2;
+ if( cmpreg->oper == this->oper ) {
+ (void) CmpRegionList( cmpreg, nreg, reg_list, status );
+ add = 0;
+ }
+ }
+
+ if( add ) {
+ *reg_list = astGrow( *reg_list, *nreg + 1, sizeof( AstRegion * ) );
+ if( astOK ) {
+ ( *reg_list )[ *nreg ] = astClone( this->region2 );
+ ( *nreg )++;
+ }
+ }
+
+ result = this->oper;
+ }
+
+/* Return the boolean operator used to combine the regions in the
+ returned array. */
+ return result;
+}
+
+static void Decompose( AstMapping *this_mapping, AstMapping **map1,
+ AstMapping **map2, int *series, int *invert1,
+ int *invert2, int *status ) {
+/*
+*
+* Name:
+* Decompose
+
+* Purpose:
+* Decompose a CmpRegion into two component Regions.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void Decompose( AstMapping *this, AstMapping **map1,
+* AstMapping **map2, int *series,
+* int *invert1, int *invert2, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the protected astDecompose
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns pointers to two Mappings which, when applied
+* either in series or parallel, are equivalent to the supplied Mapping.
+*
+* Since the Frame class inherits from the Mapping class, Frames can
+* be considered as special types of Mappings and so this method can
+* be used to decompose either CmpMaps, CmpFrames, CmpRegions or Prisms.
+
+* Parameters:
+* this
+* Pointer to the Mapping.
+* map1
+* Address of a location to receive a pointer to first component
+* Mapping.
+* map2
+* Address of a location to receive a pointer to second component
+* Mapping.
+* series
+* Address of a location to receive a value indicating if the
+* component Mappings are applied in series or parallel. A non-zero
+* value means that the supplied Mapping is equivalent to applying map1
+* followed by map2 in series. A zero value means that the supplied
+* Mapping is equivalent to applying map1 to the lower numbered axes
+* and map2 to the higher numbered axes, in parallel.
+* invert1
+* The value of the Invert attribute to be used with map1.
+* invert2
+* The value of the Invert attribute to be used with map2.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - Any changes made to the component rames using the returned
+* pointers will be reflected in the supplied CmpFrame.
+
+*-
+*/
+
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the CmpMap structure. */
+ this = (AstCmpRegion *) this_mapping;
+
+/* The components Frames of a CmpRegion are considered to be series
+ Mappings. */
+ if( series ) *series = 1;
+
+/* The Frames are returned in their original order whether or not the
+ CmpRegion has been inverted. */
+ if( map1 ) *map1 = astClone( this->region1 );
+ if( map2 ) *map2 = astClone( this->region2 );
+
+/* The invert flags dont mean anything for a Region, but we return them
+ anyway. If the CmpRegion has been inverted, return inverted Invert flags. */
+ if( astGetInvert( this ) ) {
+ if( invert1 ) *invert1 = astGetInvert( this->region1 ) ? 0 : 1;
+ if( invert2 ) *invert2 = astGetInvert( this->region2 ) ? 0 : 1;
+
+/* If the CmpRegion has not been inverted, return the current Invert flags. */
+ } else {
+ if( invert1 ) *invert1 = astGetInvert( this->region1 );
+ if( invert2 ) *invert2 = astGetInvert( this->region2 );
+ }
+}
+
+static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
+/*
+* Name:
+* Equal
+
+* Purpose:
+* Test if two Objects are equivalent.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* int Equal( AstObject *this_object, AstObject *that_object, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astEqual protected
+* method inherited from the Region class).
+
+* Description:
+* This function returns a boolean result (0 or 1) to indicate whether
+* two CmpRegions are equivalent.
+
+* Parameters:
+* this
+* Pointer to the first CmpRegion.
+* that
+* Pointer to the second CmpRegion.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* One if the CmpRegions are equivalent, zero otherwise.
+
+* Notes:
+* - The CmpRegions are equivalent if their component Regions are
+* equivalent and if they have the same boolean operation, negation
+* and closed flags.
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *that;
+ AstCmpRegion *this;
+ int result;
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Invoke the Equal method inherited from the parent Region class. This checks
+ that the Objects are both of the same class, and have the same Negated
+ and Closed flags (amongst other things). */
+ if( (*parent_equal)( this_object, that_object, status ) ) {
+
+/* Obtain pointers to the two CmpRegion structures. */
+ this = (AstCmpRegion *) this_object;
+ that = (AstCmpRegion *) that_object;
+
+/* Test their first component Regions for equality. */
+ if( astEqual( this->region1, that->region1 ) ) {
+
+/* Test their second component Regions for equality. */
+ if( astEqual( this->region2, that->region2 ) ) {
+
+/* Test their boolean operator for equality. */
+ if( this->oper == that->oper ) result = 1;
+ }
+ }
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result, */
+ return result;
+}
+
+/*
+* Name:
+* MAKE_SET
+
+* Purpose:
+* Define a function to set an attribute value for a CmpRegion.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "cmpregion.h"
+* MAKE_SET(attribute,lattribute,type)
+
+* Class Membership:
+* Defined by the CmpRegion class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static void Set<Attribute>( AstRegion *this, <Type> value )
+*
+* that sets the value of a specified Region attribute in the parent
+* Region structure and also in the component Regions.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+* lattribute
+* Name of the attribute, all in lower case.
+* type
+* The C type of the attribute.
+*/
+
+/* Define the macro. */
+#define MAKE_SET(attribute,lattribute,type) \
+static void Set##attribute( AstRegion *this_region, type value, int *status ) { \
+\
+/* Local Variables: */ \
+ AstCmpRegion *this; /* Pointer to the CmpRegion structure */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Use the parent method to set the value in the parent Region structure. */ \
+ (*parent_set##lattribute)( this_region, value, status ); \
+\
+/* Also set the value in the two component Regions. */ \
+ this = (AstCmpRegion *) this_region; \
+ astSet##attribute( this->region1, value ); \
+ astSet##attribute( this->region2, value ); \
+}
+
+/* Use the above macro to create accessors for the MeshSize and Closed attributes. */
+MAKE_SET(MeshSize,meshsize,int)
+MAKE_SET(Closed,closed,int)
+
+/* Undefine the macro. */
+#undef MAKE_SET
+
+/*
+* Name:
+* MAKE_CLEAR
+
+* Purpose:
+* Define a function to clear an attribute value for a CmpRegion.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "cmpregion.h"
+* MAKE_CLEAR(attribute,lattribute)
+
+* Class Membership:
+* Defined by the CmpRegion class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static void Clear<Attribute>( AstRegion *this )
+*
+* that sets the value of a specified Region attribute in the parent
+* Region structure and also in the component Regions.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+* lattribute
+* Name of the attribute, all in lower case.
+*/
+
+/* Define the macro. */
+#define MAKE_CLEAR(attribute,lattribute) \
+static void Clear##attribute( AstRegion *this_region, int *status ) { \
+\
+/* Local Variables: */ \
+ AstCmpRegion *this; /* Pointer to the CmpRegion structure */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Use the parent method to clear the value in the parent Region structure. */ \
+ (*parent_clear##lattribute)( this_region, status ); \
+\
+/* Also clear the value in the two component Regions. */ \
+ this = (AstCmpRegion *) this_region; \
+ astClear##attribute( this->region1 ); \
+ astClear##attribute( this->region2 ); \
+}
+
+/* Use the above macro to create accessors for the MeshSize and Closed attributes. */
+MAKE_CLEAR(MeshSize,meshsize)
+MAKE_CLEAR(Closed,closed)
+
+/* Undefine the macro. */
+#undef MAKE_CLEAR
+
+static int GetBounded( AstRegion *this_region, int *status ) {
+/*
+* Name:
+* GetBounded
+
+* Purpose:
+* Is the Region bounded?
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* int GetBounded( AstRegion *this, int *status )
+
+* Class Membership:
+* CmpRegion method (over-rides the astGetBounded method inherited from
+* the Region class).
+
+* Description:
+* This function returns a flag indicating if the Region is bounded.
+* The implementation provided by the base Region class is suitable
+* for Region sub-classes representing the inside of a single closed
+* curve (e.g. Circle, Ellipse, Box, etc). Other sub-classes (such as
+* CmpRegion, PointList, etc ) may need to provide their own
+* implementations.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Non-zero if the Region is bounded. Zero otherwise.
+
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion structure */
+ AstRegion *reg1; /* Pointer to first component Region */
+ AstRegion *reg2; /* Pointer to second component Region */
+ int neg1; /* Negated flag to use with first component */
+ int neg2; /* Negated flag to use with second component */
+ int oper; /* Combination operator */
+ int overlap; /* Nature of overlap between components */
+ int reg1b; /* Is the first component Region bounded?*/
+ int reg2b; /* Is the second component Region bounded?*/
+ int result; /* Returned result */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* Only calculated a new value if there is no cached value in the Region. */
+ if( this->bounded == -INT_MAX ) {
+
+/* Get the component Regions, how they should be combined, and the
+ Negated values which should be used with them. The returned values
+ take account of whether the supplied CmpRegion has itself been Negated
+ or not. The returned Regions represent regions within the base Frame
+ of the FrameSet encapsulated by the parent Region structure. */
+ GetRegions( this, &reg1, &reg2, &oper, &neg1, &neg2, status );
+
+/* If the first component Region does not have the required value for
+ its "Negated" attribute, use the negation of "reg1" in place of "reg1"
+ itself. */
+ if( neg1 != astGetNegated( reg1 ) ) {
+ AstRegion *tmp = astGetNegation( reg1 );
+ (void) astAnnul( reg1 );
+ reg1 = tmp;
+ }
+
+/* If the second component Region does not have the required value for
+ its "Negated" attribute, use the negation of "reg2" in place of "reg2"
+ itself. */
+ if( neg2 != astGetNegated( reg2 ) ) {
+ AstRegion *tmp = astGetNegation( reg2 );
+ (void) astAnnul( reg2 );
+ reg2 = tmp;
+ }
+
+/* See if either of the component Regions is bounded. */
+ reg1b = astGetBounded( reg1 );
+ reg2b = astGetBounded( reg2 );
+
+/* If the regions are ANDed... */
+ if( oper == AST__AND ) {
+
+/* If either one of the two components are bounded, then the AND region is
+ bounded. */
+ if( reg1b || reg2b ) {
+ result = 1;
+
+/* If neither of the two components is bounded, then the AND region is
+ unbounded if there is partial or no overlap between them and is bounded
+ otherwise. */
+ } else {
+ overlap = astOverlap( reg1, reg2 );
+ if( overlap == 1 || overlap == 4 || overlap == 6 ) {
+ result = 0;
+ } else {
+ result = 1;
+ }
+ }
+
+/* If the regions are ORed... */
+ } else {
+
+/* If either one of the two components is unbounded, then the OR region is
+ unbounded. */
+ if( !reg1b || !reg2b ) {
+ result = 0;
+
+/* If both of the two components are bounded, then the OR region is also
+ bounded. */
+ } else {
+ result = 1;
+ }
+ }
+
+/* Free resources. */
+ reg1 = astAnnul( reg1 );
+ reg2 = astAnnul( reg2 );
+
+/* Cache the value in the CmpRegion. */
+ this->bounded = astOK ? result : -INT_MAX;
+ }
+
+/* Return zero if an error occurred. Otherwise, return the cached value. */
+ if( astOK ) {
+ result = ( this->bounded == -INT_MAX ) ? 0 : this->bounded;
+ } else {
+ result = 0;
+ }
+
+/* Return the required pointer. */
+ return result;
+}
+
+static double GetFillFactor( AstRegion *this_region, int *status ) {
+/*
+* Name:
+* GetFillFactor
+
+* Purpose:
+* Obtain the value of the FillFactor attribute for a CmpRegion.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* double GetFillFactor( AstRegion *this, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astGetFillFactor method inherited
+* from the Region class).
+
+* Description:
+* This function returns the value of the FillFactor attribute for a
+* CmpRegion. A suitable default value is returned if no value has
+* previously been set.
+
+* Parameters:
+* this
+* Pointer to the CmpRegion.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The FillFactor value to use.
+
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this;
+ double result;
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Obtain a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* See if a FillFactor value has been set. If so, use the parent
+ astGetFillFactor method to obtain it. */
+ if ( astTestFillFactor( this ) ) {
+ result = (*parent_getfillfactor)( this_region, status );
+
+/* Otherwise, we will generate a default value equal to the FillFactor values
+ of the first component Region. */
+ } else {
+ result = astGetFillFactor( this->region1 );
+ }
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = AST__BAD;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetObjSize( AstObject *this_object, int *status ) {
+/*
+* Name:
+* GetObjSize
+
+* Purpose:
+* Return the in-memory size of an Object.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* int GetObjSize( AstObject *this, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astGetObjSize protected
+* method inherited from the parent class).
+
+* Description:
+* This function returns the in-memory size of the supplied CmpRegion,
+* in bytes.
+
+* Parameters:
+* this
+* Pointer to the CmpRegion.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The Object size, in bytes.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion structure */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointers to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_object;
+
+/* Invoke the GetObjSize method inherited from the parent class, and then
+ add on any components of the class structure defined by this class
+ which are stored in dynamically allocated memory. */
+ result = (*parent_getobjsize)( this_object, status );
+
+ result += astGetObjSize( this->region1 );
+ result += astGetObjSize( this->region2 );
+ if( this->xor1 ) result += astGetObjSize( this->xor1 );
+ if( this->xor2 ) result += astGetObjSize( this->xor2 );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result, */
+ return result;
+}
+
+static void GetRegions( AstCmpRegion *this, AstRegion **reg1, AstRegion **reg2,
+ int *oper, int *neg1, int *neg2, int *status ) {
+/*
+*
+* Name:
+* GetRegions
+
+* Purpose:
+* Get the component Regions of a CmpRegion.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "region.h"
+* void GetRegions( AstCmpRegion *this, AstRegion **reg1, AstRegion **reg2,
+* int *oper, int *neg1, int *neg2, int *status )
+
+* Class Membership:
+* CmpRegion member function
+
+* Description:
+* This function returns pointers to two Regions which, when applied
+* using the returned boolean operator, are equivalent to the supplied
+* Region. If the CmpRegion has been negated, then the returned operator
+* and "negated" flags will be set such that they represent the
+* negated CmpRegion.
+*
+* The current Frames in both the returned component Regions will be
+* equivalent to the base Frame in the FrameSet encapsulated by the
+* parent Region structure.
+
+* Parameters:
+* this
+* Pointer to the CmpRegion.
+* reg1
+* Address of a location to receive a pointer to first component
+* Region. The current Frame in this region will be equivalent to
+* the base Frame in the FrameSet
+* reg2
+* Address of a location to receive a pointer to second component
+* Region.
+* oper
+* Address of a location to receive a value indicating how the
+* component Regions are combined together. This will be one of
+* AST__AND or AST__OR
+* neg1
+* The value of the Negated attribute to be used with reg1.
+* neg2
+* The value of the Negated attribute to be used with reg2.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - Any changes made to the component Regions using the returned
+* pointers will be reflected in the supplied CmpRegion.
+
+*-
+*/
+
+/* Initialise */
+ if( reg1 ) *reg1 = NULL;
+ if( reg2 ) *reg2 = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Return the component Region pointers. */
+ if( reg1 ) *reg1 = astClone( this->region1 );
+ if( reg2 ) *reg2 = astClone( this->region2 );
+
+/* Initialise the other returned items. Note, the CmpRegion initialiser
+ stored a deep copy of the supplied component Regions, and so we do not
+ need to worry about attributes of the components having been changed
+ after the creation of the CmpRegion. This is different to the CmpMap
+ class which merely clones its supplied component pointers and so has
+ to save copies of the original Invert settings within the CmpMap
+ structure. */
+ if( oper ) *oper = this->oper;
+ if( neg1 ) *neg1 = astGetNegated( this->region1 );
+ if( neg2 ) *neg2 = astGetNegated( this->region2 );
+
+/* If the CmpRegion has been inverted, we modify the boolean operator and
+ negation flags so that they reflect the inverted CmpRegion. */
+ if( astGetNegated( this ) ) {
+
+/* If the component Regions are combined using AND, then the negated
+ CmpRegion combines its negated components using OR. */
+ if( this->oper == AST__AND ){
+ if( oper ) *oper = AST__OR;
+ if( neg1 ) *neg1 = *neg1 ? 0 : 1;
+ if( neg2 ) *neg2 = *neg2 ? 0 : 1;
+
+/* If the component Regions are combined using OR, then the negated CmpRegion
+ combines its negated components using AND. */
+ } else if( this->oper == AST__OR ){
+ if( oper ) *oper = AST__AND;
+ if( neg1 ) *neg1 = *neg1 ? 0 : 1;
+ if( neg2 ) *neg2 = *neg2 ? 0 : 1;
+
+ } else if( astOK ) {
+ astError( AST__INTER, "GetRegions(%s): The %s refers to an unknown "
+ "boolean operator with identifier %d (internal AST "
+ "programming error).", status, astGetClass( this ),
+ astGetClass( this ), this->oper );
+ }
+ }
+}
+
+static AstRegion *GetDefUnc( AstRegion *this_region, int *status ) {
+/*
+* Name:
+* GetDefUnc
+
+* Purpose:
+* Obtain a pointer to the default uncertainty Region for a given Region.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* AstRegion *GetDefUnc( AstRegion *this )
+
+* Class Membership:
+* CmpRegion method (over-rides the astGetDefUnc method inherited from
+* the Region class).
+
+* This function returns a pointer to a Region which represents the
+* default uncertainty associated with a position on the boundary of the
+* given Region. The returned Region refers to the base Frame within the
+* FrameSet encapsulated by the supplied Region.
+
+* Parameters:
+* this
+* Pointer to the Region.
+
+* Returned Value:
+* A pointer to the Region. This should be annulled (using astAnnul)
+* when no longer needed.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion structure */
+ AstRegion *result; /* Returned pointer */
+
+/* Initialise */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* If the first component region has non-default uncertainty, use it as
+ the default uncertainty for the CmpRegion. Note, the current Frame of
+ an uncertainty Region is assumed to be the same as the base Frame in the
+ CmpRegion. */
+ if( astTestUnc( this->region1 ) ) {
+ result = astGetUncFrm( this->region1, AST__CURRENT );
+
+/* Otherwise, if the second component region has non-default uncertainty,
+ use it as the default uncertainty for the CmpRegion. */
+ } else if( astTestUnc( this->region2 ) ) {
+ result = astGetUncFrm( this->region2, AST__CURRENT );
+
+/* Otherwise, use the parent method to determine the default uncertainty. */
+ } else {
+ result = (* parent_getdefunc)( this_region, status );
+ }
+
+/* Return NULL if an error occurred. */
+ if( !astOK ) result = astAnnul( result );
+
+/* Return the required pointer. */
+ return result;
+}
+
+void astInitCmpRegionVtab_( AstCmpRegionVtab *vtab, const char *name, int *status ) {
+/*
+*+
+* Name:
+* astInitCmpRegionVtab
+
+* Purpose:
+* Initialise a virtual function table for a CmpRegion.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void astInitCmpRegionVtab( AstCmpRegionVtab *vtab, const char *name )
+
+* Class Membership:
+* CmpRegion vtab initialiser.
+
+* Description:
+* This function initialises the component of a virtual function
+* table which is used by the CmpRegion class.
+
+* Parameters:
+* vtab
+* Pointer to the virtual function table. The components used by
+* all ancestral classes will be initialised if they have not already
+* been initialised.
+* name
+* Pointer to a constant null-terminated character string which contains
+* the name of the class to which the virtual function table belongs (it
+* is this pointer value that will subsequently be returned by the Object
+* astClass function).
+*-
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */
+ AstObjectVtab *object; /* Pointer to Object component of Vtab */
+ AstRegionVtab *region; /* Pointer to Region component of Vtab */
+
+/* Check the local error status. */
+ if ( !astOK ) return;
+
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Initialize the component of the virtual function table used by the
+ parent class. */
+ astInitRegionVtab( (AstRegionVtab *) vtab, name );
+
+/* Store a unique "magic" value in the virtual function table. This
+ will be used (by astIsACmpRegion) to determine if an object belongs to
+ this class. We can conveniently use the address of the (static)
+ class_check variable to generate this unique value. */
+ vtab->id.check = &class_check;
+ vtab->id.parent = &(((AstRegionVtab *) vtab)->id);
+
+/* Initialise member function pointers. */
+/* ------------------------------------ */
+/* Store pointers to the member functions (implemented here) that
+ provide virtual methods for this class. */
+
+ vtab->CmpRegionList = CmpRegionList;
+
+/* Save the inherited pointers to methods that will be extended, and
+ replace them with pointers to the new member functions. */
+ object = (AstObjectVtab *) vtab;
+ mapping = (AstMappingVtab *) vtab;
+ region = (AstRegionVtab *) vtab;
+
+ parent_transform = mapping->Transform;
+ mapping->Transform = Transform;
+
+ parent_simplify = mapping->Simplify;
+ mapping->Simplify = Simplify;
+
+ parent_getdefunc = region->GetDefUnc;
+ region->GetDefUnc = GetDefUnc;
+
+ parent_setregfs = region->SetRegFS;
+ region->SetRegFS = SetRegFS;
+
+ parent_resetcache = region->ResetCache;
+ region->ResetCache = ResetCache;
+
+ parent_equal = object->Equal;
+ object->Equal = Equal;
+
+ parent_getobjsize = object->GetObjSize;
+ object->GetObjSize = GetObjSize;
+
+#if defined(THREAD_SAFE)
+ parent_managelock = object->ManageLock;
+ object->ManageLock = ManageLock;
+#endif
+
+ parent_clearclosed = region->ClearClosed;
+ region->ClearClosed = ClearClosed;
+
+ parent_clearmeshsize = region->ClearMeshSize;
+ region->ClearMeshSize = ClearMeshSize;
+
+ parent_setclosed = region->SetClosed;
+ region->SetClosed = SetClosed;
+
+ parent_setmeshsize = region->SetMeshSize;
+ region->SetMeshSize = SetMeshSize;
+
+ parent_getfillfactor = region->GetFillFactor;
+ region->GetFillFactor = GetFillFactor;
+
+ parent_regsetattrib = region->RegSetAttrib;
+ region->RegSetAttrib = RegSetAttrib;
+
+ parent_regclearattrib = region->RegClearAttrib;
+ region->RegClearAttrib = RegClearAttrib;
+
+/* Store replacement pointers for methods which will be over-ridden by
+ new member functions implemented here. */
+ mapping->Decompose = Decompose;
+ region->RegBaseBox = RegBaseBox;
+ region->RegBaseBox2 = RegBaseBox2;
+ region->RegBaseMesh = RegBaseMesh;
+ region->RegSplit = RegSplit;
+ region->RegPins = RegPins;
+ region->RegTrace = RegTrace;
+ region->GetBounded = GetBounded;
+ region->RegBasePick = RegBasePick;
+
+/* Declare the copy constructor, destructor and class dump function. */
+ astSetCopy( vtab, Copy );
+ astSetDelete( vtab, Delete );
+ astSetDump( vtab, Dump, "CmpRegion", "Combination of two Regions" );
+
+/* If we have just initialised the vtab for the current class, indicate
+ that the vtab is now initialised, and store a pointer to the class
+ identifier in the base "object" level of the vtab. */
+ if( vtab == &class_vtab ) {
+ class_init = 1;
+ astSetVtabClassIdentifier( vtab, &(vtab->id) );
+ }
+}
+
+#if defined(THREAD_SAFE)
+static int ManageLock( AstObject *this_object, int mode, int extra,
+ AstObject **fail, int *status ) {
+/*
+* Name:
+* ManageLock
+
+* Purpose:
+* Manage the thread lock on an Object.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "object.h"
+* AstObject *ManageLock( AstObject *this, int mode, int extra,
+* AstObject **fail, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astManageLock protected
+* method inherited from the parent class).
+
+* Description:
+* This function manages the thread lock on the supplied Object. The
+* lock can be locked, unlocked or checked by this function as
+* deteremined by parameter "mode". See astLock for details of the way
+* these locks are used.
+
+* Parameters:
+* this
+* Pointer to the Object.
+* mode
+* An integer flag indicating what the function should do:
+*
+* AST__LOCK: Lock the Object for exclusive use by the calling
+* thread. The "extra" value indicates what should be done if the
+* Object is already locked (wait or report an error - see astLock).
+*
+* AST__UNLOCK: Unlock the Object for use by other threads.
+*
+* AST__CHECKLOCK: Check that the object is locked for use by the
+* calling thread (report an error if not).
+* extra
+* Extra mode-specific information.
+* fail
+* If a non-zero function value is returned, a pointer to the
+* Object that caused the failure is returned at "*fail". This may
+* be "this" or it may be an Object contained within "this". Note,
+* the Object's reference count is not incremented, and so the
+* returned pointer should not be annulled. A NULL pointer is
+* returned if this function returns a value of zero.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A local status value:
+* 0 - Success
+* 1 - Could not lock or unlock the object because it was already
+* locked by another thread.
+* 2 - Failed to lock a POSIX mutex
+* 3 - Failed to unlock a POSIX mutex
+* 4 - Bad "mode" value supplied.
+
+* Notes:
+* - This function attempts to execute even if an error has already
+* occurred.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion structure */
+ int result; /* Returned status value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the supplied pointer is not NULL. */
+ if( !this_object ) return result;
+
+/* Obtain a pointers to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_object;
+
+/* Invoke the ManageLock method inherited from the parent class. */
+ if( !result ) result = (*parent_managelock)( this_object, mode, extra,
+ fail, status );
+
+/* Invoke the astManageLock method on any Objects contained within
+ the supplied Object. */
+ if( !result ) result = astManageLock( this->region1, mode, extra, fail );
+ if( !result ) result = astManageLock( this->region2, mode, extra, fail );
+
+ return result;
+
+}
+#endif
+
+static AstRegion *MatchRegion( AstRegion *this, int ifrm, AstRegion *that,
+ const char *method, int *status ) {
+/*
+* Name:
+* MatchRegion
+
+* Purpose:
+* Map a Region into the Frame of another Region.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* AstRegion *MatchRegion( AstRegion *this, int ifrm, AstRegion *that,
+* const char *method, int *status )
+
+* Class Membership:
+* CmpRegion method.
+
+* Description:
+* This function returns a pointer to a new Region which is a copy of
+* "that" mapped into either the base or current Frame of "this".
+
+* Parameters:
+* this
+* Pointer to a Region defining the Frame of the returned Region.
+* ifrm
+* The index of a Frame within the FrameSet encapsulated by "this".
+* The returned Region will refer to the requested Frame. It should
+* be either AST__CURRENT or AST__BASE.
+* that
+* Pointer to a Region defining the shape and extent of the
+* returned Region.
+* method
+* Pointer to a string holding the calling method.This is only used
+* in error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to a new Region. This should be annulled (using astAnnul)
+* when no longer needed.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *frm; /* Current Frame from "fs" */
+ AstFrameSet *fs; /* FrameSet connecting that to this */
+ AstMapping *map; /* Base->Current Mapping from "fs" */
+ AstRegion *result; /* Returned pointer */
+
+/* Initialise */
+ result = NULL;
+
+/* Check the global error status. Also return NULL if no Regions were
+ supplied. */
+ if ( !astOK || !this || !that ) return result;
+
+/* Temporarily invert "this" if we are matching its base Frame (since the
+ astConvert method matches current Frames). */
+ if( ifrm == AST__BASE ) astInvert( this );
+
+/* Find a FrameSet connecting the current Frames of the two Regions */
+ fs = astConvert( that, this, "" );
+
+/* Re-instate the original Frame indices in "this" if required. */
+ if( ifrm == AST__BASE ) astInvert( this );
+
+/* Check a conversion path was found. */
+ if( fs ) {
+
+/* Get the Frame and Mapping form the FrameSet. */
+ frm = astGetFrame( fs, AST__CURRENT );
+ map = astGetMapping( fs, AST__BASE, AST__CURRENT );
+
+/* Re-map the Region. */
+ result = astMapRegion( that, map, frm );
+
+/* Free resources. */
+ frm = astAnnul( frm );
+ map = astAnnul( map );
+ fs = astAnnul( fs );
+
+/* Report an error if there is no conversion between the two Frames. */
+ } else {
+ astError( AST__INTER, "%s(%s): MatchRegion cannot convert between "
+ "the two supplied coordinate Frames (internal AST "
+ "programming error).", status, method, astGetClass( this ) );
+ }
+
+/* Annul the returned pointer if an error has occurred. */
+ if( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static void RegBaseBox( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){
+/*
+* Name:
+* RegBaseBox
+
+* Purpose:
+* Returns the bounding box of an un-negated Region in the base Frame of
+* the encapsulated FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astRegBaseBox protected
+* method inherited from the Region class).
+
+* Description:
+* This function returns the upper and lower axis bounds of a Region in
+* the base Frame of the encapsulated FrameSet, assuming the Region
+* has not been negated. That is, the value of the Negated attribute
+* is ignored.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* lbnd
+* Pointer to an array in which to return the lower axis bounds
+* covered by the Region in the base Frame of the encapsulated
+* FrameSet. It should have at least as many elements as there are
+* axes in the base Frame.
+* ubnd
+* Pointer to an array in which to return the upper axis bounds
+* covered by the Region in the base Frame of the encapsulated
+* FrameSet. It should have at least as many elements as there are
+* axes in the base Frame.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion structure */
+ AstPointSet *ps; /* Mesh pointset */
+ AstRegion *reg1; /* Pointer to first component Region */
+ AstRegion *reg2; /* Pointer to second component Region */
+ double **ptr; /* Pointer to mesh data */
+ double *clbnd1; /* Point to 1st comp lower bounds array */
+ double *clbnd2; /* Point to 2nd comp lower bounds array */
+ double *cubnd1; /* Point to 1st comp upper bounds array */
+ double *cubnd2; /* Point to 2nd comp upper bounds array */
+ double *p; /* Pointer to next coordinate value */
+ double lb; /* Lower limit */
+ double ub; /* Upper limit */
+ int i; /* Axis index */
+ int icoord; /* Coordinate index */
+ int inc1; /* First component interval is included? */
+ int inc2; /* Second component interval is included? */
+ int ipoint; /* Point index */
+ int nax; /* Number of axes in Frame */
+ int ncoord; /* Number of coords */
+ int neg1; /* First component negated? */
+ int neg2; /* Second component negated? */
+ int npoint; /* Number of points */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the CmpRegion structure */
+ this = (AstCmpRegion *) this_region;
+
+/* If the CmpRegion is bounded, we find the bounding box using a mesh of
+ points spread evenly over the boundary of the CmpRegion. */
+ if( astGetBounded( this ) ) {
+ ps = astRegBaseMesh( this_region );
+ ptr = astGetPoints( ps );
+ ncoord = astGetNcoord( ps );
+ npoint = astGetNpoint( ps );
+
+ if( astOK ) {
+ for( icoord = 0; icoord < ncoord; icoord++ ) {
+ lbnd[ icoord ] = DBL_MAX;
+ ubnd[ icoord ] = -DBL_MAX;
+ p = ptr[ icoord ];
+ for( ipoint = 0; ipoint < npoint; ipoint++, p++ ) {
+ if( *p != AST__BAD ) {
+ if( *p < lbnd[ icoord ] ) lbnd[ icoord ] = *p;
+ if( *p > ubnd[ icoord ] ) ubnd[ icoord ] = *p;
+ }
+ }
+ }
+ }
+ ps = astAnnul( ps );
+
+/* If the CmpRegion is not bounded we look at each axis individually. */
+ } else {
+
+/* Get pointers to the component Regions. */
+ reg1 = this->region1;
+ reg2 = this->region2;
+
+/* Get their negated flags */
+ neg1 = astGetNegated( reg1 );
+ neg2 = astGetNegated( reg2 );
+
+/* The base Frame of the parent Region structure is the current Frame of
+ the component Regions. Get the no. of axes in this Frame. */
+ nax = astGetNaxes( reg1 );
+
+/* Get the bounding boxes of the component Regions in this Frame. */
+ clbnd1 = astMalloc( sizeof( double )*(size_t) nax );
+ cubnd1 = astMalloc( sizeof( double )*(size_t) nax );
+ clbnd2 = astMalloc( sizeof( double )*(size_t) nax );
+ cubnd2 = astMalloc( sizeof( double )*(size_t) nax );
+ if( astOK ) {
+ astGetRegionBounds( reg1, clbnd1, cubnd1 );
+ astGetRegionBounds( reg2, clbnd2, cubnd2 );
+
+/* Loop round every axis. */
+ for( i = 0; i < nax; i++ ) {
+
+/* If the first component Region has been negated, the lower and upper
+ bounds from the first component are the bounds of an *excluded* axis
+ interval, not an included interval. If either of the bounds are
+ infinite, we can swap it to an included interval. If both bounds are
+ finite, we cannot convert to an included interval. In this case, we
+ assume that the gap will be filled at some point on another axis, if
+ there is more than 1 axis, and convert it to an unbouded included
+ interval. */
+ inc1 = 1;
+ if( neg1 ) {
+ lb = clbnd1[ i ];
+ ub = cubnd1[ i ];
+ if( lb == -DBL_MAX ) clbnd1[ i ] = ub;
+ if( ub == DBL_MAX ) cubnd1[ i ] = lb;
+ if( lb != -DBL_MAX && ub != DBL_MAX ) {
+ if( nax == 1 ) {
+ inc1 = 0;
+ } else {
+ clbnd1[ i ] = -DBL_MAX;
+ cubnd1[ i ] = DBL_MAX;
+ }
+ }
+ }
+
+/* Likewise attempt to convert an excluded interval into an included
+ interval for the second component Region. */
+ inc2 = 1;
+ if( neg2 ) {
+ lb = clbnd2[ i ];
+ ub = cubnd2[ i ];
+ if( lb == -DBL_MAX ) clbnd2[ i ] = ub;
+ if( ub == DBL_MAX ) cubnd2[ i ] = lb;
+ if( lb != -DBL_MAX && ub != DBL_MAX ) {
+ if( nax == 1 ) {
+ inc2 = 0;
+ } else {
+ clbnd2[ i ] = -DBL_MAX;
+ cubnd2[ i ] = DBL_MAX;
+ }
+ }
+ }
+
+/* If the component Regions are combined using AND, find the overlap of
+ the axis intervals. This depends on whether the intervals are included
+ or excluded. */
+ if( this->oper == AST__AND ) {
+
+ if( inc1 ) {
+ if( inc2 ) {
+ lbnd[ i ] = astMAX( clbnd1[ i ], clbnd2[ i ] );
+ ubnd[ i ] = astMIN( cubnd1[ i ], cubnd2[ i ] );
+ } else {
+ lbnd[ i ] = clbnd1[ i ] < clbnd2[ i ] ? clbnd1[ i ] : cubnd2[ i ];
+ ubnd[ i ] = cubnd1[ i ] > cubnd2[ i ] ? cubnd1[ i ] : clbnd2[ i ];
+ }
+ } else {
+ if( inc2 ) {
+ lbnd[ i ] = clbnd2[ i ] < clbnd1[ i ] ? clbnd2[ i ] : cubnd1[ i ];
+ ubnd[ i ] = cubnd2[ i ] > cubnd1[ i ] ? cubnd2[ i ] : clbnd1[ i ];
+ } else {
+ lbnd[ i ] = clbnd1[ i ] < clbnd2[ i ] ? clbnd1[ i ] : cubnd2[ i ];
+ ubnd[ i ] = cubnd1[ i ] > cubnd2[ i ] ? cubnd1[ i ] : clbnd2[ i ];
+ }
+ }
+
+/* If the component Regions are not combined using AND, find the union of
+ the axis intervals. */
+ } else {
+ if( inc1 && inc2 ) {
+ lbnd[ i ] = astMIN( clbnd1[ i ], clbnd2[ i ] );
+ ubnd[ i ] = astMAX( cubnd1[ i ], cubnd2[ i ] );
+ } else {
+ lbnd[ i ] = -DBL_MAX;
+ ubnd[ i ] = DBL_MAX;
+ }
+ }
+ }
+ }
+
+/* Free resources. */
+ clbnd1 = astFree( clbnd1 );
+ cubnd1 = astFree( cubnd1 );
+ clbnd2 = astFree( clbnd2 );
+ cubnd2 = astFree( cubnd2 );
+ }
+}
+
+static void RegBaseBox2( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){
+/*
+* Name:
+* RegBaseBox2
+
+* Purpose:
+* Returns the bounding box of an un-negated Region in the base Frame of
+* the encapsulated FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void RegBaseBox2( AstRegion *this, double *lbnd, double *ubnd, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astRegBaseBox2 protected
+* method inherited from the Region class).
+
+* Description:
+* This function is similar to astRegBaseBox in that it returns the
+* upper and lower axis bounds of a Region in the base Frame of the
+* encapsulated FrameSet. But, in addition to assuming that the
+* supplied Region has not been negated, it also assumes that any
+* component Regions contained within the supplied Region have not been
+* negated.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* lbnd
+* Pointer to an array in which to return the lower axis bounds
+* covered by the Region in the base Frame of the encapsulated
+* FrameSet. It should have at least as many elements as there are
+* axes in the base Frame.
+* ubnd
+* Pointer to an array in which to return the upper axis bounds
+* covered by the Region in the base Frame of the encapsulated
+* FrameSet. It should have at least as many elements as there are
+* axes in the base Frame.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion structure */
+ AstRegion *reg1; /* Pointer to first component Region */
+ AstRegion *reg2; /* Pointer to second component Region */
+ double *clbnd1; /* Point to 1st comp lower bounds array */
+ double *clbnd2; /* Point to 2nd comp lower bounds array */
+ double *cubnd1; /* Point to 1st comp upper bounds array */
+ double *cubnd2; /* Point to 2nd comp upper bounds array */
+ int i; /* Axis index */
+ int nax; /* Number of axes in Frame */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the CmpRegion structure */
+ this = (AstCmpRegion *) this_region;
+
+/* Get pointers to the component Regions. */
+ reg1 = this->region1;
+ reg2 = this->region2;
+
+/* The base Frame of the parent Region structure is the current Frame of
+ the component Regions. Get the no. of axes in this Frame. */
+ nax = astGetNaxes( reg1 );
+
+/* Get the bounding boxes of the component Regions in this Frame. */
+ clbnd1 = astMalloc( sizeof( double )*(size_t) nax );
+ cubnd1 = astMalloc( sizeof( double )*(size_t) nax );
+ clbnd2 = astMalloc( sizeof( double )*(size_t) nax );
+ cubnd2 = astMalloc( sizeof( double )*(size_t) nax );
+ if( astOK ) {
+ astGetRegionBounds2( reg1, clbnd1, cubnd1 );
+ astGetRegionBounds2( reg2, clbnd2, cubnd2 );
+
+/* How we combine the two bounding boxes depends on the boolean operator
+ associated with this CmpRegion. For AND find the overlap of the two
+ bounding boxes. For other operators find the union. */
+ if( this->oper == AST__AND ) {
+ for( i = 0; i < nax; i++ ) {
+ lbnd[ i ]= astMAX( clbnd1[ i ], clbnd2[ i ] );
+ ubnd[ i ]= astMIN( cubnd1[ i ], cubnd2[ i ] );
+ }
+
+ } else {
+ for( i = 0; i < nax; i++ ) {
+ lbnd[ i ]= astMIN( clbnd1[ i ], clbnd2[ i ] );
+ ubnd[ i ]= astMAX( cubnd1[ i ], cubnd2[ i ] );
+ }
+ }
+ }
+
+/* Free resources. */
+ clbnd1 = astFree( clbnd1 );
+ cubnd1 = astFree( cubnd1 );
+ clbnd2 = astFree( clbnd2 );
+ cubnd2 = astFree( cubnd2 );
+
+}
+
+static AstPointSet *RegBaseMesh( AstRegion *this_region, int *status ){
+/*
+* Name:
+* RegBaseMesh
+
+* Purpose:
+* Return a PointSet containing a mesh of points on the boundary of a
+* Region in its base Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* AstPointSet *astRegBaseMesh( AstRegion *this, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astRegBaseMesh protected
+* method inherited from the Region class).
+
+* Description:
+* This function returns a PointSet containing a mesh of points on the
+* boundary of the Region. The points refer to the base Frame of
+* the encapsulated FrameSet.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the PointSet. Annul the pointer using astAnnul when it
+* is no longer needed.
+
+* Notes:
+* - A NULL pointer is returned if an error has already occurred, or if
+* this function should fail for any reason.
+
+*/
+
+
+/* Local Variables: */
+ AstCmpRegion *this; /* The CmpRegion structure */
+ AstPointSet *mesh1; /* PointSet holding mesh for 1st component */
+ AstPointSet *mesh1b; /* Mesh for 1st component mapped by 2nd comp. */
+ AstPointSet *mesh2; /* PointSet holding mesh for 2nd component */
+ AstPointSet *mesh2b; /* Mesh for 2nd component mapped by 1st comp. */
+ AstPointSet *result; /* Returned pointer */
+ AstRegion *reg1; /* Pointer to first component Region */
+ AstRegion *reg2; /* Pointer to second component Region */
+ double **ptr1; /* Pointer to array of mesh1b axis value pointers */
+ double **ptr2; /* Pointer to array of mesh2b axis value pointers */
+ double **ptr; /* Pointer to array of total axis value pointers */
+ double *lbnd; /* Pointer to array of bounding box lower bounds */
+ double *ubnd; /* Pointer to array of bounding box upper bounds */
+ double v; /* Axis value */
+ int hasMesh1; /* Does 1st component Region have a mesh? */
+ int hasMesh2; /* Does 2nd component Region have a mesh? */
+ int ic; /* Axis index */
+ int ip; /* Input point index */
+ int jp; /* Output point index */
+ int nc; /* No. of axis values per point */
+ int np1; /* No. of points in mesh1b */
+ int np2; /* No. of points in mesh2b */
+ int np; /* No. of points in returned PointSet */
+ int ok; /* Were all axis values good at this point? */
+
+/* Initialise */
+ result= NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* If the Region structure contains a pointer to a PointSet holding
+ a previously created mesh, return it. */
+ if( this_region->basemesh ) {
+ result = astClone( this_region->basemesh );
+
+/* Otherwise, create a new mesh. */
+ } else {
+
+/* Get pointers to the component regions. */
+ reg1 = this->region1;
+ reg2 = this->region2;
+
+/* A mesh can only be produced for a Region if it is bounded when either
+ negated or un-negated. See if meshes can be produced for the component
+ Regions. */
+ hasMesh1 = astGetBounded( reg1 );
+ if( !hasMesh1 ){
+ astNegate( reg1 );
+ hasMesh1 = astGetBounded( reg1 );
+ astNegate( reg1 );
+ }
+
+ hasMesh2 = astGetBounded( reg2 );
+ if( !hasMesh2 ){
+ astNegate( reg2 );
+ hasMesh2 = astGetBounded( reg2 );
+ astNegate( reg2 );
+ }
+
+/* If neither Region has a mesh we cannot produce a mesh. */
+ if( !hasMesh1 && !hasMesh2 && astOK ) {
+ astError( AST__INTER, "astRegBaseMesh(%s): No mesh can be "
+ "produced for the %s bacause neither of its component "
+ "Regions has a mesh (internal AST programming error).", status,
+ astGetClass( this ), astGetClass( this ) );
+
+/* If only one Region has a mesh, we can produce a mesh so long as the
+ boolean operator is not OR. */
+ } else if( ( !hasMesh1 || !hasMesh2 ) && this->oper == AST__OR && astOK ) {
+ astError( AST__INTER, "astRegBaseMesh(%s): No mesh can be produced "
+ "for the %s bacause one its component Regions has no "
+ "mesh and the union of the Regions is required (internal "
+ "AST programming error).", status, astGetClass( this ), astGetClass( this ) );
+ }
+
+/* Allocate memory to hold a bounding box in the base Frame of the CmpRegion. */
+ nc = astGetNin( this_region->frameset );
+ lbnd = astMalloc( sizeof( double )*(size_t) nc );
+ ubnd = astMalloc( sizeof( double )*(size_t) nc );
+
+/* Get current Frame meshes covering the two component Regions (the current
+ Frame of the component Regions is the same as the base Frame of the parent
+ Region). We now know that at least one Region has a mesh. If the other
+ one does not have a mesh we may be able to create a mesh by taking the
+ intersection of the Region with the bounding box of the bounded Region. */
+ if( hasMesh1 ) {
+ mesh1 = astRegMesh( reg1 );
+ if( hasMesh2 ) {
+ mesh2 = astRegMesh( reg2 );
+ } else {
+ astGetRegionBounds( reg1, lbnd, ubnd );
+ mesh2 = astBndMesh( reg2, lbnd, ubnd );
+ }
+
+ } else {
+ mesh2 = astRegMesh( reg2 );
+ astGetRegionBounds( reg2, lbnd, ubnd );
+ mesh1 = astBndMesh( reg1, lbnd, ubnd );
+ }
+
+/* If the CmpRegion represents the intersection of the two component Regions
+ (AND operator), the total mesh is the sum of the component mesh points
+ which are inside the other component region. If the CmpRegion represents
+ the union of the two component Regions (OR operator), the total mesh is
+ the sum of the component mesh points which are outside the other component
+ region. So temporarily negate the component Regions if they are
+ combined using OR. */
+ if( this->oper == AST__OR ) {
+ astNegate( reg1 );
+ astNegate( reg2 );
+ }
+
+/* Transform the mesh for the first component using the second component
+ as a Mapping. Mesh points outside (or inside if "oper" is OR) the bounds
+ of the second component will be set bad. */
+ mesh1b = astTransform( reg2, mesh1, 1, NULL );
+
+/* Transform the mesh for the second component using the first component
+ as a Mapping. Mesh points outside (or inside if "oper" is OR) the bounds
+ of the first component will be set bad. */
+ mesh2b = astTransform( reg1, mesh2, 1, NULL );
+
+/* If required, negate them again to bring them back to their original state.*/
+ if( this->oper == AST__OR ) {
+ astNegate( reg1 );
+ astNegate( reg2 );
+ }
+
+/* The required mesh contains all the good points form both mesh1b and
+ mesh2b (i.e. all boundary points which are inside -or inside if "oper"
+ is OR- the other component Region). Create a PointSet assuming that all
+ points are good. First allocate an array to hold pointers to the arrays
+ holding coordinate values for each axis. */
+ nc = astGetNcoord( mesh1b );
+ np1 = astGetNpoint( mesh1b );
+ np2 = astGetNpoint( mesh2b );
+ np = np1 + np2;
+ result = astPointSet( np, nc, "", status );
+ ptr = astGetPoints( result );
+
+/* Get points to the axis values of the mapped meshes. */
+ ptr1 = astGetPoints( mesh1b );
+ ptr2 = astGetPoints( mesh2b );
+
+/* Check pointers can be used safely. */
+ if( astOK ) {
+
+/* Initialise the index of the next point in the total mesh. */
+ jp = 0;
+
+/* Loop round all the points in the transformed mesh for the first
+ component. */
+ for( ip = 0; ip < np1; ip++ ) {
+
+/* Assume this point has good axis values */
+ ok = 1;
+
+/* Copy the axis values into the total mesh. Break if a bad axis value is
+ found. */
+ for( ic = 0; ic < nc; ic++ ) {
+ v = ptr1[ ic ][ ip ];
+ if( v != AST__BAD ) {
+ ptr[ ic ][ jp ] = v;
+ } else {
+ ok = 0;
+ break;
+ }
+ }
+
+/* If no bad axis values were found, increment the index of the next
+ point in the total mesh. */
+ if( ok ) jp++;
+ }
+
+/* Now similarly copy the good values from the second transformed mesh onto
+ the end of the total mesh array. */
+ for( ip = 0; ip < np2; ip++ ) {
+ ok = 1;
+ for( ic = 0; ic < nc; ic++ ) {
+ v = ptr2[ ic ][ ip ];
+ if( v != AST__BAD ) {
+ ptr[ ic ][ jp ] = v;
+ } else {
+ ok = 0;
+ break;
+ }
+ }
+ if( ok ) jp++;
+ }
+
+/* If the total mesh contains no good points, we will create a PointSet
+ holding a single bad position. */
+ if( jp == 0 ) {
+ np = 1;
+ for( ic = 0; ic < nc; ic++ ) ptr[ ic ][ 0 ] = AST__BAD;
+ } else {
+ np = jp;
+ }
+
+/* Adjust the size of the returned PointSet to exclude the extra space
+ caused by any axis values being bad in the transformed meshes. */
+ astSetNpoint( result, np );
+
+ }
+
+/* Free resources. */
+ mesh1 = astAnnul( mesh1 );
+ mesh2 = astAnnul( mesh2 );
+ mesh1b = astAnnul( mesh1b );
+ mesh2b = astAnnul( mesh2b );
+ lbnd = astFree( lbnd );
+ ubnd = astFree( ubnd );
+
+/* Save the returned pointer in the Region structure so that it does not
+ need to be created again next time this function is called. */
+ if( astOK && result ) this_region->basemesh = astClone( result );
+ }
+
+/* Annul the result if an error has occurred. */
+ if( !astOK ) result = astAnnul( result );
+
+/* Return a pointer to the output PointSet. */
+ return result;
+}
+
+static AstRegion *RegBasePick( AstRegion *this_region, int naxes,
+ const int *axes, int *status ){
+/*
+* Name:
+* RegBasePick
+
+* Purpose:
+* Return a Region formed by picking selected base Frame axes from the
+* supplied Region.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* AstRegion *RegBasePick( AstRegion *this, int naxes, const int *axes,
+* int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astRegBasePick protected
+* method inherited from the Region class).
+
+* Description:
+* This function attempts to return a Region that is spanned by selected
+* axes from the base Frame of the encapsulated FrameSet of the supplied
+* Region. This may or may not be possible, depending on the class of
+* Region. If it is not possible a NULL pointer is returned.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* naxes
+* The number of base Frame axes to select.
+* axes
+* An array holding the zero-based indices of the base Frame axes
+* that are to be selected.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the Region, or NULL if no region can be formed.
+
+* Notes:
+* - A NULL pointer is returned if an error has already occurred, or if
+* this function should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion structure */
+ AstFrame *frm1; /* Axes picked from the 1st encapsulated Region */
+ AstFrame *frm2; /* Axes picked from the 2nd encapsulated Region */
+ AstRegion *result; /* Returned Region */
+
+/* Initialise */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the CmpRegion information. */
+ this = (AstCmpRegion *) this_region;
+
+/* Both encapsulated regions refer to the same Frame (the base Frame of
+ the parent Region), so attempt to pick the requested axs from them.
+ If the resulting Frames are not Regions, we cannot pick the requested
+ axes so return the NULL Frame pointer initialised above. */
+ frm1 = astPickAxes( this->region1, naxes, axes, NULL );
+ if( astIsARegion( frm1 ) ) {
+ frm2 = astPickAxes( this->region2, naxes, axes, NULL );
+ if( astIsARegion( frm2 ) ) {
+
+/* Create the new CmpRegion. */
+ result = (AstRegion *) astCmpRegion( (AstRegion *) frm1,
+ (AstRegion *) frm2,
+ this->oper, "", status );
+ }
+
+/* Free resources */
+ frm2 = astAnnul( frm2 );
+ }
+ frm1 = astAnnul( frm1 );
+
+/* Return a NULL pointer if an error has occurred. */
+ if( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
+ int **mask, int *status ){
+/*
+* Name:
+* RegPins
+
+* Purpose:
+* Check if a set of points fall on the boundary of a given CmpRegion.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* int RegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc,
+* int **mask, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astRegPins protected
+* method inherited from the Region class).
+
+* Description:
+* This function returns a flag indicating if the supplied set of
+* points all fall on the boundary of the given CmpRegion.
+*
+* Some tolerance is allowed, as specified by the uncertainty Region
+* stored in the supplied CmpRegion "this", and the supplied uncertainty
+* Region "unc" which describes the uncertainty of the supplied points.
+
+* Parameters:
+* this
+* Pointer to the CmpRegion.
+* pset
+* Pointer to the PointSet. The points are assumed to refer to the
+* base Frame of the FrameSet encapsulated by "this".
+* unc
+* Pointer to a Region representing the uncertainties in the points
+* given by "pset". The Region is assumed to represent the base Frame
+* of the FrameSet encapsulated by "this". Zero uncertainity is assumed
+* if NULL is supplied.
+* mask
+* Pointer to location at which to return a pointer to a newly
+* allocated dynamic array of ints. The number of elements in this
+* array is equal to the value of the Npoint attribute of "pset".
+* Each element in the returned array is set to 1 if the
+* corresponding position in "pset" is on the boundary of the Region
+* and is set to zero otherwise. A NULL value may be supplied
+* in which case no array is created. If created, the array should
+* be freed using astFree when no longer needed.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Non-zero if the points all fall on the boundary of the given
+* Region, to within the tolerance specified. Zero otherwise.
+
+*/
+
+/* Local variables: */
+ AstCmpRegion *this; /* Pointer to the CmpRegion structure. */
+ AstPointSet *pset1; /* Points masked by 1st component Region */
+ AstPointSet *pset2; /* Points masked by 2nd component Region */
+ AstPointSet *psetb1; /* Points in base Frame of 1st component Region */
+ AstPointSet *psetb2; /* Points in base Frame of 2nd component Region */
+ AstRegion *reg1; /* Pointer to first component Region */
+ AstRegion *reg2; /* Pointer to second component Region */
+ AstRegion *unc1; /* Base Frame uncertainty in 1st component Region */
+ AstRegion *unc2; /* Base Frame uncertainty in 2nd component Region */
+ double **ptr1; /* Pointer to axis values in "pset1" */
+ double **ptr2; /* Pointer to axis values in "pset2" */
+ double *p1; /* Pointer to next axis zero value for pset1 */
+ double *p2; /* Pointer to next axis zero value for pset2 */
+ int *mask1; /* Mask for first component boundary */
+ int *mask2; /* Mask for second component boundary */
+ int ip; /* Point index */
+ int np; /* Number of points */
+ int result; /* Returned flag */
+
+/* Initialise */
+ result = 0;
+ if( mask ) *mask = NULL;
+
+/* Check the inherited status. */
+ if( !astOK ) return result;
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* Get pointers to the two component Regions. */
+ reg1 = this->region1;
+ reg2 = this->region2;
+
+/* Get a mask which indicates if each supplied point is on or off the
+ boundary of the first component Region. astRegPins expects its "pset"
+ argument to contain positions in the base Frame of the Region, so
+ we must first transform the supplied points into the base Frame of
+ "reg1". We must also map the uncertainty into the base Frame of the
+ component Region. */
+ psetb1 = astRegTransform( reg1, pset, 0, NULL, NULL );
+ unc1 = MatchRegion( reg1, AST__BASE, unc, "astRegPins", status );
+ astRegPins( reg1, psetb1, unc1, &mask1 );
+
+/* Likewise, get a mask which indicates if each supplied point is on or off
+ the boundary of the second component Region. */
+ psetb2 = astRegTransform( reg2, pset, 0, NULL, NULL );
+ unc2 = MatchRegion( reg2, AST__BASE, unc, "astRegPins", status );
+ astRegPins( reg2, psetb2, unc2, &mask2 );
+
+/* The criteria for a point to be on the boundary of the CmpRegion depend
+ on the boolean operator being used. If component regions A and B are
+ ANDed together, then a point is on the boundary of the CmpRegion if
+ either 1) it is on the boundary of A and inside B, or 2) it is on the
+ boundary of B and inside A. If the component regions are ORed together,
+ then a point is on the boundary of the CmpRegion if either 1) it is on
+ the boundary of A and outside B, or 2) it is on the boundary of B and
+ outside A. Either we need to transform the supplied PointSet using each
+ component Region as a Mapping. But if using OR we temporarily negate
+ the Regions. */
+ if( this->oper == AST__OR ) {
+ astNegate( reg1 );
+ astNegate( reg2 );
+ }
+ pset1 = astTransform( reg1, pset, 1, NULL );
+ pset2 = astTransform( reg2, pset, 1, NULL );
+ if( this->oper == AST__OR ) {
+ astNegate( reg1 );
+ astNegate( reg2 );
+ }
+
+/* Get pointers to the axis values in these PointSets */
+ ptr1 = astGetPoints( pset1 );
+ ptr2 = astGetPoints( pset2 );
+
+/* If required, create an output mask array */
+ np = astGetNpoint( pset );
+ if( mask ) *mask = astMalloc( sizeof(int)*(size_t) np );
+
+/* Check pointers can be used safely. */
+ if( astOK ) {
+
+/* We can use the values for the first axis to indicate if a point is
+ inside or outside a Region. So store pointers to the first axis arrays. */
+ p1 = ptr1[ 0 ];
+ p2 = ptr2[ 0 ];
+
+/* Assume all points are on the boundary of the CmpRegion. */
+ result = 1;
+
+/* If we are creating an output mask, we must check every point. Otherwise
+ we can stop checking when we find the first point which is not on the
+ boundary of the CmpRegion. */
+ if( mask ) {
+
+ for( ip = 0; ip < np; ip++ ) {
+ if( ( mask1[ ip ] && p2[ ip ] != AST__BAD ) ||
+ ( mask2[ ip ] && p1[ ip ] != AST__BAD ) ){
+ (*mask)[ ip ] = 1;
+ } else {
+ (*mask)[ ip ] = 0;
+ result = 0;
+ }
+ }
+
+ } else {
+
+ for( ip = 0; ip < np; ip++ ) {
+ if( ( !mask1[ ip ] || p2[ ip ] == AST__BAD ) &&
+ ( !mask2[ ip ] || p1[ ip ] == AST__BAD ) ){
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+
+/* Free resources */
+ mask1 = astFree( mask1 );
+ mask2 = astFree( mask2 );
+ pset1 = astAnnul( pset1 );
+ pset2 = astAnnul( pset2 );
+ psetb1 = astAnnul( psetb1 );
+ psetb2 = astAnnul( psetb2 );
+ if( unc1 ) unc1 = astAnnul( unc1 );
+ if( unc2 ) unc2 = astAnnul( unc2 );
+
+/* If an error has occurred, return zero. */
+ if( !astOK ) {
+ result = 0;
+ if( mask ) *mask = astFree( *mask );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static void RegSetAttrib( AstRegion *this_region, const char *setting,
+ char **base_setting, int *status ) {
+/*
+* Name:
+* RegSetAttrib
+
+* Purpose:
+* Set an attribute value for a Region.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void RegSetAttrib( AstRegion *this, const char *setting,
+* char **base_setting, int *status )
+
+* Class Membership:
+* CmpRegion method (over-rides the astRegSetAttrib method inherited from
+* the Region class).
+
+* Description:
+* This function assigns an attribute value to both the base and
+* current Frame in the FrameSet encapsulated within a Region, without
+* remapping either Frame.
+*
+* No error is reported if the attribute is not recognised by the base
+* Frame.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* setting
+* Pointer to a null terminated attribute setting string. NOTE, IT
+* SHOULD BE ENTIRELY LOWER CASE. The supplied string will be
+* interpreted using the public interpretation implemented by
+* astSetAttrib. This can be different to the interpretation of the
+* protected accessor functions. For instance, the public
+* interpretation of an unqualified floating point value for the
+* Epoch attribute is to interpet the value as a gregorian year,
+* but the protected interpretation is to interpret the value as an
+* MJD.
+* base_setting
+* Address of a location at which to return a pointer to the null
+* terminated attribute setting string which was applied to the
+* base Frame of the encapsulated FrameSet. This may differ from
+* the supplied setting if the supplied setting contains an axis
+* index and the current->base Mapping in the FrameSet produces an
+* axis permutation. The returned pointer should be freed using
+* astFree when no longer needed. A NULL pointer may be supplied in
+* which case no pointer is returned.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this;
+ char *bset;
+ int rep;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* Use the RegSetAttrib method inherited from the parent class to apply the
+ setting to the current and base Frames in the FrameSet encapsulated by the
+ parent Region structure. */
+ (*parent_regsetattrib)( this_region, setting, &bset, status );
+
+/* Now apply the base Frame setting to the component Regions (the current
+ Frame within the component Regions is equivalent to the base Frame in the
+ parent Region structure). Annul any "attribute unknown" error that results
+ from attempting to do this. */
+ if( astOK ) {
+ rep = astReporting( 0 );
+ astRegSetAttrib( this->region1, bset, NULL );
+ astRegSetAttrib( this->region2, bset, NULL );
+ if( astStatus == AST__BADAT ) astClearStatus;
+ astReporting( rep );
+ }
+
+/* If required, return the base Frame setting string, otherwise free it. */
+ if( base_setting ) {
+ *base_setting = bset;
+ } else {
+ bset = astFree( bset );
+ }
+}
+
+static AstRegion **RegSplit( AstRegion *this_region, int *nlist, int *status ){
+/*
+*+
+* Name:
+* RegSplit
+
+* Purpose:
+* Split a Region into a list of disjoint component Regions.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "region.h"
+* AstRegion **astRegSplit( AstRegion *this, int *nlist )
+
+* Class Membership:
+* CmpRegion member function (overrides the astRegSplit method
+* inherited from the parent Region class).
+
+* Description:
+* This function splits the supplied Region into a set of disjoint
+* component Regions. If the Region cannot be split, then the returned
+* array contains only one pointer - a clone of the supplied Region
+* pointer.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* nlist
+* Pointer to an int in which to return the number of elements in
+* the returned array.
+
+* Returned Value:
+* Pointer to dynamically alloctaed memory holding an array of Region
+* pointers. The length of this array is given by the value returned
+* in "*nlist". The pointers in the returned array should be annulled
+* using astAnnul when no longer needed, and the memory used to hold
+* the array should be freed using astFree.
+
+* Notes:
+* - A NULL pointer is returned if an error has already occurred, or if
+* this function should fail for any reason.
+*-
+*/
+
+/* Local Variables; */
+ AstCmpRegion *new;
+ AstCmpRegion *this;
+ AstFrame *frm;
+ AstFrameSet *fs;
+ AstMapping *map;
+ AstRegion **cmplist;
+ AstRegion **result;
+ AstRegion *cmpreg;
+ AstRegion *new_reg;
+ int icomp;
+ int ifirst;
+ int ilist;
+ int iw;
+ int jcomp;
+ int ncomp;
+ int nn;
+ int unbounded;
+
+/* Initialise. */
+ result = NULL;
+ *nlist = 0;
+
+/* Check the local error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* Indicate we have not yet found any unbounded component regions. */
+ unbounded = 0;
+
+/* Can only split non-inverted CmpRegions that combine their components
+ using the OR operator. */
+ if( this->oper == AST__OR && !astGetNegated( this->region1 ) &&
+ !astGetNegated( this->region2 ) ) {
+
+/* Process each of the two component Regions in turn. */
+ for( icomp = 0; icomp < 2 && !unbounded; icomp++ ) {
+ cmpreg = icomp ? this->region2 : this->region1;
+
+/* Create a set of disjoint Regions that are equivalent to the current
+ component Region, and loop round them. */
+ cmplist = astRegSplit( cmpreg, &ncomp );
+ for( jcomp = 0; jcomp < ncomp; jcomp++ ) {
+
+/* If any of the components are unbounds, we cannot split the supplied
+ Region. */
+ unbounded = unbounded || !astGetBounded( cmplist[ jcomp ] );
+ if( ! unbounded ) {
+
+/* Initialise the index within the returned list of the first Region that
+ overlaps the current disjoint component Region. */
+ ifirst = -1;
+
+/* Loop round all the Regions currently in the returned list. */
+ for( ilist = 0; ilist < *nlist; ilist++ ) {
+ if( result[ ilist ] ) {
+
+/* See if the current disjoint component overlaps the current entry in
+ the returned list. */
+ if( astOverlap( cmplist[ jcomp ], result[ ilist ] ) > 1 ) {
+
+/* If this is the first overlap found for the current disjoint component,
+ form a CmpRegion that combines the two overlapping Regions, and use it
+ to replace the current entry in the returned list. */
+ if( ifirst == -1 ) {
+ new = astCmpRegion( cmplist[ jcomp ], result[ ilist ],
+ AST__OR, " ", status );
+ (void) astAnnul( result[ ilist ] );
+ result[ ilist ] = (AstRegion *) new;
+
+/* Note the index within the returned list of the first Region that overlaps
+ the current disjoint component Region. */
+ ifirst = ilist;
+
+/* If this is the second or later overlap, add the overlapping returned Region
+ into the CmpRegion that it is stored at index "ifirsT" in the returned
+ list. */
+ } else {
+ new = astCmpRegion( result[ ilist ], result[ ifirst ],
+ AST__OR, " ", status );
+ result[ ilist ] = astAnnul( result[ ilist ] );
+ (void) astAnnul( result[ ifirst ] );
+ result[ ifirst ] = (AstRegion *) new;
+ }
+ }
+ }
+ }
+
+/* If the current disjoint component does not overlap any of the Regions
+ already in the returned list, append the current disjoint component to
+ the end of the returned list. */
+ if( ifirst == -1 ) {
+ ilist = (*nlist)++;
+ result = astGrow( result, *nlist, sizeof( *result ) );
+ if( astOK ) result[ ilist ] = astClone( cmplist[ jcomp ] );
+ }
+ }
+
+/* Annul the pointer to the disjoint component Region. */
+ cmplist[ jcomp ] = astAnnul( cmplist[ jcomp ] );
+ }
+
+/* Free the mnemory holding the list of disjoint components. */
+ cmplist = astFree( cmplist );
+ }
+ }
+
+/* If any unbounded components were found, ensure the returned list is
+ empty. */
+ if( unbounded && result ) {
+ for( ilist = 0; ilist < *nlist; ilist++ ) {
+ if( result[ ilist ] ) result[ ilist ] = astAnnul( result[ ilist ] );
+ }
+ result = astFree( result );
+ *nlist = 0;
+
+/* Otherwise, shuffle later entries down to fill any NULL slots in the returned
+ list. */
+ } else if( result ){
+ nn = *nlist;
+ iw = 0;
+ for( ilist = 0; ilist < nn; ilist++ ) {
+ if( result[ ilist ] ) result[ iw++ ] = result[ ilist ];
+ }
+ *nlist = iw;
+ }
+
+/* If this CmpRegion cannot be split, the returned list just holds a
+ clone of the Region pointer. */
+ if( !result ) {
+ result = astMalloc( sizeof( *result ) );
+ if( astOK ) {
+ result[ 0 ] = astClone( this );
+ *nlist = 1;
+ }
+ }
+
+/* Remap any returned Regions so that they are defined within the same
+ coordinate system as the supplied Region. */
+ if( result && *nlist > 0 ) {
+ fs = this_region->frameset;
+ map = astGetMapping( fs, AST__BASE, AST__CURRENT );
+ frm = astGetFrame( fs, AST__CURRENT );
+ for( ilist = 0; ilist < *nlist; ilist++ ) {
+ new_reg = astMapRegion( result[ ilist ], map, frm );
+ (void) astAnnul( result[ ilist ] );
+ result[ ilist ] = new_reg;
+ }
+ map = astAnnul( map );
+ frm = astAnnul( frm );
+ }
+
+/* Free all returned pointers if an error has occurred. */
+ if( !astOK && result ) {
+ for( ilist = 0; ilist < *nlist; ilist++ ) {
+ result[ ilist ] = astAnnul( result[ ilist ] );
+ }
+ result = astFree( result );
+ *nlist = 0;
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int RegTrace( AstRegion *this_region, int n, double *dist, double **ptr,
+ int *status ){
+/*
+*+
+* Name:
+* RegTrace
+
+* Purpose:
+* Return requested positions on the boundary of a 2D Region.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* int astRegTrace( AstRegion *this, int n, double *dist, double **ptr );
+
+* Class Membership:
+* CmpRegion member function (overrides the astRegTrace method
+* inherited from the parent Region class).
+
+* Description:
+* This function returns positions on the boundary of the supplied
+* Region, if possible. The required positions are indicated by a
+* supplied list of scalar parameter values in the range zero to one.
+* Zero corresponds to some arbitrary starting point on the boundary,
+* and one corresponds to the end (which for a closed region will be
+* the same place as the start).
+
+* Parameters:
+* this
+* Pointer to the Region.
+* n
+* The number of positions to return. If this is zero, the function
+* returns without action (but the returned function value still
+* indicates if the method is supported or not).
+* dist
+* Pointer to an array of "n" scalar parameter values in the range
+* 0 to 1.0.
+* ptr
+* A pointer to an array of pointers. The number of elements in
+* this array should equal tthe number of axes in the Frame spanned
+* by the Region. Each element of the array should be a pointer to
+* an array of "n" doubles, in which to return the "n" values for
+* the corresponding axis. The contents of the arrays are unchanged
+* if the supplied Region belongs to a class that does not
+* implement this method.
+
+* Returned Value:
+* Non-zero if the astRegTrace method is implemented by the class
+* of Region supplied, and zero if not.
+
+* Notes:
+* - The current algorithm results in the boundary of the CmpRegion
+* being dis-contiguous - supplied distance values from zero up to some
+* mid-value correspond to positions on the first component Region, and
+* higher distance (up to 1.0) correspond to points on the second
+* component Region.
+
+*-
+*/
+
+/* Local Variables; */
+ AstCmpRegion *this;
+ AstFrame *frm;
+ AstMapping *map;
+ AstPointSet *bpset;
+ AstPointSet *cpset;
+ AstRegion *ureg1;
+ AstRegion *ureg2;
+ double **bptr;
+ int i;
+ int j;
+ int ncur;
+ int result;
+ double *rval;
+ double *off;
+ double *r1d;
+ double *r2d;
+ double *r1ptr[ 2 ];
+ double *r2ptr[ 2 ];
+ double **r1ptrb;
+ double **r2ptrb;
+ double dbreak;
+ double dtot;
+ double x;
+ double x0;
+ int r1n;
+ int r2n;
+ AstPointSet *r1pset;
+ AstPointSet *r2pset;
+ AstPointSet *r1psetb;
+ AstPointSet *r2psetb;
+
+/* Initialise */
+ result = 0;
+
+/* Check inherited status. */
+ if( ! astOK ) return result;
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* Get a pointer to the base Frame in the encapsulated FrameSet. */
+ frm = astGetFrame( this_region->frameset, AST__BASE );
+
+/* Check it is 2-dimensional. */
+ result = 1;
+ if( astGetNaxes( frm ) != 2 ) result = 0;
+
+/* Check the component Regions can be traced. */
+ if( !astRegTrace( this->region1, 0, NULL, NULL ) ||
+ !astRegTrace( this->region1, 0, NULL, NULL ) ) result = 0;
+
+/* Check we have some points to find. */
+ if( result && n > 0 ) {
+
+/* We first determine the required positions in the base Frame of the
+ Region, and then transform them into the current Frame. Get the
+ base->current Mapping, and the number of current Frame axes. */
+ map = astGetMapping( this_region->frameset, AST__BASE, AST__CURRENT );
+
+/* If it's a UnitMap we do not need to do the transformation, so put the
+ base Frame positions directly into the supplied arrays. */
+ if( astIsAUnitMap( map ) ) {
+ bpset = NULL;
+ bptr = ptr;
+ ncur = 2;
+
+/* Otherwise, create a PointSet to hold the base Frame positions. */
+ } else {
+ bpset = astPointSet( n, 2, " ", status );
+ bptr = astGetPoints( bpset );
+ ncur = astGetNout( map );
+ }
+
+ r1d = astMalloc( sizeof( double )*n );
+ r2d = astMalloc( sizeof( double )*n );
+
+/* Ensure information about the breaks in the boundary of each component
+ region is available within the CmpRegion structure. These breaks are
+ the points at which the two boundaries cross. */
+ SetBreakInfo( this, 0, status );
+ SetBreakInfo( this, 1, status );
+
+/* Get the constants needed to convert the supplied distances (normalised
+ so that the border of the entire CmpRegion has a length of 1.0), into
+ geodesic distances around the border of each component Region. */
+ dtot = this->d0[ 0 ] + this->d0[ 1 ];
+ dbreak = this->d0[ 0 ]/dtot;
+
+/* Initialise here to avoid compiler warnings. */
+ r1n = 0;
+ r2n = 0;
+
+/* Check the pointers can be used safely. */
+ if( astOK ) {
+
+/* Loop round all supplied distances, determining if they represent a
+ position on the first or second component Region. */
+ for( i = 0; i < n; i++ ) {
+
+/* If the current distance represents a point in the second component
+ Region... */
+ if( dist[ i ] > dbreak ) {
+
+/* Find the correspond distance around the used sections of the second
+ component region (normalised so that the entire border of the
+ component region has a length of "this->d0[1]"). */
+ x0 = ( dist[ i ] - dbreak )*dtot;
+ x = x0;
+
+/* Convert this into the correspond distance around the entire border of
+ the second component region (normalised so that the entire border of the
+ component region has unit length). */
+ rval = this->rvals[ 1 ];
+ off = this->offs[ 1 ];
+
+ for( j = 0; j < this->nbreak[ 1 ]; j++,rval++,off++ ) {
+ if( *rval >= x0 ) break;
+ x += *off;
+ }
+
+/* Store this as the next distance to move around the second component
+ Region, normalising it to the range 0 to 1 as required by astRegTrace. */
+ r2d[ r2n++ ] = x/this->dtot[ 1 ];
+
+/* Now we do the same if the current distance corresponds to a position
+ in the first component Region. */
+ } else {
+
+ x0 = dist[ i ]*dtot;
+ x = x0;
+
+ rval = this->rvals[ 0 ];
+ off = this->offs[ 0 ];
+
+ for( j = 0; j < this->nbreak[ 0 ]; j++,rval++,off++ ) {
+ if( *rval >= x0 ) break;
+ x += *off;
+ }
+
+ r1d[ r1n++ ] = x/this->dtot[ 0 ];
+
+ }
+
+ }
+ }
+
+/* Allocate memory to hold the axis values at the corresponding positions
+ in the first component Region. */
+ r1ptr[ 0 ] = astMalloc( sizeof( double )*r1n );
+ r1ptr[ 1 ] = astMalloc( sizeof( double )*r1n );
+
+/* Allocate memory to hold the axis values at the corresponding positions
+ in the second component Region. */
+ r2ptr[ 0 ] = astMalloc( sizeof( double )*r2n );
+ r2ptr[ 1 ] = astMalloc( sizeof( double )*r2n );
+
+/* Check the pointers can be used safely. */
+ if( astOK ) {
+
+/* Find the axis values at each of the required positions that fall in
+ the first component Region. Negate it first if needed to ensure the
+ Region is bounded (not guaranteed, but likely). */
+ if( astGetBounded( this->region1 ) ) {
+ (void) astRegTrace( this->region1, r1n, r1d, r1ptr );
+ } else {
+ AstRegion *negation = astGetNegation( this->region1 );
+ (void) astRegTrace( negation, r1n, r1d, r1ptr );
+ negation = astAnnul( negation );
+ }
+
+/* Do the same for the second component Region. */
+ if( astGetBounded( this->region2 ) ) {
+ (void) astRegTrace( this->region2, r2n, r2d, r2ptr );
+ } else {
+ AstRegion *negation = astGetNegation( this->region2 );
+ (void) astRegTrace( negation, r2n, r2d, r2ptr );
+ negation = astAnnul( negation );
+ }
+
+/* The arrays of positions returned by the above calls to astRegTrace may
+ include points that should not be there (e.g. points on the boundary
+ of one component region that should have been blanked due to being inside
+ the second component region - if the regions are ORed together). This
+ is a consequence of the relatively low value of the "NP" local constant
+ in function SetBreakInfo. So we now refine the positions to exclude
+ any such unwanted positions.
+
+ If the two component Regions are ANDed together, we want to remove the
+ positions from the boundary of the required component Region that fall
+ outside the other region. We can do this by simply using the other Region
+ as a Mapping. If the two component Regions are ORed together, we want to
+ remove the position that fall within (rather than outside) the other
+ Region. To do this we need to negate the other region first. */
+ if( this->oper == AST__OR ) {
+ ureg1 = astGetNegation( this->region1 );
+ ureg2 = astGetNegation( this->region2 );
+ } else {
+ ureg1 = astClone( this->region1 );
+ ureg2 = astClone( this->region2 );
+ }
+
+/* Now transform the points on the boundary of the first Region in order
+ to set invalid those positions which are not on the boundary of the
+ supplied CmpRegion. */
+ if( r1n > 0 ) {
+ r1pset = astPointSet( r1n, 2, " ", status );
+ astSetPoints( r1pset, r1ptr );
+ r1psetb = astTransform( ureg2, r1pset, 1, NULL );
+ r1ptrb = astGetPoints( r1psetb );
+ } else {
+ r1pset = NULL;
+ r1psetb = NULL;
+ r1ptrb = NULL;
+ }
+
+/* Now transform the points on the boundary of the second Region in order
+ to set invalid those positions which are not on the boundary of the
+ supplied CmpRegion. */
+ if( r2n > 0 ) {
+ r2pset = astPointSet( r2n, 2, " ", status );
+ astSetPoints( r2pset, r2ptr );
+ r2psetb = astTransform( ureg1, r2pset, 1, NULL );
+ r2ptrb = astGetPoints( r2psetb );
+ } else {
+ r2pset = NULL;
+ r2psetb = NULL;
+ r2ptrb = NULL;
+ }
+
+/* Free the begation pointers. */
+ ureg1 = astAnnul( ureg1 );
+ ureg2 = astAnnul( ureg2 );
+
+/* Check pointer can be used safely. */
+ if( astOK ) {
+
+/* Copy the boundary positions from each component Region into a single
+ PointSet. These positions are in the base Frame of the CmpRegion. */
+ r1n = 0;
+ r2n = 0;
+ for( i = 0; i < n; i++ ) {
+ if( dist[ i ] > dbreak ) {
+ bptr[ 0 ][ i ] = r2ptrb[ 0 ][ r2n ];
+ bptr[ 1 ][ i ] = r2ptrb[ 1 ][ r2n++ ];
+ } else {
+ bptr[ 0 ][ i ] = r1ptrb[ 0 ][ r1n ];
+ bptr[ 1 ][ i ] = r1ptrb[ 1 ][ r1n++ ];
+ }
+ }
+
+ }
+
+/* Free resources. */
+ if( r1pset ) r1pset = astAnnul( r1pset );
+ if( r2pset ) r2pset = astAnnul( r2pset );
+ if( r1psetb ) r1psetb = astAnnul( r1psetb );
+ if( r2psetb ) r2psetb = astAnnul( r2psetb );
+
+ }
+
+/* If required, transform the base frame positions into the current
+ Frame of the CmpRegion, storing them in the supplied array. Then
+ free resources. */
+ if( bpset ) {
+ cpset = astPointSet( n, ncur, " ", status );
+ astSetPoints( cpset, ptr );
+
+ (void) astTransform( map, bpset, 1, cpset );
+
+ cpset = astAnnul( cpset );
+ bpset = astAnnul( bpset );
+ }
+
+/* Free remaining resources. */
+ map = astAnnul( map );
+ }
+ frm = astAnnul( frm );
+
+/* Return the result. */
+ return result;
+}
+
+static void RegClearAttrib( AstRegion *this_region, const char *attrib,
+ char **base_attrib, int *status ) {
+/*
+* Name:
+* RegClearAttrib
+
+* Purpose:
+* Clear an attribute value for a Region.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void RegClearAttrib( AstRegion *this, const char *attrib,
+* char **base_attrib, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astRegClearAttrib method
+* inherited from the Region class).
+
+* Description:
+* This function clears the value of a named attribute in both the base
+* and current Frame in the FrameSet encapsulated within a Region, without
+* remapping either Frame.
+*
+* No error is reported if the attribute is not recognised by the base
+* Frame.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* attrib
+* Pointer to a null terminated string holding the attribute name.
+* NOTE, IT SHOULD BE ENTIRELY LOWER CASE.
+* base_attrib
+* Address of a location at which to return a pointer to the null
+* terminated string holding the attribute name which was cleared in
+* the base Frame of the encapsulated FrameSet. This may differ from
+* the supplied attribute if the supplied attribute contains an axis
+* index and the current->base Mapping in the FrameSet produces an
+* axis permutation. The returned pointer should be freed using
+* astFree when no longer needed. A NULL pointer may be supplied in
+* which case no pointer is returned.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this;
+ char *batt;
+ int rep;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* Use the RegClearAttrib method inherited from the parent class to clear the
+ attribute in the current and base Frames in the FrameSet encapsulated by
+ the parent Region structure. */
+ (*parent_regclearattrib)( this_region, attrib, &batt, status );
+
+/* Now clear the base Frame attribute to the component Regions (the current
+ Frame within the component Regions is equivalent to the base Frame in the
+ parent Region structure). Annul any "attribute unknown" error that results
+ from attempting to do this. */
+ if( astOK ) {
+ rep = astReporting( 0 );
+ astRegClearAttrib( this->region1, batt, NULL );
+ astRegClearAttrib( this->region2, batt, NULL );
+ if( astStatus == AST__BADAT ) astClearStatus;
+ astReporting( rep );
+ }
+
+/* If required, return the base Frame attribute name, otherwise free it. */
+ if( base_attrib ) {
+ *base_attrib = batt;
+ } else {
+ batt = astFree( batt );
+ }
+}
+
+static void ResetCache( AstRegion *this_region, int *status ){
+/*
+* Name:
+* ResetCache
+
+* Purpose:
+* Clear cached information within the supplied Region.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void ResetCache( AstRegion *this, int *status )
+
+* Class Membership:
+* Region member function (overrides the astResetCache method
+* inherited from the parent Region class).
+
+* Description:
+* This function clears cached information from the supplied Region
+* structure.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables *: */
+ AstCmpRegion *this;
+ int i;
+
+/* Check a Region was supplied. */
+ if( this_region ) {
+
+/* Get a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_region;
+
+/* Clear information cached in the CmpRegion structure. */
+ for( i = 0; i < 2; i++ ) {
+ this->rvals[ i ] = astFree( this->rvals[ i ] );
+ this->offs[ i ] = astFree( this->offs[ i ] );
+ this->nbreak[ i ] = 0;
+ this->d0[ i ] = AST__BAD;
+ this->dtot[ i ] = AST__BAD;
+ }
+
+ this->bounded = -INT_MAX;
+
+/* Clear information cached in the component regions. */
+ if( this->region1 ) astResetCache( this->region1 );
+ if( this->region2 ) astResetCache( this->region2 );
+
+/* Clear information cached in the parent Region structure. */
+ (*parent_resetcache)( this_region, status );
+ }
+}
+
+static void SetBreakInfo( AstCmpRegion *this, int comp, int *status ){
+/*
+* Name:
+* SetBreakInfo
+
+* Purpose:
+* Ensure that a CmpRegion has information about the breaks in the
+* boundaries of one of the two component Regions.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void SetBreakInfo( AstCmpRegion *this, int comp, int *status )
+
+* Class Membership:
+* CmpRegion method.
+
+* Description:
+* This function returns without action if the supplied CmpRegion
+* already contains break information for the specified component Region.
+* Otherwise, it creates the required information and stores it in the
+* CmpRegion.
+*
+* Each component Region in the CmpRegion has a boundary. But in
+* general only part of the boundary of a component Region will also
+* be included in the CmpRegion boundary. Thus the component Region
+* boundary can be broken up into sections; sections that form part
+* of the CmpRegion boundary, and sections that do not. This function
+* stores information about the breaks between these sections.
+*
+* The complete boundary of a component Region is parameterised by a
+* geodesic distance that goes from 0.0 to the value found by this
+* function and stored in this->dtot (the total geodesic distance
+* around the border). This function find the ranges of this parameter
+* that correspond to the sections of the boundary that are also on the
+* CmpRegion boundary, and thus finds the total length that the component
+* boundary contributes to the CmpRegion boundary. This length is stored
+* in "this->d0" (a two element array, one for each component Region).
+*
+* It also find two arrays "this->rvals" and "this->offs" that allow a
+* distance value in the range 0.0 to "this->d0" (i.e. a distance
+* measured by skipping over the parts of the component boundary that
+* are not on the CmpRegion boundary), to be converted into the
+* corresponding distance value in the range 0.0 to "this->dtot" (i.e. a
+* distance measured round the complete component boundary, including the
+* parts not on the CmpRegion boundary).
+
+* Parameters:
+* this
+* Pointer to a CmpRegion.
+* comp
+* Zero or one, indicating which component Region is to be checked.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* The number of points to be spread evenly over the entire boundary of the
+ component Region. */
+#define NP 101
+
+/* Local Variables: */
+ AstFrame *frm;
+ AstPointSet *pset1;
+ AstPointSet *pset2;
+ AstRegion *other;
+ AstRegion *reg;
+ AstRegion *uother;
+ double **ptr2;
+ double **ptr1;
+ double *d;
+ double *offs;
+ double *p0;
+ double *p1;
+ double *p;
+ double *q;
+ double *rvals;
+ double delta;
+ double dist;
+ double pnt1[ 2 ];
+ double pnt2[ 2 ];
+ double rbad;
+ double rval;
+ double totdist;
+ int i;
+ int j;
+ int nn;
+ int prevgood;
+
+/* Check inherited status */
+ if( !astOK ) return;
+
+/* If the information describing breaks in the component boundary has not
+ yet been set up, do so now. */
+ if( this->d0[ comp ] == AST__BAD ) {
+
+/* Get a pointer to the component Region for which break information is
+ required. */
+ reg = comp ? this->region2 : this->region1;
+
+/* Check the component class implements the astRegTrace method. */
+ if( astRegTrace( reg, 0, NULL, NULL ) ) {
+
+/* Create a pointSet to hold axis values at evenly spaced positions along
+ the entire boundary of the selected component region. */
+ pset1 = astPointSet( NP, 2, " ", status );
+ ptr1 = astGetPoints( pset1 );
+
+/* Allocate memory to hold an array of corresponding scalar distances around
+ the boundary. */
+ d = astMalloc( NP*sizeof( double ) );
+
+/* Check pointers can be used safely. */
+ if( astOK ) {
+
+/* Get the distance increment between points (at this point the distances
+ are normalised so that the entire boundary has unit length, as
+ required by astRegTrace). */
+ delta = 1.0/( NP - 1 );
+
+/* Set up the array of evenly spaced distances around the boundary of the
+ component region. */
+ for( i = 0; i < NP; i++ ) d[ i ] = i*delta;
+
+/* Get the corresponding Frame positions. If the Region is unbounded
+ (e.g. a negated circle, etc), then negate it first in the hope that
+ this may produced a bounded Region. */
+ if( astGetBounded( reg ) ) {
+ (void) astRegTrace( reg, NP, d, ptr1 );
+ } else {
+ AstRegion *negation = astGetNegation( reg );
+ (void) astRegTrace( negation, NP, d, ptr1 );
+ negation = astAnnul( negation );
+ }
+
+/* Get a pointer to the other component Region. */
+ other = comp ? this->region1 : this->region2;
+
+/* If the two component Regions are ANDed together, we want to remove the
+ positions from the boundary of the required component Region that fall
+ outside the other region. We can do this by simply using the other Region
+ as a Mapping. If the two component Regions are ORed together, we want to
+ remove the position that fall within (rather than outside) the other
+ Region. To do this we need to negate the other region first. */
+ if( this->oper == AST__OR ) {
+ uother = astGetNegation( other );
+ } else {
+ uother = astClone( other );
+ }
+
+/* Now transform the points on the boundary of the selected Region in
+ order to set invalid those positions which are not on the boundary of
+ the supplied CmpRegion. */
+ pset2 = astTransform( uother, pset1, 1, NULL );
+
+/* Annul the negation pointer */
+ uother = astAnnul( uother );
+
+/* Modify the distance array by setting invalid each element that is not
+ on the boundary of the CmpRegion. */
+ ptr2 = astGetPoints( pset2 );
+ if( astOK ) {
+ p = ptr2[ 0 ];
+ q = ptr2[ 1 ];
+ for( i = 0; i < NP; i++,p++,q++ ) {
+ if( *p == AST__BAD || *q == AST__BAD ) d[ i ] = AST__BAD;
+ }
+
+/* At each good/bad junction in this list, extend the good section by one
+ point. This ensures that the good sections of the curve do in fact
+ touch each other (they may in fact overlap a little but that does not
+ matter). */
+ prevgood = ( d[ 0 ] != AST__BAD );
+ for( i = 1; i < NP; i++,p++,q++ ) {
+ if( d[ i ] == AST__BAD ) {
+ if( prevgood ) d[ i ] = i*delta;
+ prevgood = 0;
+
+ } else {
+ if( !prevgood ) d[ i - 1 ] = ( i - 1 )*delta;
+ prevgood = 1;
+ }
+ }
+
+/* Find the total geodesic distance around the border. This is only an
+ approximation but it is only used to give a relative weight to this
+ component within the CmpFrame, and so does not need to be very accurate. */
+ frm = astGetFrame( reg->frameset, AST__CURRENT );
+ p0 = ptr1[ 0 ];
+ p1 = ptr1[ 1 ];
+ totdist = 0;
+ pnt1[ 0 ] = *(p0++);
+ pnt1[ 1 ] = *(p1++);
+ for( i = 1; i < NP; i++ ) {
+ pnt2[ 0 ] = *(p0++);
+ pnt2[ 1 ] = *(p1++);
+ dist = astDistance( frm, pnt1, pnt2 );
+ if( dist != AST__BAD ) totdist += dist;
+ pnt1[ 0 ] = pnt2[ 0 ];
+ pnt1[ 1 ] = pnt2[ 1 ];
+ }
+
+/* Change delta so that it represents a geodesic distance, rather than a
+ normalised distance in the range zero to one. Working in geodesic distance
+ (e.g. Radians on a SkyFrame) prevents Regions higher up in a complex nested
+ CmpRegion being given higher priority than a lower Region. */
+ delta *= totdist;
+
+/* Now create two arrays - "rvals" holds the distance travelled around
+ the used parts of the border at which breaks occur, "offs" holds the jump
+ in distance around the complete border at each break. The distance
+ around the complete border is normalised to the range [0.0,1.0].
+ Therefore the total distance around the used parts of the border will in
+ general be less than 1.0 */
+ if( d[ 0 ] == AST__BAD ) {
+ nn = 1;
+ j = 0;
+ rvals = astMalloc( sizeof( double ) );
+ offs = astMalloc( sizeof( double ) );
+ if( astOK ) rvals[ 0 ] = -0.5*delta;
+ rbad = 0.5;
+ prevgood = 0;
+ rval = -0.5*delta;
+
+ } else {
+ nn = 0;
+ rvals = NULL;
+ offs = NULL;
+ prevgood = 1;
+ rbad = 0.0;
+ rval = 0.0;
+ }
+
+ for( i = 1; i < NP; i++,p++,q++ ) {
+
+ if( d[ i ] == AST__BAD ) {
+ if( prevgood ) {
+ j = nn++;
+ rvals = astGrow( rvals, nn, sizeof( double ) );
+ offs = astGrow( offs, nn, sizeof( double ) );
+ if( astOK ) {
+ rvals[ j ] = rval + 0.5*delta;
+ rbad = 0.0;
+ } else {
+ break;
+ }
+ prevgood = 0;
+ }
+
+ rbad += 1.0;
+
+ } else {
+ if( !prevgood ) {
+ offs[ j ] = rbad*delta;
+ prevgood = 1;
+ }
+ rval += delta;
+ }
+ }
+
+ if( !prevgood ) {
+ rval += 0.5*delta;
+ offs[ j ] = rbad*delta;
+ }
+
+/* Record the information in the CmpRegion structure. */
+ this->rvals[ comp ] = rvals;
+ this->offs[ comp ] = offs;
+ this->nbreak[ comp ] = nn;
+ this->d0[ comp ] = rval;
+ this->dtot[ comp ] = totdist;
+ }
+
+/* Free resources. */
+ pset2 = astAnnul( pset2 );
+ }
+
+ pset1 = astAnnul( pset1 );
+ d = astFree( d );
+
+ }
+ }
+}
+
+#undef NP
+
+static void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) {
+/*
+* Name:
+* SetRegFS
+
+* Purpose:
+* Stores a new FrameSet in a Region
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status )
+
+* Class Membership:
+* CmpRegion method (over-rides the astSetRegFS method inherited from
+* the Region class).
+
+* Description:
+* This function creates a new FrameSet and stores it in the supplied
+* Region. The new FrameSet contains two copies of the supplied
+* Frame, connected by a UnitMap.
+
+* Parameters:
+* this
+* Pointer to the Region.
+* frm
+* The Frame to use.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstRegion *creg; /* Pointer to component Region structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Invoke the parent method to store the FrameSet in the parent Region
+ structure. */
+ (* parent_setregfs)( this_region, frm, status );
+
+/* If either component Region has a dummy FrameSet use this method
+ recursively to give them the same FrameSet. */
+ creg = ((AstCmpRegion *) this_region )->region1;
+ if( creg && !astGetRegionFS( creg ) ) astSetRegFS( creg, frm );
+
+ creg = ((AstCmpRegion *) this_region )->region2;
+ if( creg && !astGetRegionFS( creg ) ) astSetRegFS( creg, frm );
+
+}
+
+static AstMapping *Simplify( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* Simplify
+
+* Purpose:
+* Simplify a Region.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "region.h"
+* AstMapping *Simplify( AstMapping *this, int *status )
+
+* Class Membership:
+* CmpRegion method (over-rides the astSimplify method inherited from
+* the Region class).
+
+* Description:
+* This function simplifies a CmpRegion to eliminate redundant
+* computational steps, or to merge separate steps which can be
+* performed more efficiently in a single operation.
+
+* Parameters:
+* this
+* Pointer to the original Region.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A new pointer to the (possibly simplified) Region.
+
+* Notes:
+* - A NULL pointer value will be returned if this function is
+* invoked with the AST error status set, or if it should fail for
+* any reason.
+
+* Deficiencies:
+* - Currently, this function does not attempt to map the component
+* Regions into the current Frame of the parent Region structure.
+* Both components should be mapped into the current Frame, and if the
+* resulting base->current Mappings in *both* remapped component Regions are
+* UnitMaps, then a new CmpRegion should be created from the re-mapped
+* Regions.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *newb; /* New CmpRegion defined in base Frame */
+ AstCmpRegion *newc; /* New CmpRegion defined in current Frame */
+ AstFrame *frm; /* Current Frame */
+ AstMapping *map; /* Base->current Mapping */
+ AstMapping *result; /* Result pointer to return */
+ AstRegion *csreg1; /* Copy of simplified first component Region */
+ AstRegion *csreg2; /* Copy of simplified second component Region */
+ AstRegion *nullreg; /* Null or infinfite Region */
+ AstRegion *othereg; /* Non-Null and non-infinfite Region */
+ AstRegion *reg1; /* First component Region */
+ AstRegion *reg2; /* Second component Region */
+ AstRegion *sreg1; /* Simplified first component Region */
+ AstRegion *sreg2; /* Simplified second component Region */
+ int neg1; /* Negated flag to use with first component */
+ int neg2; /* Negated flag to use with second component */
+ int oper; /* Boolean operator used to combine components */
+ int overlap; /* Nature of overlap between components */
+ int simpler; /* Has any simplification taken place? */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Invoke the parent Simplify method inherited from the Region class. This
+ will simplify the encapsulated FrameSet and uncertainty Region. The
+ returned pointer identifies a region within the current Frame of the
+ FrameSet encapsulated by the parent Region structure. Note this by
+ storing the pointer in the "newc" ("c" for "current") variable. */
+ newc = (AstCmpRegion *) (*parent_simplify)( this_mapping, status );
+
+/* Note if any simplification took place. This is assumed to be the case
+ if the pointer returned by the above call is different to the supplied
+ pointer. */
+ simpler = ( (AstMapping *) newc != this_mapping );
+
+/* Below we may create a new simplified region which identifies a region
+ within the base Frame of the FrameSet encapsulated by the parent Region
+ structure. Such a result will need to be mapped into the current Frame
+ before being returned. The "newb" variable ("b" for "base") will be
+ used to store a pointer to such a result. Initialise this variable to
+ indicate that we do not yet have a base Frame result. */
+ newb = NULL;
+
+/* Get the component Regions, how they should be combined, and the
+ Negated values which should be used with them. The returned values
+ take account of whether the supplied CmpRegion has itself been Negated
+ or not. The returned Regions represent regions within the base Frame
+ of the FrameSet encapsulated by the parent Region structure. */
+ GetRegions( newc, &reg1, &reg2, &oper, &neg1, &neg2, status );
+
+/* If the first component Region does not have the required value for
+ its "Negated" attribute, use the negation of "reg1" in place of "reg1"
+ itself. */
+ if( neg1 != astGetNegated( reg1 ) ) {
+ AstRegion *tmp = astGetNegation( reg1 );
+ (void) astAnnul( reg1 );
+ reg1 = tmp;
+ }
+
+/* If the second component Region does not have the required value for
+ its "Negated" attribute, use the negation of "reg2" in place of "reg2"
+ itself. */
+ if( neg2 != astGetNegated( reg2 ) ) {
+ AstRegion *tmp = astGetNegation( reg2 );
+ (void) astAnnul( reg2 );
+ reg2 = tmp;
+ }
+
+/* Simplify each of the two components. */
+ sreg1 = astSimplify( reg1 );
+ sreg2 = astSimplify( reg2 );
+
+/* Note if any simplification took place. */
+ simpler = simpler || ( sreg1 != reg1 || sreg2 != reg2 );
+
+/* If either component is null or infinite we can exclude it from the
+ returned Region. */
+ if( astIsANullRegion( sreg1 ) || astIsANullRegion( sreg2 ) ) {
+
+/* Get a pointer to the non-null Region. The following is still valid
+ even if both regions are null or infinite. */
+ if( astIsANullRegion( sreg1 ) ){
+ nullreg = sreg1;
+ othereg = sreg2;
+ } else {
+ nullreg = sreg2;
+ othereg = sreg1;
+ }
+
+/* If null.. */
+ if( !astGetNegated( nullreg ) ){
+ if( oper == AST__AND ) {
+ newb = (AstCmpRegion *) astNullRegion( othereg,
+ astGetUnc( othereg, 0 ), "", status );
+
+ } else if( oper == AST__OR ) {
+ newb = astCopy( othereg );
+
+ } else {
+ astError( AST__INTER, "astSimplify(%s): The %s refers to an "
+ "unknown boolean operator with identifier %d (internal "
+ "AST programming error).", status, astGetClass( newc ),
+ astGetClass( newc ), oper );
+ }
+
+/* If infinite.. */
+ } else {
+ if( oper == AST__AND ) {
+ newb = astCopy( othereg );
+
+ } else if( oper == AST__OR ) {
+ newb = (AstCmpRegion *) astNullRegion( othereg,
+ astGetUnc( othereg, 0 ), "negated=1", status );
+
+ } else {
+ astError( AST__INTER, "astSimplify(%s): The %s refers to an "
+ "unknown boolean operator with identifier %d (internal "
+ "AST programming error).", status, astGetClass( newc ),
+ astGetClass( newc ), oper );
+ }
+ }
+
+/* Flag that we have done some simplication.*/
+ simpler = 1;
+
+/* If neither component is null or infinite, see if it is possible to
+ remove one or both of the components on the basis of the overlap
+ between them. */
+ } else {
+ overlap = astOverlap( sreg1, sreg2 );
+
+/* If the components have no overlap, and they are combined using AND, then
+ the CmpRegion is null. */
+ if( ( overlap == 1 || overlap == 6 ) && oper == AST__AND ) {
+ newb = (AstCmpRegion *) astNullRegion( sreg1, astGetUnc( sreg1, 0 ),
+ "", status );
+ simpler = 1;
+
+/* If one component is the negation of the other component, and they are
+ combined using OR, then the CmpRegion is infinite. This is represented
+ by a negated null region.*/
+ } else if( overlap == 6 && oper == AST__OR ) {
+ newb = (AstCmpRegion *) astNullRegion( sreg1, astGetUnc( sreg1, 0 ),
+ "negated=1", status );
+ simpler = 1;
+
+/* If the two components are identical... */
+ } else if( overlap == 5 ) {
+ simpler = 1;
+
+/* If combined with AND or OR, the CmpRegion can be replaced by the first
+ (or second) component Region. */
+ if( oper == AST__AND || oper == AST__OR ) {
+ newb = astCopy( sreg1 );
+ } else {
+ astError( AST__INTER, "astSimplify(%s): The %s refers to an "
+ "unknown boolean operator with identifier %d (internal "
+ "AST programming error).", status, astGetClass( newc ),
+ astGetClass( newc ), oper );
+ }
+
+/* If the first component is entirely contained within the second
+ component, and they are combined using AND or OR, then the CmpRegion
+ can be replaced by the first or second component. */
+ } else if( overlap == 2 && ( oper == AST__AND || oper == AST__OR ) ){
+ newb = astCopy( ( oper == AST__AND ) ? sreg1 : sreg2 );
+ simpler = 1;
+
+/* If the second component is entirely contained within the first
+ component, and they are combined using AND or OR, then the CmpRegion
+ can be replaced by the second or first component. */
+ } else if( overlap == 3 && ( oper == AST__AND || oper == AST__OR ) ){
+ newb = astCopy( ( oper == AST__AND ) ? sreg2 : sreg1 );
+ simpler = 1;
+
+/* Otherwise, no further simplication is possible, so either create a new
+ CmpRegion or leave the "newb" pointer NULL (which will cause "newc" to
+ be used), depending on whether the components were simplified. */
+ } else if( simpler ){
+ csreg1 = astCopy( sreg1 );
+ csreg2 = astCopy( sreg2 );
+ newb = astCmpRegion( csreg1, csreg2, oper, "", status );
+ csreg1 = astAnnul( csreg1 );
+ csreg2 = astAnnul( csreg2 );
+
+ }
+ }
+
+/* If any simplification took place, decide whether to use the "newc" or
+ "newb" pointer for the returned Mapping. If "newb" is non-NULL we use
+ it, otherwise we use "newc". If "newb" is used we must first map the
+ result Region from the base Frame of the FrameSet encapsulated
+ by the parent Region structure, to the current Frame. */
+ if( simpler ) {
+ if( newb ){
+ frm = astGetFrame( ((AstRegion *) newc)->frameset, AST__CURRENT );
+ map = astGetMapping( ((AstRegion *) newc)->frameset, AST__BASE, AST__CURRENT );
+ result = astMapRegion( newb, map, frm );
+ frm = astAnnul( frm );
+ map = astAnnul( map );
+ newb = astAnnul( newb );
+ } else {
+ result = astClone( newc );
+ }
+
+/* If no simplification took place, return a clone of the supplied pointer. */
+ } else {
+ result = astClone( this_mapping );
+ }
+
+/* Free resources. */
+ reg1 = astAnnul( reg1 );
+ reg2 = astAnnul( reg2 );
+ sreg1 = astAnnul( sreg1 );
+ sreg2 = astAnnul( sreg2 );
+ newc = astAnnul( newc );
+
+/* If an error occurred, annul the returned Mapping. */
+ if ( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in,
+ int forward, AstPointSet *out, int *status ) {
+/*
+* Name:
+* Transform
+
+* Purpose:
+* Apply a CmpRegion to transform a set of points.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* AstPointSet *Transform( AstMapping *this, AstPointSet *in,
+* int forward, AstPointSet *out, int *status )
+
+* Class Membership:
+* CmpRegion member function (over-rides the astTransform method inherited
+* from the Region class).
+
+* Description:
+* This function takes a CmpRegion and a set of points encapsulated in a
+* PointSet and transforms the points so as to apply the required Region.
+* This implies applying each of the CmpRegion's component Regions in turn,
+* either in series or in parallel.
+
+* Parameters:
+* this
+* Pointer to the CmpRegion.
+* in
+* Pointer to the PointSet associated with the input coordinate values.
+* forward
+* A non-zero value indicates that the forward coordinate transformation
+* should be applied, while a zero value requests the inverse
+* transformation.
+* out
+* Pointer to a PointSet which will hold the transformed (output)
+* coordinate values. A NULL value may also be given, in which case a
+* new PointSet will be created by this function.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the output (possibly new) PointSet.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+* - The number of coordinate values per point in the input PointSet must
+* match the number of coordinates for the CmpRegion being applied.
+* - If an output PointSet is supplied, it must have space for sufficient
+* number of points and coordinate values per point to accommodate the
+* result. Any excess space will be ignored.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to the CmpRegion structure */
+ AstPointSet *ps1; /* Pointer to PointSet for first component */
+ AstPointSet *ps2; /* Pointer to PointSet for second component */
+ AstPointSet *pset_tmp; /* Pointer to PointSet holding base Frame positions*/
+ AstPointSet *result; /* Pointer to output PointSet */
+ AstRegion *reg1; /* Pointer to first component Region */
+ AstRegion *reg2; /* Pointer to second component Region */
+ double **ptr1; /* Pointer to first component axis values */
+ double **ptr2; /* Pointer to second component axis values */
+ double **ptr_out; /* Pointer to output coordinate data */
+ int coord; /* Zero-based index for coordinates */
+ int good; /* Is the point inside the CmpRegion? */
+ int ncoord_out; /* No. of coordinates per output point */
+ int ncoord_tmp; /* No. of coordinates per base Frame point */
+ int neg1; /* Negated value for first component Region */
+ int neg2; /* Negated value for second component Region */
+ int npoint; /* No. of points */
+ int oper; /* Boolean operator to use */
+ int point; /* Loop counter for points */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a Pointer to the CmpRegion structure */
+ this = (AstCmpRegion *) this_mapping;
+
+/* Get the component Regions, how they should be combined, and the
+ Negated values which should be used with them. The returned values
+ take account of whether the supplied CmpRegion has itself been Negated
+ or not. The returned Regions represent regions within the base Frame
+ of the FrameSet encapsulated by the parent Region structure. */
+ GetRegions( this, &reg1, &reg2, &oper, &neg1, &neg2, status );
+
+/* If the first component Region does not have the required value for
+ its "Negated" attribute, use the negation of "reg1" in place of "reg1"
+ itself. */
+ if( neg1 != astGetNegated( reg1 ) ) {
+ AstRegion *tmp = astGetNegation( reg1 );
+ (void) astAnnul( reg1 );
+ reg1 = tmp;
+ }
+
+/* If the second component Region does not have the required value for
+ its "Negated" attribute, use the negation of "reg2" in place of "reg2"
+ itself. */
+ if( neg2 != astGetNegated( reg2 ) ) {
+ AstRegion *tmp = astGetNegation( reg2 );
+ (void) astAnnul( reg2 );
+ reg2 = tmp;
+ }
+
+/* Apply the parent mapping using the stored pointer to the Transform member
+ function inherited from the parent Region class. This function validates
+ all arguments and generates an output PointSet if necessary, containing
+ a copy of the input PointSet. */
+ result = (*parent_transform)( this_mapping, in, forward, out, status );
+
+/* We will now extend the parent astTransform method by performing the
+ calculations needed to generate the output coordinate values. */
+
+/* First use the encapsulated FrameSet in the parent Region structure to
+ transform the supplied positions from the current Frame in the
+ encapsulated FrameSet (the Frame represented by the CmpRegion), to the
+ base Frame (the Frame in which the component Regions are defined). Note,
+ the returned pointer may be a clone of the "in" pointer, and so we
+ must be carefull not to modify the contents of the returned PointSet. */
+ pset_tmp = astRegTransform( this, in, 0, NULL, NULL );
+
+/* Now transform this PointSet using each of the two component Regions in
+ turn. */
+ ps1 = astTransform( reg1, pset_tmp, 0, NULL );
+ ps2 = astTransform( reg2, pset_tmp, 0, NULL );
+
+/* Determine the numbers of points and coordinates per point for these base
+ Frame PointSets and obtain pointers for accessing the base Frame and output
+ coordinate values. */
+ npoint = astGetNpoint( pset_tmp );
+ ncoord_tmp = astGetNcoord( pset_tmp );
+ ptr1 = astGetPoints( ps1 );
+ ptr2 = astGetPoints( ps2 );
+ ncoord_out = astGetNcoord( result );
+ ptr_out = astGetPoints( result );
+
+/* Perform coordinate arithmetic. */
+/* ------------------------------ */
+ if ( astOK ) {
+
+/* First deal with ANDed Regions */
+ if( oper == AST__AND ) {
+ for ( point = 0; point < npoint; point++ ) {
+ good = 0;
+
+ for ( coord = 0; coord < ncoord_tmp; coord++ ) {
+ if( ptr1[ coord ][ point ] != AST__BAD &&
+ ptr2[ coord ][ point ] != AST__BAD ) {
+ good = 1;
+ break;
+ }
+ }
+
+ if( !good ) {
+ for ( coord = 0; coord < ncoord_out; coord++ ) {
+ ptr_out[ coord ][ point ] = AST__BAD;
+ }
+ }
+ }
+
+/* Now deal with ORed Regions */
+ } else if( oper == AST__OR ) {
+ for ( point = 0; point < npoint; point++ ) {
+ good = 0;
+
+ for ( coord = 0; coord < ncoord_tmp; coord++ ) {
+ if( ptr1[ coord ][ point ] != AST__BAD ||
+ ptr2[ coord ][ point ] != AST__BAD ) {
+ good = 1;
+ break;
+ }
+ }
+
+ if( !good ) {
+ for ( coord = 0; coord < ncoord_out; coord++ ) {
+ ptr_out[ coord ][ point ] = AST__BAD;
+ }
+ }
+ }
+
+/* Report error for any unknown operator. */
+ } else if( astOK ) {
+ astError( AST__INTER, "astTransform(%s): The %s refers to an unknown "
+ "boolean operator with identifier %d (internal AST "
+ "programming error).", status, astGetClass( this ),
+ astGetClass( this ), oper );
+ }
+ }
+
+/* Free resources. */
+ reg1 = astAnnul( reg1 );
+ reg2 = astAnnul( reg2 );
+ ps1 = astAnnul( ps1 );
+ ps2 = astAnnul( ps2 );
+ pset_tmp = astAnnul( pset_tmp );
+
+/* If an error occurred, clean up by deleting the output PointSet (if
+ allocated by this function) and setting a NULL result pointer. */
+ if ( !astOK ) {
+ if ( !out ) result = astDelete( result );
+ result = NULL;
+ }
+
+/* Return a pointer to the output PointSet. */
+ return result;
+}
+
+static void XORCheck( AstCmpRegion *this, int *status ) {
+/*
+* Name:
+* XORCheck
+
+* Purpose:
+* Check if the supplied CmpRegion represents an XOR operation.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* void XORCheck( AstCmpRegion *this, int *status )
+
+* Class Membership:
+* CmpRegion method
+
+* Decription:
+* This function analyses the component Regions within the supplied
+* CmpRegion to see if the CmpRegion is equivalent to an XOR operation
+* on two other Regions. If it is, teh Regions that are XORed are
+* stored in the supplied CmpRegion.
+
+* Parameters:
+* this
+* Pointer to the CmpRegion.
+
+*/
+
+/* Local Variables: */
+ AstCmpRegion *cmpreg1;
+ AstCmpRegion *cmpreg2;
+ int xor;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* If the CmpRegion is already known to be an XOR operation, return
+ without action. */
+ if( this->xor1 ) return;
+
+/* To be equivalent to an XOR operation, the supplied CmpRegion must be an
+ OR operation and each component Region must be a CmpRegion. */
+ if( this->oper == AST__OR && astIsACmpRegion( this->region1 )
+ && astIsACmpRegion( this->region2 ) ) {
+ cmpreg1 = (AstCmpRegion *) this->region1;
+ cmpreg2 = (AstCmpRegion *) this->region2;
+
+/* Each component CmpRegion must be an AND operation. */
+ if( cmpreg1->oper == AST__AND && cmpreg2->oper == AST__AND ) {
+
+/* Temporarily negate the first component of the first CmpRegion. */
+ astNegate( cmpreg1->region1 );
+
+/* Initially, assume the supplied CmpRegion is not equivalent to an XOR
+ operation. */
+ xor = 0;
+
+/* This negated region must be equal to one of the two component Regions
+ in the second component CmpRegion. Check the first. */
+ if( astEqual( cmpreg1->region1, cmpreg2->region1 ) ) {
+
+/* We now check that the other two Regions are equal (after negating the
+ first). If so, set "xor" non-zero. */
+ astNegate( cmpreg1->region2 );
+ if( astEqual( cmpreg1->region2, cmpreg2->region2 ) ) xor = 1;
+ astNegate( cmpreg1->region2 );
+
+/* Do equiovalent checks the other way round. */
+ } else if( astEqual( cmpreg1->region1, cmpreg2->region2 ) ) {
+ astNegate( cmpreg1->region2 );
+ if( astEqual( cmpreg1->region2, cmpreg2->region1 ) ) xor = 1;
+ astNegate( cmpreg1->region2 );
+ }
+
+/* Re-instate the original state of the Negated attribute in the first
+ component of the first CmpRegion. */
+ astNegate( cmpreg1->region1 );
+
+/* If the supplied CmpRegion is equivalent to an XOR operation, store
+ copies of the components in the supplied CmpRegion. */
+ if( xor ) {
+ this->xor1 = astCopy( cmpreg1->region1 );
+ this->xor2 = astCopy( cmpreg1->region2 );
+
+/* We need to negate one of these two Region (it doesn't matter which),
+ and we choose to negate which ever of them is already negated (so that
+ it becomes un-negated). */
+ if( astGetNegated( this->xor1 ) ) {
+ astNegate( this->xor1 );
+ } else {
+ astNegate( this->xor2 );
+ }
+ }
+ }
+ }
+}
+
+/* Copy constructor. */
+/* ----------------- */
+static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
+/*
+* Name:
+* Copy
+
+* Purpose:
+* Copy constructor for CmpRegion objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Copy( const AstObject *objin, AstObject *objout, int *status )
+
+* Description:
+* This function implements the copy constructor for CmpRegion objects.
+
+* Parameters:
+* objin
+* Pointer to the object to be copied.
+* objout
+* Pointer to the object being constructed.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* void
+
+* Notes:
+* - This constructor makes a deep copy, including a copy of the component
+* Regions within the CmpRegion.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *in; /* Pointer to input CmpRegion */
+ AstCmpRegion *out; /* Pointer to output CmpRegion */
+ int i; /* Loop count */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain pointers to the input and output CmpRegions. */
+ in = (AstCmpRegion *) objin;
+ out = (AstCmpRegion *) objout;
+
+/* For safety, start by clearing any memory references in the output
+ Region that were copied from the input Region. */
+ out->region1 = NULL;
+ out->region2 = NULL;
+ out->xor1 = NULL;
+ out->xor2 = NULL;
+
+ for( i = 0; i < 2; i++ ) {
+ out->rvals[ i ] = NULL;
+ out->offs[ i ] = NULL;
+ }
+
+/* Make copies of these Regions and store pointers to them in the output
+ CmpRegion structure. */
+ out->region1 = astCopy( in->region1 );
+ out->region2 = astCopy( in->region2 );
+ if( in->xor1 ) out->xor1 = astCopy( in->xor1 );
+ if( in->xor2 ) out->xor2 = astCopy( in->xor2 );
+
+/* Copy cached arrays. */
+ for( i = 0; i < 2; i++ ) {
+ out->rvals[ i ] = astStore( NULL, in->rvals[ i ], in->nbreak[ i ]*sizeof( **in->rvals ) );
+ out->offs[ i ] = astStore( NULL, in->offs[ i ], in->nbreak[ i ]*sizeof( **in->offs ) );
+ }
+}
+
+/* Destructor. */
+/* ----------- */
+static void Delete( AstObject *obj, int *status ) {
+/*
+* Name:
+* Delete
+
+* Purpose:
+* Destructor for CmpRegion objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Delete( AstObject *obj, int *status )
+
+* Description:
+* This function implements the destructor for CmpRegion objects.
+
+* Parameters:
+* obj
+* Pointer to the object to be deleted.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* void
+
+* Notes:
+* This function attempts to execute even if the global error status is
+* set.
+*/
+
+/* Local Variables: */
+ AstCmpRegion *this; /* Pointer to CmpRegion */
+ int i;
+
+/* Obtain a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) obj;
+
+/* Free arrays holding cached information. */
+ for( i = 0; i < 2; i++ ) {
+ this->rvals[ i ] = astFree( this->rvals[ i ] );
+ this->offs[ i ] = astFree( this->offs[ i ] );
+ }
+
+/* Annul the pointers to the component Regions. */
+ this->region1 = astAnnul( this->region1 );
+ this->region2 = astAnnul( this->region2 );
+ if( this->xor1 ) this->xor1 = astAnnul( this->xor1 );
+ if( this->xor2 ) this->xor2 = astAnnul( this->xor2 );
+}
+
+/* Dump function. */
+/* -------------- */
+static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
+/*
+* Name:
+* Dump
+
+* Purpose:
+* Dump function for CmpRegion objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Dump( AstObject *this, AstChannel *channel, int *status )
+
+* Description:
+* This function implements the Dump function which writes out data
+* for the CmpRegion class to an output Channel.
+
+* Parameters:
+* this
+* Pointer to the CmpRegion whose data are being written.
+* channel
+* Pointer to the Channel to which the data are being written.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstRegion *reg1; /* First Region to include in dump */
+ AstRegion *reg2; /* Second Region to include in dump */
+ AstCmpRegion *this; /* Pointer to the CmpRegion structure */
+ const char *comment; /* Pointer to comment string */
+ int ival; /* Integer value */
+ int oper; /* The operator to include in the dump */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the CmpRegion structure. */
+ this = (AstCmpRegion *) this_object;
+
+/* Check if this CmpRegion has an equivalent XOR representation. Is so,
+ store details of the XOR representation in the CmpRegion. */
+ XORCheck( this, status );
+
+/* Choose the operator and component regions to include in the dump. If
+ the CmpRegion originally used an XOR operator, then save the XORed
+ regions. Otherwise, store the real component Regions. */
+ if( this->xor1 ) {
+ oper = AST__XOR;
+ reg1 = this->xor1;
+ reg2 = this->xor2;
+ } else {
+ oper = this->oper;
+ reg1 = this->region1;
+ reg2 = this->region2;
+ }
+
+/* Write out values representing the instance variables for the CmpRegion
+ class. Accompany these with appropriate comment strings, possibly
+ depending on the values being written.*/
+
+/* In the case of attributes, we first use the appropriate (private)
+ Test... member function to see if they are set. If so, we then use
+ the (private) Get... function to obtain the value to be written
+ out.
+
+ For attributes which are not set, we use the astGet... method to
+ obtain the value instead. This will supply a default value
+ (possibly provided by a derived class which over-rides this method)
+ which is more useful to a human reader as it corresponds to the
+ actual default attribute value. Since "set" will be zero, these
+ values are for information only and will not be read back. */
+
+/* Oper */
+/* ------- */
+ ival = oper;
+ if( ival == AST__AND ) {
+ comment = "Regions combined using Boolean AND";
+ } else if( ival == AST__OR ) {
+ comment = "Regions combined using Boolean OR";
+ } else if( ival == AST__XOR ) {
+ comment = "Regions combined using Boolean XOR";
+ } else {
+ comment = "Regions combined using unknown operator";
+ }
+ astWriteInt( channel, "Operator", 1, 0, ival, comment );
+
+/* First Region. */
+/* -------------- */
+ astWriteObject( channel, "RegionA", 1, 1, reg1,
+ "First component Region" );
+
+/* Second Region. */
+/* --------------- */
+ astWriteObject( channel, "RegionB", 1, 1, reg2,
+ "Second component Region" );
+}
+
+/* Standard class functions. */
+/* ========================= */
+/* Implement the astIsACmpRegion and astCheckCmpRegion functions using the
+ macros defined for this purpose in the "object.h" header file. */
+astMAKE_ISA(CmpRegion,Region)
+astMAKE_CHECK(CmpRegion)
+
+AstCmpRegion *astCmpRegion_( void *region1_void, void *region2_void, int oper,
+ const char *options, int *status, ...) {
+/*
+*+
+* Name:
+* astCmpRegion
+
+* Purpose:
+* Create a CmpRegion.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* AstCmpRegion *astCmpRegion( AstRegion *region1, AstRegion *region2,
+* int oper, const char *options, ..., int *status )
+
+* Class Membership:
+* CmpRegion constructor.
+
+* Description:
+* This function creates a new CmpRegion and optionally initialises its
+* attributes.
+
+* Parameters:
+* region1
+* Pointer to the first Region.
+* region2
+* Pointer to the second Region.
+* oper
+* The boolean operator with which to combine the two Regions. Either
+* AST__AND or AST__OR.
+* options
+* Pointer to a null terminated string containing an optional
+* comma-separated list of attribute assignments to be used for
+* initialising the new CmpRegion. The syntax used is the same as for the
+* astSet method and may include "printf" format specifiers identified
+* by "%" symbols in the normal way.
+* status
+* Pointer to the inherited status variable.
+* ...
+* If the "options" string contains "%" format specifiers, then an
+* optional list of arguments may follow it in order to supply values to
+* be substituted for these specifiers. The rules for supplying these
+* are identical to those for the astSet method (and for the C "printf"
+* function).
+
+* Returned Value:
+* A pointer to the new CmpRegion.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+
+* Implementation Notes:
+* - This function implements the basic CmpRegion constructor which is
+* available via the protected interface to the CmpRegion class. A
+* public interface is provided by the astCmpRegionId_ function.
+* - Because this function has a variable argument list, it is
+* invoked by a macro that evaluates to a function pointer (not a
+* function invocation) and no checking or casting of arguments is
+* performed before the function is invoked. Because of this, the
+* "region1" and "region2" parameters are of type (void *) and are
+* converted and validated within the function itself.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstCmpRegion *new; /* Pointer to new CmpRegion */
+ AstRegion *region1; /* Pointer to first Region structure */
+ AstRegion *region2; /* Pointer to second Region structure */
+ va_list args; /* Variable argument list */
+
+/* Initialise. */
+ new = NULL;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Check the global status. */
+ if ( !astOK ) return new;
+
+/* Obtain and validate pointers to the Region structures provided. */
+ region1 = astCheckRegion( region1_void );
+ region2 = astCheckRegion( region2_void );
+ if ( astOK ) {
+
+/* Initialise the CmpRegion, allocating memory and initialising the
+ virtual function table as well if necessary. */
+ new = astInitCmpRegion( NULL, sizeof( AstCmpRegion ), !class_init,
+ &class_vtab, "CmpRegion", region1, region2,
+ oper );
+
+/* If successful, note that the virtual function table has been
+ initialised. */
+ if ( astOK ) {
+ class_init = 1;
+
+/* Obtain the variable argument list and pass it along with the
+ options string to the astVSet method to initialise the new CmpRegion's
+ attributes. */
+ va_start( args, status );
+ astVSet( new, options, NULL, args );
+ va_end( args );
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+ }
+
+/* Return a pointer to the new CmpRegion. */
+ return new;
+}
+
+AstCmpRegion *astCmpRegionId_( void *region1_void, void *region2_void,
+ int oper, const char *options, ... ) {
+/*
+*++
+* Name:
+c astCmpRegion
+f AST_CMPREGION
+
+* Purpose:
+* Create a CmpRegion.
+
+* Type:
+* Public function.
+
+* Synopsis:
+c #include "cmpregion.h"
+c AstCmpRegion *astCmpRegion( AstRegion *region1, AstRegion *region2,
+c int oper, const char *options, ... )
+f RESULT = AST_CMPREGION( REGION1, REGION2, OPER, OPTIONS, STATUS )
+
+* Class Membership:
+* CmpRegion constructor.
+
+* Description:
+* This function creates a new CmpRegion and optionally initialises
+* its attributes.
+*
+* A CmpRegion is a Region which allows two component
+* Regions (of any class) to be combined to form a more complex
+* Region. This combination may be performed a boolean AND, OR
+* or XOR (exclusive OR) operator. If the AND operator is
+* used, then a position is inside the CmpRegion only if it is
+* inside both of its two component Regions. If the OR operator is
+* used, then a position is inside the CmpRegion if it is inside
+* either (or both) of its two component Regions. If the XOR operator
+* is used, then a position is inside the CmpRegion if it is inside
+* one but not both of its two component Regions. Other operators can
+* be formed by negating one or both component Regions before using
+* them to construct a new CmpRegion.
+*
+* The two component Region need not refer to the same coordinate
+* Frame, but it must be possible for the
+c astConvert
+f AST_CONVERT
+* function to determine a Mapping between them (an error will be
+* reported otherwise when the CmpRegion is created). For instance,
+* a CmpRegion may combine a Region defined within an ICRS SkyFrame
+* with a Region defined within a Galactic SkyFrame. This is
+* acceptable because the SkyFrame class knows how to convert between
+* these two systems, and consequently the
+c astConvert
+f AST_CONVERT
+* function will also be able to convert between them. In such cases,
+* the second component Region will be mapped into the coordinate Frame
+* of the first component Region, and the Frame represented by the
+* CmpRegion as a whole will be the Frame of the first component Region.
+*
+* Since a CmpRegion is itself a Region, it can be used as a
+* component in forming further CmpRegions. Regions of arbitrary
+* complexity may be built from simple individual Regions in this
+* way.
+
+* Parameters:
+c region1
+f REGION1 = INTEGER (Given)
+* Pointer to the first component Region.
+c region2
+f REGION2 = INTEGER (Given)
+* Pointer to the second component Region. This Region will be
+* transformed into the coordinate Frame of the first region before
+* use. An error will be reported if this is not possible.
+c oper
+f OPER = INTEGER (Given)
+* The boolean operator with which to combine the two Regions. This
+* must be one of the symbolic constants AST__AND, AST__OR or AST__XOR.
+c options
+f OPTIONS = CHARACTER * ( * ) (Given)
+c Pointer to a null-terminated string containing an optional
+c comma-separated list of attribute assignments to be used for
+c initialising the new CmpRegion. The syntax used is identical to
+c that for the astSet function and may include "printf" format
+c specifiers identified by "%" symbols in the normal way.
+f A character string containing an optional comma-separated
+f list of attribute assignments to be used for initialising the
+f new CmpRegion. The syntax used is identical to that for the
+f AST_SET routine.
+c ...
+c If the "options" string contains "%" format specifiers, then
+c an optional list of additional arguments may follow it in
+c order to supply values to be substituted for these
+c specifiers. The rules for supplying these are identical to
+c those for the astSet function (and for the C "printf"
+c function).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astCmpRegion()
+f AST_CMPREGION = INTEGER
+* A pointer to the new CmpRegion.
+
+* Notes:
+* - If one of the supplied Regions has an associated uncertainty,
+* that uncertainty will also be used for the returned CmpRegion.
+* If both supplied Regions have associated uncertainties, the
+* uncertainty associated with the first Region will be used for the
+* returned CmpRegion.
+* - Deep copies are taken of the supplied Regions. This means that
+* any subsequent changes made to the component Regions using the
+* supplied pointers will have no effect on the CmpRegion.
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+*--
+
+* Implementation Notes:
+* - This function implements the external (public) interface to
+* the astCmpRegion constructor function. It returns an ID value
+* (instead of a true C pointer) to external users, and must be
+* provided because astCmpRegion_ has a variable argument list which
+* cannot be encapsulated in a macro (where this conversion would
+* otherwise occur).
+* - Because no checking or casting of arguments is performed
+* before the function is invoked, the "region1" and "region2" parameters
+* are of type (void *) and are converted from an ID value to a
+* pointer and validated within the function itself.
+* - The variable argument list also prevents this function from
+* invoking astCmpRegion_ directly, so it must be a re-implementation
+* of it in all respects, except for the conversions between IDs
+* and pointers on input/output of Objects.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstCmpRegion *new; /* Pointer to new CmpRegion */
+ AstRegion *region1; /* Pointer to first Region structure */
+ AstRegion *region2; /* Pointer to second Region structure */
+ va_list args; /* Variable argument list */
+
+ int *status; /* Pointer to inherited status value */
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Initialise. */
+ new = NULL;
+
+/* Get a pointer to the inherited status value. */
+ status = astGetStatusPtr;
+
+/* Check the global status. */
+ if ( !astOK ) return new;
+
+/* Obtain the Region pointers from the ID's supplied and validate the
+ pointers to ensure they identify valid Regions. */
+ region1 = astVerifyRegion( astMakePointer( region1_void ) );
+ region2 = astVerifyRegion( astMakePointer( region2_void ) );
+ if ( astOK ) {
+
+/* Initialise the CmpRegion, allocating memory and initialising the
+ virtual function table as well if necessary. */
+ new = astInitCmpRegion( NULL, sizeof( AstCmpRegion ), !class_init,
+ &class_vtab, "CmpRegion", region1, region2,
+ oper );
+
+/* If successful, note that the virtual function table has been initialised. */
+ if ( astOK ) {
+ class_init = 1;
+
+/* Obtain the variable argument list and pass it along with the
+ options string to the astVSet method to initialise the new CmpRegion's
+ attributes. */
+ va_start( args, options );
+ astVSet( new, options, NULL, args );
+ va_end( args );
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+ }
+
+/* Return an ID value for the new CmpRegion. */
+ return astMakeId( new );
+}
+
+AstCmpRegion *astInitCmpRegion_( void *mem, size_t size, int init,
+ AstCmpRegionVtab *vtab, const char *name,
+ AstRegion *region1, AstRegion *region2,
+ int oper, int *status ) {
+/*
+*+
+* Name:
+* astInitCmpRegion
+
+* Purpose:
+* Initialise a CmpRegion.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* AstCmpRegion *astInitCmpRegion_( void *mem, size_t size, int init,
+* AstCmpRegionVtab *vtab, const char *name,
+* AstRegion *region1, AstRegion *region2,
+* int oper )
+
+* Class Membership:
+* CmpRegion initialiser.
+
+* Description:
+* This function is provided for use by class implementations to initialise
+* a new CmpRegion object. It allocates memory (if necessary) to
+* accommodate the CmpRegion plus any additional data associated with the
+* derived class. It then initialises a CmpRegion structure at the start
+* of this memory. If the "init" flag is set, it also initialises the
+* contents of a virtual function table for a CmpRegion at the start of
+* the memory passed via the "vtab" parameter.
+
+* Parameters:
+* mem
+* A pointer to the memory in which the CmpRegion is to be initialised.
+* This must be of sufficient size to accommodate the CmpRegion data
+* (sizeof(CmpRegion)) plus any data used by the derived class. If a
+* value of NULL is given, this function will allocate the memory itself
+* using the "size" parameter to determine its size.
+* size
+* The amount of memory used by the CmpRegion (plus derived class
+* data). This will be used to allocate memory if a value of NULL is
+* given for the "mem" parameter. This value is also stored in the
+* CmpRegion structure, so a valid value must be supplied even if not
+* required for allocating memory.
+* init
+* A logical flag indicating if the CmpRegion's virtual function table
+* is to be initialised. If this value is non-zero, the virtual function
+* table will be initialised by this function.
+* vtab
+* Pointer to the start of the virtual function table to be associated
+* with the new CmpRegion.
+* name
+* Pointer to a constant null-terminated character string which contains
+* the name of the class to which the new object belongs (it is this
+* pointer value that will subsequently be returned by the Object
+* astClass function).
+* region1
+* Pointer to the first Region.
+* region2
+* Pointer to the second Region.
+* oper
+* The boolean operator to use. Must be one of AST__AND, AST__OR or
+* AST__XOR.
+
+* Returned Value:
+* A pointer to the new CmpRegion.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstCmpRegion *new; /* Pointer to new CmpRegion */
+ AstFrame *frm; /* Frame encapsulated by first Region */
+ AstFrameSet *fs; /* FrameSet connecting supplied Regions */
+ AstMapping *map; /* Mapping between two supplied Regions */
+ AstMapping *smap; /* Simplified Mapping between two supplied Regions */
+ AstRegion *new_reg1; /* Replacement for first region */
+ AstRegion *new_reg2; /* Replacement for second region */
+ AstRegion *reg1; /* First Region to store in the CmpRegion */
+ AstRegion *reg2; /* Second Region to store in the CmpRegion */
+ AstRegion *xor1; /* Copy of first supplied Region or NULL */
+ AstRegion *xor2; /* Copy of second supplied Region or NULL */
+ int i; /* Loop count */
+ int used_oper; /* The boolean operation actually used */
+
+/* Check the global status. */
+ if ( !astOK ) return NULL;
+
+/* If necessary, initialise the virtual function table. */
+ if ( init ) astInitCmpRegionVtab( vtab, name );
+
+/* Initialise. */
+ new = NULL;
+
+/* Check the supplied oper value. */
+ if( oper != AST__AND && oper != AST__OR && oper != AST__XOR && astOK ) {
+ astError( AST__INTRD, "astInitCmpRegion(%s): Illegal "
+ "boolean operator value (%d) supplied.", status, name, oper );
+ }
+
+/* Take copies of the supplied Regions. */
+ reg1 = astCopy( region1 );
+ reg2 = astCopy( region2 );
+
+/* Get the Mapping from the second to the first Region. */
+ fs = astConvert( reg2, reg1, "" );
+
+/* Report an error if not possible. */
+ if( fs == NULL ) {
+ frm = NULL;
+ if( astOK ) astError( AST__INTRD, "astInitCmpRegion(%s): No Mapping can "
+ "be found between the two supplied Regions.", status, name );
+
+/* Otherwise, map the second Region into the Frame of the first (unless
+ they are already in the same Frame). This results in both component
+ Frames having the same current Frame. This current Frame is used as the
+ encapsulated Frame within the parent Region structure. */
+ } else {
+ frm = astGetFrame( fs, AST__CURRENT );
+ map = astGetMapping( fs, AST__BASE, AST__CURRENT );
+ smap = astSimplify( map );
+ if( !astIsAUnitMap( smap ) ) {
+ new_reg2 = astMapRegion( reg2, smap, frm );
+ (void) astAnnul( reg2 );
+ reg2 = new_reg2;
+ }
+ smap = astAnnul( smap );
+ map = astAnnul( map );
+ fs = astAnnul( fs );
+ }
+
+/* The CmpRegion class does not implement XOR directly (as it does for
+ AND and OR). Instead, when requested to create an XOR CmpRegion, it
+ creates a CmpRegion that uses AND and OR to simulate XOR. The top
+ level XOR CmpRegion actually uses AST__OR and the two component
+ regions within it are CmpRegions formed by combing the two supplied
+ Regions (one being negated first) using AND. Create the required
+ component Regions. */
+ if( oper == AST__XOR ) {
+ astNegate( reg1 );
+ new_reg1 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND, " ",
+ status );
+ astNegate( reg1 );
+
+ astNegate( reg2 );
+ new_reg2 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND, " ",
+ status );
+ astNegate( reg2 );
+
+ xor1 = reg1;
+ xor2 = reg2;
+
+ reg1 = new_reg1;
+ reg2 = new_reg2;
+
+ used_oper = AST__OR;
+
+/* For AND and OR, use the supplied operator. */
+ } else {
+ xor1 = NULL;
+ xor2 = NULL;
+ used_oper = oper;
+ }
+
+/* Initialise a Region structure (the parent class) as the first component
+ within the CmpRegion structure, allocating memory if necessary. A NULL
+ PointSet is suppled as the two component Regions will perform the function
+ of defining the Region shape. The base Frame of the FrameSet in the
+ parent Region structure will be the same as the current Frames of the
+ FrameSets in the two component Regions. */
+ if ( astOK ) {
+ new = (AstCmpRegion *) astInitRegion( mem, size, 0,
+ (AstRegionVtab *) vtab, name,
+ frm, NULL, NULL );
+
+/* Initialise the CmpRegion data. */
+/* --------------------------- */
+/* Store pointers to the component Regions. */
+ new->region1 = astClone( reg1 );
+ new->region2 = astClone( reg2 );
+
+/* Note the operator used to combine the somponent Regions. */
+ new->oper = used_oper;
+
+/* If we are creating an XOR CmpRegion, save copies of the supplied
+ Regions (i.e. the supplied Regions which are XORed). These will not
+ be the same as "reg1" and "reg2" since each of those two regions will
+ be CmpRegions that combine the supplied Regions using AST__AND. */
+ if( oper == AST__XOR ) {
+ new->xor1 = xor1;
+ new->xor2 = xor2;
+ } else {
+ new->xor1 = NULL;
+ new->xor2 = NULL;
+ }
+
+/* Initialised cached values to show they have not yet been found. */
+ for( i = 0; i < 2; i++ ) {
+ new->rvals[ i ] = NULL;
+ new->offs[ i ] = NULL;
+ new->nbreak[ i ] = 0;
+ new->d0[ i ] = AST__BAD;
+ new->dtot[ i ] = AST__BAD;
+ }
+ new->bounded = -INT_MAX;
+
+/* If the base->current Mapping in the FrameSet within each component Region
+ is a UnitMap, then the FrameSet does not need to be included in the
+ Dump of the new CmpRegion. Set the RegionFS attribute of the component
+ Region to zero to flag this. */
+ map = astGetMapping( reg1->frameset, AST__BASE, AST__CURRENT );
+ if( astIsAUnitMap( map ) ) astSetRegionFS( reg1, 0 );
+ map = astAnnul( map );
+
+ map = astGetMapping( reg2->frameset, AST__BASE, AST__CURRENT );
+ if( astIsAUnitMap( map ) ) astSetRegionFS( reg2, 0 );
+ map = astAnnul( map );
+
+/* Copy attribute values from the first component Region to the parent
+ Region. */
+ if( astTestMeshSize( new->region1 ) ) {
+ astSetMeshSize( new, astGetMeshSize( new->region1 ) );
+ }
+ if( astTestClosed( new->region1 ) ) {
+ astSetClosed( new, astGetClosed( new->region1 ) );
+ }
+
+/* If an error occurred, clean up by annulling the Region pointers and
+ deleting the new object. */
+ if ( !astOK ) {
+ new->region1 = astAnnul( new->region1 );
+ new->region2 = astAnnul( new->region2 );
+ new = astDelete( new );
+ }
+ }
+
+/* Free resources */
+ reg1 = astAnnul( reg1 );
+ reg2 = astAnnul( reg2 );
+ if( frm ) frm = astAnnul( frm );
+
+/* Return a pointer to the new object. */
+ return new;
+}
+
+AstCmpRegion *astLoadCmpRegion_( void *mem, size_t size,
+ AstCmpRegionVtab *vtab, const char *name,
+ AstChannel *channel, int *status ) {
+/*
+*+
+* Name:
+* astLoadCmpRegion
+
+* Purpose:
+* Load a CmpRegion.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "cmpregion.h"
+* AstCmpRegion *astLoadCmpRegion( void *mem, size_t size,
+* AstCmpRegionVtab *vtab, const char *name,
+* AstChannel *channel )
+
+* Class Membership:
+* CmpRegion loader.
+
+* Description:
+* This function is provided to load a new CmpRegion using data read
+* from a Channel. It first loads the data used by the parent class
+* (which allocates memory if necessary) and then initialises a
+* CmpRegion structure in this memory, using data read from the input
+* Channel.
+*
+* If the "init" flag is set, it also initialises the contents of a
+* virtual function table for a CmpRegion at the start of the memory
+* passed via the "vtab" parameter.
+
+
+* Parameters:
+* mem
+* A pointer to the memory into which the CmpRegion is to be
+* loaded. This must be of sufficient size to accommodate the
+* CmpRegion data (sizeof(CmpRegion)) plus any data used by derived
+* classes. If a value of NULL is given, this function will
+* allocate the memory itself using the "size" parameter to
+* determine its size.
+* size
+* The amount of memory used by the CmpRegion (plus derived class
+* data). This will be used to allocate memory if a value of
+* NULL is given for the "mem" parameter. This value is also
+* stored in the CmpRegion structure, so a valid value must be
+* supplied even if not required for allocating memory.
+*
+* If the "vtab" parameter is NULL, the "size" value is ignored
+* and sizeof(AstCmpRegion) is used instead.
+* vtab
+* Pointer to the start of the virtual function table to be
+* associated with the new CmpRegion. If this is NULL, a pointer to
+* the (static) virtual function table for the CmpRegion class is
+* used instead.
+* name
+* Pointer to a constant null-terminated character string which
+* contains the name of the class to which the new object
+* belongs (it is this pointer value that will subsequently be
+* returned by the astGetClass method).
+*
+* If the "vtab" parameter is NULL, the "name" value is ignored
+* and a pointer to the string "CmpRegion" is used instead.
+
+* Returned Value:
+* A pointer to the new CmpRegion.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ AstCmpRegion *new; /* Pointer to the new CmpRegion */
+ AstRegion *reg1; /* First Region read from dump */
+ AstRegion *reg2; /* Second Region read from dump */
+ AstFrame *f1; /* Base Frame in parent Region */
+ AstRegion *creg; /* Pointer to component Region */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ int i; /* Loop count */
+ int oper; /* The operator to include in the dump */
+
+/* Initialise. */
+ new = NULL;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(channel);
+
+/* Check the global error status. */
+ if ( !astOK ) return new;
+
+/* If a NULL virtual function table has been supplied, then this is
+ the first loader to be invoked for this CmpRegion. In this case the
+ CmpRegion belongs to this class, so supply appropriate values to be
+ passed to the parent class loader (and its parent, etc.). */
+ if ( !vtab ) {
+ size = sizeof( AstCmpRegion );
+ vtab = &class_vtab;
+ name = "CmpRegion";
+
+/* If required, initialise the virtual function table for this class. */
+ if ( !class_init ) {
+ astInitCmpRegionVtab( vtab, name );
+ class_init = 1;
+ }
+ }
+
+/* Invoke the parent class loader to load data for all the ancestral
+ classes of the current one, returning a pointer to the resulting
+ partly-built CmpRegion. */
+ new = astLoadRegion( mem, size, (AstRegionVtab *) vtab, name,
+ channel );
+
+ if ( astOK ) {
+
+/* Read input data. */
+/* ================ */
+/* Request the input Channel to read all the input data appropriate to
+ this class into the internal "values list". */
+ astReadClassData( channel, "CmpRegion" );
+
+/* Now read each individual data item from this list and use it to
+ initialise the appropriate instance variable(s) for this class. */
+
+/* In the case of attributes, we first read the "raw" input value,
+ supplying the "unset" value as the default. If a "set" value is
+ obtained, we then use the appropriate (private) Set... member
+ function to validate and set the value properly. */
+
+/* Operator */
+/* -------- */
+ oper = astReadInt( channel, "operator", AST__AND );
+
+/* First Region. */
+/* -------------- */
+ reg1 = astReadObject( channel, "regiona", NULL );
+
+/* Second Region. */
+/* --------------- */
+ reg2 = astReadObject( channel, "regionb", NULL );
+
+/* Initialised cached values to show they have not yet been found. */
+ for( i = 0; i < 2; i++ ) {
+ new->rvals[ i ] = NULL;
+ new->offs[ i ] = NULL;
+ new->nbreak[ i ] = 0;
+ new->d0[ i ] = AST__BAD;
+ new->dtot[ i ] = AST__BAD;
+ }
+ new->bounded = -INT_MAX;
+
+/* The CmpRegion class does not implement XOR directly (as it does for
+ AND and OR). Instead, when requested to create an XOR CmpRegion, it
+ creates a CmpRegion that uses AND and OR to simulate XOR. The top
+ level XOR CmpRegion actually uses AST__OR and the two component
+ regions within it are CmpRegions formed by combing the two supplied
+ Regions (one being negated first) using AND. Create the required
+ component Regions. */
+ if( oper == AST__XOR ) {
+ astNegate( reg1 );
+ new->region1 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND,
+ " ", status );
+ astNegate( reg1 );
+
+ astNegate( reg2 );
+ new->region2 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND,
+ " ", status );
+ astNegate( reg2 );
+
+ new->xor1 = reg1;
+ new->xor2 = reg2;
+
+ new->oper = AST__OR;
+
+/* For AND and OR, use the supplied Regions and operator. */
+ } else {
+ new->region1 = reg1;
+ new->region2 = reg2;
+ new->xor1 = NULL;
+ new->xor2 = NULL;
+ new->oper = oper;
+ }
+
+/* If either component Region has a dummy FrameSet rather than the correct
+ FrameSet, the correct FrameSet will have copies of the base Frame of the
+ new CmpRegion as both its current and base Frames, connected by a UnitMap
+ (this is equivalent to a FrameSet containing a single Frame). However if
+ the new CmpRegion being loaded has itself got a dummy FrameSet, then we do
+ not do this since we do not yet know what the correct FrameSet is. In this
+ case we wait until the parent Region invokes the astSetRegFS method on the
+ new CmpRegion. */
+ if( !astRegDummyFS( new ) ) {
+ f1 = astGetFrame( ((AstRegion *) new)->frameset, AST__BASE );
+ creg = new->region1;
+ if( astRegDummyFS( creg ) ) astSetRegFS( creg, f1 );
+ creg = new->region2;
+ if( astRegDummyFS( creg ) ) astSetRegFS( creg, f1 );
+ f1 = astAnnul( f1 );
+ }
+
+/* If an error occurred, clean up by deleting the new CmpRegion. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return the new CmpRegion pointer. */
+ return new;
+}
+
+/* Virtual function interfaces. */
+/* ============================ */
+/* These provide the external interface to the virtual functions defined by
+ this class. Each simply checks the global error status and then locates and
+ executes the appropriate member function, using the function pointer stored
+ in the object's virtual function table (this pointer is located using the
+ astMEMBER macro defined in "object.h").
+
+ Note that the member function may not be the one defined here, as it may
+ have been over-ridden by a derived class. However, it should still have the
+ same interface. */
+
+int astCmpRegionList_( AstCmpRegion *this, int *nreg, AstRegion ***reg_list,
+ int *status ) {
+ if ( !astOK ) return AST__AND;
+ return (**astMEMBER(this,CmpRegion,CmpRegionList))( this, nreg, reg_list,
+ status );
+}
+
+
+
+
+
+