summaryrefslogtreecommitdiffstats
path: root/ast/polygon.c
diff options
context:
space:
mode:
Diffstat (limited to 'ast/polygon.c')
-rw-r--r--ast/polygon.c7087
1 files changed, 0 insertions, 7087 deletions
diff --git a/ast/polygon.c b/ast/polygon.c
deleted file mode 100644
index 1dfae39..0000000
--- a/ast/polygon.c
+++ /dev/null
@@ -1,7087 +0,0 @@
-/*
-*class++
-* Name:
-* Polygon
-
-* Purpose:
-* A polygonal region within a 2-dimensional Frame.
-
-* Constructor Function:
-c astPolygon
-f AST_POLYGON
-
-* Description:
-* The Polygon class implements a polygonal area, defined by a
-* collection of vertices, within a 2-dimensional Frame. The vertices
-* are connected together by geodesic curves within the encapsulated Frame.
-* For instance, if the encapsulated Frame is a simple Frame then the
-* geodesics will be straight lines, but if the Frame is a SkyFrame then
-* the geodesics will be great circles. Note, the vertices must be
-* supplied in an order such that the inside of the polygon is to the
-* left of the boundary as the vertices are traversed. Supplying them
-* in the reverse order will effectively negate the polygon.
-*
-* Within a SkyFrame, neighbouring vertices are always joined using the
-* shortest path. Thus if an edge of 180 degrees or more in length is
-* required, it should be split into section each of which is less
-* than 180 degrees. The closed path joining all the vertices in order
-* will divide the celestial sphere into two disjoint regions. The
-* inside of the polygon is the region which is circled in an
-* anti-clockwise manner (when viewed from the inside of the celestial
-* sphere) when moving through the list of vertices in the order in
-* which they were supplied when the Polygon was created (i.e. the
-* inside is to the left of the boundary when moving through the
-* vertices in the order supplied).
-
-* Inheritance:
-* The Polygon class inherits from the Region class.
-
-* Attributes:
-* In addition to those attributes common to all Regions, every
-* Polygon also has the following attributes:
-* - SimpVertices: Simplify by transforming the vertices?
-
-* Functions:
-c In addition to those functions applicable to all Regions, the
-c following functions may also be applied to all Polygons:
-f In addition to those routines applicable to all Regions, the
-f following routines may also be applied to all Polygons:
-*
-c - astDownsize: Reduce the number of vertices in a Polygon.
-f - AST_DOWNSIZE: Reduce the number of vertices in a Polygon.
-c - astConvex<X>: Create a Polygon giving the convex hull of a pixel array
-f - AST_CONVEX<X>: Create a Polygon giving the convex hull of a pixel array
-c - astOutline<X>: Create a Polygon outlining values in a pixel array
-f - AST_OUTLINE<X>: Create a Polygon outlining values in a pixel array
-
-* Copyright:
-* Copyright (C) 1997-2006 Council for the Central Laboratory of the
-* Research Councils
-* Copyright (C) 2009 Science & Technology Facilities Council.
-* All Rights Reserved.
-
-* Licence:
-* This program is free software: you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation, either
-* version 3 of the License, or (at your option) any later
-* version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General
-* License along with this program. If not, see
-* <http://www.gnu.org/licenses/>.
-
-* Authors:
-* DSB: David S. Berry (Starlink)
-
-* History:
-* 26-OCT-2004 (DSB):
-* Original version.
-* 28-MAY-2009 (DSB):
-* Added astDownsize.
-* 29-MAY-2009 (DSB):
-* Added astOutline<X>.
-* 30-JUN-2009 (DSB):
-* Override astGetBounded.
-* 4-NOV-2013 (DSB):
-* Modify RegPins so that it can handle uncertainty regions that straddle
-* a discontinuity. Previously, such uncertainty Regions could have a huge
-* bounding box resulting in matching region being far too big.
-* 6-DEC-2013 (DSB):
-* Reverse the order of the vertices when the Polygon is created,
-* if necessary, to ensure that the unnegated Polygon is bounded.
-* The parent Region class assumes that unnegated regions are
-* bounded.
-* 6-JAN-2014 (DSB):
-* Free edges when clearing the cache, not when establishing a new
-* cache, as the number of edges may have changed.
-* 10-JAN-2014 (DSB):
-* - Remove unused parameter description in prologue of for astOutline<X>
-* 24-FEB-2014 (DSB):
-* Added astConvex<X>.
-* 25-FEB-2014 (DSB):
-* Added attribute SimpVertices.
-* 7-SEP-2015 (DSB):
-* Shrink outline polygons by a small fraction of a pixel, in order
-* to avoid placing vertices exactly on pixel edges. This is because
-* rounding errors in subsequent code may push the vertices into
-* neighbouring pixels, which may have bad WCS coords (e.g.
-* vertices on the boundary of a polar cusp in an HPX map).
-*class--
-*/
-
-/* Module Macros. */
-/* ============== */
-/* Set the name of the class we are implementing. This indicates to
- the header files that define class interfaces that they should make
- "protected" symbols available. */
-#define astCLASS Polygon
-
-/* Define a macro for testing if a pixel value <V> satisfies the requirements
- specified by <Oper> and <Value>. Compiler optimisation should remove
- all the "if" testing from this expression. */
-#define ISVALID(V,OperI,Value) ( \
- ( OperI == AST__LT ) ? ( (V) < Value ) : ( \
- ( OperI == AST__LE ) ? ( (V) <= Value ) : ( \
- ( OperI == AST__EQ ) ? ( (V) == Value ) : ( \
- ( OperI == AST__GE ) ? ( (V) >= Value ) : ( \
- ( OperI == AST__NE ) ? ( (V) != Value ) : ( \
- (V) > Value \
- ) \
- ) \
- ) \
- ) \
- ) \
-)
-
-/* Macros specifying whether a point is inside, outside or on the
- boundary of the polygon. */
-#define UNKNOWN 0
-#define IN 1
-#define OUT 2
-#define ON 3
-
-/* Size of pertubation (in pixels) used to avoid placing vertices exactly
- on a pixel edge. */
-#define DELTA 0.01
-
-/* Include files. */
-/* ============== */
-/* Interface definitions. */
-/* ---------------------- */
-
-#include "globals.h" /* Thread-safe global data access */
-#include "error.h" /* Error reporting facilities */
-#include "memory.h" /* Memory allocation facilities */
-#include "object.h" /* Base Object class */
-#include "pointset.h" /* Sets of points/coordinates */
-#include "region.h" /* Coordinate regions (parent class) */
-#include "channel.h" /* I/O channels */
-#include "box.h" /* Box Regions */
-#include "wcsmap.h" /* Definitons of AST__DPI etc */
-#include "polygon.h" /* Interface definition for this class */
-#include "mapping.h" /* Position mappings */
-#include "unitmap.h" /* Unit Mapping */
-#include "pal.h" /* SLALIB library interface */
-#include "frame.h" /* Coordinate system description */
-
-/* Error code definitions. */
-/* ----------------------- */
-#include "ast_err.h" /* AST error codes */
-
-/* C header files. */
-/* --------------- */
-#include <float.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <limits.h>
-
-/* Type definitions. */
-/* ================= */
-
-/* A structure that holds information about an edge of the new Polygon
- being created by astDownsize. The edge is a line betweeen two of the
- vertices of the original Polygon. */
-typedef struct Segment {
- int i1; /* Index of starting vertex within old Polygon */
- int i2; /* Index of ending vertex within old Polygon */
- double error; /* Max geodesic distance from any old vertex to the line */
- int imax; /* Index of the old vertex at which max error is reached */
- struct Segment *next;/* Pointer to next Segment in a double link list */
- struct Segment *prev;/* Pointer to previous Segment in a double link list */
-} Segment;
-
-
-/* Module Variables. */
-/* ================= */
-
-/* Address of this static variable is used as a unique identifier for
- member of this class. */
-static int class_check;
-
-/* Pointers to parent class methods which are extended by this class. */
-static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
-static AstMapping *(* parent_simplify)( AstMapping *, int * );
-static void (* parent_setregfs)( AstRegion *, AstFrame *, int * );
-static void (* parent_resetcache)( AstRegion *, int * );
-static const char *(* parent_getattrib)( AstObject *, const char *, int * );
-static int (* parent_testattrib)( AstObject *, const char *, int * );
-static void (* parent_clearattrib)( AstObject *, const char *, int * );
-static void (* parent_setattrib)( AstObject *, const char *, int * );
-
-
-#ifdef THREAD_SAFE
-/* Define how to initialise thread-specific globals. */
-#define GLOBAL_inits \
- globals->Class_Init = 0; \
- globals->GetAttrib_Buff[ 0 ] = 0;
-
-/* Create the function that initialises global data for this module. */
-astMAKE_INITGLOBALS(Polygon)
-
-/* Define macros for accessing each item of thread specific global data. */
-#define class_init astGLOBAL(Polygon,Class_Init)
-#define class_vtab astGLOBAL(Polygon,Class_Vtab)
-#define getattrib_buff astGLOBAL(Polygon,GetAttrib_Buff)
-
-
-#include <pthread.h>
-
-
-#else
-
-static char getattrib_buff[ 51 ];
-
-/* Define the class virtual function table and its initialisation flag
- as static variables. */
-static AstPolygonVtab class_vtab; /* Virtual function table */
-static int class_init = 0; /* Virtual function table initialised? */
-
-#endif
-
-/* External Interface Function Prototypes. */
-/* ======================================= */
-/* The following functions have public prototypes only (i.e. no
- protected prototypes), so we must provide local prototypes for use
- within this module. */
-AstPolygon *astPolygonId_( void *, int, int, const double *, void *, const char *, ... );
-
-/* Prototypes for Private Member Functions. */
-/* ======================================== */
-
-/* Define a macro that expands to a single prototype for function
- FindInsidePoint for a given data type and operation. */
-#define FINDINSIDEPOINT_PROTO0(X,Xtype,Oper) \
-static void FindInsidePoint##Oper##X( Xtype, const Xtype *, const int[2], const int[2], int *, int *, int *, int * );
-
-/* Define a macro that expands to a set of prototypes for all operations
- for function FindInsidePoint for a given data type. */
-#define FINDINSIDEPOINT_PROTO(X,Xtype) \
-FINDINSIDEPOINT_PROTO0(X,Xtype,LT) \
-FINDINSIDEPOINT_PROTO0(X,Xtype,LE) \
-FINDINSIDEPOINT_PROTO0(X,Xtype,EQ) \
-FINDINSIDEPOINT_PROTO0(X,Xtype,GE) \
-FINDINSIDEPOINT_PROTO0(X,Xtype,GT) \
-FINDINSIDEPOINT_PROTO0(X,Xtype,NE)
-
-/* Use the above macros to define all FindInsidePoint prototypes for all
- data types and operations. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-FINDINSIDEPOINT_PROTO(LD,long double)
-#endif
-FINDINSIDEPOINT_PROTO(D,double)
-FINDINSIDEPOINT_PROTO(L,long int)
-FINDINSIDEPOINT_PROTO(UL,unsigned long int)
-FINDINSIDEPOINT_PROTO(I,int)
-FINDINSIDEPOINT_PROTO(UI,unsigned int)
-FINDINSIDEPOINT_PROTO(S,short int)
-FINDINSIDEPOINT_PROTO(US,unsigned short int)
-FINDINSIDEPOINT_PROTO(B,signed char)
-FINDINSIDEPOINT_PROTO(UB,unsigned char)
-FINDINSIDEPOINT_PROTO(F,float)
-
-/* Define a macro that expands to a single prototype for function
- TraceEdge for a given data type and operation. */
-#define TRACEEDGE_PROTO0(X,Xtype,Oper) \
-static AstPointSet *TraceEdge##Oper##X( Xtype, const Xtype *, const int[2], const int[2], int, int, int, int, int, int * );
-
-/* Define a macro that expands to a set of prototypes for all operations
- for function TraceEdge for a given data type. */
-#define TRACEEDGE_PROTO(X,Xtype) \
-TRACEEDGE_PROTO0(X,Xtype,LT) \
-TRACEEDGE_PROTO0(X,Xtype,LE) \
-TRACEEDGE_PROTO0(X,Xtype,EQ) \
-TRACEEDGE_PROTO0(X,Xtype,GE) \
-TRACEEDGE_PROTO0(X,Xtype,GT) \
-TRACEEDGE_PROTO0(X,Xtype,NE)
-
-/* Use the above macros to define all TraceEdge prototypes for all
- data types and operations. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-TRACEEDGE_PROTO(LD,long double)
-#endif
-TRACEEDGE_PROTO(D,double)
-TRACEEDGE_PROTO(L,long int)
-TRACEEDGE_PROTO(UL,unsigned long int)
-TRACEEDGE_PROTO(I,int)
-TRACEEDGE_PROTO(UI,unsigned int)
-TRACEEDGE_PROTO(S,short int)
-TRACEEDGE_PROTO(US,unsigned short int)
-TRACEEDGE_PROTO(B,signed char)
-TRACEEDGE_PROTO(UB,unsigned char)
-TRACEEDGE_PROTO(F,float)
-
-/* Define a macro that expands to a single prototype for function
- PartHull for a given data type and operation. */
-#define PARTHULL_PROTO0(X,Xtype,Oper) \
-static void PartHull##Oper##X( Xtype, const Xtype[], int, int, int, int, int, int, int, const int[2], double **, double **, int *, int * );
-
-/* Define a macro that expands to a set of prototypes for all operations
- for function PartHull for a given data type. */
-#define PARTHULL_PROTO(X,Xtype) \
-PARTHULL_PROTO0(X,Xtype,LT) \
-PARTHULL_PROTO0(X,Xtype,LE) \
-PARTHULL_PROTO0(X,Xtype,EQ) \
-PARTHULL_PROTO0(X,Xtype,GE) \
-PARTHULL_PROTO0(X,Xtype,GT) \
-PARTHULL_PROTO0(X,Xtype,NE)
-
-/* Use the above macros to define all PartHull prototypes for all
- data types and operations. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-PARTHULL_PROTO(LD,long double)
-#endif
-PARTHULL_PROTO(D,double)
-PARTHULL_PROTO(L,long int)
-PARTHULL_PROTO(UL,unsigned long int)
-PARTHULL_PROTO(I,int)
-PARTHULL_PROTO(UI,unsigned int)
-PARTHULL_PROTO(S,short int)
-PARTHULL_PROTO(US,unsigned short int)
-PARTHULL_PROTO(B,signed char)
-PARTHULL_PROTO(UB,unsigned char)
-PARTHULL_PROTO(F,float)
-
-/* Define a macro that expands to a single prototype for function
- ConvexHull for a given data type and operation. */
-#define CONVEXHULL_PROTO0(X,Xtype,Oper) \
-static AstPointSet *ConvexHull##Oper##X( Xtype, const Xtype[], const int[2], int, int, int, int * );
-
-/* Define a macro that expands to a set of prototypes for all operations
- for function ConvexHull for a given data type. */
-#define CONVEXHULL_PROTO(X,Xtype) \
-CONVEXHULL_PROTO0(X,Xtype,LT) \
-CONVEXHULL_PROTO0(X,Xtype,LE) \
-CONVEXHULL_PROTO0(X,Xtype,EQ) \
-CONVEXHULL_PROTO0(X,Xtype,GE) \
-CONVEXHULL_PROTO0(X,Xtype,GT) \
-CONVEXHULL_PROTO0(X,Xtype,NE)
-
-/* Use the above macros to define all ConvexHull prototypes for all
- data types and operations. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-CONVEXHULL_PROTO(LD,long double)
-#endif
-CONVEXHULL_PROTO(D,double)
-CONVEXHULL_PROTO(L,long int)
-CONVEXHULL_PROTO(UL,unsigned long int)
-CONVEXHULL_PROTO(I,int)
-CONVEXHULL_PROTO(UI,unsigned int)
-CONVEXHULL_PROTO(S,short int)
-CONVEXHULL_PROTO(US,unsigned short int)
-CONVEXHULL_PROTO(B,signed char)
-CONVEXHULL_PROTO(UB,unsigned char)
-CONVEXHULL_PROTO(F,float)
-
-/* Define a macro that expands to a single prototype for function
- FindBoxEdge for a given data type and operation. */
-#define FINDBOXEDGE_PROTO0(X,Xtype,Oper) \
-static void FindBoxEdge##Oper##X( Xtype, const Xtype[], int, int, int, int, int *, int *, int *, int * );
-
-/* Define a macro that expands to a set of prototypes for all operations
- for function FindBoxEdge for a given data type. */
-#define FINDBOXEDGE_PROTO(X,Xtype) \
-FINDBOXEDGE_PROTO0(X,Xtype,LT) \
-FINDBOXEDGE_PROTO0(X,Xtype,LE) \
-FINDBOXEDGE_PROTO0(X,Xtype,EQ) \
-FINDBOXEDGE_PROTO0(X,Xtype,GE) \
-FINDBOXEDGE_PROTO0(X,Xtype,GT) \
-FINDBOXEDGE_PROTO0(X,Xtype,NE)
-
-/* Use the above macros to define all FindBoxEdge prototypes for all
- data types and operations. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-FINDBOXEDGE_PROTO(LD,long double)
-#endif
-FINDBOXEDGE_PROTO(D,double)
-FINDBOXEDGE_PROTO(L,long int)
-FINDBOXEDGE_PROTO(UL,unsigned long int)
-FINDBOXEDGE_PROTO(I,int)
-FINDBOXEDGE_PROTO(UI,unsigned int)
-FINDBOXEDGE_PROTO(S,short int)
-FINDBOXEDGE_PROTO(US,unsigned short int)
-FINDBOXEDGE_PROTO(B,signed char)
-FINDBOXEDGE_PROTO(UB,unsigned char)
-FINDBOXEDGE_PROTO(F,float)
-
-
-
-
-
-
-
-
-
-/* Non-generic function prototypes. */
-static AstMapping *Simplify( AstMapping *, int * );
-static AstPointSet *DownsizePoly( AstPointSet *, double, int, AstFrame *, int * );
-static AstPointSet *RegBaseMesh( AstRegion *, int * );
-static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
-static AstPolygon *Downsize( AstPolygon *, double, int, int * );
-static Segment *AddToChain( Segment *, Segment *, int * );
-static Segment *NewSegment( Segment *, int, int, int, int * );
-static Segment *RemoveFromChain( Segment *, Segment *, int * );
-static double Polywidth( AstFrame *, AstLineDef **, int, int, double[ 2 ], int * );
-static int GetBounded( AstRegion *, int * );
-static int IntCmp( const void *, const void * );
-static int RegPins( AstRegion *, AstPointSet *, AstRegion *, int **, int * );
-static int RegTrace( AstRegion *, int, double *, double **, int * );
-static void Cache( AstPolygon *, int * );
-static void Copy( const AstObject *, AstObject *, int * );
-static void Delete( AstObject *, int * );
-static void Dump( AstObject *, AstChannel *, int * );
-static void EnsureInside( AstPolygon *, int * );
-static void FindMax( Segment *, AstFrame *, double *, double *, int, int, int * );
-static void RegBaseBox( AstRegion *this, double *, double *, int * );
-static void ResetCache( AstRegion *this, int * );
-static void SetPointSet( AstPolygon *, AstPointSet *, int * );
-static void SetRegFS( AstRegion *, AstFrame *, int * );
-static void SmoothPoly( AstPointSet *, int, double, int * );
-
-static const char *GetAttrib( AstObject *, const char *, int * );
-static void ClearAttrib( AstObject *, const char *, int * );
-static void SetAttrib( AstObject *, const char *, int * );
-static int TestAttrib( AstObject *, const char *, int * );
-
-static int GetSimpVertices( AstPolygon *, int * );
-static int TestSimpVertices( AstPolygon *, int * );
-static void ClearSimpVertices( AstPolygon *, int * );
-static void SetSimpVertices( AstPolygon *, int, int * );
-
-
-/* Member functions. */
-/* ================= */
-static Segment *AddToChain( Segment *head, Segment *seg, int *status ){
-/*
-* Name:
-* AddToChain
-
-* Purpose:
-* Add a Segment into the linked list of Segments, maintaining the
-* required order in the list.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* Segment *AddToChain( Segment *head, Segment *seg, int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* The linked list of Segments maintained by astDownsize is searched
-* from the high error end (the head), until a Segment is foound which
-* has a lower error than the supplied segment. The supplied Segment
-* is then inserted into the list at that point.
-
-* Parameters:
-* head
-* The Segment structure at the head of the list (i.e. the segment
-* with maximum error).
-* seg
-* The Segment to be added into the list.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to the link head (which will have changed if "seg" has a
-* higher error than the original head).
-
-*/
-
-/* Local Variables: */
- Segment *tseg;
-
-/* Check the global error status. */
- if ( !astOK ) return head;
-
-/* If the list is empty, return the supplied segment as the new list
- head. */
- if( !head ) {
- head = seg;
-
-/* If the supplied segment has a higher error than the original head,
- insert the new segment in front of the original head. */
- } else if( seg->error > head->error ){
- seg->next = head;
- head->prev = seg;
- head = seg;
-
-/* Otherwise, move down the list from the head until a segment is found
- which has a lower error than the supplied Segment. Then insert the
- supplied segment into the list in front of it. */
- } else {
- tseg = head;
- seg->next = NULL;
-
- while( tseg->next ) {
- if( seg->error > tseg->next->error ) {
- seg->next = tseg->next;
- seg->prev = tseg;
- tseg->next->prev = seg;
- tseg->next = seg;
- break;
- }
- tseg = tseg->next;
- }
-
- if( !seg->next ) {
- tseg->next = seg;
- seg->prev = tseg;
- }
- }
-
-/* Return the new head. */
- return head;
-}
-
-static void Cache( AstPolygon *this, int *status ){
-/*
-* Name:
-* Cache
-
-* Purpose:
-* Calculate intermediate values and cache them in the Polygon structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void Cache( AstPolygon *this, int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* This function uses the PointSet stored in the parent Region to calculate
-* some intermediate values which are useful in other methods. These
-* values are stored within the Polygon structure.
-
-* Parameters:
-* this
-* Pointer to the Polygon.
-* status
-* Pointer to the inherited status variable.
-
-*/
-
-/* Local Variables: */
- AstFrame *frm; /* Pointer to base Frame in Polygon */
- double **ptr; /* Pointer to data in the encapsulated PointSet */
- double end[ 2 ]; /* Start position for edge */
- double maxwid; /* Maximum polygon width found so far */
- double polcen[ 2 ]; /* Polygon centre perpendicular to current edge */
- double polwid; /* Polygon width perpendicular to current edge */
- double start[ 2 ]; /* Start position for edge */
- int i; /* Axis index */
- int nv; /* Number of vertices in Polygon */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Do nothing if the cached information is up to date. */
- if( this->stale ) {
-
-/* Get a pointer to the base Frame. */
- frm = astGetFrame( ((AstRegion *) this)->frameset, AST__BASE );
-
-/* Get the number of vertices. */
- nv = astGetNpoint( ((AstRegion *) this)->points );
-
-/* Get pointers to the coordinate data in the parent Region structure. */
- ptr = astGetPoints( ((AstRegion *) this)->points );
-
-/* Free any existing edge information in the Polygon structure. */
- if( this->edges ) {
- for( i = 0; i < nv; i++ ) {
- this->edges[ i ] = astFree( this->edges[ i ] );
- }
-
-/* Allocate memory to store new edge information if necessary. */
- } else {
- this->edges = astMalloc( sizeof( AstLineDef *)*(size_t) nv );
- this->startsat = astMalloc( sizeof( double )*(size_t) nv );
- }
-
-/* Check pointers can be used safely. */
- if( this->edges ) {
-
-/* Create and store a description of each edge. Also form the total
- distance round the polygon, and the distance from the first vertex
- at which each edge starts. */
- this->totlen = 0.0;
- start[ 0 ] = ptr[ 0 ][ nv - 1 ];
- start[ 1 ] = ptr[ 1 ][ nv - 1 ];
-
- for( i = 0; i < nv; i++ ) {
- end[ 0 ] = ptr[ 0 ][ i ];
- end[ 1 ] = ptr[ 1 ][ i ];
- this->edges[ i ] = astLineDef( frm, start, end );
- start[ 0 ] = end[ 0 ];
- start[ 1 ] = end[ 1 ];
-
- this->startsat[ i ] = this->totlen;
- this->totlen += this->edges[ i ]->length;
- }
-
-/* We now look for a point that is inside the polygon. We want a point
- that is well within the polygon, since points that are only just inside
- the polygon can give numerical problems. Loop round each edge with
- non-zero length. */
- maxwid = -1.0;
- for( i = 0; i < nv; i++ ) {
- if( this->edges[ i ]->length > 0.0 ) {
-
-/* We define another line perpendicular to the current edge, passing
- through the mid point of the edge, extending towards the inside of the
- polygon. The following function returns the distance we can travel
- along this line before we hit any of the other polygon edges. It also
- puts the position corresponding to half that distance into "polcen". */
- polwid = Polywidth( frm, this->edges, i, nv, polcen, status );
-
-/* If the width of the polygon perpendicular to the current edge is
- greater than the width perpdeicular to any other edge, record the
- width and also store the current polygon centre. */
- if( polwid > maxwid && polwid != AST__BAD ) {
- maxwid = polwid;
- (this->in)[ 0 ] = polcen[ 0 ];
- (this->in)[ 1 ] = polcen[ 1 ];
- }
- }
- }
-
-/* If no width was found it probably means that the polygon vertices were
- given in clockwise order, resulting in the above process probing the
- infinite extent outside the polygonal hole. In this case any point
- outside the hole will do, so we use the current contents of the
- "polcen" array. Set a flag indicating if the vertices are stored in
- anti-clockwise order. */
- if( maxwid < 0.0 ) {
- (this->in)[ 0 ] = polcen[ 0 ];
- (this->in)[ 1 ] = polcen[ 1 ];
- this->acw = 0;
- } else {
- this->acw = 1;
- }
- }
-
-/* Free resources */
- frm = astAnnul( frm );
-
-/* Indicate cached information is up to date. */
- this->stale = 0;
- }
-}
-
-static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
-/*
-* Name:
-* ClearAttrib
-
-* Purpose:
-* Clear an attribute value for a Polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void ClearAttrib( AstObject *this, const char *attrib, int *status )
-
-* Class Membership:
-* Polygon member function (over-rides the astClearAttrib protected
-* method inherited from the Region class).
-
-* Description:
-* This function clears the value of a specified attribute for a
-* Polygon, so that the default value will subsequently be used.
-
-* Parameters:
-* this
-* Pointer to the Polygon.
-* attrib
-* Pointer to a null terminated string specifying the attribute
-* name. This should be in lower case with no surrounding white
-* space.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- AstPolygon *this; /* Pointer to the Polygon structure */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Obtain a pointer to the Polygon structure. */
- this = (AstPolygon *) this_object;
-
-/* Check the attribute name and clear the appropriate attribute. */
-
-/* SimpVertices. */
-/* ------------- */
- if ( !strcmp( attrib, "simpvertices" ) ) {
- astClearSimpVertices( this );
-
-/* If the attribute is not recognised, pass it on to the parent method
- for further interpretation. */
- } else {
- (*parent_clearattrib)( this_object, attrib, status );
- }
-}
-
-/*
-*++
-* Name:
-c astConvex<X>
-f AST_CONVEX<X>
-
-* Purpose:
-* Create a new Polygon representing the convex hull of a 2D data grid.
-
-* Type:
-* Public function.
-
-* Synopsis:
-c #include "polygon.h"
-c AstPolygon *astConvex<X>( <Xtype> value, int oper, const <Xtype> array[],
-c const int lbnd[2], const int ubnd[2], int starpix )
-f RESULT = AST_CONVEX<X>( VALUE, OPER, ARRAY, LBND, UBND, STARPIX, STATUS )
-
-* Class Membership:
-* Polygon method.
-
-* Description:
-* This is a set of functions that create the shortest Polygon that
-* encloses all pixels with a specified value within a gridded
-* 2-dimensional data array (e.g. an image).
-*
-* A basic 2-dimensional Frame is used to represent the pixel coordinate
-* system in the returned Polygon. The Domain attribute is set to
-* "PIXEL", the Title attribute is set to "Pixel coordinates", and the
-* Unit attribute for each axis is set to "pixel". All other
-* attributes are left unset. The nature of the pixel coordinate system
-* is determined by parameter
-c "starpix".
-f STARPIX.
-*
-* You should use a function which matches the numerical type of the
-* data you are processing by replacing <X> in the generic function
-* name
-c astConvex<X>
-f AST_CONVEX<X>
-c by an appropriate 1- or 2-character type code. For example, if you
-* are procesing data with type
-c "float", you should use the function astConvexF
-f REAL, you should use the function AST_CONVEXR
-* (see the "Data Type Codes" section below for the codes appropriate to
-* other numerical types).
-
-* Parameters:
-c value
-f VALUE = <Xtype> (Given)
-* A data value that specifies the pixels to be included within the
-* convex hull.
-c oper
-f OPER = INTEGER (Given)
-* Indicates how the
-c "value"
-f VALUE
-* parameter is used to select the required pixels. It can
-* have any of the following values:
-c - AST__LT: include pixels with value less than "value".
-c - AST__LE: include pixels with value less than or equal to "value".
-c - AST__EQ: include pixels with value equal to "value".
-c - AST__NE: include pixels with value not equal to "value".
-c - AST__GE: include pixels with value greater than or equal to "value".
-c - AST__GT: include pixels with value greater than "value".
-f - AST__LT: include pixels with value less than VALUE.
-f - AST__LE: include pixels with value less than or equal to VALUE.
-f - AST__EQ: include pixels with value equal to VALUE.
-f - AST__NE: include pixels with value not equal to VALUE.
-f - AST__GE: include pixels with value greater than or equal to VALUE.
-f - AST__GT: include pixels with value greater than VALUE.
-c array
-f ARRAY( * ) = <Xtype> (Given)
-c Pointer to a
-f A
-* 2-dimensional array containing the data to be processed. The
-* numerical type of this array should match the 1- or
-* 2-character type code appended to the function name (e.g. if
-c you are using astConvexF, the type of each array element
-c should be "float").
-f you are using AST_CONVEXR, the type of each array element
-f should be REAL).
-*
-* The storage order of data within this array should be such
-* that the index of the first grid dimension varies most
-* rapidly and that of the second dimension least rapidly
-c (i.e. Fortran array indexing is used).
-f (i.e. normal Fortran array storage order).
-c lbnd
-f LBND( 2 ) = INTEGER (Given)
-c Pointer to an array of two integers
-f An array
-* containing the coordinates of the centre of the first pixel
-* in the input grid along each dimension.
-c ubnd
-f UBND( 2) = INTEGER (Given)
-c Pointer to an array of two integers
-f An array
-* containing the coordinates of the centre of the last pixel in
-* the input grid along each dimension.
-*
-c Note that "lbnd" and "ubnd" together define the shape
-f Note that LBND and UBND together define the shape
-* and size of the input grid, its extent along a particular
-c (j'th) dimension being ubnd[j]-lbnd[j]+1 (assuming the
-c index "j" to be zero-based). They also define
-f (J'th) dimension being UBND(J)-LBND(J)+1. They also define
-* the input grid's coordinate system, each pixel having unit
-* extent along each dimension with integral coordinate values
-* at its centre or upper corner, as selected by parameter
-c "starpix".
-f STARPIX.
-c starpix
-f STARPIX = LOGICAL (Given)
-* A flag indicating the nature of the pixel coordinate system used
-* to describe the vertex positions in the returned Polygon. If
-c non-zero,
-f .TRUE.,
-* the standard Starlink definition of pixel coordinate is used in
-* which a pixel with integer index I spans a range of pixel coordinate
-* from (I-1) to I (i.e. pixel corners have integral pixel coordinates).
-c If zero,
-f If .FALSE.,
-* the definition of pixel coordinate used by other AST functions
-c such as astResample, astMask,
-f such as AST_RESAMPLE, AST_MASK,
-* etc., is used. In this definition, a pixel with integer index I
-* spans a range of pixel coordinate from (I-0.5) to (I+0.5) (i.e.
-* pixel centres have integral pixel coordinates).
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astConvex<X>()
-f AST_CONVEX<X> = INTEGER
-* A pointer to the required Polygon.
-c NULL
-f AST__NULL
-* is returned without error if the array contains no pixels that
-* satisfy the criterion specified by
-c "value" and "oper".
-f VALUE and OPER.
-
-* Notes:
-c - NULL
-f - AST__NULL
-* will be returned if this function is invoked with the global
-* error status set, or if it should fail for any reason.
-
-* Data Type Codes:
-* To select the appropriate masking function, you should
-c replace <X> in the generic function name astConvex<X> with a
-f replace <X> in the generic function name AST_CONVEX<X> with a
-* 1- or 2-character data type code, so as to match the numerical
-* type <Xtype> of the data you are processing, as follows:
-c - D: double
-c - F: float
-c - L: long int
-c - UL: unsigned long int
-c - I: int
-c - UI: unsigned int
-c - S: short int
-c - US: unsigned short int
-c - B: byte (signed char)
-c - UB: unsigned byte (unsigned char)
-f - D: DOUBLE PRECISION
-f - R: REAL
-f - I: INTEGER
-f - UI: INTEGER (treated as unsigned)
-f - S: INTEGER*2 (short integer)
-f - US: INTEGER*2 (short integer, treated as unsigned)
-f - B: BYTE (treated as signed)
-f - UB: BYTE (treated as unsigned)
-*
-c For example, astConvexD would be used to process "double"
-c data, while astConvexS would be used to process "short int"
-c data, etc.
-f For example, AST_CONVEXD would be used to process DOUBLE
-f PRECISION data, while AST_CONVEXS would be used to process
-f short integer data (stored in an INTEGER*2 array), etc.
-f
-f For compatibility with other Starlink facilities, the codes W
-f and UW are provided as synonyms for S and US respectively (but
-f only in the Fortran interface to AST).
-
-*--
-*/
-/* Define a macro to implement the function for a specific data
- type. Note, this function cannot be a virtual function since the
- argument list does not include a Polygon, and so no virtual function
- table is available. */
-#define MAKE_CONVEX(X,Xtype) \
-AstPolygon *astConvex##X##_( Xtype value, int oper, const Xtype array[], \
- const int lbnd[2], const int ubnd[2], \
- int starpix, int *status ) { \
-\
-/* Local Variables: */ \
- AstFrame *frm; /* Frame in which to define the Polygon */ \
- AstPointSet *candidate; /* Candidate polygon vertices */ \
- AstPolygon *result; /* Result value to return */ \
- int xdim; /* Number of pixels per row */ \
- int ydim; /* Number of rows */ \
- static double junk[ 6 ] = {0.0, 0.0, 1.0, 1.0, 0.0, 1.0 }; /* Junk poly */ \
-\
-/* Initialise. */ \
- result = NULL; \
- candidate = NULL; \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return result; \
-\
-/* Get the array dimensions. */ \
- xdim = ubnd[ 0 ] - lbnd[ 0 ] + 1; \
- ydim = ubnd[ 1 ] - lbnd[ 1 ] + 1; \
-\
-/* Get the basic concvex hull. */ \
- if( oper == AST__LT ) { \
- candidate = ConvexHullLT##X( value, array, lbnd, starpix, xdim, ydim, status ); \
-\
- } else if( oper == AST__LE ) { \
- candidate = ConvexHullLE##X( value, array, lbnd, starpix, xdim, ydim, status ); \
-\
- } else if( oper == AST__EQ ) { \
- candidate = ConvexHullEQ##X( value, array, lbnd, starpix, xdim, ydim, status ); \
-\
- } else if( oper == AST__NE ) { \
- candidate = ConvexHullNE##X( value, array, lbnd, starpix, xdim, ydim, status ); \
-\
- } else if( oper == AST__GE ) { \
- candidate = ConvexHullGE##X( value, array, lbnd, starpix, xdim, ydim, status ); \
-\
- } else if( oper == AST__GT ) { \
- candidate = ConvexHullGT##X( value, array, lbnd, starpix, xdim, ydim, status ); \
-\
- } else if( astOK ){ \
- astError( AST__OPRIN, "astConvex"#X": Invalid operation code " \
- "(%d) supplied (programming error).", status, oper ); \
- } \
-\
-/* Check some good selected values were found. */ \
- if( candidate ) { \
-\
-/* Create a default Polygon with 3 junk vertices. */ \
- frm = astFrame( 2, "Domain=PIXEL,Unit(1)=pixel,Unit(2)=pixel," \
- "Title=Pixel coordinates", status ); \
- result = astPolygon( frm, 3, 3, junk, NULL, " ", status ); \
-\
-/* Change the PointSet within the Polygon to the one created above. */ \
- SetPointSet( result, candidate, status ); \
-\
-/* Free resources. */ \
- frm = astAnnul( frm ); \
- candidate = astAnnul( candidate ); \
- } \
-\
-/* If an error occurred, clear the returned result. */ \
- if ( !astOK ) result = astAnnul( result ); \
-\
-/* Return the result. */ \
- return result; \
-}
-
-
-/* Expand the above macro to generate a function for each required
- data type. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-MAKE_CONVEX(LD,long double)
-#endif
-MAKE_CONVEX(D,double)
-MAKE_CONVEX(L,long int)
-MAKE_CONVEX(UL,unsigned long int)
-MAKE_CONVEX(I,int)
-MAKE_CONVEX(UI,unsigned int)
-MAKE_CONVEX(S,short int)
-MAKE_CONVEX(US,unsigned short int)
-MAKE_CONVEX(B,signed char)
-MAKE_CONVEX(UB,unsigned char)
-MAKE_CONVEX(F,float)
-
-/* Undefine the macros. */
-#undef MAKE_CONVEX
-
-/*
-* Name:
-* ConvexHull
-
-* Purpose:
-* Find the convex hull enclosing selected pixels in a 2D array.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* AstPointSet *ConvexHull<Oper><X>( <Xtype> value, const <Xtype> array[],
-* const int lbnd[2], int starpix,
-* int xdim, int ydim, int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* This function uses an algorithm similar to "Andrew's Monotone Chain
-* Algorithm" to create a list of vertices describing the convex hull
-* enclosing the selected pixels in the supplied array. The vertices
-* are returned in a PointSet.
-
-* Parameters:
-* value
-* A data value that specifies the pixels to be selected.
-* array
-* Pointer to a 2-dimensional array containing the data to be
-* processed. The numerical type of this array should match the 1-
-* or 2-character type code appended to the function name.
-* lbnd
-* The lower pixel index bounds of the array.
-* starpix
-* If non-zero, the usual Starlink definition of pixel coordinate
-* is used (integral values at pixel corners). Otherwise, the
-* system used by other AST functions such as astResample is used
-* (integral values at pixel centres).
-* xdim
-* The number of pixels along each row of the array.
-* ydim
-* The number of rows in the array.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A PointSet holding the vertices of the convex hull, or NULL if an
-* error occurs.
-
-* Notes:
-* - The following code has been designed with a view to it being
-* multi-threaded at some point.
-
-*/
-
-/* Define a macro to implement the function for a specific data
- type and operation. */
-#define MAKE_CONVEXHULL(X,Xtype,Oper,OperI) \
-static AstPointSet *ConvexHull##Oper##X( Xtype value, const Xtype array[], \
- const int lbnd[2], int starpix, \
- int xdim, int ydim, int *status ) { \
-\
-/* Local Variables: */ \
- AstPointSet *result; \
- double **ptr; \
- double *xv1; \
- double *xv2; \
- double *xv3; \
- double *xv4; \
- double *xvert; \
- double *yv1; \
- double *yv2; \
- double *yv3; \
- double *yv4; \
- double *yvert; \
- int nv1; \
- int nv2; \
- int nv3; \
- int nv4; \
- int nv; \
- int xhi; \
- int xhiymax; \
- int xhiymin; \
- int xlo; \
- int xloymax; \
- int xloymin; \
- int yhi; \
- int yhixmax; \
- int yhixmin; \
- int ylo; \
- int yloxmax; \
- int yloxmin; \
-\
-/* Initialise */ \
- result = NULL; \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return result; \
-\
-/* Find the lowest Y value at any selected pixel, and find the max and \
- min X value of the selected pixels at that lowest Y value. */ \
- FindBoxEdge##Oper##X( value, array, xdim, ydim, 1, 1, &ylo, &yloxmax, \
- &yloxmin, status ); \
-\
-/* Skip if there are no selected values in the array. */ \
- if( ylo > 0 ) { \
-\
-/* Find the highest Y value at any selected pixel, and find the max and \
- min X value of the selected pixels at that highest Y value. */ \
- FindBoxEdge##Oper##X( value, array, xdim, ydim, 1, 0, &yhi, &yhixmax, \
- &yhixmin, status ); \
-\
-/* Find the lowest X value at any selected pixel, and find the max and \
- min Y value of the selected pixels at that lowest X value. */ \
- FindBoxEdge##Oper##X( value, array, xdim, ydim, 0, 1, &xlo, &xloymax, \
- &xloymin, status ); \
-\
-/* Find the highest X value at any selected pixel, and find the max and \
- min Y value of the selected pixels at that highest X value. */ \
- FindBoxEdge##Oper##X( value, array, xdim, ydim, 0, 0, &xhi, &xhiymax, \
- &xhiymin, status ); \
-\
-/* Create a list of vertices for the bottom right corner of the bounding \
- box of the selected pixels. */ \
- PartHull##Oper##X( value, array, xdim, ydim, yloxmax, ylo, xhi, xhiymin, \
- starpix, lbnd, &xv1, &yv1, &nv1, status ); \
-\
-/* Create a list of vertices for the top right corner of the bounding \
- box of the selected pixels. */ \
- PartHull##Oper##X( value, array, xdim, ydim, xhi, xhiymax, yhixmax, yhi, \
- starpix, lbnd, &xv2, &yv2, &nv2, status ); \
-\
-/* Create a list of vertices for the top left corner of the bounding \
- box of the selected pixels. */ \
- PartHull##Oper##X( value, array, xdim, ydim, yhixmin, yhi, xlo, xloymax, \
- starpix, lbnd, &xv3, &yv3, &nv3, status ); \
-\
-/* Create a list of vertices for the bottom left corner of the bounding \
- box of the selected pixels. */ \
- PartHull##Oper##X( value, array, xdim, ydim, xlo, xloymin, yloxmin, ylo, \
- starpix, lbnd, &xv4, &yv4, &nv4, status ); \
-\
-/* Concatenate the four vertex lists and store them in the returned \
- PointSet. */ \
- nv = nv1 + nv2 + nv3 + nv4; \
- result = astPointSet( nv, 2, " ", status ); \
- ptr = astGetPoints( result ); \
- if( astOK ) { \
- xvert = ptr[ 0 ]; \
- yvert = ptr[ 1 ]; \
-\
- memcpy( xvert, xv1, nv1*sizeof( double ) ); \
- memcpy( yvert, yv1, nv1*sizeof( double ) ); \
- xvert += nv1; \
- yvert += nv1; \
-\
- memcpy( xvert, xv2, nv2*sizeof( double ) ); \
- memcpy( yvert, yv2, nv2*sizeof( double ) ); \
- xvert += nv2; \
- yvert += nv2; \
-\
- memcpy( xvert, xv3, nv3*sizeof( double ) ); \
- memcpy( yvert, yv3, nv3*sizeof( double ) ); \
- xvert += nv3; \
- yvert += nv3; \
-\
- memcpy( xvert, xv4, nv4*sizeof( double ) ); \
- memcpy( yvert, yv4, nv4*sizeof( double ) ); \
- } \
-\
-/* Free resources. */ \
- xv1 = astFree( xv1 ); \
- xv2 = astFree( xv2 ); \
- xv3 = astFree( xv3 ); \
- xv4 = astFree( xv4 ); \
- yv1 = astFree( yv1 ); \
- yv2 = astFree( yv2 ); \
- yv3 = astFree( yv3 ); \
- yv4 = astFree( yv4 ); \
- } \
-\
-/* Free the returned PointSet if an error occurred. */ \
- if( result && !astOK ) result = astAnnul( result ); \
-\
-/* Return the result. */ \
- return result; \
-}
-
-/* Define a macro that uses the above macro to to create implementations
- of ConvexHull for all operations. */
-#define MAKEALL_CONVEXHULL(X,Xtype) \
-MAKE_CONVEXHULL(X,Xtype,LT,AST__LT) \
-MAKE_CONVEXHULL(X,Xtype,LE,AST__LE) \
-MAKE_CONVEXHULL(X,Xtype,EQ,AST__EQ) \
-MAKE_CONVEXHULL(X,Xtype,NE,AST__NE) \
-MAKE_CONVEXHULL(X,Xtype,GE,AST__GE) \
-MAKE_CONVEXHULL(X,Xtype,GT,AST__GT)
-
-/* Expand the above macro to generate a function for each required
- data type and operation. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-MAKEALL_CONVEXHULL(LD,long double)
-#endif
-MAKEALL_CONVEXHULL(D,double)
-MAKEALL_CONVEXHULL(L,long int)
-MAKEALL_CONVEXHULL(UL,unsigned long int)
-MAKEALL_CONVEXHULL(I,int)
-MAKEALL_CONVEXHULL(UI,unsigned int)
-MAKEALL_CONVEXHULL(S,short int)
-MAKEALL_CONVEXHULL(US,unsigned short int)
-MAKEALL_CONVEXHULL(B,signed char)
-MAKEALL_CONVEXHULL(UB,unsigned char)
-MAKEALL_CONVEXHULL(F,float)
-
-/* Undefine the macros. */
-#undef MAKE_CONVEXHULL
-#undef MAKEALL_CONVEXHULL
-
-static AstPolygon *Downsize( AstPolygon *this, double maxerr, int maxvert,
- int *status ) {
-/*
-*++
-* Name:
-c astDownsize
-f AST_DOWNSIZE
-
-* Purpose:
-* Reduce the number of vertices in a Polygon.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "polygon.h"
-c AstPolygon *astDownsize( AstPolygon *this, double maxerr, int maxvert )
-f RESULT = AST_DOWNSIZE( THIS, MAXERR, MAXVERT, STATUS )
-
-* Class Membership:
-* Polygon method.
-
-* Description:
-* This function returns a pointer to a new Polygon that contains a
-* subset of the vertices in the supplied Polygon. The subset is
-* chosen so that the returned Polygon is a good approximation to
-* the supplied Polygon, within the limits specified by the supplied
-* parameter values. That is, the density of points in the returned
-* Polygon is greater at points where the curvature of the boundary of
-* the supplied Polygon is greater.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the Polygon.
-c maxerr
-f MAXERR = DOUBLE PRECISION (Given)
-* The maximum allowed discrepancy between the supplied and
-* returned Polygons, expressed as a geodesic distance within the
-* Polygon's coordinate frame. If this is zero or less, the
-* returned Polygon will have the number of vertices specified by
-c maxvert.
-f MAXVERT.
-c maxvert
-f MAXVERT = INTEGER (Given)
-* The maximum allowed number of vertices in the returned Polygon.
-* If this is less than 3, the number of vertices in the returned
-* Polygon will be the minimum needed to achieve the maximum
-* discrepancy specified by
-c maxerr.
-f MAXERR.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astDownsize()
-f AST_DOWNSIZE = INTEGER
-* Pointer to the new Polygon.
-
-* Notes:
-* - A null Object pointer (AST__NULL) will be returned if this
-c function is invoked with the AST error status set, or if it
-f function is invoked with STATUS set to an error value, or if it
-* should fail for any reason.
-*--
-*/
-
-/* Local Variables: */
- AstFrame *frm; /* Base Frame from the Polygon */
- AstPointSet *pset; /* PointSet holding vertices of downsized polygon */
- AstPolygon *result; /* Returned pointer to new Polygon */
-
-/* Initialise. */
- result = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Get a pointer to the base Frame of the Polygon. */
- frm = astGetFrame( ((AstRegion *) this)->frameset, AST__BASE );
-
-/* Create a PointSet holding the vertices of the downsized polygon. */
- pset = DownsizePoly( ((AstRegion *) this)->points, maxerr, maxvert,
- frm, status );
-
-/* Take a deep copy of the supplied Polygon. */
- result = astCopy( this );
-
-/* Change the PointSet within the result Polygon to the one created above. */ \
- SetPointSet( result, pset, status ); \
-
-/* Free resources. */
- frm = astAnnul( frm );
- pset = astAnnul( pset );
-
-/* If an error occurred, annul the returned Polygon. */
- if ( !astOK ) result = astAnnul( result );
-
-/* Return the result. */
- return result;
-}
-
-static AstPointSet *DownsizePoly( AstPointSet *pset, double maxerr,
- int maxvert, AstFrame *frm, int *status ) {
-/*
-* Name:
-* DownsizePoly
-
-* Purpose:
-* Reduce the number of vertices in a Polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* AstPointSet *DownsizePoly( AstPointSet *pset, double maxerr, int maxvert,
-* AstFrame *frm, int *status )
-
-* Class Membership:
-* Polygon member function.
-
-* Description:
-* This function returns a pointer to a new PointSet that contains a
-* subset of the vertices in the supplied PointSet. The subset is
-* chosen so that the returned polygon is a good approximation to
-* the supplied polygon, within the limits specified by the supplied
-* parameter values. That is, the density of points in the returned
-* polygon is greater at points where the curvature of the boundary of
-* the supplied polygon is greater.
-
-* Parameters:
-* pset
-* Pointer to the PointSet holding the polygon vertices.
-* maxerr
-* The maximum allowed discrepancy between the supplied and
-* returned Polygons, expressed as a geodesic distance within the
-* Polygon's coordinate frame. If this is zero or less, the
-* returned Polygon will have the number of vertices specified by
-* maxvert.
-* maxvert
-* The maximum allowed number of vertices in the returned Polygon.
-* If this is less than 3, the number of vertices in the returned
-* Polygon will be the minimum needed to achieve the maximum
-* discrepancy specified by
-* maxerr.
-* frm
-* Pointer to the Frame in which the polygon is defined.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to the new PointSet.
-
-* Notes:
-* - A null Object pointer (AST__NULL) will be returned if this
-* function is invoked with the AST error status set, or if it
-* should fail for any reason.
-*/
-
-/* Local Variables: */
- AstPointSet *result; /* Returned pointer to new PointSet */
- Segment *head; /* Pointer to new polygon edge with highest error */
- Segment *seg1; /* Pointer to new polygon edge */
- Segment *seg2; /* Pointer to new polygon edge */
- Segment *seg3; /* Pointer to new polygon edge */
- double **ptr; /* Pointer to arrays of axis values */
- double *x; /* Pointer to array of X values for old Polygon */
- double *xnew; /* Pointer to array of X values for new Polygon */
- double *y; /* Pointer to array of Y values for old Polygon */
- double *ynew; /* Pointer to array of Y values for new Polygon */
- double x1; /* Lowest X value at any vertex */
- double x2; /* Highest X value at any vertex */
- double y1; /* Lowest Y value at any vertex */
- double y2; /* Highest Y value at any vertex */
- int *newpoly; /* Holds indices of retained input vertices */
- int i1; /* Index of first vertex added to output polygon */
- int i1x; /* Index of vertex with lowest X */
- int i1y; /* Index of vertex with lowest Y */
- int i2; /* Index of second vertex added to output polygon */
- int i2x; /* Index of vertex with highest X */
- int i2y; /* Index of vertex with highest Y */
- int i3; /* Index of third vertex added to output polygon */
- int iadd; /* Normalised vertex index */
- int iat; /* Index at which to store new vertex index */
- int newlen; /* Number of vertices currently in new Polygon */
- int nv; /* Number of vertices in old Polygon */
-
-/* Initialise. */
- result = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Get the number of vertices in the supplied polygon. */
- nv = astGetNpoint( pset );
-
-/* If the maximum error allowed is zero, and the maximum number of
- vertices is equal to or greater than the number in the supplied
- polygon, just return a deep copy of the supplied PointSet. */
- if( maxerr <= 0.0 && ( maxvert < 3 || maxvert >= nv ) ) {
- result = astCopy( pset );
-
-/* Otherwise... */
- } else {
-
-/* Get pointers to the X and Y arrays holding the vertex coordinates in
- the supplied polygon. */
- ptr = astGetPoints( pset );
- x = ptr[ 0 ];
- y = ptr[ 1 ];
-
-/* Allocate memory for an array to hold the original indices of the vertices
- to be used to create the returned Polygon. This array is expanded as
- needed. */
- newpoly = astMalloc( 10*sizeof( int ) );
-
-/* Check the pointers can be used safely. */
- if( astOK ) {
-
-/* We first need to decide on three widely spaced vertices which form a
- reasonable triangular approximation to the whole polygon. First find
- the vertices with the highest and lowest Y values, and the highest and
- lowest X values. */
- x1 = DBL_MAX;
- x2 = -DBL_MAX;
- y1 = DBL_MAX;
- y2 = -DBL_MAX;
-
- i1y = i1x = 0;
- i2y = i2x = nv/2;
-
- for( i3 = 0; i3 < nv; i3++ ) {
- if( y[ i3 ] < y1 ) {
- y1 = y[ i3 ];
- i1y = i3;
- } else if( y[ i3 ] > y2 ) {
- y2 = y[ i3 ];
- i2y = i3;
- }
-
- if( x[ i3 ] < x1 ) {
- x1 = x[ i3 ];
- i1x = i3;
- } else if( x[ i3 ] > x2 ) {
- x2 = x[ i3 ];
- i2x = i3;
- }
- }
-
-/* Use the axis which spans the greater range. */
- if( y2 - y1 > x2 - x1 ) {
- i1 = i1y;
- i2 = i2y;
- } else {
- i1 = i1x;
- i2 = i2x;
- }
-
-/* The index with vertex i1 is definitely going to be one of our three
- vertices. We are going to use the line from i1 to i2 to choose the two
- other vertices to use. Create a structure describing the segment of the
- Polygon from the lowest value on the selected axis (X or Y) to the
- highest value. As always, the polygons is traversed in an anti-clockwise
- direction. */
- seg1 = NewSegment( NULL, i1, i2, nv, status );
-
-/* Find the vertex within this segment which is furthest away from the
- line on the right hand side (as moving from vertex i1 to vertex i2). */
- FindMax( seg1, frm, x, y, nv, 0, status );
-
-/* Likewise, create a structure describing the remained of the Polygon
- (i.e. the segment from the highest value on the selected axis to the
- lowest value). Then find the vertex within this segment which is
- furthest away from the line on the right hand side. */
- seg2 = NewSegment( NULL, i2, i1, nv, status );
- FindMax( seg2, frm, x, y, nv, 0, status );
-
-/* Select the segment for which the found vertex is furthest from the
- line. */
- if( seg2->error > seg1->error ) {
-
-/* If the second segment, we will use the vertex that is farthest from
- the line as one of our threee vertices. To ensure that movement from
- vertex i1 to i2 to i3 is anti-clockwise, we must use this new vertex
- as vertex i3, not i2. */
- i3 = seg2->imax;
-
-/* Create a description of the polygon segment from vertex i1 to i3, and
- find the vertex which is furthest to the right of the line joining the
- two vertices. We use this as the middle vertex (i2). */
- seg1 = NewSegment( seg1, i1, i3, nv, status );
- FindMax( seg1, frm, x, y, nv, 0, status );
- i2 = seg1->imax;
-
-/* Do the same if we are choosing the other segment, ordering the
- vertices to retain anti-clockwise movement from i1 to i2 to i3. */
- } else {
- i2 = seg1->imax;
- seg1 = NewSegment( seg1, i2, i1, nv, status );
- FindMax( seg1, frm, x, y, nv, 0, status );
- i3 = seg1->imax;
- }
-
-/* Ensure the vertex indices are in the first cycle. */
- if( i2 >= nv ) i2 -= nv;
- if( i3 >= nv ) i3 -= nv;
-
-/* Create Segment structures to describe each of these three edges. */
- seg1 = NewSegment( seg1, i1, i2, nv, status );
- seg2 = NewSegment( seg2, i2, i3, nv, status );
- seg3 = NewSegment( NULL, i3, i1, nv, status );
-
-/* Record these 3 vertices in an array holding the original indices of
- the vertices to be used to create the returned Polygon. */
- newpoly[ 0 ] = i1;
- newpoly[ 1 ] = i2;
- newpoly[ 2 ] = i3;
-
-/* Indicate the new polygon currently has 3 vertices. */
- newlen = 3;
-
-/* Search the old vertices between the start and end of segment 3, looking
- for the vertex which lies furthest from the line of segment 3. The
- residual between this point and the line is stored in the Segment
- structure, as is the index of the vertex at which this maximum residual
- occurred. */
- FindMax( seg3, frm, x, y, nv, 1, status );
-
-/* The "head" variable points to the head of a double linked list of
- Segment structures. This list is ordered by residual, so that the
- Segment with the maximum residual is at the head, and the Segment
- with the minimum residual is at the tail. Initially "seg3" is at the
- head. */
- head = seg3;
-
-/* Search the old vertices between the start and end of segment 1, looking
- for the vertex which lies furthest from the line of segment 1. The
- residual between this point and the line is stored in the Segment
- structure, as is the index of the vertex at which this maximum residual
- occurred. */
- FindMax( seg1, frm, x, y, nv, 1, status );
-
-/* Insert segment 1 into the linked list of Segments, at a position that
- maintains the ordering of the segments by error. Thus the head of the
- list will still have the max error. */
- head = AddToChain( head, seg1, status );
-
-/* Do the same for segment 2. */
- FindMax( seg2, frm, x, y, nv, 1, status );
- head = AddToChain( head, seg2, status );
-
-/* If the maximum allowed number of vertices in the output Polygon is
- less than 3, allow any number of vertices up to the number in the
- input Polygon (termination will then be determined just by "maxerr"). */
- if( maxvert < 3 ) maxvert = nv;
-
-/* Loop round adding an extra vertex to the returned Polygon until the
- maximum residual between the new and old polygons is no more than
- "maxerr". Abort early if the specified maximum number of vertices is
- reached. */
- while( head->error > maxerr && newlen < maxvert ) {
-
-/* The segment at the head of the list has the max error (that is, it is
- the segment that departs most from the supplied Polygon). To make the
- new polygon a better fit to the old polygon, we add the vertex that is
- furthest away from this segment to the new polygon. Remember that a
- polygon is cyclic so if the vertex has an index that is greater than the
- number of vertices in the old polygon, reduce the index by the number
- of vertices in the old polygon. */
- iadd = head->imax;
- if( iadd >= nv ) iadd -= nv;
- iat = newlen++;
- newpoly = astGrow( newpoly, newlen, sizeof( int ) );
- if( !astOK ) break;
- newpoly[ iat ] = iadd;
-
-/* We now split the segment that had the highest error into two segments.
- The split occurs at the vertex that had the highest error. */
- seg1 = NewSegment( NULL, head->imax, head->i2, nv, status );
- seg2 = head;
- seg2->i2 = head->imax;
-
-/* We do not know where these two new segments should be in the ordered
- linked list, so remove them from the list. */
- head = RemoveFromChain( head, seg1, status );
- head = RemoveFromChain( head, seg2, status );
-
-/* Find the vertex that deviates most from the first of these two new
- segments, and then add the segment into the list of vertices, using
- the maximum deviation to determine the position of the segment within
- the list. */
- FindMax( seg1, frm, x, y, nv, 1, status );
- head = AddToChain( head, seg1, status );
-
-/* Do the same for the second new segment. */
- FindMax( seg2, frm, x, y, nv, 1, status );
- head = AddToChain( head, seg2, status );
- }
-
-/* Now we have reached the required accuracy, free resources. */
- while( head ) {
- seg1 = head;
- head = head->next;
- seg1 = astFree( seg1 );
- }
-
-/* If no vertices have been left out, return a deep copy of the supplied
- PointSet. */
- if( newlen == nv ) {
- result = astCopy( pset );
-
-/* Otherwise, sort the indices of the vertices to be retained so that they
- are in the same order as they were in the supplied Polygon. */
- } else if( astOK ){
- qsort( newpoly, newlen, sizeof( int ), IntCmp );
-
-/* Create a new PointSet and get pointers to its axis values. */
- result = astPointSet( newlen, 2, " ", status );
- ptr = astGetPoints( result );
- xnew = ptr[ 0 ];
- ynew = ptr[ 1 ];
-
-/* Copy the axis values for the retained vertices from the old to the new
- PointSet. */
- if( astOK ) {
- for( iat = 0; iat < newlen; iat++ ) {
- *(xnew++) = x[ newpoly[ iat ] ];
- *(ynew++) = y[ newpoly[ iat ] ];
- }
- }
- }
- }
-
-/* Free resources. */
- newpoly = astFree( newpoly );
- }
-
-/* If an error occurred, annul the returned PointSet. */
- if ( !astOK ) result = astAnnul( result );
-
-/* Return the result. */
- return result;
-}
-
-static void EnsureInside( AstPolygon *this, int *status ){
-/*
-* Name:
-* EnsureInside
-
-* Purpose:
-* Ensure the unnegated Polygon represents the inside of the polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void EnsureInside( AstPolygon *this, int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* Reversing the order of the vertices of a Polygon is like negating
-* the Polygon. But the parent Region class assumes that an unnegated
-* region bounded by closed curves (e.g. boxes, circles, ellipses, etc)
-* is bounded. So we need to have a way to ensure that a Polygon also
-* follows this convention. So this function reverses the order of the
-* vertices in the Polygon, if necessary, to ensure that the unnegated
-* Polygon is bounded.
-
-* Parameters:
-* this
-* The Polygon.
-* status
-* Pointer to the inherited status variable.
-
-*/
-
-/* Local Variables: */
- AstRegion *this_region;
- double **ptr;
- double *p;
- double *q;
- double tmp;
- int bounded;
- int i;
- int j;
- int jmid;
- int negated;
- int np;
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Is the unnegated Polygon unbounded? If so, we need to reverse the
- vertices. */
- bounded = astGetBounded( this );
- negated = astGetNegated( this );
- if( ( bounded && negated ) || ( !bounded && !negated ) ) {
- this_region = (AstRegion *) this;
-
-/* Get a pointer to the arrays holding the coordinates at the Polygon
- vertices. */
- ptr = astGetPoints( this_region->points );
-
-/* Get the number of vertices. */
- np = astGetNpoint( this_region->points );
-
-/* Store the index of the last vertex to swap. For odd "np" the central
- vertex does not need to be swapped. */
- jmid = np/2;
-
-/* Loop round the two axes spanned by the Polygon. */
- for( i = 0; i < 2; i++ ) {
-
-/* Get pointers to the first pair of axis values to be swapped - i.e. the
- first and last axis values. */
- p = ptr[ i ];
- q = p + np - 1;
-
-/* Loop round all pairs of axis values. */
- for( j = 0; j < jmid; j++ ) {
-
-/* Swap the pair. */
- tmp = *p;
- *(p++) = *q;
- *(q--) = tmp;
- }
- }
-
-/* Invert the value of the "Negated" attribute to cancel out the effect
- of the above vertex reversal. */
- astNegate( this );
-
-/* Indicate the cached information in the Polygon structure is stale. */
- this->stale = 1;
- }
-}
-
-/*
-* Name:
-* FindBoxEdge
-
-* Purpose:
-* Find an edge of the bounding box containing the selected pixels.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void FindBoxEdge<Oper><X>( <Xtype> value, const <Xtype> array[],
-* int xdim, int ydim, int axis, int low,
-* int *val, int *valmax, int *valmin,
-* int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* This function search for an edge of the bounding box containing the
-* selected pixels in the supplied array.
-
-* Parameters:
-* value
-* A data value that specifies the pixels to be selected.
-* array
-* Pointer to a 2-dimensional array containing the data to be
-* processed. The numerical type of this array should match the 1-
-* or 2-character type code appended to the function name.
-* xdim
-* The number of pixels along each row of the array.
-* ydim
-* The number of rows in the array.
-* axis
-* The index (0 or 1) of the pixel axis perpendicular to the edge of the
-* bounding box being found.
-* low
-* If non-zero, the lower edge of the bounding box on the axis
-* specified by "axis" is found and returned. Otherwise, the higher
-* edge of the bounding box on the axis specified by "axis" is
-* found and returned.
-* val
-* Address of an int in which to return the value on axis "axis" of
-* the higher or lower (as specified by "low") edge of the bounding
-* box.
-* valmax
-* Address of an int in which to return the highest value on axis
-* "1-axis" of the selected pixels on the returned edge.
-* valmin
-* Address of an int in which to return the lowest value on axis
-* "1-axis" of the selected pixels on the returned edge.
-* status
-* Pointer to the inherited status variable.
-
-* Notes;
-* - Zero is returned for "*val" if no good values are found, or if
-* an error occurs.
-
-*/
-
-/* Define a macro to implement the function for a specific data
- type and operation. */
-#define MAKE_FINDBOXEDGE(X,Xtype,Oper,OperI) \
-static void FindBoxEdge##Oper##X( Xtype value, const Xtype array[], int xdim, \
- int ydim, int axis, int low, int *val, \
- int *valmax, int *valmin, int *status ) { \
-\
-/* Local Variables: */ \
- int astep; \
- int bstep; \
- int a0; \
- int a1; \
- int b0; \
- int b1; \
- int inc; \
- int a; \
- int b; \
- const Xtype *pc; \
-\
-/* Initialise. */ \
- *val = 0; \
- *valmin = 0; \
- *valmax = 0; \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return; \
-\
-/* If we are finding an edge that is parallel to the X axis... */ \
- if( axis ) { \
-\
-/* Get the vector step between adjacent pixels on the selected axis, and \
- on the other axis. */ \
- astep = xdim; \
- bstep = 1; \
-\
-/* Get the first and last value to check on the selected axis, and the \
- increment between checks. */ \
- if( low ) { \
- a0 = 1; \
- a1 = ydim; \
- inc = 1; \
- } else { \
- a0 = ydim; \
- a1 = 1; \
- inc = -1; \
- } \
-\
-/* The first and last value to check on the other axis. */ \
- b0 = 1; \
- b1 = xdim; \
-\
-/* Do the same if we are finding an edge that is parallel to the Y axis. */ \
- } else { \
- astep = 1; \
- bstep = xdim; \
-\
- if( low ) { \
- a0 = 1; \
- a1 = xdim; \
- inc = 1; \
- } else { \
- a0 = xdim; \
- a1 = 1; \
- inc = -1; \
- } \
-\
- b0 = 1; \
- b1 = ydim; \
- } \
-\
-/* Loop round the axis values. */ \
- a = a0; \
- while( 1 ) { \
-\
-/* Get a pointer to the first value to be checked at this axis value. */ \
- pc = array + (a - 1)*astep + (b0 - 1)*bstep; \
-\
-/* Scan the other axis to find the first and last selected pixel. */ \
- for( b = b0; b <= b1; b++ ) { \
- if( ISVALID(*pc,OperI,value) ) { \
- if( *valmin == 0 ) *valmin = b; \
- *valmax = b; \
- } \
- pc += bstep; \
- } \
-\
-/* If any selected pixels were found, store the axis value and exit. */ \
- if( *valmax ) { \
- *val = a; \
- break; \
- } \
-\
-/* Move on to the next axis value. */ \
- if( a != a1 ) { \
- a += inc; \
- } else { \
- break; \
- } \
-\
- } \
-}
-
-/* Define a macro that uses the above macro to to create implementations
- of FindBoxEdge for all operations. */
-#define MAKEALL_FINDBOXEDGE(X,Xtype) \
-MAKE_FINDBOXEDGE(X,Xtype,LT,AST__LT) \
-MAKE_FINDBOXEDGE(X,Xtype,LE,AST__LE) \
-MAKE_FINDBOXEDGE(X,Xtype,EQ,AST__EQ) \
-MAKE_FINDBOXEDGE(X,Xtype,NE,AST__NE) \
-MAKE_FINDBOXEDGE(X,Xtype,GE,AST__GE) \
-MAKE_FINDBOXEDGE(X,Xtype,GT,AST__GT)
-
-/* Expand the above macro to generate a function for each required
- data type and operation. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-MAKEALL_FINDBOXEDGE(LD,long double)
-#endif
-MAKEALL_FINDBOXEDGE(D,double)
-MAKEALL_FINDBOXEDGE(L,long int)
-MAKEALL_FINDBOXEDGE(UL,unsigned long int)
-MAKEALL_FINDBOXEDGE(I,int)
-MAKEALL_FINDBOXEDGE(UI,unsigned int)
-MAKEALL_FINDBOXEDGE(S,short int)
-MAKEALL_FINDBOXEDGE(US,unsigned short int)
-MAKEALL_FINDBOXEDGE(B,signed char)
-MAKEALL_FINDBOXEDGE(UB,unsigned char)
-MAKEALL_FINDBOXEDGE(F,float)
-
-/* Undefine the macros. */
-#undef MAKE_FINDBOXEDGE
-#undef MAKEALL_FINDBOXEDGE
-
-/*
-* Name:
-* FindInsidePoint
-
-* Purpose:
-* Find a point that is inside the required outline.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void FindInsidePoint<Oper><X>( <Xtype> value, const <Xtype> array[],
-* const int lbnd[ 2 ], const int ubnd[ 2 ],
-* int *inx, int *iny, int *iv,
-* int *status );
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* The central pixel in the array is checked to see if its value meets
-* the requirements implied by <Oper> and "value". If so, its pixel
-* indices and vector index are returned> if not, a spiral search is
-* made until such a pixel value is found.
-
-* Parameters:
-* value
-* The data value defining valid pixels.
-* array
-* The data array.
-* lbnd
-* The lower pixel index bounds of the array.
-* ubnd
-* The upper pixel index bounds of the array.
-* inx
-* Pointer to an int in which to return the X pixel index of the
-* first point that meets the requirements implied by <oper> and
-* "value".
-* iny
-* Pointer to an int in which to return the Y pixel index of the
-* first point that meets the requirements implied by <oper> and
-* "value".
-* iv
-* Pointer to an int in which to return the vector index of the
-* first point that meets the requirements implied by <oper> and
-* "value".
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - <Oper> must be one of LT, LE, EQ, NE, GE, GT.
-
-
-*/
-
-/* Define a macro to implement the function for a specific data
- type and operation. */
-#define MAKE_FINDINSIDEPOINT(X,Xtype,Oper,OperI) \
-static void FindInsidePoint##Oper##X( Xtype value, const Xtype array[], \
- const int lbnd[ 2 ], const int ubnd[ 2 ], \
- int *inx, int *iny, int *iv, \
- int *status ){ \
-\
-/* Local Variables: */ \
- const Xtype *pv; /* Pointer to next data value to test */ \
- const char *text; /* Pointer to text describing oper */ \
- int cy; /* Central row index */ \
- int iskin; /* Index of spiral layer being searched */ \
- int nskin; /* Number of spiral layers to search */ \
- int nx; /* Pixel per row */ \
- int tmp; /* Temporary storage */ \
- int xhi; /* High X pixel index bound of current skin */ \
- int xlo; /* Low X pixel index bound of current skin */ \
- int yhi; /* High X pixel index bound of current skin */ \
- int ylo; /* Low X pixel index bound of current skin */ \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return; \
-\
-/* Find number of pixels in one row of the array. */ \
- nx = ( ubnd[ 0 ] - lbnd[ 0 ] + 1 ); \
-\
-/* Find the pixel indices of the central pixel */ \
- *inx = ( ubnd[ 0 ] + lbnd[ 0 ] )/2; \
- *iny = ( ubnd[ 1 ] + lbnd[ 1 ] )/2; \
-\
-/* Initialise the vector index and pointer to refer to the central pixel. */ \
- *iv = ( *inx - lbnd[ 0 ] ) + nx*( *iny - lbnd[ 1 ] ) ; \
- pv = array + (*iv); \
-\
-/* Test the pixel value, returning if it is valid. This \
- relies on the compiler optimisation to remove the "if" statements \
- for all but the operation appropriate to the function being defined. */ \
- if( OperI == AST__LT ) { \
- if( *pv < value ) return; \
-\
- } else if( OperI == AST__LE ) { \
- if( *pv <= value ) return; \
-\
- } else if( OperI == AST__EQ ) { \
- if( *pv == value ) return; \
-\
- } else if( OperI == AST__NE ) { \
- if( *pv != value ) return; \
-\
- } else if( OperI == AST__GE ) { \
- if( *pv >= value ) return; \
-\
- } else { \
- if( *pv > value ) return; \
- } \
-\
-/* The central pixel is invalid if we arrive here. So we need to do a \
- spiral search out from the centre looking for a valid pixel. Record \
- the central row index (this is the row at which we jump to the next \
- outer skin when doing the spiral search below). */ \
- cy = *iny; \
-\
-/* Find how many skins can be searched as part of the spiral search \
- before the edge of the array is encountered. */ \
- nskin = ubnd[ 0 ] - *inx; \
- tmp = *inx - lbnd[ 0 ]; \
- if( tmp < nskin ) nskin = tmp; \
- tmp = ubnd[ 1 ] - *iny; \
- if( tmp < nskin ) nskin = tmp; \
- tmp = *iny - lbnd[ 1 ]; \
- if( tmp < nskin ) nskin = tmp; \
-\
-/* Initialise the skin box bounds to be just the central pixel. */ \
- xlo = xhi = *inx; \
- ylo = yhi = *iny; \
-\
-/* Loop round each skin looking for a valid test pixel. */ \
- for( iskin = 0; iskin < nskin; iskin++ ) { \
-\
-/* Increment the upper and lower bounds of the box forming the next \
- skin. */ \
- xhi++; \
- xlo--; \
- yhi++; \
- ylo--; \
-\
-/* Initialise things for the first pixel in the new skin by moving one \
- pixel to the right. */ \
- pv++; \
- (*iv)++; \
- (*inx)++; \
-\
-/* Move up the right hand edge of the box corresponding to the current \
- skin. We start at the middle of the right hand edge. */ \
- for( *iny = cy; *iny <= yhi; (*iny)++ ) { \
-\
-/* Test the pixel value, returning if it is valid. This relies on the \
- compiler optimisation to remove the "if" statements for all but the \
- operation appropriate to the function being defined. */ \
- if( OperI == AST__LT ) { \
- if( *pv < value ) return; \
-\
- } else if( OperI == AST__LE ) { \
- if( *pv <= value ) return; \
-\
- } else if( OperI == AST__EQ ) { \
- if( *pv == value ) return; \
-\
- } else if( OperI == AST__NE ) { \
- if( *pv != value ) return; \
-\
- } else if( OperI == AST__GE ) { \
- if( *pv >= value ) return; \
-\
- } else { \
- if( *pv > value ) return; \
- } \
-\
-/* Move up a pixel. */ \
- pv += nx; \
- *iv += nx; \
- } \
-\
-/* Move down a pixel so that *iny == yhi. */ \
- pv -= nx; \
- *iv -= nx; \
- (*iny)--; \
-\
-/* Move left along the top edge of the box corresponding to the current \
- skin. */ \
- for( *inx = xhi; *inx >= xlo; (*inx)-- ) { \
-\
-/* Test the pixel value, returning if it is valid. */ \
- if( OperI == AST__LT ) { \
- if( *pv < value ) return; \
-\
- } else if( OperI == AST__LE ) { \
- if( *pv <= value ) return; \
-\
- } else if( OperI == AST__EQ ) { \
- if( *pv == value ) return; \
-\
- } else if( OperI == AST__NE ) { \
- if( *pv != value ) return; \
-\
- } else if( OperI == AST__GE ) { \
- if( *pv >= value ) return; \
-\
- } else { \
- if( *pv > value ) return; \
- } \
-\
-/* Move left a pixel. */ \
- pv--; \
- (*iv)--; \
- } \
-\
-/* Move right a pixel so that *inx == xlo. */ \
- pv++; \
- (*iv)++; \
- (*inx)++; \
-\
-/* Move down along the left hand edge of the box corresponding to the current \
- skin. */ \
- for( *iny = yhi; *iny >= ylo; (*iny)-- ) { \
-\
-/* Test the pixel value, returning if it is valid. */ \
- if( OperI == AST__LT ) { \
- if( *pv < value ) return; \
-\
- } else if( OperI == AST__LE ) { \
- if( *pv <= value ) return; \
-\
- } else if( OperI == AST__EQ ) { \
- if( *pv == value ) return; \
-\
- } else if( OperI == AST__NE ) { \
- if( *pv != value ) return; \
-\
- } else if( OperI == AST__GE ) { \
- if( *pv >= value ) return; \
-\
- } else { \
- if( *pv > value ) return; \
- } \
-\
-/* Move down a pixel. */ \
- pv -= nx; \
- *iv -= nx; \
- } \
-\
-/* Move up a pixel so that *iny == ylo. */ \
- pv += nx; \
- *iv += nx; \
- (*iny)++; \
-\
-/* Move right along the bottom edge of the box corresponding to the current \
- skin. */ \
- for( *inx = xlo; *inx <= xhi; (*inx)++ ) { \
-\
-/* Test the pixel value, returning if it is valid. */ \
- if( OperI == AST__LT ) { \
- if( *pv < value ) return; \
-\
- } else if( OperI == AST__LE ) { \
- if( *pv <= value ) return; \
-\
- } else if( OperI == AST__EQ ) { \
- if( *pv == value ) return; \
-\
- } else if( OperI == AST__NE ) { \
- if( *pv != value ) return; \
-\
- } else if( OperI == AST__GE ) { \
- if( *pv >= value ) return; \
-\
- } else { \
- if( *pv > value ) return; \
- } \
-\
-/* Move right a pixel. */ \
- pv++; \
- (*iv)++; \
- } \
-\
-/* Move left a pixel so that *inx == xhi. */ \
- pv--; \
- (*iv)--; \
- (*inx)--; \
-\
-/* Move up the right hand edge of the box correspionding to the current \
- skin. We stop just below the middle of the right hand edge. */ \
- for( *iny = ylo; *iny < cy; (*iny)++ ) { \
-\
-/* Test the pixel value, returning if it is valid. This relies on the \
- compiler optimisation to remove the "if" statements for all but the \
- operation appropriate to the function being defined. */ \
- if( OperI == AST__LT ) { \
- if( *pv < value ) return; \
-\
- } else if( OperI == AST__LE ) { \
- if( *pv <= value ) return; \
-\
- } else if( OperI == AST__EQ ) { \
- if( *pv == value ) return; \
-\
- } else if( OperI == AST__NE ) { \
- if( *pv != value ) return; \
-\
- } else if( OperI == AST__GE ) { \
- if( *pv >= value ) return; \
-\
- } else { \
- if( *pv > value ) return; \
- } \
-\
-/* Move up a pixel. */ \
- pv += nx; \
- *iv += nx; \
- } \
- } \
-\
-/* Report an error if no inside pooint could be found. */ \
- if( OperI == AST__LT ) { \
- text = "less than"; \
- } else if( OperI == AST__LE ) { \
- text = "less than or equal to"; \
- } else if( OperI == AST__EQ ) { \
- text = "equal to"; \
- } else if( OperI == AST__NE ) { \
- text = "not equal to"; \
- } else if( OperI == AST__GE ) { \
- text = "greater than or equal to"; \
- } else { \
- text = "greater than"; \
- } \
- astError( AST__NONIN, "astOutline"#X": Could not find a pixel value %s " \
- "%g in the supplied array.", status, text, (double) value ); \
-}
-
-/* Define a macro that uses the above macro to to create implementations
- of FindInsidePoint for all operations. */
-#define MAKEALL_FINDINSIDEPOINT(X,Xtype) \
-MAKE_FINDINSIDEPOINT(X,Xtype,LT,AST__LT) \
-MAKE_FINDINSIDEPOINT(X,Xtype,LE,AST__LE) \
-MAKE_FINDINSIDEPOINT(X,Xtype,EQ,AST__EQ) \
-MAKE_FINDINSIDEPOINT(X,Xtype,GE,AST__GE) \
-MAKE_FINDINSIDEPOINT(X,Xtype,GT,AST__GT) \
-MAKE_FINDINSIDEPOINT(X,Xtype,NE,AST__NE)
-
-/* Expand the above macro to generate a function for each required
- data type and operation. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-MAKEALL_FINDINSIDEPOINT(LD,long double)
-#endif
-MAKEALL_FINDINSIDEPOINT(D,double)
-MAKEALL_FINDINSIDEPOINT(L,long int)
-MAKEALL_FINDINSIDEPOINT(UL,unsigned long int)
-MAKEALL_FINDINSIDEPOINT(I,int)
-MAKEALL_FINDINSIDEPOINT(UI,unsigned int)
-MAKEALL_FINDINSIDEPOINT(S,short int)
-MAKEALL_FINDINSIDEPOINT(US,unsigned short int)
-MAKEALL_FINDINSIDEPOINT(B,signed char)
-MAKEALL_FINDINSIDEPOINT(UB,unsigned char)
-MAKEALL_FINDINSIDEPOINT(F,float)
-
-/* Undefine the macros. */
-#undef MAKE_FINDINSIDEPOINT
-#undef MAKEALL_FINDINSIDEPOINT
-
-static void FindMax( Segment *seg, AstFrame *frm, double *x, double *y,
- int nv, int abs, int *status ){
-/*
-* Name:
-* FindMax
-
-* Purpose:
-* Find the maximum discrepancy between a given line segment and the
-* Polygon being downsized.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void FindMax( Segment *seg, AstFrame *frm, double *x, double *y,
-* int nv, int abs, int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* The supplied Segment structure describes a range of vertices in
-* the polygon being downsized. This function checks each of these
-* vertices to find the one that lies furthest from the line joining the
-* first and last vertices in the segment. The maximum error, and the
-* vertex index at which this maximum error is found, is stored in the
-* Segment structure.
-
-* Parameters:
-* seg
-* The structure describing the range of vertices to check. It
-* corresponds to a candidate edge in the downsized polygon.
-* frm
-* The Frame in which the positions are defined.
-* x
-* Pointer to the X axis values in the original Polygon.
-* y
-* Pointer to the Y axis values in the original Polygon.
-* nv
-* Total number of vertics in the old Polygon..
-* abs
-* If non-zero, then the stored maximum is the position with
-* maximum absolute error. Otherwise, the stored maximum is the
-* position with maximum positive error (positive errors are to the
-* right when travelling from start to end of the segment).
-* status
-* Pointer to the inherited status variable.
-
-*/
-
-/* Local Variables: */
- AstPointSet *pset1; /* PointSet holding vertex positions */
- AstPointSet *pset2; /* PointSet holding offset par/perp components */
- double **ptr1; /* Pointers to "pset1" data arrays */
- double **ptr2; /* Pointers to "pset2" data arrays */
- double *px; /* Pointer to next X value */
- double *py; /* Pointer to next Y value */
- double ax; /* X value at start */
- double ay; /* Y value at start */
- double ba; /* Distance between a and b */
- double bax; /* X increment from a to b */
- double bay; /* Y increment from a to b */
- double cax; /* X increment from a to c */
- double cay; /* Y increment from a to c */
- double end[ 2 ]; /* Position of starting vertex */
- double error; /* Error value for current vertex */
- double start[ 2 ]; /* Position of starting vertex */
- int i1; /* Starting index (always in first cycle) */
- int i2; /* Ending index converted to first cycle */
- int i2b; /* Upper vertex limit in first cycle */
- int i; /* Loop count */
- int n; /* Number of vertices to check */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Stuff needed for handling cyclic redundancy of vertex indices. */
- i1 = seg->i1;
- i2 = seg->i2;
- n = i2 - i1 - 1;
- i2b = i2;
- if( i2 >= nv ) {
- i2 -= nv;
- i2b = nv;
- }
-
-/* If the segment has no intermediate vertices, set the segment error to
- zero and return. */
- if( n < 1 ) {
- seg->error = 0.0;
- seg->imax = i1;
-
-/* For speed, we use simple plane geometry if the Polygon is defined in a
- simple Frame. */
- } else if( !strcmp( astGetClass( frm ), "Frame" ) ) {
-
-/* Point "a" is the vertex that marks the start of the segment. Point "b"
- is the vertex that marks the end of the segment. */
- ax = x[ i1 ];
- ay = y[ i1 ];
- bax = x[ i2 ] - ax;
- bay = y[ i2 ] - ay;
- ba = sqrt( bax*bax + bay*bay );
-
-/* Initialise the largest error found so far. */
- seg->error = -1.0;
-
-/* Check the vertices from the start (plus one) up to the end (minus one)
- or the last vertex (which ever comes first). */
- for( i = i1 + 1; i < i2b; i++ ) {
-
-/* Position "c" is the vertex being tested. Find the squared distance from
- "c" to the line joining "a" and "b". */
- cax = x[ i ] - ax;
- cay = y[ i ] - ay;
- error = ( bay*cax - cay*bax )/ba;
- if( abs ) error = fabs( error );
-
-/* If this is the largest value found so far, record it. Note the error
- here is a squared distance. */
- if( error > seg->error ) {
- seg->error = error;
- seg->imax = i;
- }
- }
-
-/* If the end vertex is in the next cycle, check the remaining vertex
- posI would have thought a telentitions in the same way. */
- if( i2b != i2 ) {
-
- for( i = 0; i < i2; i++ ) {
-
- cax = x[ i ] - ax;
- cay = y[ i ] - ay;
- error = ( bay*cax - cay*bax )/ba;
- if( abs ) error = fabs( error );
-
- if( error > seg->error ) {
- seg->error = error;
- seg->imax = i + i2b;
- }
-
- }
- }
-
-/* If the polygon is not defined in a simple Frame, we use the overloaded
- Frame methods to do the geometry. */
- } else {
-
-/* Create a PointSet to hold the positions of the vertices to test. We do
- not need to test the start or end vertex. */
- pset1 = astPointSet( n, 2, " ", status );
- ptr1 = astGetPoints( pset1 );
- if( astOK ) {
-
-/* Copy the vertex axis values form the start (plus one) up to the end
- (minus one) vertex or the last vertex (which ever comes first). */
- px = ptr1[ 0 ];
- py = ptr1[ 1 ];
-
- for( i = i1 + 1; i < i2b; i++ ){
- *(px++) = x[ i ];
- *(py++) = y[ i ];
- }
-
-/* If the end vertex is in the next cycle, copy the remaining vertex
- positions into the PointSet. */
- if( i2b != i2 ) {
- for( i = 0; i < i2; i++ ) {
- *(px++) = x[ i ];
- *(py++) = y[ i ];
- }
- }
-
-/* Record the start and end vertex positions. */
- start[ 0 ] = x[ i1 ];
- start[ 1 ] = y[ i1 ];
- end[ 0 ] = x[ i2 ];
- end[ 1 ] = y[ i2 ];
-
-/* Resolve the vector from the start to each vertex into two components,
- parallel and perpendicular to the start->end vector. */
- pset2 = astResolvePoints( frm, start, end, pset1, NULL );
- ptr2 = astGetPoints( pset2 );
- if( astOK ) {
-
-/* Find the vertex with largest perpendicular component. */
- seg->error = -1.0;
- py = ptr2[ 1 ];
- for( i = 1; i <= n; i++ ) {
-
- error = *(py++);
- if( abs ) error = fabs( error );
-
- if( error > seg->error ) {
- seg->error = error;
- seg->imax = i + i1;
- }
-
- }
- }
-
-/* Free resources. */
- pset2 = astAnnul( pset2 );
- }
- pset1 = astAnnul( pset1 );
- }
-}
-
-static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
-/*
-* Name:
-* GetAttrib
-
-* Purpose:
-* Get the value of a specified attribute for a Polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* const char *GetAttrib( AstObject *this, const char *attrib, int *status )
-
-* Class Membership:
-* Polygon member function (over-rides the protected astGetAttrib
-* method inherited from the Region class).
-
-* Description:
-* This function returns a pointer to the value of a specified
-* attribute for a Polygon, formatted as a character string.
-
-* Parameters:
-* this
-* Pointer to the Polygon.
-* attrib
-* Pointer to a null-terminated string containing the name of
-* the attribute whose value is required. This name should be in
-* lower case, with all white space removed.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* - Pointer to a null-terminated string containing the attribute
-* value.
-
-* Notes:
-* - The returned string pointer may point at memory allocated
-* within the Polygon, or at static memory. The contents of the
-* string may be over-written or the pointer may become invalid
-* following a further invocation of the same function or any
-* modification of the Polygon. A copy of the string should
-* therefore be made if necessary.
-* - A NULL pointer will be returned if this function is invoked
-* with the global error status set, or if it should fail for any
-* reason.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstPolygon *this; /* Pointer to the Polygon structure */
- const char *result; /* Pointer value to return */
- int ival; /* Integer attribute value */
-
-/* Initialise. */
- result = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Get a pointer to the thread specific global data structure. */
- astGET_GLOBALS(this_object);
-
-/* Obtain a pointer to the Polygon structure. */
- this = (AstPolygon *) this_object;
-
-/* Compare "attrib" with each recognised attribute name in turn,
- obtaining the value of the required attribute. If necessary, write
- the value into "getattrib_buff" as a null-terminated string in an appropriate
- format. Set "result" to point at the result string. */
-
-/* SimpVertices. */
-/* ------------- */
- if ( !strcmp( attrib, "simpvertices" ) ) {
- ival = astGetSimpVertices( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* If the attribute name was not recognised, pass it on to the parent
- method for further interpretation. */
- } else {
- result = (*parent_getattrib)( this_object, attrib, status );
- }
-
-/* Return the result. */
- return result;
-
-}
-
-static int GetBounded( AstRegion *this, int *status ) {
-/*
-* Name:
-* GetBounded
-
-* Purpose:
-* Is the Region bounded?
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* int GetBounded( AstRegion *this, int *status )
-
-* Class Membership:
-* Polygon method (over-rides the astGetBounded method inherited from
-* the Region class).
-
-* Description:
-* This function returns a flag indicating if the Region is bounded.
-* The implementation provided by the base Region class is suitable
-* for Region sub-classes representing the inside of a single closed
-* curve (e.g. Circle, Interval, Box, etc). Other sub-classes (such as
-* CmpRegion, PointList, etc ) may need to provide their own
-* implementations.
-
-* Parameters:
-* this
-* Pointer to the Region.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Non-zero if the Region is bounded. Zero otherwise.
-
-*/
-
-/* Local Variables: */
- int neg; /* Has the Polygon been negated? */
- int result; /* Returned result */
-
-/* Initialise */
- result = 0;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Ensure cached information is available. */
- Cache( (AstPolygon *) this, status );
-
-/* See if the Polygon has been negated. */
- neg = astGetNegated( this );
-
-/* If the polygon vertices are stored in anti-clockwise order, then the
- polygon is bounded if it has not been negated. */
- if( ( (AstPolygon *) this)->acw ) {
- result = (! neg );
-
-/* If the polygon vertices are stored in clockwise order, then the
- polygon is bounded if it has been negated. */
- } else {
- result = neg;
- }
-
-/* Return the result. */
- return result;
-}
-
-void astInitPolygonVtab_( AstPolygonVtab *vtab, const char *name, int *status ) {
-/*
-*+
-* Name:
-* astInitPolygonVtab
-
-* Purpose:
-* Initialise a virtual function table for a Polygon.
-
-* Type:
-* Protected function.
-
-* Synopsis:
-* #include "polygon.h"
-* void astInitPolygonVtab( AstPolygonVtab *vtab, const char *name )
-
-* Class Membership:
-* Polygon vtab initialiser.
-
-* Description:
-* This function initialises the component of a virtual function
-* table which is used by the Polygon class.
-
-* Parameters:
-* vtab
-* Pointer to the virtual function table. The components used by
-* all ancestral classes will be initialised if they have not already
-* been initialised.
-* name
-* Pointer to a constant null-terminated character string which contains
-* the name of the class to which the virtual function table belongs (it
-* is this pointer value that will subsequently be returned by the Object
-* astClass function).
-*-
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */
- AstRegionVtab *region; /* Pointer to Region component of Vtab */
- AstObjectVtab *object; /* Pointer to Object component of Vtab */
-
-/* Check the local error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the thread specific global data structure. */
- astGET_GLOBALS(NULL);
-
-/* Initialize the component of the virtual function table used by the
- parent class. */
- astInitRegionVtab( (AstRegionVtab *) vtab, name );
-
-/* Store a unique "magic" value in the virtual function table. This
- will be used (by astIsAPolygon) to determine if an object belongs
- to this class. We can conveniently use the address of the (static)
- class_check variable to generate this unique value. */
- vtab->id.check = &class_check;
- vtab->id.parent = &(((AstRegionVtab *) vtab)->id);
-
-/* Initialise member function pointers. */
-/* ------------------------------------ */
-/* Store pointers to the member functions (implemented here) that provide
- virtual methods for this class. */
- vtab->Downsize = Downsize;
-
-/* Save the inherited pointers to methods that will be extended, and
- replace them with pointers to the new member functions. */
- object = (AstObjectVtab *) vtab;
- mapping = (AstMappingVtab *) vtab;
- region = (AstRegionVtab *) vtab;
-
- parent_transform = mapping->Transform;
- mapping->Transform = Transform;
-
- parent_simplify = mapping->Simplify;
- mapping->Simplify = Simplify;
-
- parent_setregfs = region->SetRegFS;
- region->SetRegFS = SetRegFS;
-
- parent_resetcache = region->ResetCache;
- region->ResetCache = ResetCache;
-
- parent_clearattrib = object->ClearAttrib;
- object->ClearAttrib = ClearAttrib;
- parent_getattrib = object->GetAttrib;
- object->GetAttrib = GetAttrib;
- parent_setattrib = object->SetAttrib;
- object->SetAttrib = SetAttrib;
- parent_testattrib = object->TestAttrib;
- object->TestAttrib = TestAttrib;
-
- region->RegPins = RegPins;
- region->RegBaseMesh = RegBaseMesh;
- region->RegBaseBox = RegBaseBox;
- region->RegTrace = RegTrace;
- region->GetBounded = GetBounded;
-
- vtab->ClearSimpVertices = ClearSimpVertices;
- vtab->GetSimpVertices = GetSimpVertices;
- vtab->SetSimpVertices = SetSimpVertices;
- vtab->TestSimpVertices = TestSimpVertices;
-
-/* Store replacement pointers for methods which will be over-ridden by
- new member functions implemented here. */
-
-/* Declare the copy constructor, destructor and class dump
- functions. */
- astSetDump( vtab, Dump, "Polygon", "Polygonal region" );
- astSetDelete( vtab, Delete );
- astSetCopy( vtab, Copy );
-
-/* If we have just initialised the vtab for the current class, indicate
- that the vtab is now initialised, and store a pointer to the class
- identifier in the base "object" level of the vtab. */
- if( vtab == &class_vtab ) {
- class_init = 1;
- astSetVtabClassIdentifier( vtab, &(vtab->id) );
- }
-}
-
-static int IntCmp( const void *a, const void *b ){
-/*
-* Name:
-* IntCmp
-
-* Purpose:
-* An integer comparison function for the "qsort" function.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* int IntCmp( const void *a, const void *b )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* See the docs for "qsort".
-
-* Parameters:
-* a
-* Pointer to the first int
-* b
-* Pointer to the second int
-
-* Returnd Value:
-* Positive, negative or zero, depending on whether a is larger than,
-* equal to, or less than b.
-
-*/
-
- return *((int*)a) - *((int*)b);
-}
-
-static Segment *NewSegment( Segment *seg, int i1, int i2, int nvert,
- int *status ){
-/*
-* Name:
-* NewSegment
-
-* Purpose:
-* Initialise a structure describing a segment of the new Polygon
-* created by astDownsize.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* Segment *NewSegment( Segment *seg, int i1, int i2, int nvert,
-* int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* This function initialises the contents of a structure describing
-* the specified range of vertices within a Polygon. The cyclic nature
-* of vertex indices is taken into account.
-*
-* If no structure is supplied, memory is allocated to hold a new
-* structure.
-
-* Parameters:
-* seg
-* Pointer to a structure to initialise, or NULL if a new structure
-* is to be allocated.
-* i1
-* The index of a vertex within the old Polygon (supplied to
-* astDownsize) that marks the start of the new line segment in
-* the downsized polygon.
-* i2
-* The index of a vertex within the old Polygon (supplied to
-* astDownsize) that marks the end of the new line segment in
-* the downsized polygon.
-* nvert
-* Total number of vertics in the old Polygon..
-* status
-* Pointer to the inherited status variable.
-
-* Returnd Value:
-* Pointer to the initialised Segment structure. It should be freed using
-* astFree when no longer needed.
-
-*/
-
-/* Local Variables: */
- Segment *result;
-
-/* Check the global error status. */
- if ( !astOK ) return NULL;
-
-/* Get a pointer to the structure to be initialised, allocating memory
- for a new structure if none was supplied. */
- result = seg ? seg : astMalloc( sizeof( Segment ) );
-
-/* Check the pointer can be used safely. */
- if( result ) {
-
-/* If the supplied ending index is less than the starting index, the
- ending index must have gone all the way round the polygon and started
- round again. Increase the ending index by the number of vertices to
- put it in the same cycle as the starting index. */
- if( i2 < i1 ) i2 += nvert;
-
-/* If the supplied starting index is within the first cycle (i.e. zero ->
- nvert-1 ), use the indices as they are (which may mean that the ending
- index is greater than nvert, but this is handled correctly by other
- functions). */
- if( i1 < nvert ) {
- result->i1 = i1;
- result->i2 = i2;
-
-/* If the supplied starting index is within the second cycle (i.e. nvert
- or greater) the ending index will be even greater, so we can reduce
- both by "nvert" to put them both in the first cycle. The goal is that
- the starting index should always be in the first cycle, but the ending
- index may possibly be in the second cycle. */
- } else {
- result->i1 = i1 - nvert;
- result->i2 = i2 - nvert;
- }
-
-/* Nullify the links to other Segments */
- result->next = NULL;
- result->prev = NULL;
- }
-
-/* Return the pointer to the new Segment structure. */
- return result;
-}
-
-/*
-*++
-* Name:
-c astOutline<X>
-f AST_OUTLINE<X>
-
-* Purpose:
-* Create a new Polygon outling values in a 2D data grid.
-
-* Type:
-* Public function.
-
-* Synopsis:
-c #include "polygon.h"
-c AstPolygon *astOutline<X>( <Xtype> value, int oper, const <Xtype> array[],
-c const int lbnd[2], const int ubnd[2], double maxerr,
-c int maxvert, const int inside[2], int starpix )
-f RESULT = AST_OUTLINE<X>( VALUE, OPER, ARRAY, LBND, UBND, MAXERR,
-f MAXVERT, INSIDE, STARPIX, STATUS )
-
-* Class Membership:
-* Polygon method.
-
-* Description:
-* This is a set of functions that create a Polygon enclosing a single
-* contiguous set of pixels that have a specified value within a gridded
-* 2-dimensional data array (e.g. an image).
-*
-* A basic 2-dimensional Frame is used to represent the pixel coordinate
-* system in the returned Polygon. The Domain attribute is set to
-* "PIXEL", the Title attribute is set to "Pixel coordinates", and the
-* Unit attribute for each axis is set to "pixel". All other
-* attributes are left unset. The nature of the pixel coordinate system
-* is determined by parameter
-c "starpix".
-f STARPIX.
-*
-* The
-c "maxerr" and "maxvert"
-f MAXERR and MAXVERT
-* parameters can be used to control how accurately the returned
-* Polygon represents the required region in the data array. The
-* number of vertices in the returned Polygon will be the minimum
-* needed to achieve the required accuracy.
-*
-* You should use a function which matches the numerical type of the
-* data you are processing by replacing <X> in the generic function
-* name
-c astOutline<X>
-f AST_OUTLINE<X>
-c by an appropriate 1- or 2-character type code. For example, if you
-* are procesing data with type
-c "float", you should use the function astOutlineF
-f REAL, you should use the function AST_OUTLINER
-* (see the "Data Type Codes" section below for the codes appropriate to
-* other numerical types).
-
-* Parameters:
-c value
-f VALUE = <Xtype> (Given)
-* A data value that specifies the pixels to be outlined.
-c oper
-f OPER = INTEGER (Given)
-* Indicates how the
-c "value"
-f VALUE
-* parameter is used to select the outlined pixels. It can
-* have any of the following values:
-c - AST__LT: outline pixels with value less than "value".
-c - AST__LE: outline pixels with value less than or equal to "value".
-c - AST__EQ: outline pixels with value equal to "value".
-c - AST__NE: outline pixels with value not equal to "value".
-c - AST__GE: outline pixels with value greater than or equal to "value".
-c - AST__GT: outline pixels with value greater than "value".
-f - AST__LT: outline pixels with value less than VALUE.
-f - AST__LE: outline pixels with value less than or equal to VALUE.
-f - AST__EQ: outline pixels with value equal to VALUE.
-f - AST__NE: outline pixels with value not equal to VALUE.
-f - AST__GE: outline pixels with value greater than or equal to VALUE.
-f - AST__GT: outline pixels with value greater than VALUE.
-c array
-f ARRAY( * ) = <Xtype> (Given)
-c Pointer to a
-f A
-* 2-dimensional array containing the data to be processed. The
-* numerical type of this array should match the 1- or
-* 2-character type code appended to the function name (e.g. if
-c you are using astOutlineF, the type of each array element
-c should be "float").
-f you are using AST_OUTLINER, the type of each array element
-f should be REAL).
-*
-* The storage order of data within this array should be such
-* that the index of the first grid dimension varies most
-* rapidly and that of the second dimension least rapidly
-c (i.e. Fortran array indexing is used).
-f (i.e. normal Fortran array storage order).
-c lbnd
-f LBND( 2 ) = INTEGER (Given)
-c Pointer to an array of two integers
-f An array
-* containing the pixel index of the first pixel in the input grid
-* along each dimension.
-c ubnd
-f UBND( 2) = INTEGER (Given)
-c Pointer to an array of two integers
-f An array
-* containing the pixel index of the last pixel in the input grid
-* along each dimension.
-*
-c Note that "lbnd" and "ubnd" together define the shape
-f Note that LBND and UBND together define the shape
-* and size of the input pixel grid, its extent along a particular
-c (j'th) dimension being ubnd[j]-lbnd[j]+1 pixels.
-f (J'th) dimension being UBND(J)-LBND(J)+1 pixels.
-* For FITS images,
-c the lbnd values will be 1 and the ubnd
-f the LBND values will be 1 and the UBND
-* values will be equal to the NAXISi header values. Other
-* data systems, such as the Starlink NDF system, allow an
-c arbitrary pixel origin to be used (i.e. lbnd
-f arbitrary pixel origin to be used (i.e. LBND
-* is not necessarily 1).
-*
-* These bounds also define the input grid's floating point coordinate
-* system, each pixel having unit extent along each dimension with
-* integral coordinate values at its centre or upper corner, as selected
-* by parameter
-c "starpix".
-f STARPIX.
-c maxerr
-f MAXERR = DOUBLE PRECISION (Given)
-* Together with
-c "maxvert",
-f MAXVERT,
-* this determines how accurately the returned Polygon represents
-* the required region of the data array. It gives the target
-* discrepancy between the returned Polygon and the accurate outline
-* in the data array, expressed as a number of pixels. Insignificant
-* vertices are removed from the accurate outline, one by one, until
-* the number of vertices remaining in the returned Polygon equals
-c "maxvert",
-f MAXVERT,
-* or the largest discrepancy between the accurate outline and the
-* returned Polygon is greater than
-c "maxerr". If "maxerr"
-f MAXERR. If MAXERR
-* is zero or less, its value is ignored and the returned Polygon will
-* have the number of vertices specified by
-c "maxvert".
-f MAXVERT.
-c maxvert
-f MAXVERT = INTEGER (Given)
-* Together with
-c "maxerr",
-f MAXERR,
-* this determines how accurately the returned Polygon represents
-* the required region of the data array. It gives the maximum
-* allowed number of vertices in the returned Polygon. Insignificant
-* vertices are removed from the accurate outline, one by one, until
-* the number of vertices remaining in the returned Polygon equals
-c "maxvert",
-f MAXVERT,
-* or the largest discrepancy between the accurate outline and the
-* returned Polygon is greater than
-c "maxerr". If "maxvert"
-f MAXERR. If MAXVERT
-* is less than 3, its value is ignored and the number of vertices in
-* the returned Polygon will be the minimum needed to ensure that the
-* discrepancy between the accurate outline and the returned
-* Polygon is less than
-c "maxerr".
-f MAXERR.
-c inside
-f INSIDE( 2 ) = INTEGER (Given)
-c Pointer to an array of two integers
-f An array
-* containing the pixel indices of a pixel known to be inside the
-* required region. This is needed because the supplied data
-* array may contain several disjoint areas of pixels that satisfy
-* the criterion specified by
-c "value" and "oper".
-f VALUE and OPER.
-* In such cases, the area described by the returned Polygon will
-* be the one that contains the pixel specified by
-c "inside".
-f INSIDE.
-* If the specified pixel is outside the bounds given by
-c "lbnd" and "ubnd",
-f LBND and UBND,
-* or has a value that does not meet the criterion specified by
-c "value" and "oper",
-f VALUE and OPER,
-* then this function will search for a suitable pixel. The search
-* starts at the central pixel and proceeds in a spiral manner until
-* a pixel is found that meets the specified crierion.
-c starpix
-f STARPIX = LOGICAL (Given)
-* A flag indicating the nature of the pixel coordinate system used
-* to describe the vertex positions in the returned Polygon. If
-c non-zero,
-f .TRUE.,
-* the standard Starlink definition of pixel coordinate is used in
-* which a pixel with integer index I spans a range of pixel coordinate
-* from (I-1) to I (i.e. pixel corners have integral pixel coordinates).
-c If zero,
-f If .FALSE.,
-* the definition of pixel coordinate used by other AST functions
-c such as astResample, astMask,
-f such as AST_RESAMPLE, AST_MASK,
-* etc., is used. In this definition, a pixel with integer index I
-* spans a range of pixel coordinate from (I-0.5) to (I+0.5) (i.e.
-* pixel centres have integral pixel coordinates).
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astOutline<X>()
-f AST_OUTLINE<X> = INTEGER
-* A pointer to the required Polygon.
-
-* Notes:
-* - This function proceeds by first finding a very accurate polygon,
-* and then removing insignificant vertices from this fine polygon
-* using
-c astDownsize.
-f AST_DOWNSIZE.
-* - The returned Polygon is the outer boundary of the contiguous set
-* of pixels that includes ths specified "inside" point, and satisfy
-* the specified value requirement. This set of pixels may potentially
-* include "holes" where the pixel values fail to meet the specified
-* value requirement. Such holes will be ignored by this function.
-c - NULL
-f - AST__NULL
-* will be returned if this function is invoked with the global
-* error status set, or if it should fail for any reason.
-
-* Data Type Codes:
-* To select the appropriate masking function, you should
-c replace <X> in the generic function name astOutline<X> with a
-f replace <X> in the generic function name AST_OUTLINE<X> with a
-* 1- or 2-character data type code, so as to match the numerical
-* type <Xtype> of the data you are processing, as follows:
-c - D: double
-c - F: float
-c - L: long int
-c - UL: unsigned long int
-c - I: int
-c - UI: unsigned int
-c - S: short int
-c - US: unsigned short int
-c - B: byte (signed char)
-c - UB: unsigned byte (unsigned char)
-f - D: DOUBLE PRECISION
-f - R: REAL
-f - I: INTEGER
-f - UI: INTEGER (treated as unsigned)
-f - S: INTEGER*2 (short integer)
-f - US: INTEGER*2 (short integer, treated as unsigned)
-f - B: BYTE (treated as signed)
-f - UB: BYTE (treated as unsigned)
-*
-c For example, astOutlineD would be used to process "double"
-c data, while astOutlineS would be used to process "short int"
-c data, etc.
-f For example, AST_OUTLINED would be used to process DOUBLE
-f PRECISION data, while AST_OUTLINES would be used to process
-f short integer data (stored in an INTEGER*2 array), etc.
-f
-f For compatibility with other Starlink facilities, the codes W
-f and UW are provided as synonyms for S and US respectively (but
-f only in the Fortran interface to AST).
-
-*--
-*/
-/* Define a macro to implement the function for a specific data
- type. Note, this function cannot be a virtual function since the
- argument list does not include a Polygon, and so no virtual function
- table is available. */
-#define MAKE_OUTLINE(X,Xtype) \
-AstPolygon *astOutline##X##_( Xtype value, int oper, const Xtype array[], \
- const int lbnd[2], const int ubnd[2], double maxerr, \
- int maxvert, const int inside[2], int starpix, \
- int *status ) { \
-\
-/* Local Variables: */ \
- AstFrame *frm; /* Frame in which to define the Polygon */ \
- AstPointSet *candidate; /* Candidate polygon vertices */ \
- AstPointSet *pset; /* PointSet holding downsized polygon vertices */ \
- AstPolygon *result; /* Result value to return */ \
- const Xtype *pv; /* Pointer to next test point */ \
- Xtype v; /* Value of current pixel */ \
- double **ptr; /* Pointers to PointSet arrays */ \
- int boxsize; /* Half width of smoothign box in vertices */ \
- int inx; /* X index of inside point */ \
- int iny; /* Y index of inside point */ \
- int iv; /* Vector index of next test pixel */ \
- int ixv; /* X pixel index of next test point */ \
- int nv0; /* Number of vertices in accurate outline */ \
- int nx; /* Length of array x axis */ \
- int smooth; /* Do we need to smooth the polygon? */ \
- int stop_at_invalid; /* Indicates when to stop rightwards search */ \
- int tmp; /* Alternative boxsize */ \
- int valid; /* Does current pixel meet requirements? */ \
- static double junk[ 6 ] = {0.0, 0.0, 1.0, 1.0, 0.0, 1.0 }; /* Junk poly */ \
-\
-/* Initialise. */ \
- result = NULL; \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return result; \
-\
-/* Avoid compiler warnings. */ \
- iv = 0; \
-\
-/* If we are going to be smoothing the polygon before downsizing it, we \
- need to ensure that the full polygon is retained within TraceEdge. if \
- this is not the case, TraceEdge can remove all vertices from straight \
- lines, except for the vertices that mark the beinning and end of the \
- straight line. */ \
- smooth = ( maxerr > 0.0 || maxvert > 2 ); \
-\
-/* Store the X dimension of the array. */ \
- nx = ubnd[ 0 ] - lbnd[ 0 ] + 1; \
-\
-/* See if a valid inside point was supplied. It must be inside the bounds \
- of the array, and must have a pixel value that meets the specified \
- requirement. */ \
- inx = inside[ 0 ]; \
- iny = inside[ 1 ]; \
- valid = ( inx >= lbnd[ 0 ] && inx <= ubnd[ 0 ] && \
- iny >= lbnd[ 1 ] && iny <= ubnd[ 1 ] ); \
-\
- if( valid ) { \
- iv = ( inx - lbnd[ 0 ] ) + (iny - lbnd[ 1 ] )*nx; \
- v = array[ iv ]; \
-\
- if( oper == AST__LT ) { \
- valid = ( v < value ); \
-\
- } else if( oper == AST__LE ) { \
- valid = ( v <= value ); \
-\
- } else if( oper == AST__EQ ) { \
- valid = ( v == value ); \
-\
- } else if( oper == AST__NE ) { \
- valid = ( v != value ); \
-\
- } else if( oper == AST__GE ) { \
- valid = ( v >= value ); \
-\
- } else if( oper == AST__GT ) { \
- valid = ( v > value ); \
-\
- } else if( astOK ){ \
- astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \
- "(%d) supplied (programming error).", status, oper ); \
- } \
- } \
-\
-/* If no valid inside point was supplied, find one now. */ \
- if( !valid ) { \
-\
- if( oper == AST__LT ) { \
- FindInsidePointLT##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \
-\
- } else if( oper == AST__LE ) { \
- FindInsidePointLE##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \
-\
- } else if( oper == AST__EQ ) { \
- FindInsidePointEQ##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \
-\
- } else if( oper == AST__NE ) { \
- FindInsidePointNE##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \
-\
- } else if( oper == AST__GE ) { \
- FindInsidePointGE##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \
-\
- } else if( oper == AST__GT ) { \
- FindInsidePointGT##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \
-\
- } else if( astOK ){ \
- astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \
- "(%d) supplied (programming error).", status, oper ); \
- } \
- } \
-\
-/* We now need to find a point on the boundary of the region containing \
- the inside point. Starting at the inside point, move to the right \
- through the array until a pixel is found which fails to meet the value \
- requirement or the edge of the array is reached. */ \
-\
- candidate = NULL; \
- pv = array + iv; \
- ixv = inx; \
- stop_at_invalid = 1; \
-\
- while( ++ixv <= ubnd[ 0 ] ) { \
-\
-/* Get the next pixel value. */ \
- v = *(++pv); \
-\
-/* See if it meets the value requirement. */ \
- if( oper == AST__LT ) { \
- valid = ( v < value ); \
-\
- } else if( oper == AST__LE ) { \
- valid = ( v <= value ); \
-\
- } else if( oper == AST__EQ ) { \
- valid = ( v == value ); \
-\
- } else if( oper == AST__NE ) { \
- valid = ( v != value ); \
-\
- } else if( oper == AST__GE ) { \
- valid = ( v >= value ); \
-\
- } else if( oper == AST__GT ) { \
- valid = ( v > value ); \
-\
- } else if( astOK ){ \
- astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \
- "(%d) supplied (programming error).", status, oper ); \
- break; \
- } \
-\
-/* If we are currently looking for the next invalid pixel, and this pixel \
- is invalid... */ \
- if( stop_at_invalid ) { \
- if( ! valid ) { \
-\
-/* The current pixel may be on the required polygon, or it may be on the \
- edge of a hole contained within the region being outlined. We would \
- like to jump over such holes so that we can continue to look for the \
- real edge of the region being outlined. In order to determine if we \
- have reached a hole, we trace the edge that passes through the current \
- pixel, forming a candidate polygon in the process. In the process, We \
- see if the inside point falls within this candidate polygon. If it does \
- then the polygon is accepted as the required polygon. Otherwise, it is \
- rejected as a mere hole, and we continue moving away from the inside \
- point, looking for a new edge. */ \
- if( oper == AST__LT ) { \
- candidate = TraceEdgeLT##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__LE ) { \
- candidate = TraceEdgeLE##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__EQ ) { \
- candidate = TraceEdgeEQ##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__NE ) { \
- candidate = TraceEdgeNE##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__GE ) { \
- candidate = TraceEdgeGE##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__GT ) { \
- candidate = TraceEdgeGT##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( astOK ){ \
- astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \
- "(%d) supplied (programming error).", status, oper ); \
- } \
-\
-/* If the candidate polygon is the required polygon, break out of the \
- loop. Otherwise, indicate that we want to continue moving right, \
- across the hole, until we reach the far side of the hole (i.e. find \
- the next valid pixel). */ \
- if( candidate ) { \
- break; \
- } else { \
- stop_at_invalid = 0; \
- } \
- } \
-\
-/* If we are currently looking for the next valid pixel, and the current \
- pixel is valid... */ \
- } else if( valid ) { \
-\
-/* We have reached the far side of a hole. Continue moving right, looking \
- now for the next invalid pixel (which may be on the required polygon). */ \
- stop_at_invalid = 1; \
- } \
- } \
-\
-/* If we have not yet found the required polygon, we must have reached \
- the right hand edge of the array. So we now follow the edge of the \
- array round until we meet the boundary of the required region. */ \
- if( !candidate ) { \
- if( oper == AST__LT ) { \
- candidate = TraceEdgeLT##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__LE ) { \
- candidate = TraceEdgeLE##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__EQ ) { \
- candidate = TraceEdgeEQ##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__NE ) { \
- candidate = TraceEdgeNE##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__GE ) { \
- candidate = TraceEdgeGE##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( oper == AST__GT ) { \
- candidate = TraceEdgeGT##X( value, array, lbnd, ubnd, iv - 1, \
- ixv - 1, iny, starpix, smooth, status ); \
-\
- } else if( astOK ){ \
- astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \
- "(%d) supplied (programming error).", status, oper ); \
- } \
- } \
-\
-/* If required smooth the full resolution polygon before downsizing it. */ \
- if( smooth ) { \
-\
-/* Initially, set the boxsize to be equal to the required accouracy. */ \
- if( maxerr > 0 ) { \
- boxsize = (int) maxerr; \
- } else { \
- boxsize = INT_MAX; \
- } \
-\
-/* Determine a second box size equal to the average number of vertices in \
- the accurate outline, per vertex in the returned Polygon. */ \
- nv0 = astGetNpoint( candidate ); \
- if( maxvert > 2 ) { \
- tmp = nv0/(2*maxvert); \
- } else { \
- tmp = INT_MAX; \
- } \
-\
-/* Use the minimum of the two box sizes. */ \
- if( tmp < boxsize ) boxsize = tmp; \
-\
-/* Ensure the box is sufficiently small to allow at least 10 full boxes \
- (=20 half boxes) around the polygon. */ \
- tmp = nv0/20; \
- if( tmp < boxsize ) boxsize = tmp; \
- if( boxsize == 0 ) boxsize = 1; \
-\
-/* Smooth the polygon. */ \
- SmoothPoly( candidate, boxsize, 1.0, status ); \
- } \
-\
-/* Reduce the number of vertices in the outline. */ \
- frm = astFrame( 2, "Domain=PIXEL,Unit(1)=pixel,Unit(2)=pixel," \
- "Title=Pixel coordinates", status ); \
- pset = DownsizePoly( candidate, maxerr, maxvert, frm, status ); \
-\
-/* Create a default Polygon with 3 junk vertices. */ \
- result = astPolygon( frm, 3, 3, junk, NULL, " ", status ); \
-\
-/* Change the PointSet within the Polygon to the one created above. */ \
- SetPointSet( result, pset, status ); \
-\
-/* Free resources. Note, we need to free the arrays within the candidate \
- PointSet explicitly, since they were not created as part of the \
- construction of the PointSet (see TraceEdge). */ \
- pset = astAnnul( pset ); \
- frm = astAnnul( frm ); \
- ptr = astGetPoints( candidate ); \
- if( astOK ) { \
- astFree( ptr[ 0 ] ); \
- astFree( ptr[ 1 ] ); \
- } \
- candidate = astAnnul( candidate ); \
-\
-/* If an error occurred, clear the returned result. */ \
- if ( !astOK ) result = astAnnul( result ); \
-\
-/* Return the result. */ \
- return result; \
-}
-
-
-/* Expand the above macro to generate a function for each required
- data type. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-MAKE_OUTLINE(LD,long double)
-#endif
-MAKE_OUTLINE(D,double)
-MAKE_OUTLINE(L,long int)
-MAKE_OUTLINE(UL,unsigned long int)
-MAKE_OUTLINE(I,int)
-MAKE_OUTLINE(UI,unsigned int)
-MAKE_OUTLINE(S,short int)
-MAKE_OUTLINE(US,unsigned short int)
-MAKE_OUTLINE(B,signed char)
-MAKE_OUTLINE(UB,unsigned char)
-MAKE_OUTLINE(F,float)
-
-/* Undefine the macros. */
-#undef MAKE_OUTLINE
-
-/*
-* Name:
-* PartHull
-
-* Purpose:
-* Find the convex hull enclosing selected pixels in one corner of a 2D array.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void PartHull<Oper><X>( <Xtype> value, const <Xtype> array[], int xdim,
-* int ydim, int xs, int ys, int xe, int ye,
-* int starpix, const int lbnd[2], double **xvert,
-* double **yvert, int *nvert, int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* This function uses an algorithm similar to "Andrew's Monotone Chain
-* Algorithm" to create a list of vertices describing one corner of the
-* convex hull enclosing the selected pixels in the supplied array.
-* The corner is defined to be the area of the array to the right of
-* the line from (xs,ys) to (xe,ye).
-
-* Parameters:
-* value
-* A data value that specifies the pixels to be selected.
-* array
-* Pointer to a 2-dimensional array containing the data to be
-* processed. The numerical type of this array should match the 1-
-* or 2-character type code appended to the function name.
-* xdim
-* The number of pixels along each row of the array.
-* ydim
-* The number of rows in the array.
-* xs
-* The X GRID index of the first pixel on the line to be checked.
-* ys
-* The Y GRID index of the first pixel on the line to be checked.
-* xe
-* The X GRID index of the last pixel on the line to be checked.
-* ye
-* The Y GRID index of the last pixel on the line to be checked.
-* starpix
-* If non-zero, the usual Starlink definition of pixel coordinate
-* is used (integral values at pixel corners). Otherwise, the
-* system used by other AST functions such as astResample is used
-* (integral values at pixel centres).
-* lbnd
-* The lower pixel index bounds of the array.
-* xvert
-* Address of a pointer in which to return a pointer to the list
-* of GRID x values on the hull.
-* yvert
-* Address of a pointer in which to return a pointer to the list
-* of GRID y values on the hull.
-* nvert
-* Address of a pointer in which to return the number of points in
-* the returned xvert and yvert arrays.
-* status
-* Pointer to the inherited status variable.
-
-*/
-
-/* Define a macro to implement the function for a specific data
- type and operation. */
-#define MAKE_PARTHULL(X,Xtype,Oper,OperI) \
-static void PartHull##Oper##X( Xtype value, const Xtype array[], int xdim, \
- int ydim, int xs, int ys, int xe, int ye, \
- int starpix, const int lbnd[2], \
- double **xvert, double **yvert, int *nvert, \
- int *status ) { \
-\
-/* Local Variables: */ \
- const Xtype *pc; \
- double *pxy; \
- double dx2; \
- double dx1; \
- double dy1; \
- double dy2; \
- double off; \
- double xdelta; \
- int ivert; \
- int ix; \
- int iy; \
- int x0; \
- int x1; \
- int xl; \
- int xlim; \
- int xr; \
- int yinc; \
-\
-/* Initialise */ \
- *yvert = NULL; \
- *xvert = NULL; \
- *nvert = 0; \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return; \
-\
-/* If the line has zero length. just return a single vertex. */ \
- if( xs == xe && ys == ye ) { \
- *xvert = astMalloc( sizeof( double ) ); \
- *yvert = astMalloc( sizeof( double ) ); \
- if( astOK ) { \
- if( starpix ) { \
- (*xvert)[ 0 ] = xs + lbnd[ 0 ] - 1.5; \
- (*yvert)[ 0 ] = ys + lbnd[ 1 ] - 1.5; \
- } else { \
- (*xvert)[ 0 ] = xs + lbnd[ 0 ] - 1.0; \
- (*yvert)[ 0 ] = ys + lbnd[ 1 ] - 1.0; \
- } \
- *nvert = 1; \
- } \
- return; \
- } \
-\
-/* Otherwise check the line is sloping. */ \
- if( xs == xe ) { \
- astError( AST__INTER, "astOutline(Polygon): Bounding box " \
- "has zero width (internal AST programming error).", \
- status ); \
- return; \
- } else if( ys == ye ) { \
- astError( AST__INTER, "astOutline(Polygon): Bounding box " \
- "has zero height (internal AST programming error).", \
- status ); \
- return; \
- } \
-\
-/* Calculate the difference in length between adjacent rows of the area \
- to be tested. */ \
- xdelta = ((double)( xe - xs ))/((double)( ye - ys )); \
-\
-/* The left and right X limits */ \
- if( xe > xs ) { \
- xl = xs; \
- xr = xe; \
- } else { \
- xl = xe; \
- xr = xs; \
- } \
-\
-/* Get the increment in row number as we move from the start to the end \
- of the line. */ \
- yinc = ( ye > ys ) ? 1 : -1; \
-\
-/* Loop round all rows that cross the region to be tested, from start to \
- end of the supplied line. */ \
- iy = ys; \
- while( astOK ) { \
-\
-/* Get the GRID X coord where the line crosses this row. */ \
- xlim = (int)( 0.5 + xs + xdelta*( iy - ys ) ); \
-\
-/* Get the index of the first and last columns to be tested on this row. */ \
- if( yinc < 0 ) { \
- x0 = xl; \
- x1 = xlim; \
- } else { \
- x0 = xlim; \
- x1 = xr; \
- } \
-\
-/* Get a pointer to the first pixel to be tested at this row. */ \
- pc = array + ( iy - 1 )*xdim + x0 - 1; \
-\
-/* Loop round all columns to be tested in this row. */ \
- for( ix = x0; ix <= x1 && astOK; ix++,pc++ ) { \
-\
-/* Ignore pixels that are not selected. */ \
- if( ISVALID(*pc,OperI,value) ) { \
-\
-/* If this is the very first pixel, initialise the hull to contain just \
- the first pixel. */ \
- if( *nvert == 0 ){ \
- *xvert = astMalloc( 200*sizeof( double ) ); \
- *yvert = astMalloc( 200*sizeof( double ) ); \
- if( astOK ) { \
- (*xvert)[ 0 ] = ix; \
- (*yvert)[ 0 ] = iy; \
- *nvert = 1; \
- } else { \
- break; \
- } \
-\
-/* Otherwise.... */ \
- } else { \
-\
-/* Loop until the hull has been corrected to include the current pixel. */ \
- while( 1 ) { \
-\
-/* If the hull currently contains only one pixel, add the current pixel to \
- the end of the hull. */ \
- if( *nvert == 1 ){ \
- (*xvert)[ 1 ] = ix; \
- (*yvert)[ 1 ] = iy; \
- *nvert = 2; \
- break; \
-\
-/* Otherwise... */ \
- } else { \
-\
-/* Extend the line from the last-but-one pixel on the hull to the last \
- pixel on the hull, and see if the current pixel is to the left of \
- this line. If it is, it too is on the hull and so push it onto the end \
- of the list of vertices. */ \
- dx1 = (*xvert)[ *nvert - 1 ] - (*xvert)[ *nvert - 2 ]; \
- dy1 = (*yvert)[ *nvert - 1 ] - (*yvert)[ *nvert - 2 ]; \
- dx2 = ix - (*xvert)[ *nvert - 2 ]; \
- dy2 = iy - (*yvert)[ *nvert - 2 ]; \
-\
- if( dx1*dy2 > dx2*dy1 ) { \
- ivert = (*nvert)++; \
- *xvert = astGrow( *xvert, *nvert, sizeof( double ) ); \
- *yvert = astGrow( *yvert, *nvert, sizeof( double ) ); \
- if( astOK ) { \
- (*xvert)[ ivert ] = ix; \
- (*yvert)[ ivert ] = iy; \
- } \
-\
-/* Leave the loop now that the new point is on the hull. */ \
- break; \
-\
-/* If the new point is to the left of the line, then the last point \
- previously thought to be on hull is in fact not on the hull, so remove \
- it. We then loop again to compare the new pixel with modified hull. */ \
- } else { \
- (*nvert)--; \
- } \
- } \
- } \
- } \
- } \
- } \
-\
- if( iy == ye ) { \
- break; \
- } else { \
- iy += yinc; \
- } \
-\
- } \
-\
-/* Convert GRID coords to PIXEL coords. */ \
- if( astOK ) { \
- pxy = *xvert; \
- off = starpix ? lbnd[ 0 ] - 1.5 : lbnd[ 0 ] - 1.0; \
- for( ivert = 0; ivert < *nvert; ivert++ ) *(pxy++) += off; \
-\
- pxy = *yvert; \
- off = starpix ? lbnd[ 1 ] - 1.5 : lbnd[ 1 ] - 1.0; \
- for( ivert = 0; ivert < *nvert; ivert++ ) *(pxy++) += off; \
-\
-/* Free lists if an error has occurred. */ \
- } else { \
- *xvert = astFree( *xvert ); \
- *yvert = astFree( *yvert ); \
- *nvert = 0; \
- } \
-}
-
-/* Define a macro that uses the above macro to to create implementations
- of PartHull for all operations. */
-#define MAKEALL_PARTHULL(X,Xtype) \
-MAKE_PARTHULL(X,Xtype,LT,AST__LT) \
-MAKE_PARTHULL(X,Xtype,LE,AST__LE) \
-MAKE_PARTHULL(X,Xtype,EQ,AST__EQ) \
-MAKE_PARTHULL(X,Xtype,NE,AST__NE) \
-MAKE_PARTHULL(X,Xtype,GE,AST__GE) \
-MAKE_PARTHULL(X,Xtype,GT,AST__GT)
-
-/* Expand the above macro to generate a function for each required
- data type and operation. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-MAKEALL_PARTHULL(LD,long double)
-#endif
-MAKEALL_PARTHULL(D,double)
-MAKEALL_PARTHULL(L,long int)
-MAKEALL_PARTHULL(UL,unsigned long int)
-MAKEALL_PARTHULL(I,int)
-MAKEALL_PARTHULL(UI,unsigned int)
-MAKEALL_PARTHULL(S,short int)
-MAKEALL_PARTHULL(US,unsigned short int)
-MAKEALL_PARTHULL(B,signed char)
-MAKEALL_PARTHULL(UB,unsigned char)
-MAKEALL_PARTHULL(F,float)
-
-/* Undefine the macros. */
-#undef MAKE_PARTHULL
-#undef MAKEALL_PARTHULL
-
-static double Polywidth( AstFrame *frm, AstLineDef **edges, int i, int nv,
- double cen[ 2 ], int *status ){
-/*
-* Name:
-* Polywidth
-
-* Purpose:
-* Find the width of a polygon perpendicular to a given edge.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* double Polywidth( AstFrame *frm, AstLineDef **edges, int i, int nv,
-* double cen[ 2 ], int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* This function defines a line perpendicular to a given polygon edge,
-* passing through the mid point of the edge, extending towards the
-* inside of the polygon. It returns the distance that can be travelled
-* along this line before any of the other polygon edges are hit (the
-* "width" of the polygon perpendicular to the given edge). It also
-* puts the position corresponding to half that distance into "cen".
-
-* Parameters:
-* frm
-* The Frame in which the lines are defined.
-* edges
-* Array of "nv" pointers to AstLineDef structures, each defining an
-* edge of the polygon.
-* i
-* The index of the edge that is to define the polygon width.
-* nv
-* Total number of edges.
-* cen
-* An array into which are put the coords of the point half way
-* along the polygon width line.
-* status
-* Pointer to the inherited status variable.
-
-* Returnd Value:
-* The width of the polygon perpendicular to the given edge, or
-* AST__BAD if the width cannot be determined (usually because the
-* vertices been supplied in a clockwise direction, effectively
-* negating the Polygon).
-
-*/
-
-/* Local Variables: */
- AstLineDef *line;
- double *cross;
- double d;
- double end[ 2 ];
- double l1;
- double l2;
- double result;
- double start[ 2 ];
- int j;
-
-/* Check the global error status. */
- result = AST__BAD;
- if ( !astOK ) return result;
-
-/* Create a Line description for a line perpendicular to the specified
- edge, passing through the mid point of the edge, and extending towards
- the inside of the polygon. First move away from the start along the
- line to the mid point. This gives the start of the new line. */
- l1 = 0.5*( edges[ i ]->length );
- astLineOffset( frm, edges[ i ], l1, 0.0, start );
-
-/* We now move away from this position at right angles to the line. We
- start off by moving 5 times the length of the specified edge. For
- some Frames (e.g. SkyFrames) this may result in a position that is
- much too close (i.e. if it goes all the way round the great circle
- and comes back to the beginning). Therefore, we check that the end
- point is the requested distance from the start point, and if not, we
- halve the length of the line and try again. */
- l2 = 10.0*l1;
- while( 1 ) {
- astLineOffset( frm, edges[ i ], l1, l2, end );
- d = astDistance( frm, start, end );
- if( d != AST__BAD && fabs( d - l2 ) < 1.0E-6*l2 ) break;
- l2 *= 0.5;
- }
-
-/* Create a description of the required line. */
- line = astLineDef( frm, start, end );
-
-/* Loop round every edge, except for the supplied edge. */
- for( j = 0; j < nv; j++ ) {
- if( j != i ) {
-
-/* Find the position at which the line created above crosses the current
- edge. Skip to the next edge if the line does not intersect the edge
- within the length of the edge. */
- if( astLineCrossing( frm, line, edges[ j ], &cross ) ) {
-
-/* Find the distance between the crossing point and the line start. */
- d = astDistance( frm, start, cross );
-
-/* If this is less than the smallest found so far, record it. */
- if( d != AST__BAD && ( d < result || result == AST__BAD ) ) {
- result = d;
- }
- }
-
-/* Free resources */
- cross = astFree( cross );
- }
- }
- line = astFree( line );
-
-/* If a width was found, return the point half way across the polygon. */
- if( result != AST__BAD ) {
- astOffset( frm, start, end, 0.5*result, cen );
-
-/* The usual reason for not finding a width is if the polygon vertices
- are supplied in clockwise order, effectively negating the polygon, and
- resulting in the "inside" of the polygon being the infinite region
- outside a polygonal hole. In this case, the end point of the line
- perpendicular to the initial edge can be returned as a representative
- "inside" point. */
- } else {
- cen[ 0 ] = end[ 0 ];
- cen[ 1 ] = end[ 1 ];
- }
-
-/* Return the width. */
- return result;
-
-}
-
-static void RegBaseBox( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){
-/*
-* Name:
-* RegBaseBox
-
-* Purpose:
-* Returns the bounding box of an un-negated Region in the base Frame of
-* the encapsulated FrameSet.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status )
-
-* Class Membership:
-* Polygon member function (over-rides the astRegBaseBox protected
-* method inherited from the Region class).
-
-* Description:
-* This function returns the upper and lower axis bounds of a Region in
-* the base Frame of the encapsulated FrameSet, assuming the Region
-* has not been negated. That is, the value of the Negated attribute
-* is ignored.
-
-* Parameters:
-* this
-* Pointer to the Region.
-* lbnd
-* Pointer to an array in which to return the lower axis bounds
-* covered by the Region in the base Frame of the encapsulated
-* FrameSet. It should have at least as many elements as there are
-* axes in the base Frame.
-* ubnd
-* Pointer to an array in which to return the upper axis bounds
-* covered by the Region in the base Frame of the encapsulated
-* FrameSet. It should have at least as many elements as there are
-* axes in the base Frame.
-* status
-* Pointer to the inherited status variable.
-
-*/
-
-/* Local Variables: */
- AstFrame *frm; /* Pointer to encapsulated Frame */
- AstPointSet *pset; /* Pointer to PointSet defining the Region */
- AstPolygon *this; /* Pointer to Polygon structure */
- AstRegion *reg; /* Base Frame equivalent of supplied Polygon */
- double **ptr; /* Pointer to PointSet data */
- double *x; /* Pointer to next X axis value */
- double *y; /* Pointer to next Y axis value */
- double dist; /* Offset along an axis */
- double x0; /* The first X axis value */
- double y0; /* The first Y axis value */
- int ip; /* Point index */
- int np; /* No. of points in PointSet */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the Polygon structure. */
- this = (AstPolygon *) this_region;
-
-/* If the base Frame bounding box has already been found, return the
- values stored in the Polygon structure. */
- if( this->lbnd[ 0 ] != AST__BAD ) {
- lbnd[ 0 ] = this->lbnd[ 0 ];
- lbnd[ 1 ] = this->lbnd[ 1 ];
- ubnd[ 0 ] = this->ubnd[ 0 ];
- ubnd[ 1 ] = this->ubnd[ 1 ];
-
-/* If the base Frame bounding box has not yet been found, find it now and
- store it in the Polygon structure. */
- } else {
-
-/* Get the axis values for the PointSet which defines the location and
- extent of the region in the base Frame of the encapsulated FrameSet. */
- pset = this_region->points;
- ptr = astGetPoints( pset );
- np = astGetNpoint( pset );
-
-/* Get a pointer to the base Frame in the frameset encapsulated by the
- parent Region structure. */
- frm = astGetFrame( this_region->frameset, AST__BASE );
-
-/* Find the upper and lower bounds of the box enclosing all the vertices.
- The box is expressed in terms of axis offsets from the first vertex, in
- order to avoid problems with boxes that cross RA=0 or RA=12h */
- lbnd[ 0 ] = 0.0;
- lbnd[ 1 ] = 0.0;
- ubnd[ 0 ] = 0.0;
- ubnd[ 1 ] = 0.0;
-
- x = ptr[ 0 ];
- y = ptr[ 1 ];
-
- x0 = *x;
- y0 = *y;
-
- for( ip = 0; ip < np; ip++, x++, y++ ) {
-
- dist = astAxDistance( frm, 1, x0, *x );
- if( dist < lbnd[ 0 ] ) {
- lbnd[ 0 ] = dist;
- } else if( dist > ubnd[ 0 ] ) {
- ubnd[ 0 ] = dist;
- }
-
- dist = astAxDistance( frm, 2, y0, *y );
- if( dist < lbnd[ 1 ] ) {
- lbnd[ 1 ] = dist;
- } else if( dist > ubnd[ 1 ] ) {
- ubnd[ 1 ] = dist;
- }
-
- }
-
-/* Convert the box bounds to absolute values, rather than values relative
- to the first vertex. */
- lbnd[ 0 ] += x0;
- lbnd[ 1 ] += y0;
- ubnd[ 0 ] += x0;
- ubnd[ 1 ] += y0;
-
-/* The astNormBox requires a Mapping which can be used to test points in
- this base Frame. Create a copy of the Polygon and then set its
- FrameSet so that the current Frame in the copy is the same as the base
- Frame in the original. */
- reg = astCopy( this );
- astSetRegFS( reg, frm );
- astSetNegated( reg, 0 );
-
-/* Normalise this box. */
- astNormBox( frm, lbnd, ubnd, reg );
-
-/* Free resources */
- reg = astAnnul( reg );
- frm = astAnnul( frm );
-
-/* Store it in the olygon structure for future use. */
- this->lbnd[ 0 ] = lbnd[ 0 ];
- this->lbnd[ 1 ] = lbnd[ 1 ];
- this->ubnd[ 0 ] = ubnd[ 0 ];
- this->ubnd[ 1 ] = ubnd[ 1 ];
-
- }
-}
-
-static AstPointSet *RegBaseMesh( AstRegion *this_region, int *status ){
-/*
-* Name:
-* RegBaseMesh
-
-* Purpose:
-* Return a PointSet containing a mesh of points on the boundary of a
-* Region in its base Frame.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* AstPointSet *astRegBaseMesh( AstRegion *this, int *status )
-
-* Class Membership:
-* Polygon member function (over-rides the astRegBaseMesh protected
-* method inherited from the Region class).
-
-* Description:
-* This function returns a PointSet containing a mesh of points on the
-* boundary of the Region. The points refer to the base Frame of
-* the encapsulated FrameSet.
-
-* Parameters:
-* this
-* Pointer to the Region.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to the PointSet. Annul the pointer using astAnnul when it
-* is no longer needed.
-
-* Notes:
-* - A NULL pointer is returned if an error has already occurred, or if
-* this function should fail for any reason.
-
-*/
-
-/* Local Variables: */
- AstFrame *frm; /* Base Frame in encapsulated FrameSet */
- AstPointSet *result; /* Returned pointer */
- AstPolygon *this; /* The Polygon structure */
- double **rptr; /* Pointers to returned mesh data */
- double **vptr; /* Pointers to vertex data */
- double *lens; /* Pointer to work space holding edge lengths */
- double d; /* Length of this edge */
- double delta; /* Angular separation of points */
- double end[ 2 ]; /* End position */
- double mp; /* No. of mesh points per unit distance */
- double p[ 2 ]; /* Position in 2D Frame */
- double start[ 2 ]; /* Start position */
- double total; /* Total length of polygon */
- int ip; /* Point index */
- int iv; /* Vertex index */
- int n; /* No. of points on this edge */
- int next; /* Index of next point in returned PointSet */
- int np; /* No. of points in returned PointSet */
- int nv; /* No. of polygon vertices */
-
-/* Initialise */
- result= NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* If the Region structure contains a pointer to a PointSet holding
- a previously created mesh, return it. */
- if( this_region->basemesh ) {
- result = astClone( this_region->basemesh );
-
-/* Otherwise, create a new mesh. */
- } else {
-
-/* Get a pointer to the Polygon structure. */
- this = (AstPolygon *) this_region;
-
-/* Get a pointer to the base Frame in the encapsulated FrameSet. */
- frm = astGetFrame( this_region->frameset, AST__BASE );
-
-/* Get the number of vertices and pointers to the vertex axis values. */
- nv = astGetNpoint( this_region->points );
- vptr = astGetPoints( this_region->points );
-
-/* Allocate memory to hold the geodesic length of each edge. */
- lens = astMalloc( sizeof( double )*(size_t) nv );
-
- if( astOK ) {
-
-/* Find the total geodesic distance around the boundary. */
- total = 0.0;
-
- start[ 0 ] = vptr[ 0 ][ 0 ];
- start[ 1 ] = vptr[ 1 ][ 0 ];
-
- for( iv = 1; iv < nv; iv++ ) {
- end[ 0 ] = vptr[ 0 ][ iv ];
- end[ 1 ] = vptr[ 1 ][ iv ];
-
- d = astDistance( frm, start, end );
- if( d != AST__BAD ) total += fabs( d );
- lens[ iv ] = d;
- start[ 0 ] = end[ 0 ];
- start[ 1 ] = end[ 1 ];
- }
-
- end[ 0 ] = vptr[ 0 ][ 0 ];
- end[ 1 ] = vptr[ 1 ][ 0 ];
-
- d = astDistance( frm, start, end );
- if( d != AST__BAD ) total += fabs( d );
- lens[ 0 ] = d;
-
-/* Find the number of mesh points per unit geodesic distance. */
- if( total > 0.0 ){
- mp = astGetMeshSize( this )/total;
-
-/* Find the total number of mesh points required. */
- np = 0;
- for( iv = 0; iv < nv; iv++ ) {
- if( lens[ iv ] != AST__BAD ) np += 1 + (int)( lens[ iv ]*mp );
- }
-
-/* Create a suitable PointSet to hold the returned positions. */
- result = astPointSet( np, 2, "", status );
- rptr = astGetPoints( result );
- if( astOK ) {
-
-/* Initialise the index of the next point to be added to the returned
- PointSet. */
- next = 0;
-
-/* Loop round each good edge of the polygon. The edge ends at vertex "iv". */
- start[ 0 ] = vptr[ 0 ][ 0 ];
- start[ 1 ] = vptr[ 1 ][ 0 ];
-
- for( iv = 1; iv < nv; iv++ ) {
- end[ 0 ] = vptr[ 0 ][ iv ];
- end[ 1 ] = vptr[ 1 ][ iv ];
- if( lens[ iv ] != AST__BAD ) {
-
-/* Add the position of the starting vertex to the returned mesh. */
- rptr[ 0 ][ next ] = start[ 0 ];
- rptr[ 1 ][ next ] = start[ 1 ];
- next++;
-
-/* Find the number of points on this edge, and the geodesic distance
- between them. */
- n = 1 + (int) ( lens[ iv ]*mp );
-
-/* If more than one point, find the distance between points. */
- if( n > 1 ) {
- delta = lens[ iv ]/n;
-
-/* Loop round the extra points. */
- for( ip = 1; ip < n; ip++ ) {
-
-/* Find the position of the next mesh point. */
- astOffset( frm, start, end, delta*ip, p );
-
-/* Add it to the mesh. */
- rptr[ 0 ][ next ] = p[ 0 ];
- rptr[ 1 ][ next ] = p[ 1 ];
- next++;
-
- }
- }
- }
-
-/* The end of this edge becomes the start of the next. */
- start[ 0 ] = end[ 0 ];
- start[ 1 ] = end[ 1 ];
- }
-
-/* Now do the edge which ends at the first vertex. */
- end[ 0 ] = vptr[ 0 ][ 0 ];
- end[ 1 ] = vptr[ 1 ][ 0 ];
- if( lens[ 0 ] != AST__BAD ) {
- rptr[ 0 ][ next ] = start[ 0 ];
- rptr[ 1 ][ next ] = start[ 1 ];
- next++;
-
- n = 1 + (int)( lens[ 0 ]*mp );
- if( n > 1 ) {
- delta = lens[ 0 ]/n;
- for( ip = 1; ip < n; ip++ ) {
- astOffset( frm, start, end, delta*ip, p );
- rptr[ 0 ][ next ] = p[ 0 ];
- rptr[ 1 ][ next ] = p[ 1 ];
- next++;
- }
- }
- }
-
-/* Check the PointSet size was correct. */
- if( next != np && astOK ) {
- astError( AST__INTER, "astRegBaseMesh(%s): Error in the "
- "allocated PointSet size (%d) - should have "
- "been %d (internal AST programming error).", status,
- astGetClass( this ), np, next );
- }
-
-/* Save the returned pointer in the Region structure so that it does not
- need to be created again next time this function is called. */
- if( astOK ) this_region->basemesh = astClone( result );
-
- }
-
- } else if( astOK ) {
- astError( AST__BADIN, "astRegBaseMesh(%s): The boundary of "
- "the supplied %s has an undefined length.", status,
- astGetClass( this ), astGetClass( this ) );
- }
-
- }
-
-/* Free resources. */
- frm = astAnnul( frm );
- lens = astFree( lens );
- }
-
-/* Annul the result if an error has occurred. */
- if( !astOK ) result = astAnnul( result );
-
-/* Return a pointer to the output PointSet. */
- return result;
-}
-
-static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
- int **mask, int *status ){
-/*
-* Name:
-* RegPins
-
-* Purpose:
-* Check if a set of points fall on the boundary of a given Polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* int RegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc,
-* int **mask, int *status )
-
-* Class Membership:
-* Polygon member function (over-rides the astRegPins protected
-* method inherited from the Region class).
-
-* Description:
-* This function returns a flag indicating if the supplied set of
-* points all fall on the boundary of the given Polygon.
-*
-* Some tolerance is allowed, as specified by the uncertainty Region
-* stored in the supplied Polygon "this", and the supplied uncertainty
-* Region "unc" which describes the uncertainty of the supplied points.
-
-* Parameters:
-* this
-* Pointer to the Polygon.
-* pset
-* Pointer to the PointSet. The points are assumed to refer to the
-* base Frame of the FrameSet encapsulated by "this".
-* unc
-* Pointer to a Region representing the uncertainties in the points
-* given by "pset". The Region is assumed to represent the base Frame
-* of the FrameSet encapsulated by "this". Zero uncertainity is assumed
-* if NULL is supplied.
-* mask
-* Pointer to location at which to return a pointer to a newly
-* allocated dynamic array of ints. The number of elements in this
-* array is equal to the value of the Npoint attribute of "pset".
-* Each element in the returned array is set to 1 if the
-* corresponding position in "pset" is on the boundary of the Region
-* and is set to zero otherwise. A NULL value may be supplied
-* in which case no array is created. If created, the array should
-* be freed using astFree when no longer needed.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Non-zero if the points all fall on the boundary of the given
-* Region, to within the tolerance specified. Zero otherwise.
-
-*/
-
-/* Local variables: */
- AstFrame *frm; /* Base Frame in supplied Polygon */
- AstPointSet *pset1; /* Pointer to copy of supplied PointSet */
- AstPointSet *pset2; /* Pointer to PointSet holding resolved components */
- AstPolygon *this; /* Pointer to the Polygon structure. */
- AstRegion *tunc; /* Uncertainity Region from "this" */
- double **ptr1; /* Pointer to axis values in "pset1" */
- double **ptr2; /* Pointer to axis values in "pset2" */
- double **vptr; /* Pointer to axis values at vertices */
- double *safe; /* An interior point in "this" */
- double edge_len; /* Length of current edge */
- double end[2]; /* Position of end of current edge */
- double l1; /* Length of bounding box diagonal */
- double l2; /* Length of bounding box diagonal */
- double lbnd_tunc[2]; /* Lower bounds of "this" uncertainty Region */
- double lbnd_unc[2]; /* Lower bounds of supplied uncertainty Region */
- double par; /* Parallel component */
- double parmax; /* Max acceptable parallel component */
- double prp; /* Perpendicular component */
- double start[2]; /* Position of start of current edge */
- double ubnd_tunc[2]; /* Upper bounds of "this" uncertainty Region */
- double ubnd_unc[2]; /* Upper bounds of supplied uncertainty Region */
- double wid; /* Width of acceptable margin around polygon */
- int *m; /* Pointer to next mask value */
- int i; /* Edge index */
- int ip; /* Point index */
- int np; /* No. of supplied points */
- int nv; /* No. of vertices */
- int result; /* Returned flag */
-
-/* Initialise */
- result = 0;
- if( mask ) *mask = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return result;
-
-/* Get a pointer to the Polygon structure. */
- this = (AstPolygon *) this_region;
-
-/* Check the supplied PointSet has 2 axis values per point. */
- if( astGetNcoord( pset ) != 2 && astOK ) {
- astError( AST__INTER, "astRegPins(%s): Illegal number of axis "
- "values per point (%d) in the supplied PointSet - should be "
- "2 (internal AST programming error).", status, astGetClass( this ),
- astGetNcoord( pset ) );
- }
-
-/* Get the number of axes in the uncertainty Region and check it is also 2. */
- if( unc && astGetNaxes( unc ) != 2 && astOK ) {
- astError( AST__INTER, "astRegPins(%s): Illegal number of axes (%d) "
- "in the supplied uncertainty Region - should be 2 "
- "(internal AST programming error).", status, astGetClass( this ),
- astGetNaxes( unc ) );
- }
-
-/* Get pointers to the axis values at the polygon vertices. */
- vptr = astGetPoints( this_region->points );
-
-/* Get the number of vertices. */
- nv = astGetNpoint( this_region->points );
-
-/* Take a copy of the supplied PointSet and get pointers to its axis
- values,and its size */
- pset1 = astCopy( pset );
- ptr1 = astGetPoints( pset1 );
- np = astGetNpoint( pset1 );
-
-/* Create a PointSet to hold the resolved components and get pointers to its
- axis data. */
- pset2 = astPointSet( np, 2, "", status );
- ptr2 = astGetPoints( pset2 );
-
-/* Create a mask array if required. */
- if( mask ) *mask = astMalloc( sizeof(int)*(size_t) np );
-
-/* Get the centre of the region in the base Frame. We use this as a "safe"
- interior point within the region. */
- safe = astRegCentre( this, NULL, NULL, 0, AST__BASE );
-
-/* We now find the maximum distance on each axis that a point can be from the
- boundary of the Polygon for it still to be considered to be on the boundary.
- First get the Region which defines the uncertainty within the Polygon
- being checked (in its base Frame), re-centre it on the interior point
- found above (to avoid problems if the uncertainty region straddles a
- discontinuity), and get its bounding box. The current Frame of the
- uncertainty Region is the same as the base Frame of the Polygon. */
- tunc = astGetUncFrm( this, AST__BASE );
- if( safe ) astRegCentre( tunc, safe, NULL, 0, AST__CURRENT );
- astGetRegionBounds( tunc, lbnd_tunc, ubnd_tunc );
-
-/* Find the geodesic length within the base Frame of "this" of the diagonal of
- the bounding box. */
- frm = astGetFrame( this_region->frameset, AST__BASE );
- l1 = astDistance( frm, lbnd_tunc, ubnd_tunc );
-
-/* Also get the Region which defines the uncertainty of the supplied
- points and get its bounding box. First re-centre the uncertainty at the
- interior position to avoid problems from uncertainties that straddle a
- discontinuity. */
- if( unc ) {
- if( safe ) astRegCentre( unc, safe, NULL, 0, AST__CURRENT );
- astGetRegionBounds( unc, lbnd_unc, ubnd_unc );
-
-/* Find the geodesic length of the diagonal of this bounding box. */
- l2 = astDistance( frm, lbnd_unc, ubnd_unc );
-
-/* Assume zero uncertainty if no "unc" Region was supplied. */
- } else {
- l2 = 0.0;
- }
-
-/* The required border width is half of the total diagonal of the two bounding
- boxes. */
- if( astOK ) {
- wid = 0.5*( l1 + l2 );
-
-/* Loop round each edge of the polygon. Edge "i" starts at vertex "i-1"
- and ends at vertex "i". Edge zero starts at vertex "nv-1" and ends at
- vertex zero. */
- start[ 0 ] = vptr[ 0 ][ nv - 1 ];
- start[ 1 ] = vptr[ 1 ][ nv - 1 ];
- for( i = 0; i < nv; i++ ) {
- end[ 0 ] = vptr[ 0 ][ i ];
- end[ 1 ] = vptr[ 1 ][ i ];
-
-/* Find the length of this edge. */
- edge_len = astDistance( frm, start, end );
-
-/* Resolve all the supplied mesh points into components parallel and
- perpendicular to this edge. */
- (void) astResolvePoints( frm, start, end, pset1, pset2 );
-
-/* A point is effectively on this edge if the parallel component is
- greater than (-wid) and less than (edge_len+wid) AND the perpendicular
- component has an absolute value less than wid. Identify such positions
- and set them bad in pset1. */
- parmax = edge_len + wid;
- for( ip = 0; ip < np; ip++ ) {
- par = ptr2[ 0 ][ ip ];
- prp = ptr2[ 1 ][ ip ];
-
- if( par != AST__BAD && prp != AST__BAD ) {
- if( par > -wid && par < parmax && prp > -wid && prp < wid ) {
- ptr1[ 0 ][ ip ] = AST__BAD;
- ptr1[ 1 ][ ip ] = AST__BAD;
- }
- }
- }
-
-/* The end of the current edge becomes the start of the next. */
- start[ 0 ] = end[ 0 ];
- start[ 1 ] = end[ 1 ];
- }
-
-/* See if any good points are left in pset1. If so, it means that those
- points were not on any edge of hte Polygon. We use two alogorithms
- here depending on whether we are creating a mask array, since we can
- abort the check upon finding the first good point if we are not
- producing a mask. */
- result = 1;
- if( mask ) {
- m = *mask;
- for( ip = 0; ip < np; ip++, m++ ) {
- if( ptr1[ 0 ][ ip ] != AST__BAD &&
- ptr1[ 1 ][ ip ] != AST__BAD ) {
- *m = 0;
- result = 0;
- } else {
- *m = 1;
- }
- }
- } else {
- for( ip = 0; ip < np; ip++ ) {
- if( ptr1[ 0 ][ ip ] != AST__BAD &&
- ptr1[ 1 ][ ip ] != AST__BAD ) {
- result = 0;
- break;
- }
- }
- }
- }
-
-/* Free resources. */
- tunc = astAnnul( tunc );
- frm = astAnnul( frm );
- safe = astFree( safe );
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
-
-/* If an error has occurred, return zero. */
- if( !astOK ) {
- result = 0;
- if( mask ) *mask = astAnnul( *mask );
- }
-
-/* Return the result. */
- return result;
-}
-
-static int RegTrace( AstRegion *this_region, int n, double *dist, double **ptr,
- int *status ){
-/*
-*+
-* Name:
-* RegTrace
-
-* Purpose:
-* Return requested positions on the boundary of a 2D Region.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* int astTraceRegion( AstRegion *this, int n, double *dist, double **ptr );
-
-* Class Membership:
-* Polygon member function (overrides the astTraceRegion method
-* inherited from the parent Region class).
-
-* Description:
-* This function returns positions on the boundary of the supplied
-* Region, if possible. The required positions are indicated by a
-* supplied list of scalar parameter values in the range zero to one.
-* Zero corresponds to some arbitrary starting point on the boundary,
-* and one corresponds to the end (which for a closed region will be
-* the same place as the start).
-
-* Parameters:
-* this
-* Pointer to the Region.
-* n
-* The number of positions to return. If this is zero, the function
-* returns without action (but the returned function value still
-* indicates if the method is supported or not).
-* dist
-* Pointer to an array of "n" scalar parameter values in the range
-* 0 to 1.0.
-* ptr
-* A pointer to an array of pointers. The number of elements in
-* this array should equal tthe number of axes in the Frame spanned
-* by the Region. Each element of the array should be a pointer to
-* an array of "n" doubles, in which to return the "n" values for
-* the corresponding axis. The contents of the arrays are unchanged
-* if the supplied Region belongs to a class that does not
-* implement this method.
-
-* Returned Value:
-* Non-zero if the astTraceRegion method is implemented by the class
-* of Region supplied, and zero if not.
-
-*-
-*/
-
-/* Local Variables; */
- AstFrame *frm;
- AstMapping *map;
- AstPointSet *bpset;
- AstPointSet *cpset;
- AstPolygon *this;
- double **bptr;
- double d;
- double p[ 2 ];
- int i;
- int j0;
- int j;
- int ncur;
- int nv;
- int monotonic;
-
-/* Check inherited status, and the number of points to return, returning
- a non-zero value to indicate that this class supports the astRegTrace
- method. */
- if( ! astOK || n == 0 ) return 1;
-
-/* Get a pointer to the Polygon structure. */
- this = (AstPolygon *) this_region;
-
-/* Ensure cached information is available. */
- Cache( this, status );
-
-/* Get a pointer to the base Frame in the encapsulated FrameSet. */
- frm = astGetFrame( this_region->frameset, AST__BASE );
-
-/* We first determine the required positions in the base Frame of the
- Region, and then transform them into the current Frame. Get the
- base->current Mapping, and the number of current Frame axes. */
- map = astGetMapping( this_region->frameset, AST__BASE, AST__CURRENT );
-
-/* If it's a UnitMap we do not need to do the transformation, so put the
- base Frame positions directly into the supplied arrays. */
- if( astIsAUnitMap( map ) ) {
- bpset = NULL;
- bptr = ptr;
- ncur = 2;
-
-/* Otherwise, create a PointSet to hold the base Frame positions (known
- to be 2D since this is an polygon). */
- } else {
- bpset = astPointSet( n, 2, " ", status );
- bptr = astGetPoints( bpset );
- ncur = astGetNout( map );
- }
-
-/* Check the pointers can be used safely. */
- if( astOK ) {
-
-/* Get the number of vertices. */
- nv = astGetNpoint( this_region->points );
-
-/* If we have a reasonable number of pointsand there are a reasonable
- number of vertices, we can be quicker if we know if the parameteric
- distances are monotonic increasing. Find out now. */
- if( n > 5 && nv > 5 ) {
-
- monotonic = 1;
- for( i = 1; i < n; i++ ) {
- if( dist[ i ] < dist[ i - 1 ] ) {
- monotonic = 0;
- break;
- }
- }
-
- } else {
- monotonic = 0;
- }
-
-/* Loop round each point. */
- j0 = 1;
- for( i = 0; i < n; i++ ) {
-
-/* Get the required round the polygon, starting from vertex zero. */
- d = dist[ i ]*this->totlen;
-
-/* Loop round each vertex until we find one which is beyond the required
- point. If the supplied distances are monotonic increasing, we can
- start the checks at the same vertex that was used for the previous
- since we know there will never be a backward step. */
- for( j = j0; j < nv; j++ ) {
- if( this->startsat[ j ] > d ) break;
- }
-
-/* If the distances are monotonic increasing, record the vertex that we
- have reached so far. */
- if( monotonic ) j0 = j;
-
-/* Find the distance to travel beyond the previous vertex. */
- d -= this->startsat[ j - 1 ];
-
-/* Find the position, that is the required distance from the previous
- vertex towards the next vertex. */
- astLineOffset( frm, this->edges[ j - 1 ], d, 0.0, p );
-
-/* Store the resulting axis values. */
- bptr[ 0 ][ i ] = p[ 0 ];
- bptr[ 1 ][ i ] = p[ 1 ];
- }
- }
-
-/* If required, transform the base frame positions into the current
- Frame, storing them in the supplied array. Then free resources. */
- if( bpset ) {
- cpset = astPointSet( n, ncur, " ", status );
- astSetPoints( cpset, ptr );
-
- (void) astTransform( map, bpset, 1, cpset );
-
- cpset = astAnnul( cpset );
- bpset = astAnnul( bpset );
- }
-
-/* Free remaining resources. */
- map = astAnnul( map );
- frm = astAnnul( frm );
-
-/* Return a non-zero value to indicate that this class supports the
- astRegTrace method. */
- return 1;
-}
-
-static Segment *RemoveFromChain( Segment *head, Segment *seg, int *status ){
-/*
-* Name:
-* RemoveFromChain
-
-* Purpose:
-* Remove a Segment from the link list maintained by astDownsize.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* Segment *RemoveFromChain( Segment *head, Segment *seg, int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* The supplied Segment is removed form the list, and the gap is
-* closed up.
-
-* Parameters:
-* head
-* The Segment structure at the head of the list.
-* seg
-* The Segment to be removed from the list.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to the link head (which will have changed if "seg" was the
-* original head).
-
-*/
-
-/* Check the global error status. */
- if ( !astOK ) return head;
-
-/* If the Segment was the original head, make the next segment the new
- head. */
- if( head == seg ) head = seg->next;
-
-/* Close up the links between the Segments on either side of the segment
- being removed. */
- if( seg->prev ) seg->prev->next = seg->next;
- if( seg->next ) seg->next->prev = seg->prev;
-
-/* Nullify the links in the segment being removed. */
- seg->next = NULL;
- seg->prev = NULL;
-
-/* Return the new head. */
- return head;
-}
-
-static void ResetCache( AstRegion *this_region, int *status ){
-/*
-* Name:
-* ResetCache
-
-* Purpose:
-* Clear cached information within the supplied Region.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void ResetCache( AstRegion *this, int *status )
-
-* Class Membership:
-* Region member function (overrides the astResetCache method
-* inherited from the parent Region class).
-
-* Description:
-* This function clears cached information from the supplied Region
-* structure.
-
-* Parameters:
-* this
-* Pointer to the Region.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- AstPolygon *this;
- int i;
- int nv;
-
-/* Get a pointer to the Polygon structure. */
- this = (AstPolygon *) this_region;
-
-/* If a Polygon was supplied, indicate cached information needs to be
- recalculated. */
- if( this ) {
- this->stale = 1;
- this->lbnd[ 0 ] = AST__BAD;
-
-/* Free any edge structures (number of vertices may be about to change so
- this cannot be left until the next call to "Cache()". */
- if( this->edges ) {
- nv = astGetNpoint( this_region->points );
- for( i = 0; i < nv; i++ ) {
- this->edges[ i ] = astFree( this->edges[ i ] );
- }
- this->edges = astFree( this->edges );
- }
-
-/* Clear the cache of the parent class. */
- (*parent_resetcache)( this_region, status );
- }
-}
-
-static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
-/*
-* Name:
-* SetAttrib
-
-* Purpose:
-* Set an attribute value for a Polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void SetAttrib( AstObject *this, const char *setting, int *status )
-
-* Class Membership:
-* Polygon member function (extends the astSetAttrib method inherited from
-* the Region class).
-
-* Description:
-* This function assigns an attribute value for a Polygon, the attribute
-* and its value being specified by means of a string of the form:
-*
-* "attribute= value "
-*
-* Here, "attribute" specifies the attribute name and should be in lower
-* case with no white space present. The value to the right of the "="
-* should be a suitable textual representation of the value to be assigned
-* and this will be interpreted according to the attribute's data type.
-* White space surrounding the value is only significant for string
-* attributes.
-
-* Parameters:
-* this
-* Pointer to the Polygon.
-* setting
-* Pointer to a null terminated string specifying the new attribute
-* value.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* void
-*/
-
-/* Local Vaiables: */
- AstPolygon *this; /* Pointer to the Polygon structure */
- int ival; /* Integer attribute value */
- int len; /* Length of setting string */
- int nc; /* Number of characters read by astSscanf */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Obtain a pointer to the Polygon structure. */
- this = (AstPolygon *) this_object;
-
-/* Obtain the length of the setting string. */
- len = strlen( setting );
-
-/* Test for each recognised attribute in turn, using "astSscanf" to parse the
- setting string and extract the attribute value (or an offset to it in the
- case of string values). In each case, use the value set in "nc" to check
- that the entire string was matched. Once a value has been obtained, use the
- appropriate method to set it. */
-
-/* SimpVertices. */
-/* ------------- */
- if ( nc = 0,
- ( 1 == astSscanf( setting, "simpvertices= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetSimpVertices( this, ival );
-
-/* Pass any unrecognised setting to the parent method for further
- interpretation. */
- } else {
- (*parent_setattrib)( this_object, setting, status );
- }
-}
-
-static void SetPointSet( AstPolygon *this, AstPointSet *pset, int *status ){
-/*
-* Name:
-* SetPointSet
-
-* Purpose:
-* Store a new set of vertices in an existing Polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void SetPointSet( AstPolygon *this, AstPointSet *pset, int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* The PointSet in the supplied Polygon is annulled, and replaced by a
-* clone of the supplied PointSet pointer.
-
-* Parameters:
-* this
-* Pointer to the Polygon to be changed.
-* pset
-* The PointSet containing the new vertex information.
-* status
-* Pointer to the inherited status variable.
-
-*/
-
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Indicate the cached information in the polygon will need to be
- re-calculated when needed. */
- astResetCache( this );
-
-/* Annul the pointer to the PointSet already in the supplied Polygon. */
- (void) astAnnul( ((AstRegion *) this)->points );
-
-/* Store a clone of the supplied new PointSet pointer. */
- ((AstRegion *) this)->points = astClone( pset );
-
-}
-
-static void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) {
-/*
-* Name:
-* SetRegFS
-
-* Purpose:
-* Stores a new FrameSet in a Region
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status )
-
-* Class Membership:
-* Polygon method (over-rides the astSetRegFS method inherited from
-* the Region class).
-
-* Description:
-* This function creates a new FrameSet and stores it in the supplied
-* Region. The new FrameSet contains two copies of the supplied
-* Frame, connected by a UnitMap.
-
-* Parameters:
-* this
-* Pointer to the Region.
-* frm
-* The Frame to use.
-* status
-* Pointer to the inherited status variable.
-
-*/
-
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Indicate cached information eeds re-calculating. */
- astResetCache( this_region );
-
-/* Invoke the parent method to store the FrameSet in the parent Region
- structure. */
- (* parent_setregfs)( this_region, frm, status );
-
-}
-
-static AstMapping *Simplify( AstMapping *this_mapping, int *status ) {
-/*
-* Name:
-* Simplify
-
-* Purpose:
-* Simplify the Mapping represented by a Region.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* AstMapping *Simplify( AstMapping *this, int *status )
-
-* Class Membership:
-* Polygon method (over-rides the astSimplify method inherited
-* from the Region class).
-
-* Description:
-* This function invokes the parent Region Simplify method, and then
-* performs any further region-specific simplification.
-*
-* If the Mapping from base to current Frame is not a UnitMap, this
-* will include attempting to fit a new Region to the boundary defined
-* in the current Frame.
-
-* Parameters:
-* this
-* Pointer to the original Region.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the simplified Region. A cloned pointer to the
-* supplied Region will be returned if no simplication could be
-* performed.
-
-* Notes:
-* - A NULL pointer value will be returned if this function is
-* invoked with the AST error status set, or if it should fail for
-* any reason.
-*/
-
-/* Local Variables: */
- AstFrame *frm; /* Current Frame */
- AstMapping *map; /* Base -> current Mapping */
- AstMapping *result; /* Result pointer to return */
- AstPointSet *mesh; /* Mesh of current Frame positions */
- AstPointSet *ps2; /* Polygon PointSet in current Frame */
- AstPolygon *newpol; /* New Polygon */
- AstRegion *new; /* Pointer to simplified Region */
- AstRegion *this; /* Pointer to supplied Region structure */
- AstRegion *unc; /* Pointer to uncertainty Region */
- double **ptr2; /* Pointer axis values in "ps2" */
- double *mem; /* Pointer to array holding new vertex coords */
- double *p; /* Pointer to next vertex coords */
- double *q; /* Pointer to next vertex coords */
- int iv; /* Vertex index */
- int nv; /* Number of vertices in polygon */
- int ok; /* Are the new polygon vertices good? */
- int simpler; /* Has some simplication taken place? */
-
-/* Initialise. */
- result = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Get a pointer to the supplied Region structure. */
- this = (AstRegion *) this_mapping;
-
-/* Invoke the parent Simplify method inherited from the Region class. This
- will simplify the encapsulated FrameSet and uncertainty Region. */
- new = (AstRegion *) (*parent_simplify)( this_mapping, status );
-
-/* Note if any simplification took place. This is assumed to be the case
- if the pointer returned by the above call is different to the supplied
- pointer. */
- simpler = ( new != this );
-
-/* We attempt to simplify the Polygon by re-defining it within its current
- Frame. Transforming the Polygon from its base to its current Frame may
- result in the region no having the same edges. If required, we test this
- by transforming a set of bounds on the Polygon boundary. This can only
- be done if the current Frame is 2-dimensional. Also, there is only any
- point in doing it if the Mapping from base to current Frame in the
- Polygon is not a UnitMap. */
- map = astGetMapping( new->frameset, AST__BASE, AST__CURRENT );
- if( !astIsAUnitMap( map ) && astGetNout( map ) == 2 ) {
-
-/* Get a pointer to the Frame represented by the Polgon. */
- frm = astGetFrame( new->frameset, AST__CURRENT );
-
-/* Get the Region describing the positional uncertainty in this Frame. */
- unc = astGetUncFrm( new, AST__CURRENT );
-
-/* Get the positions of the vertices within this Frame. */
- ps2 = astRegTransform( this, this->points, 1, NULL, NULL );
- ptr2 = astGetPoints( ps2 );
-
-/* Get the number of vertices. */
- nv = astGetNpoint( ps2 );
-
-/* Re-organise the vertex axis values into the form required by the
- Polygon constructor function. */
- mem = astMalloc( sizeof( double)*(size_t)( 2*nv ) );
- if( astOK ) {
- ok = 1;
- p = mem;
- q = ptr2[ 0 ];
- for( iv = 0; iv < nv; iv++ ) {
- if( ( *(p++) = *(q++) ) == AST__BAD ) ok = 0;
- }
- q = ptr2[ 1 ];
- for( iv = 0; iv < nv; iv++ ) *(p++) = *(q++);
-
-/* Create a new Polygon using these transformed vertices. */
- if( ok ) {
- newpol = astPolygon( frm, nv, nv, mem, unc, "", status );
-
-/* If the SimpVertices attribute is zero, we now check that the
- transformation has not bent the edges of the polygon significantly.
- If it has, we annul the new Polygon. */
- if( !astGetSimpVertices( this ) ) {
-
-/* Get a mesh of points covering the Polygon in this Frame. */
- mesh = astRegMesh( new );
-
-/* See if all points within the mesh created from the original Polygon fall
- on the boundary of the new Polygon, to within the uncertainty of the
- Region. If not, annul the new Polgon. */
- if( !astRegPins( newpol, mesh, NULL, NULL ) ) {
- newpol = astAnnul( newpol );
- }
-
-/* Free the mesh. */
- mesh = astAnnul( mesh );
- }
-
-/* If we still have a new polygon, use the new Polygon in place of the
- original Region. */
- if( newpol ) {
- (void) astAnnul( new );
- new = (AstRegion *) newpol;
- simpler = 1;
- }
- }
- }
-
-/* Free other resources. */
- frm = astAnnul( frm );
- unc = astAnnul( unc );
- ps2 = astAnnul( ps2 );
- mem = astFree( mem );
- }
- map = astAnnul( map );
-
-/* If any simplification could be performed, copy Region attributes from
- the supplied Region to the returned Region, and return a pointer to it.
- If the supplied Region had no uncertainty, ensure the returned Region
- has no uncertainty. Otherwise, return a clone of the supplied pointer. */
- if( simpler ){
- astRegOverlay( new, this, 1 );
- result = (AstMapping *) new;
-
- } else {
- new = astAnnul( new );
- result = astClone( this );
- }
-
-/* If an error occurred, annul the returned pointer. */
- if ( !astOK ) result = astAnnul( result );
-
-/* Return the result. */
- return result;
-}
-
-static void SmoothPoly( AstPointSet *pset, int boxsize, double strength,
- int *status ) {
-/*
-* Name:
-* SmoothPoly
-
-* Purpose:
-* Smoooth a polygon assuming plane geometry.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void SmoothPoly( AstPointSet *pset, int boxsize, double strength,
-* int *status )
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* This function smooths a polygon, without changing the number of
-* vertices. It assumes plane geometry, so should not be used to
-* smooth polygons defined within a SkyFrame or CmpFrame.
-*
-* Each vertex is replaced by a new vertex determined as follows: the
-* mean X and Y axis value of the vertices in a section of the polygon
-* centred on the vertex being replaced are found (the length of the
-* section is given by parameter "boxsize"). The new vertex position
-* is then the weighted mean of this mean (X,Y) position and the old
-* vertex position. The weight for the mean (X,Y) position is given
-* by parameter "strength", and the weight for the old vertex
-* position is (1.0 - strength)
-
-* Parameters:
-* pset
-* A PointSet holding the polygon vertices.
-* boxsize
-* Half width of the box filter, given as a number of vertices.
-* strength
-* The weight to use for the mean (X,Y) position when finding each
-* new vertex position. Should be in the range 0.0 to 1.0. A value
-* of zero results in no change being made to the polygon. A value
-* of 1.0 results in the returned polygon being fully smoothed.
-* status
-* Pointer to the inherited status variable.
-
-*/
-
-/* Local Variables: */
- double **ptr;
- double *newx;
- double *newy;
- double *nx;
- double *ny;
- double *oldx;
- double *oldy;
- double *ox;
- double *oy;
- double *px;
- double *py;
- double *qx;
- double *qy;
- double a;
- double b;
- double sx;
- double sy;
- int half_width;
- int i;
- int nv;
- int top;
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get the number of vertices. */
- nv = astGetNpoint( pset );
-
-/* Get pointers to arrays holding the supplied vertex positions. */
- ptr = astGetPoints( pset );
- oldx = ptr[ 0 ];
- oldy = ptr[ 1 ];
-
-/* Allocate arrays to hold the returned vertex positions. */
- newx = astMalloc( nv*sizeof( double ) );
- newy = astMalloc( nv*sizeof( double ) );
-
-/* Check these pointers can be used safely. */
- if( astOK ) {
-
-/* Get weighting factors for the fully smoothed and unsmoothed positions. */
- a = strength;
- b = 1.0 - a;
-
-/* Ensure the box size is sufficiently small for there to be room for
- two boxes along the polygon. */
- half_width = nv/4 - 1;
- if( boxsize < half_width ) half_width = boxsize;
- if( half_width < 1 ) half_width = 1;
-
-/* Modify the weight for the fully smoothed position to include the
- normalisation factor needed to account for the box width. */
- a /= 2*half_width + 1;
-
-/* Find the sum of the x and y coordinates within a box centred on the
- first vertex. This includes vertices from the end of the polygon. */
- px = oldx + 1;
- qx = oldx + nv;
- sx = (oldx)[ 0 ];
-
- py = oldy + 1;
- qy = oldy + nv;
- sy = (oldy)[ 0 ];
-
- for( i = 0; i < half_width; i++ ) {
- sx += *(px++) + *(--qx);
- sy += *(py++) + *(--qy);
- }
-
-/* Replacing vertices within the first half box will include vertices at
- both ends of the polygon. Set up the pointers accordingly, and then
- find replacements for each vertex in the first half box.*/
- ox = oldx;
- oy = oldy;
- nx = newx;
- ny = newy;
- for( i = 0; i < half_width; i++ ) {
-
-/* Form the new vertex (x,y) values as the weighted mean of the mean
- (x,y) values in the box, and the old (x,y) values. */
- *(nx++) = a*sx + b*( *(ox++) );
- *(ny++) = a*sy + b*( *(oy++) );
-
-/* Add in the next vertex X and Y axis values to the running sums, and
- remove the position that has now passed out of the box. */
- sx += *(px++) - *(qx++);
- sy += *(py++) - *(qy++);
- }
-
-/* Adjust the pointer for the rest of the polygon, up to one half box away
- from the end. In this section, the smoothing box does not touch either
- end of the polygon. */
- top = nv - half_width - 1;
- qx = oldx;
- qy = oldy;
- for( ; i < top; i++ ){
-
-/* Form the new vertex (x,y) values as the weighted mean of the mean
- (x,y) values in the box, and the old (x,y) values. */
- *(nx++) = a*sx + b*( *(ox++) );
- *(ny++) = a*sy + b*( *(oy++) );
-
-/* Add in the next vertex X and Y axis values to the running sums, and
- remove the position that has now passed out of the box. */
- sx += *(px++) - *(qx++);
- sy += *(py++) - *(qy++);
- }
-
-/* Now do the last half box (which includes vertices from the start of
- the polygon). */
- top = nv;
- px = oldx;
- py = oldy;
- for( ; i < top; i++ ){
- *(nx++) = a*sx + b*( *(ox++) );
- *(ny++) = a*sy + b*( *(oy++) );
- sx += *(px++) - *(qx++);
- sy += *(py++) - *(qy++);
- }
-
-/* Replace the data points in the PointSet. */
- ptr[ 0 ] = newx;
- ptr[ 1 ] = newy;
- oldx = astFree( oldx );
- oldy = astFree( oldy );
- }
-}
-
-static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
-/*
-* Name:
-* TestAttrib
-
-* Purpose:
-* Test if a specified attribute value is set for a Polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* int TestAttrib( AstObject *this, const char *attrib, int *status )
-
-* Class Membership:
-* Polygon member function (over-rides the astTestAttrib protected
-* method inherited from the Region class).
-
-* Description:
-* This function returns a boolean result (0 or 1) to indicate whether
-* a value has been set for one of a Polygon's attributes.
-
-* Parameters:
-* this
-* Pointer to the Polygon.
-* attrib
-* Pointer to a null terminated string specifying the attribute
-* name. This should be in lower case with no surrounding white
-* space.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* One if a value has been set, otherwise zero.
-
-* Notes:
-* - A value of zero will be returned if this function is invoked
-* with the global status set, or if it should fail for any reason.
-*/
-
-/* Local Variables: */
- AstPolygon *this; /* Pointer to the Polygon structure */
- int result; /* Result value to return */
-
-/* Initialise. */
- result = 0;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Obtain a pointer to the Polygon structure. */
- this = (AstPolygon *) this_object;
-
-/* Check the attribute name and test the appropriate attribute. */
-
-/* SimpVertices. */
-/* ------------- */
- if ( !strcmp( attrib, "simpvertices" ) ) {
- result = astTestSimpVertices( this );
-
-/* If the attribute is not recognised, pass it on to the parent method
- for further interpretation. */
- } else {
- result = (*parent_testattrib)( this_object, attrib, status );
- }
-
-/* Return the result, */
- return result;
-}
-
-/*
-* Name:
-* TraceEdge
-
-* Purpose:
-* Find a point that is inside the required outline.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* void TraceEdge<Oper><X>( <Xtype> value, const <Xtype> array[],
-* const int lbnd[ 2 ], const int ubnd[ 2 ],
-* int iv0, int ix0, int iy0, int starpix,
-* int full, int *status );
-
-* Class Membership:
-* Polygon member function
-
-* Description:
-* This function forms a polygon enclosing the region of the data
-* array specified by <Oper> and "value". If this polygon contains
-* the point "(inx,iny)", then a PointSet is returned holding the
-* pixel coordinates of the Polygon vertices. If the polygon
-* does not contain "(inx,iny)", a NULL pointer is returned.
-*
-* Each vertex in the polygon corresponds to a corner of a pixel in
-* the data array.
-
-* Parameters:
-* value
-* The data value defining valid pixels.
-* array
-* The data array.
-* lbnd
-* The lower pixel index bounds of the array.
-* ubnd
-* The upper pixel index bounds of the array.
-* iv0
-* The vector index of a pixel inside the region such that the
-* pixel to the right is NOT inside the region. This defines the
-* start of the polygon.
-* ix0
-* The X pixel index of the pixel specified by "iv0".
-* inx
-* The X pixel index of a point which must be inside the polygon
-* for the polygon to be acceptable.
-* iny
-* The Y pixel index of a point which must be inside the polygon
-* for the polygon to be acceptable.
-* starpix
-* If non-zero, the usual Starlink definition of pixel coordinate
-* is used (integral values at pixel corners). Otherwise, the
-* system used by other AST functions such as astResample is used
-* (integral values at pixel centres).
-* full
-* If non-zero, the full polygon is stored. If zero, vertices in the
-* middle of straight sections of the Polygon are omitted.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to a PointSet holding the vertices of the polygon, or
-* NULL if the polygon did not contain "(inx,iny)".
-
-* Notes:
-* - <Oper> must be one of LT, LE, EQ, GE, GT, NE.
-
-
-*/
-
-/* Define a macro to implement the function for a specific data
- type and operation. */
-#define MAKE_TRACEEDGE(X,Xtype,Oper,OperI) \
-static AstPointSet *TraceEdge##Oper##X( Xtype value, const Xtype array[], \
- const int lbnd[ 2 ], const int ubnd[ 2 ], \
- int iv0, int ix0, int iy0, \
- int starpix, int full, \
- int *status ){ \
-\
-/* Local Variables: */ \
- AstPointSet *result; /* Pointer to text describing oper */ \
- const Xtype *pa; /* Pointer to current valid pixel value */ \
- const Xtype *pb; /* Pointer to neigbouring valid pixel value */ \
- const Xtype *pc; /* Pointer to neigbouring valid pixel value */ \
- double *ptr[ 2 ]; /* PointSet data pointers */ \
- double *xvert; /* Pointer to array holding vertex X axis values */ \
- double *yvert; /* Pointer to array holding vertex Y axis values */ \
- double dx; /* Pertubation in X (pixels) to avoid the pixel edge */ \
- double dy; /* Pertubation in Y (pixels) to avoid the pixel edge */ \
- double xx; /* Pixel X coord at corner */ \
- double yy; /* Pixel Y coord at corner */ \
- int at; /* The pixel corner to draw to */ \
- int done; /* Have we arrived back at the start of the polygon? */ \
- int ii; /* Index of new vertex */ \
- int ix; /* X pixel index of current valid pixel */ \
- int iy; /* Y pixel index of current valid pixel */ \
- int nright; /* Overall number of right hand turns along polygon */ \
- int nvert; /* Number of vertices */ \
- int nx; /* Pixels per row */ \
-\
-/* Initialise */ \
- result = NULL; \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return result; \
-\
-\
-/* Initialise pointers to arrays holding the X and Y pixel coordinates at \
- the vertices of the polygon. */ \
- xvert = NULL; \
- yvert = NULL; \
- nvert = 0; \
-\
-/* Find number of pixels in one row of the array. */ \
- nx = ( ubnd[ 0 ] - lbnd[ 0 ] + 1 ); \
-\
-/* The four corners of a pixel are numbered as follows: 0=bottom left, \
- 1=top left, 2=top right, 3=bottom right. The following algorithm moves \
- along pixel edges, from corner to corner, using the above numbering \
- scheme to identify the corners. We start the polygon by moving from the \
- bottom right to the top right corner of pixel "(ix0,iy0)". */ \
- ix = ix0; \
- iy = iy0; \
- at = 2; \
-\
-/* Store a pointer to the first good pixel value. */ \
- pa = array + ( ix - lbnd[ 0 ] ) + nx*( iy - lbnd[ 1 ] ) ; \
-\
-/* We count the number of times the polygon turns to the right compared \
- to the left. Initialise it to zero. */ \
- nright = 0; \
-\
-/* Loop round tracing out the polygon until we arrive back at the \
- beginning. The Polygon class requires that the inside of the polygon \
- is to the left as we move round the polygon in an anti-clockwise \
- direction. So at each corner, we attempt to move to the next \
- anti-clockwise good pixel corner. */ \
- done = 0; \
- while( !done ) { \
-\
-/* If we have arrived at the bottom left corner of the good pixel, we must \
- have come from the top left corner since all movements around a pixel \
- must be anti-clockwise. */ \
- if( at == 0 ) { \
-\
-/* Note the pixel coordinates at the bottom left corner of the current \
- pixel. */ \
- if( starpix ) { \
- xx = ix - 1.0; \
- yy = iy - 1.0; \
- } else { \
- xx = ix - 0.5; \
- yy = iy - 0.5; \
- } \
-\
-/* Get a pointer to lower left pixel value */ \
- pb = pa - nx - 1; \
-\
-/* Get a pointer to lower mid pixel value. */ \
- pc = pb + 1; \
-\
-/* If the lower left pixel is within the array and meets the validity \
- requirements, move to the left along its top edge. */ \
- if( iy > lbnd[ 1 ] && ix > lbnd[ 0 ] && ISVALID(*pb,OperI,value) ) { \
- nright++; \
- pa = pb; \
- at = 1; \
- ix--; \
- iy--; \
- dx = DELTA; \
- dy = -DELTA; \
-\
-/* Otherwise, if lower mid pixel is good, move down its left edge. */ \
- } else if( iy > lbnd[ 1 ] && ISVALID(*pc,OperI,value) ) { \
- pa = pc; \
- at = 0; \
- iy--; \
- dx = DELTA; \
- dy = 0.0; \
-\
-/* Otherwise, move to the right along the bottom edge of the current pixel. */ \
- } else { \
- nright--; \
- at = 3; \
- dx = DELTA; \
- dy = DELTA; \
- } \
-\
-/* If the polygon bends at this point, or if we will be smoothing the \
- polygon, append the pixel coordinates at this pixel corner to the \
- polygon. */ \
- if( full || pa != pc ) ADD( xx, yy ); \
-\
-/* If we have arrived at the top left corner of the good pixel, we must \
- have come from the top right corner. */ \
- } else if( at == 1 ) { \
-\
-/* Note the pixel coordinates at the top left corner of the current \
- pixel. */ \
- if( starpix ) { \
- xx = ix - 1.0; \
- yy = iy; \
- } else { \
- xx = ix - 0.5; \
- yy = iy + 0.5; \
- } \
-\
-/* Get a pointer to upper left pixel value */ \
- pb = pa + nx - 1; \
-\
-/* Get a pointer to mid left pixel value. */ \
- pc = pa - 1; \
-\
-/* If upper left pixel is good, move up its left edge. */ \
- if( iy < ubnd[ 1 ] && ix > lbnd[ 0 ] && ISVALID(*pb,OperI,value) ) { \
- nright++; \
- pa = pb; \
- at = 2; \
- ix--; \
- iy++; \
- dx = -DELTA; \
- dy = -DELTA; \
-\
-/* Otherwise, if left mid pixel is good, move left along its top edge. */ \
- } else if( ix > lbnd[ 0 ] && ISVALID(*pc,OperI,value) ) { \
- pa = pc; \
- at = 1; \
- ix--; \
- dx = 0.0; \
- dy = -DELTA; \
-\
-/* Otherwise, move down the left edge of the current pixel. */ \
- } else { \
- nright--; \
- at = 0; \
- dx = DELTA; \
- dy = -DELTA; \
- } \
-\
-/* If the polygon bends at this point, or if we will be smoothing the \
- polygon, append the pixel coordinates at this pixel corner to the \
- polygon. */ \
- if( full || pa != pc ) ADD( xx, yy ); \
-\
-/* If we have arrived at the top right corner of the good pixel, we must \
- have come from the bottom right corner. */ \
- } else if( at == 2 ) { \
-\
-/* Note the pixel coordinates at the top right corner of the current \
- pixel. */ \
- if( starpix ) { \
- xx = ix; \
- yy = iy; \
- } else { \
- xx = ix + 0.5; \
- yy = iy + 0.5; \
- } \
-\
-/* Pointer to upper right pixel value */ \
- pb = pa + nx + 1; \
-\
-/* Pointer to top mid pixel value. */ \
- pc = pa + nx; \
-\
-/* If upper right pixel is good, move right along its bottom edge. */ \
- if( iy < ubnd[ 1 ] && ix < ubnd[ 0 ] && ISVALID(*pb,OperI,value) ){ \
- nright++; \
- pa = pb; \
- at = 3; \
- ix++; \
- iy++; \
- dx = -DELTA; \
- dy = DELTA; \
-\
-/* Otherwise, if upper mid pixel is good, move up its right edge. */ \
- } else if( iy < ubnd[ 1 ] && ISVALID(*pc,OperI,value) ) { \
- pa = pc; \
- at = 2; \
- iy++; \
- dx = -DELTA; \
- dy = 0.0; \
-\
-/* Otherwise, move left along the top edge of the current pixel. */ \
- } else { \
- nright--; \
- at = 1; \
- dx = -DELTA; \
- dy = -DELTA; \
- } \
-\
-/* If the polygon bends at this point, or if we will be smoothing the \
- polygon, append the pixel coordinates at this pixel corner to the \
- polygon. */ \
- if( full || pa != pc ) ADD( xx, yy ); \
-\
-/* Arrived at bottom right corner of good pixel from lower left. */ \
- } else { \
-\
-/* Note the pixel coordinates at the bottom right corner of the current \
- pixel. */ \
- if( starpix ) { \
- xx = ix; \
- yy = iy - 1.0; \
- } else { \
- xx = ix + 0.5; \
- yy = iy - 0.5; \
- } \
-\
-/* Pointer to lower right pixel value */ \
- pb = pa - ( nx - 1 ); \
-\
-/* Pointer to mid right pixel value. */ \
- pc = pa + 1; \
-\
-/* If lower right pixel is good, move down its left edge. */ \
- if( iy > lbnd[ 1 ] && ix < ubnd[ 0 ] && ISVALID(*pb,OperI,value) ) { \
- nright++; \
- pa = pb; \
- at = 0; \
- ix++; \
- iy--; \
- dx = DELTA; \
- dy = DELTA; \
-\
-/* Otherwise, if right mid pixel is good, move right along its lower edge. */ \
- } else if( ix < ubnd[ 0 ] && ISVALID(*pc,OperI,value) ) { \
- pa = pc; \
- at = 3; \
- ix++; \
- dx = 0.0; \
- dy = DELTA; \
-\
-/* Otherwise, move up the right edge of the current pixel. */ \
- } else { \
- nright--; \
- at = 2; \
- dx = -DELTA; \
- dy = DELTA; \
- } \
-\
-/* If the polygon bends at this point, or if we will be smoothing the \
- polygon, append the pixel coordinates at this pixel corner to the \
- polygon. */ \
- if( full || pa != pc ) ADD( xx, yy ); \
- } \
-\
-/* If we have arrived back at the start, break out of the loop. */ \
- if( ix == ix0 && iy == iy0 && at == 2 ) done = 1; \
- } \
-\
-/* If we have circled round to the right, the polygon will not enclosed \
- the specified position, so free resources and return a NULL pointer. */ \
- if( nright > 0 ) { \
- xvert = astFree( xvert ); \
- yvert = astFree( yvert ); \
-\
-/* If we have circled round to the left, the polygon will enclose \
- the specified position, so create and return a PointSet. */ \
- } else { \
- result = astPointSet( nvert, 2, " ", status ); \
- ptr[ 0 ] = xvert; \
- ptr[ 1 ] = yvert; \
- astSetPoints( result, ptr ); \
- } \
-\
-/* Annul the returned PointSet if anythign went wrong. */ \
- if( !astOK && result ) result = astAnnul( result ); \
-\
-/* Return the PointSet pointer. */ \
- return result; \
-}
-
-/* Define a macro to add a vertex position to dynamically allocated
- arrays of X and Y positions. We offset the supplied position by
- a small fraction of a pixel towards the centre of hte polygon to
- avoid placing vertices exactly on the edge, which may cause problems
- later for pixels that are on the edge of an area of bad pixel. */
-#define ADD(X,Y) {\
- ii = nvert++; \
- xvert = (double *) astGrow( xvert, nvert, sizeof( double ) ); \
- yvert = (double *) astGrow( yvert, nvert, sizeof( double ) ); \
- if( astOK ) { \
- xvert[ ii ] = (X+dx); \
- yvert[ ii ] = (Y+dy); \
- } \
-}
-
-/* Define a macro that uses the above macro to to create implementations
- of TraceEdge for all operations. */
-#define MAKEALL_TRACEEDGE(X,Xtype) \
-MAKE_TRACEEDGE(X,Xtype,LT,AST__LT) \
-MAKE_TRACEEDGE(X,Xtype,LE,AST__LE) \
-MAKE_TRACEEDGE(X,Xtype,EQ,AST__EQ) \
-MAKE_TRACEEDGE(X,Xtype,NE,AST__NE) \
-MAKE_TRACEEDGE(X,Xtype,GE,AST__GE) \
-MAKE_TRACEEDGE(X,Xtype,GT,AST__GT)
-
-/* Expand the above macro to generate a function for each required
- data type and operation. */
-#if HAVE_LONG_DOUBLE /* Not normally implemented */
-MAKEALL_TRACEEDGE(LD,long double)
-#endif
-MAKEALL_TRACEEDGE(D,double)
-MAKEALL_TRACEEDGE(L,long int)
-MAKEALL_TRACEEDGE(UL,unsigned long int)
-MAKEALL_TRACEEDGE(I,int)
-MAKEALL_TRACEEDGE(UI,unsigned int)
-MAKEALL_TRACEEDGE(S,short int)
-MAKEALL_TRACEEDGE(US,unsigned short int)
-MAKEALL_TRACEEDGE(B,signed char)
-MAKEALL_TRACEEDGE(UB,unsigned char)
-MAKEALL_TRACEEDGE(F,float)
-
-/* Undefine the macros. */
-#undef MAKE_TRACEEDGE
-#undef MAKEALL_TRACEEDGE
-
-static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in,
- int forward, AstPointSet *out, int *status ) {
-/*
-* Name:
-* Transform
-
-* Purpose:
-* Apply a Polygon to transform a set of points.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* AstPointSet *Transform( AstMapping *this, AstPointSet *in,
-* int forward, AstPointSet *out, int *status )
-
-* Class Membership:
-* Polygon member function (over-rides the astTransform protected
-* method inherited from the Region class).
-
-* Description:
-* This function takes a Polygon and a set of points encapsulated in a
-* PointSet and transforms the points by setting axis values to
-* AST__BAD for all points which are outside the region. Points inside
-* the region are copied unchanged from input to output.
-
-* Parameters:
-* this
-* Pointer to the Polygon.
-* in
-* Pointer to the PointSet holding the input coordinate data.
-* forward
-* A non-zero value indicates that the forward coordinate transformation
-* should be applied, while a zero value requests the inverse
-* transformation.
-* out
-* Pointer to a PointSet which will hold the transformed (output)
-* coordinate values. A NULL value may also be given, in which case a
-* new PointSet will be created by this function.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to the output (possibly new) PointSet.
-
-* Notes:
-* - The forward and inverse transformations are identical for a
-* Region.
-* - A null pointer will be returned if this function is invoked with the
-* global error status set, or if it should fail for any reason.
-* - The number of coordinate values per point in the input PointSet must
-* match the number of axes in the Frame represented by the Polygon.
-* - If an output PointSet is supplied, it must have space for sufficient
-* number of points and coordinate values per point to accommodate the
-* result. Any excess space will be ignored.
-*/
-
-/* Local Variables: */
- AstFrame *frm; /* Pointer to base Frame in FrameSet */
- AstLineDef *a; /* Line from inside point to test point */
- AstLineDef *b; /* Polygon edge */
- AstPointSet *in_base; /* PointSet holding base Frame input positions*/
- AstPointSet *result; /* Pointer to output PointSet */
- AstPolygon *this; /* Pointer to Polygon */
- double **ptr_in; /* Pointer to input base Frame coordinate data */
- double **ptr_out; /* Pointer to output current Frame coordinate data */
- double *px; /* Pointer to array of first axis values */
- double *py; /* Pointer to array of second axis values */
- double p[ 2 ]; /* Current test position */
- int closed; /* Is the boundary part of the Region? */
- int i; /* Edge index */
- int icoord; /* Coordinate index */
- int in_region; /* Is the point inside the Region? */
- int ncoord_out; /* No. of current Frame axes */
- int ncross; /* Number of crossings */
- int neg; /* Has the Region been negated? */
- int npoint; /* No. of input points */
- int nv; /* No. of vertices */
- int point; /* Loop counter for input points */
- int pos; /* Is test position in, on, or outside boundary? */
-
-/* Check the global error status. */
- if ( !astOK ) return NULL;
-
-/* Obtain a pointer to the Polygon structure. */
- this = (AstPolygon *) this_mapping;
-
-/* Apply the parent mapping using the stored pointer to the Transform member
- function inherited from the parent Region class. This function validates
- all arguments and generates an output PointSet if necessary,
- containing a copy of the input PointSet. */
- result = (*parent_transform)( this_mapping, in, forward, out, status );
-
-/* Get the number of points to be transformed. */
- npoint = astGetNpoint( result );
-
-/* Get a pointer to the output axis values. */
- ptr_out = astGetPoints( result );
-
-/* Find the number of axes in the current Frame. This need not be 2 (the
- number of axes in the *base* Frame must be 2 however). */
- ncoord_out = astGetNcoord( result );
-
-/* We will now extend the parent astTransform method by performing the
- calculations needed to generate the output coordinate values. */
-
-/* First use the encapsulated FrameSet to transform the supplied positions
- from the current Frame in the encapsulated FrameSet (the Frame
- represented by the Region), to the base Frame (the Frame in which the
- Region is defined). This call also returns a pointer to the base Frame
- of the encapsulated FrameSet. Note, the returned pointer may be a
- clone of the "in" pointer, and so we must be carefull not to modify the
- contents of the returned PointSet. */
- in_base = astRegTransform( this, in, 0, NULL, &frm );
- ptr_in = astGetPoints( in_base );
-
-/* Get the number of vertices in the polygon. */
- nv = astGetNpoint( ((AstRegion *) this)->points );
-
-/* See if the boundary is part of the Region. */
- closed = astGetClosed( this );
-
-/* See if the Region has been negated. */
- neg = astGetNegated( this );
-
-/* Perform coordinate arithmetic. */
-/* ------------------------------ */
- if ( astOK ) {
- px = ptr_in[ 0 ];
- py = ptr_in[ 1 ];
-
-/* Loop round each supplied point in the base Frame of the polygon. */
- for ( point = 0; point < npoint; point++, px++, py++ ) {
-
-/* If the input point is bad, indicate that bad output values should be
- returned. */
- if( *px == AST__BAD || *py == AST__BAD ) {
- in_region = 0;
-
-/* Otherwise, we first determine if the point is inside, outside, or on,
- the Polygon boundary. Initialially it is unknown. */
- } else {
-
-/* Ensure cached information is available.*/
- Cache( this, status );
-
-/* Create a definition of the line from a point which is inside the
- polygon to the supplied point. This is a structure which includes
- cached intermediate information which can be used to speed up
- subsequent calculations. */
- p[ 0 ] = *px;
- p[ 1 ] = *py;
- a = astLineDef( frm, this->in, p );
-
-/* We now determine the number of times this line crosses the polygon
- boundary. Initialise the number of crossings to zero. */
- ncross = 0;
- pos = UNKNOWN;
-
-/* Loop rouind all edges of the polygon. */
- for( i = 0; i < nv; i++ ) {
- b = this->edges[ i ];
-
-/* If this point is on the current edge, then we need do no more checks
- since we know it is either inside or outside the polygon (depending on
- whether the polygon is closed or not). */
- if( astLineContains( frm, b, 0, p ) ) {
- pos = ON;
- break;
-
-/* Otherwise, see if the two lines cross within their extent. If so,
- increment the number of crossings. */
- } else if( astLineCrossing( frm, b, a, NULL ) ) {
- ncross++;
- }
- }
-
-/* Free resources */
- a = astFree( a );
-
-/* If the position is not on the boundary, it is inside the boundary if
- the number of crossings is even, and outside otherwise. */
- if( pos == UNKNOWN ) pos = ( ncross % 2 == 0 )? IN : OUT;
-
-/* Whether the point is in the Region depends on whether the point is
- inside the polygon boundary, whether the Polygon has been negated, and
- whether the polygon is closed. */
- if( neg ) {
- if( pos == IN ) {
- in_region = 0;
- } else if( pos == OUT ) {
- in_region = 1;
- } else if( closed ) {
- in_region = 1;
- } else {
- in_region = 0;
- }
-
- } else {
- if( pos == IN ) {
- in_region = 1;
- } else if( pos == OUT ) {
- in_region = 0;
- } else if( closed ) {
- in_region = 1;
- } else {
- in_region = 0;
- }
- }
- }
-
-/* If the point is not inside the Region, store bad output values. */
- if( !in_region ) {
- for ( icoord = 0; icoord < ncoord_out; icoord++ ) {
- ptr_out[ icoord ][ point ] = AST__BAD;
- }
- }
- }
- }
-
-/* Free resources */
- in_base = astAnnul( in_base );
- frm = astAnnul( frm );
-
-/* Annul the result if an error has occurred. */
- if( !astOK ) result = astAnnul( result );
-
-/* Return a pointer to the output PointSet. */
- return result;
-}
-
-/* Functions which access class attributes. */
-/* ---------------------------------------- */
-/* Implement member functions to access the attributes associated with
- this class using the macros defined for this purpose in the
- "object.h" file. For a description of each attribute, see the class
- interface (in the associated .h file). */
-
-/*
-*att++
-* Name:
-* SimpVertices
-
-* Purpose:
-* Simplify a Polygon by transforming its vertices?
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer (boolean).
-
-* Description:
-* This attribute controls the behaviour of the
-c astSimplify
-f AST_SIMPLIFY
-* method when applied to a Polygon. The simplified Polygon is created
-* by transforming the vertices from the Frame in which the Polygon
-* was originally defined into the Frame currently represented by the
-* Polygon. If SimpVertices is non-zero (the default) then this
-* simplified Polygon is returned without further checks. If SimpVertices
-* is zero, a check is made that the edges of the new Polygon do not
-* depart significantly from the edges of the original Polygon (as
-* determined by the uncertainty associated with the Polygon). This
-* could occur, for instance, if the Mapping frrm the original to the
-* current Frame is highly non-linear. If this check fails, the
-* original unsimplified Polygon is returned without change.
-
-* Applicability:
-* Polygon
-* All Polygons have this attribute.
-
-*att--
-*/
-astMAKE_CLEAR(Polygon,SimpVertices,simp_vertices,-INT_MAX)
-astMAKE_GET(Polygon,SimpVertices,int,0,( ( this->simp_vertices != -INT_MAX ) ?
- this->simp_vertices : 1 ))
-astMAKE_SET(Polygon,SimpVertices,int,simp_vertices,( value != 0 ))
-astMAKE_TEST(Polygon,SimpVertices,( this->simp_vertices != -INT_MAX ))
-
-/* Copy constructor. */
-/* ----------------- */
-static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
-/*
-* Name:
-* Copy
-
-* Purpose:
-* Copy constructor for Polygon objects.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void Copy( const AstObject *objin, AstObject *objout, int *status )
-
-* Description:
-* This function implements the copy constructor for Polygon objects.
-
-* Parameters:
-* objin
-* Pointer to the object to be copied.
-* objout
-* Pointer to the object being constructed.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - This constructor makes a deep copy.
-*/
-
-/* Local Variables: */
- AstPolygon *out; /* Pointer to output Polygon */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Obtain pointers to the output Polygon. */
- out = (AstPolygon *) objout;
-
-/* For safety, first clear any references to the input memory from
- the output Polygon. */
- out->edges = NULL;
- out->startsat = NULL;
-
-/* Indicate cached information needs nre-calculating. */
- astResetCache( (AstPolygon *) out );
-}
-
-
-/* Destructor. */
-/* ----------- */
-static void Delete( AstObject *obj, int *status ) {
-/*
-* Name:
-* Delete
-
-* Purpose:
-* Destructor for Polygon objects.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void Delete( AstObject *obj, int *status )
-
-* Description:
-* This function implements the destructor for Polygon objects.
-
-* Parameters:
-* obj
-* Pointer to the object to be deleted.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* This function attempts to execute even if the global error status is
-* set.
-*/
-
-/* Local Variables: */
- AstPointSet *ps; /* Pointer to PointSet inside Region */
- AstPolygon *this; /* Pointer to Polygon */
- int i; /* Index of vertex */
- int istat; /* Original AST error status */
- int nv; /* Number of vertices */
- int rep; /* Original error reporting state */
-
-/* Obtain a pointer to the Polygon structure. */
- this = (AstPolygon *) obj;
-
-/* Annul all resources. */
- ps = ((AstRegion *) this)->points;
- if( this->edges && ps ) {
-
-/* Ensure we get a value for "nv" even if an error has occurred. */
- istat = astStatus;
- astClearStatus;
- rep = astReporting( 0 );
-
- nv = astGetNpoint( ps );
-
- astSetStatus( istat );
- astReporting( rep );
-
-/* Free the structures holding the edge information. */
- for( i = 0; i < nv; i++ ) {
- this->edges[ i ] = astFree( this->edges[ i ] );
- }
- this->edges = astFree( this->edges );
- this->startsat = astFree( this->startsat );
-
- }
-}
-
-/* Dump function. */
-/* -------------- */
-static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
-/*
-* Name:
-* Dump
-
-* Purpose:
-* Dump function for Polygon objects.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void Dump( AstObject *this, AstChannel *channel, int *status )
-
-* Description:
-* This function implements the Dump function which writes out data
-* for the Polygon class to an output Channel.
-
-* Parameters:
-* this
-* Pointer to the Polygon whose data are being written.
-* channel
-* Pointer to the Channel to which the data are being written.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- AstPolygon *this; /* Pointer to the Polygon structure */
- int ival; /* Integer attribute value */
- int set; /* Attribute value set? */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Obtain a pointer to the Polygon structure. */
- this = (AstPolygon *) this_object;
-
-/* Write out values representing the instance variables for the
- Polygon class. Accompany these with appropriate comment strings,
- possibly depending on the values being written.*/
-
-/* In the case of attributes, we first use the appropriate (private)
- Test... member function to see if they are set. If so, we then use
- the (private) Get... function to obtain the value to be written
- out.
-
- For attributes which are not set, we use the astGet... method to
- obtain the value instead. This will supply a default value
- (possibly provided by a derived class which over-rides this method)
- which is more useful to a human reader as it corresponds to the
- actual default attribute value. Since "set" will be zero, these
- values are for information only and will not be read back. */
-
-/* SimpVertices. */
-/* ------------ */
-/* Write out the forward-inverse simplification flag. */
- set = TestSimpVertices( this, status );
- ival = set ? GetSimpVertices( this, status ) : astGetSimpVertices( this );
- astWriteInt( channel, "SimpVT", set, 0, ival, "Simplify by transforming vertices?" );
-
-/* A flag indicating the convention used for determining the interior of
- the polygon. A zero value indicates that the old AST system is in
- use (inside to the left when moving anti-clockwise round the vertices
- as viewed from the outside of the celestial sphere). A non-zero value
- indicates the STC system is in use (inside to the left when moving
- anti-clockwise round the vertices as viewed from the inside of the
- celestial sphere). AST currently uses the STC system. */
- astWriteInt( channel, "Order", 1, 0, 1, "Polygon uses STC vertex order convention" );
-}
-
-/* Standard class functions. */
-/* ========================= */
-/* Implement the astIsAPolygon and astCheckPolygon functions using the macros
- defined for this purpose in the "object.h" header file. */
-astMAKE_ISA(Polygon,Region)
-astMAKE_CHECK(Polygon)
-
-AstPolygon *astPolygon_( void *frame_void, int npnt, int dim,
- const double *points, AstRegion *unc,
- const char *options, int *status, ...) {
-/*
-*++
-* Name:
-c astPolygon
-f AST_POLYGON
-
-* Purpose:
-* Create a Polygon.
-
-* Type:
-* Public function.
-
-* Synopsis:
-c #include "polygon.h"
-c AstPolygon *astPolygon( AstFrame *frame, int npnt, int dim,
-c const double *points, AstRegion *unc,
-c const char *options, ... )
-f RESULT = AST_POLYGON( FRAME, NPNT, DIM, POINTS, UNC, OPTIONS, STATUS )
-
-* Class Membership:
-* Polygon constructor.
-
-* Description:
-* This function creates a new Polygon object and optionally initialises
-* its attributes.
-*
-* The Polygon class implements a polygonal area, defined by a
-* collection of vertices, within a 2-dimensional Frame. The vertices
-* are connected together by geodesic curves within the encapsulated Frame.
-* For instance, if the encapsulated Frame is a simple Frame then the
-* geodesics will be straight lines, but if the Frame is a SkyFrame then
-* the geodesics will be great circles. Note, the vertices must be
-* supplied in an order such that the inside of the polygon is to the
-* left of the boundary as the vertices are traversed. Supplying them
-* in the reverse order will effectively negate the polygon.
-*
-* Within a SkyFrame, neighbouring vertices are always joined using the
-* shortest path. Thus if an edge of 180 degrees or more in length is
-* required, it should be split into section each of which is less
-* than 180 degrees. The closed path joining all the vertices in order
-* will divide the celestial sphere into two disjoint regions. The
-* inside of the polygon is the region which is circled in an
-* anti-clockwise manner (when viewed from the inside of the celestial
-* sphere) when moving through the list of vertices in the order in
-* which they were supplied when the Polygon was created (i.e. the
-* inside is to the left of the boundary when moving through the
-* vertices in the order supplied).
-
-* Parameters:
-c frame
-f FRAME = INTEGER (Given)
-* A pointer to the Frame in which the region is defined. It must
-* have exactly 2 axes. A deep copy is taken of the supplied Frame.
-* This means that any subsequent changes made to the Frame using the
-* supplied pointer will have no effect the Region.
-c npnt
-f NPNT = INTEGER (Given)
-* The number of points in the Region.
-c dim
-f DIM = INTEGER (Given)
-c The number of elements along the second dimension of the "points"
-f The number of elements along the first dimension of the POINTS
-* array (which contains the point coordinates). This value is
-* required so that the coordinate values can be correctly
-* located if they do not entirely fill this array. The value
-c given should not be less than "npnt".
-f given should not be less than NPNT.
-c points
-f POINTS( DIM, 2 ) = DOUBLE PRECISION (Given)
-c The address of the first element of a 2-dimensional array of
-c shape "[2][dim]" giving the physical coordinates of the vertices.
-c These should be stored such that the value of coordinate
-c number "coord" for point number "pnt" is found in element
-c "in[coord][pnt]".
-f A 2-dimensional array giving the physical coordinates of the
-f vertices. These should be stored such that the value of coordinate
-f number COORD for point number PNT is found in element IN(PNT,COORD).
-c unc
-f UNC = INTEGER (Given)
-* An optional pointer to an existing Region which specifies the
-* uncertainties associated with the boundary of the Polygon being created.
-* The uncertainty in any point on the boundary of the Polygon is found by
-* shifting the supplied "uncertainty" Region so that it is centred at
-* the boundary point being considered. The area covered by the
-* shifted uncertainty Region then represents the uncertainty in the
-* boundary position. The uncertainty is assumed to be the same for
-* all points.
-*
-* If supplied, the uncertainty Region must be of a class for which
-* all instances are centro-symetric (e.g. Box, Circle, Ellipse, etc.)
-* or be a Prism containing centro-symetric component Regions. A deep
-* copy of the supplied Region will be taken, so subsequent changes to
-* the uncertainty Region using the supplied pointer will have no
-* effect on the created Polygon. Alternatively,
-f a null Object pointer (AST__NULL)
-c a NULL Object pointer
-* may be supplied, in which case a default uncertainty is used
-* equivalent to a box 1.0E-6 of the size of the Polygon being created.
-*
-* The uncertainty Region has two uses: 1) when the
-c astOverlap
-f AST_OVERLAP
-* function compares two Regions for equality the uncertainty
-* Region is used to determine the tolerance on the comparison, and 2)
-* when a Region is mapped into a different coordinate system and
-* subsequently simplified (using
-c astSimplify),
-f AST_SIMPLIFY),
-* the uncertainties are used to determine if the transformed boundary
-* can be accurately represented by a specific shape of Region.
-c options
-f OPTIONS = CHARACTER * ( * ) (Given)
-c Pointer to a null-terminated string containing an optional
-c comma-separated list of attribute assignments to be used for
-c initialising the new Polygon. The syntax used is identical to
-c that for the astSet function and may include "printf" format
-c specifiers identified by "%" symbols in the normal way.
-f A character string containing an optional comma-separated
-f list of attribute assignments to be used for initialising the
-f new Polygon. The syntax used is identical to that for the
-f AST_SET routine.
-c ...
-c If the "options" string contains "%" format specifiers, then
-c an optional list of additional arguments may follow it in
-c order to supply values to be substituted for these
-c specifiers. The rules for supplying these are identical to
-c those for the astSet function (and for the C "printf"
-c function).
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astPolygon()
-f AST_POLYGON = INTEGER
-* A pointer to the new Polygon.
-
-* Notes:
-* - A null Object pointer (AST__NULL) will be returned if this
-c function is invoked with the AST error status set, or if it
-f function is invoked with STATUS set to an error value, or if it
-* should fail for any reason.
-
-* Status Handling:
-* The protected interface to this function includes an extra
-* parameter at the end of the parameter list descirbed above. This
-* parameter is a pointer to the integer inherited status
-* variable: "int *status".
-
-*--
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstFrame *frame; /* Pointer to Frame structure */
- AstPolygon *new; /* Pointer to new Polygon */
- va_list args; /* Variable argument list */
-
-/* Get a pointer to the thread specific global data structure. */
- astGET_GLOBALS(NULL);
-
-/* Check the global status. */
- if ( !astOK ) return NULL;
-
-/* Obtain and validate a pointer to the supplied Frame structure. */
- frame = astCheckFrame( frame_void );
-
-/* Initialise the Polygon, allocating memory and initialising the
- virtual function table as well if necessary. */
- new = astInitPolygon( NULL, sizeof( AstPolygon ), !class_init,
- &class_vtab, "Polygon", frame, npnt,
- dim, points, unc );
-
-/* If successful, note that the virtual function table has been
- initialised. */
- if ( astOK ) {
- class_init = 1;
-
-/* Obtain the variable argument list and pass it along with the options string
- to the astVSet method to initialise the new Polygon's attributes. */
- va_start( args, status );
- astVSet( new, options, NULL, args );
- va_end( args );
-
-/* If an error occurred, clean up by deleting the new object. */
- if ( !astOK ) new = astDelete( new );
- }
-
-/* Return a pointer to the new Polygon. */
- return new;
-}
-
-AstPolygon *astPolygonId_( void *frame_void, int npnt, int dim,
- const double *points, void *unc_void,
- const char *options, ... ) {
-/*
-* Name:
-* astPolygonId_
-
-* Purpose:
-* Create a Polygon.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "polygon.h"
-* AstPolygon *astPolygonId_( void *frame_void, int npnt,
-* int dim, const double *points, void *unc_void,
-* const char *options, ... )
-
-* Class Membership:
-* Polygon constructor.
-
-* Description:
-* This function implements the external (public) interface to the
-* astPolygon constructor function. It returns an ID value (instead
-* of a true C pointer) to external users, and must be provided
-* because astPolygon_ has a variable argument list which cannot be
-* encapsulated in a macro (where this conversion would otherwise
-* occur).
-*
-* The variable argument list also prevents this function from
-* invoking astPolygon_ directly, so it must be a re-implementation
-* of it in all respects, except for the final conversion of the
-* result to an ID value.
-
-* Parameters:
-* As for astPolygon_.
-
-* Returned Value:
-* The ID value associated with the new Polygon.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstFrame *frame; /* Pointer to Frame structure */
- AstPolygon *new; /* Pointer to new Polygon */
- AstRegion *unc; /* Pointer to Region structure */
- va_list args; /* Variable argument list */
-
- int *status; /* Get a pointer to the thread specific global data structure. */
- astGET_GLOBALS(NULL);
-
-/* Get a pointer to the inherited status value. */
- status = astGetStatusPtr;
-
-/* Check the global status. */
- if ( !astOK ) return NULL;
-
-/* Obtain a Frame pointer from the supplied ID and validate the
- pointer to ensure it identifies a valid Frame. */
- frame = astVerifyFrame( astMakePointer( frame_void ) );
-
-/* Obtain a Region pointer from the supplied "unc" ID and validate the
- pointer to ensure it identifies a valid Region . */
- unc = unc_void ? astCheckRegion( astMakePointer( unc_void ) ) : NULL;
-
-/* Initialise the Polygon, allocating memory and initialising the
- virtual function table as well if necessary. */
- new = astInitPolygon( NULL, sizeof( AstPolygon ), !class_init,
- &class_vtab, "Polygon", frame, npnt, dim,
- points, unc );
-
-/* If successful, note that the virtual function table has been
- initialised. */
- if ( astOK ) {
- class_init = 1;
-
-/* Obtain the variable argument list and pass it along with the options string
- to the astVSet method to initialise the new Polygon's attributes. */
- va_start( args, options );
- astVSet( new, options, NULL, args );
- va_end( args );
-
-/* If an error occurred, clean up by deleting the new object. */
- if ( !astOK ) new = astDelete( new );
- }
-
-/* Return an ID value for the new Polygon. */
- return astMakeId( new );
-}
-
-
-AstPolygon *astInitPolygon_( void *mem, size_t size, int init, AstPolygonVtab *vtab,
- const char *name, AstFrame *frame, int npnt,
- int dim, const double *points, AstRegion *unc, int *status ) {
-/*
-*+
-* Name:
-* astInitPolygon
-
-* Purpose:
-* Initialise a Polygon.
-
-* Type:
-* Protected function.
-
-* Synopsis:
-* #include "polygon.h"
-* AstPolygon *astInitPolygon( void *mem, size_t size, int init, AstPolygonVtab *vtab,
-* const char *name, AstFrame *frame, int npnt,
-* int dim, const double *points, AstRegion *unc )
-
-* Class Membership:
-* Polygon initialiser.
-
-* Description:
-* This function is provided for use by class implementations to initialise
-* a new Polygon object. It allocates memory (if necessary) to accommodate
-* the Polygon plus any additional data associated with the derived class.
-* It then initialises a Polygon structure at the start of this memory. If
-* the "init" flag is set, it also initialises the contents of a virtual
-* function table for a Polygon at the start of the memory passed via the
-* "vtab" parameter.
-
-* Parameters:
-* mem
-* A pointer to the memory in which the Polygon is to be initialised.
-* This must be of sufficient size to accommodate the Polygon data
-* (sizeof(Polygon)) plus any data used by the derived class. If a value
-* of NULL is given, this function will allocate the memory itself using
-* the "size" parameter to determine its size.
-* size
-* The amount of memory used by the Polygon (plus derived class data).
-* This will be used to allocate memory if a value of NULL is given for
-* the "mem" parameter. This value is also stored in the Polygon
-* structure, so a valid value must be supplied even if not required for
-* allocating memory.
-* init
-* A logical flag indicating if the Polygon's virtual function table is
-* to be initialised. If this value is non-zero, the virtual function
-* table will be initialised by this function.
-* vtab
-* Pointer to the start of the virtual function table to be associated
-* with the new Polygon.
-* name
-* Pointer to a constant null-terminated character string which contains
-* the name of the class to which the new object belongs (it is this
-* pointer value that will subsequently be returned by the astGetClass
-* method).
-* frame
-* A pointer to the Frame in which the region is defined.
-* npnt
-* The number of points in the Region.
-* dim
-* The number of elements along the second dimension of the "points"
-* array (which contains the point coordinates). This value is
-* required so that the coordinate values can be correctly
-* located if they do not entirely fill this array. The value
-* given should not be less than "npnt".
-* points
-* The address of the first element of a 2-dimensional array of
-* shape "[2][dim]" giving the physical coordinates of the
-* points. These should be stored such that the value of coordinate
-* number "coord" for point number "pnt" is found in element
-* "in[coord][pnt]".
-* unc
-* A pointer to a Region which specifies the uncertainty in the
-* supplied positions (all points in the new Polygon being
-* initialised are assumed to have the same uncertainty). A NULL
-* pointer can be supplied, in which case default uncertainties equal
-* to 1.0E-6 of the dimensions of the new Polygon's bounding box are
-* used. If an uncertainty Region is supplied, it must be either a Box,
-* a Circle or an Ellipse, and its encapsulated Frame must be related
-* to the Frame supplied for parameter "frame" (i.e. astConvert
-* should be able to find a Mapping between them). Two positions
-* the "frame" Frame are considered to be co-incident if their
-* uncertainty Regions overlap. The centre of the supplied
-* uncertainty Region is immaterial since it will be re-centred on the
-* point being tested before use. A deep copy is taken of the supplied
-* Region.
-
-* Returned Value:
-* A pointer to the new Polygon.
-
-* Notes:
-* - A null pointer will be returned if this function is invoked with the
-* global error status set, or if it should fail for any reason.
-*-
-*/
-
-/* Local Variables: */
- AstPolygon *new; /* Pointer to new Polygon */
- AstPointSet *pset; /* Pointer to PointSet holding points */
- const double *q; /* Pointer to next supplied axis value */
- double **ptr; /* Pointer to data in pset */
- double *p; /* Pointer to next PointSet axis value */
- int i; /* Axis index */
- int j; /* Point index */
- int nin; /* No. of axes */
-
-/* Check the global status. */
- if ( !astOK ) return NULL;
-
-/* If necessary, initialise the virtual function table. */
- if ( init ) astInitPolygonVtab( vtab, name );
-
-/* Initialise. */
- new = NULL;
-
-/* Check the number of axis values per position is correct. */
- nin = astGetNaxes( frame );
- if( nin != 2 ) {
- astError( AST__BADIN, "astInitPolygon(%s): The supplied %s has %d "
- "axes - polygons must have exactly 2 axes.", status, name,
- astGetClass( frame ), nin );
-
-/* If so create a PointSet and store the supplied points in it. Check
- none are bad. */
- } else {
- pset = astPointSet( npnt, 2, "", status );
- ptr = astGetPoints( pset );
- for( i = 0; i < 2 && astOK; i++ ) {
- p = ptr[ i ];
- q = points + i*dim;
- for( j = 0; j < npnt; j++ ) {
- if( (*(p++) = *(q++)) == AST__BAD ) {
- astError( AST__BADIN, "astInitPolygon(%s): One or more "
- "bad axis values supplied for the vertex "
- "number %d.", status, name, j + 1 );
- break;
- }
- }
- }
-
-/* Initialise a Region structure (the parent class) as the first component
- within the Polygon structure, allocating memory if necessary. */
- new = (AstPolygon *) astInitRegion( mem, size, 0, (AstRegionVtab *) vtab,
- name, frame, pset, unc );
- if ( astOK ) {
-
-/* Initialise the Polygon data. */
-/* ------------------------------ */
- new->lbnd[ 0 ] = AST__BAD;
- new->ubnd[ 0 ] = AST__BAD;
- new->lbnd[ 1 ] = AST__BAD;
- new->ubnd[ 1 ] = AST__BAD;
- new->simp_vertices = -INT_MAX;
- new->edges = NULL;
- new->startsat = NULL;
- new->totlen = 0.0;
- new->acw = 1;
- new->stale = 1;
-
-/* Ensure the vertices are stored such that the unnegated Polygon
- represents the inside of the polygon. */
- EnsureInside( new, status );
-
-/* If an error occurred, clean up by deleting the new Polygon. */
- if ( !astOK ) new = astDelete( new );
- }
-
-/* Free resources. */
- pset = astAnnul( pset );
-
- }
-
-/* Return a pointer to the new Polygon. */
- return new;
-}
-
-AstPolygon *astLoadPolygon_( void *mem, size_t size, AstPolygonVtab *vtab,
- const char *name, AstChannel *channel, int *status ) {
-/*
-*+
-* Name:
-* astLoadPolygon
-
-* Purpose:
-* Load a Polygon.
-
-* Type:
-* Protected function.
-
-* Synopsis:
-* #include "polygon.h"
-* AstPolygon *astLoadPolygon( void *mem, size_t size, AstPolygonVtab *vtab,
-* const char *name, AstChannel *channel )
-
-* Class Membership:
-* Polygon loader.
-
-* Description:
-* This function is provided to load a new Polygon using data read
-* from a Channel. It first loads the data used by the parent class
-* (which allocates memory if necessary) and then initialises a
-* Polygon structure in this memory, using data read from the input
-* Channel.
-*
-* If the "init" flag is set, it also initialises the contents of a
-* virtual function table for a Polygon at the start of the memory
-* passed via the "vtab" parameter.
-
-* Parameters:
-* mem
-* A pointer to the memory into which the Polygon is to be
-* loaded. This must be of sufficient size to accommodate the
-* Polygon data (sizeof(Polygon)) plus any data used by derived
-* classes. If a value of NULL is given, this function will
-* allocate the memory itself using the "size" parameter to
-* determine its size.
-* size
-* The amount of memory used by the Polygon (plus derived class
-* data). This will be used to allocate memory if a value of
-* NULL is given for the "mem" parameter. This value is also
-* stored in the Polygon structure, so a valid value must be
-* supplied even if not required for allocating memory.
-*
-* If the "vtab" parameter is NULL, the "size" value is ignored
-* and sizeof(AstPolygon) is used instead.
-* vtab
-* Pointer to the start of the virtual function table to be
-* associated with the new Polygon. If this is NULL, a pointer
-* to the (static) virtual function table for the Polygon class
-* is used instead.
-* name
-* Pointer to a constant null-terminated character string which
-* contains the name of the class to which the new object
-* belongs (it is this pointer value that will subsequently be
-* returned by the astGetClass method).
-*
-* If the "vtab" parameter is NULL, the "name" value is ignored
-* and a pointer to the string "Polygon" is used instead.
-
-* Returned Value:
-* A pointer to the new Polygon.
-
-* Notes:
-* - A null pointer will be returned if this function is invoked
-* with the global error status set, or if it should fail for any
-* reason.
-*-
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstPolygon *new; /* Pointer to the new Polygon */
- int order; /* Is the new (STC) order convention used? */
-
-/* Initialise. */
- new = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return new;
-
-/* Get a pointer to the thread specific global data structure. */
- astGET_GLOBALS(channel);
-
-/* If a NULL virtual function table has been supplied, then this is
- the first loader to be invoked for this Polygon. In this case the
- Polygon belongs to this class, so supply appropriate values to be
- passed to the parent class loader (and its parent, etc.). */
- if ( !vtab ) {
- size = sizeof( AstPolygon );
- vtab = &class_vtab;
- name = "Polygon";
-
-/* If required, initialise the virtual function table for this class. */
- if ( !class_init ) {
- astInitPolygonVtab( vtab, name );
- class_init = 1;
- }
- }
-
-/* Invoke the parent class loader to load data for all the ancestral
- classes of the current one, returning a pointer to the resulting
- partly-built Polygon. */
- new = astLoadRegion( mem, size, (AstRegionVtab *) vtab, name,
- channel );
-
- if ( astOK ) {
-
-/* Read input data. */
-/* ================ */
-/* Request the input Channel to read all the input data appropriate to
- this class into the internal "values list". */
- astReadClassData( channel, "Polygon" );
-
-/* Now read each individual data item from this list and use it to
- initialise the appropriate instance variable(s) for this class. */
-
-/* In the case of attributes, we first read the "raw" input value,
- supplying the "unset" value as the default. If a "set" value is
- obtained, we then use the appropriate (private) Set... member
- function to validate and set the value properly. */
-
- new->simp_vertices = astReadInt( channel, "simpvt", -INT_MAX );
- if ( TestSimpVertices( new, status ) ) SetSimpVertices( new, new->simp_vertices, status );
-
-/* A flag indicating what order the vertices are stored in. See the Dump
- function. */
- order = astReadInt( channel, "order", 0 );
-
-/* Initialise other class properties. */
- new->lbnd[ 0 ] = AST__BAD;
- new->ubnd[ 0 ] = AST__BAD;
- new->lbnd[ 1 ] = AST__BAD;
- new->ubnd[ 1 ] = AST__BAD;
- new->edges = NULL;
- new->startsat = NULL;
- new->totlen = 0.0;
- new->acw = 1;
- new->stale = 1;
-
-/* If the order in which the vertices were written used the old AST
- convention, negate the Polygon so that it is consistent with the
- current conevtion (based on STC). */
- if( ! order ) astNegate( new );
-
-/* Ensure the vertices are stored such that the unnegated Polygon
- represents the inside of the polygon. */
- EnsureInside( new, status );
-
-/* If an error occurred, clean up by deleting the new Polygon. */
- if ( !astOK ) new = astDelete( new );
- }
-
-/* Return the new Polygon pointer. */
- return new;
-}
-
-/* Virtual function interfaces. */
-/* ============================ */
-/* These provide the external interface to the virtual functions defined by
- this class. Each simply checks the global error status and then locates and
- executes the appropriate member function, using the function pointer stored
- in the object's virtual function table (this pointer is located using the
- astMEMBER macro defined in "object.h").
-
- Note that the member function may not be the one defined here, as it may
- have been over-ridden by a derived class. However, it should still have the
- same interface. */
-
-
-AstPolygon *astDownsize_( AstPolygon *this, double maxerr, int maxvert,
- int *status ) {
- if ( !astOK ) return NULL;
- return (**astMEMBER(this,Polygon,Downsize))( this, maxerr, maxvert, status );
-}
-
-