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