8
static int Pt_in_Poly( double x, double y, int nPts, double *Pts );
10
/*---------------------------------------------------------------------------*/
11
int ffrrgn( const char *filename,
15
/* Read regions from a SAO-style region file and return the information */
16
/* in the "SAORegion" structure. If it is nonNULL, use wcs to convert the */
17
/* region coordinates to pixels. Return an error if region is in degrees */
18
/* but no WCS data is provided. */
19
/*---------------------------------------------------------------------------*/
22
char *namePtr, *paramPtr, *currLoc;
24
long allocLen, lineLen, hh, mm, dd;
25
double *coords = 0, X, Y, R, x, y, ss, xsave= 0., ysave= 0.;
26
int nParams, nCoords, negdec;
31
RgnShape *newShape, *tmpShape;
33
if( *status ) return( *status );
35
aRgn = (SAORegion *)malloc( sizeof(SAORegion) );
37
ffpmsg("Couldn't allocate memory to hold Region file contents.");
38
return(*status = MEMORY_ALLOCATION );
42
if( wcs && wcs->exists )
47
cFmt = pixel_fmt; /* set default format */
49
/* Allocate Line Buffer */
52
currLine = (char *)malloc( allocLen * sizeof(char) );
55
ffpmsg("Couldn't allocate memory to hold Region file contents.");
56
return(*status = MEMORY_ALLOCATION );
59
/* Open Region File */
61
if( (rgnFile = fopen( filename, "r" ))==NULL ) {
62
sprintf(currLine,"Could not open Region file %s.",filename);
66
return( *status = FILE_NOT_OPENED );
69
/* Read in file, line by line */
71
while( fgets(currLine,allocLen,rgnFile) != NULL ) {
73
/* Make sure we have a full line of text */
75
lineLen = strlen(currLine);
76
while( lineLen==allocLen-1 && currLine[lineLen-1]!='\n' ) {
77
currLoc = (char *)realloc( currLine, 2 * allocLen * sizeof(char) );
79
ffpmsg("Couldn't allocate memory to hold Region file contents.");
80
*status = MEMORY_ALLOCATION;
85
fgets( currLine+lineLen, allocLen+1, rgnFile );
87
lineLen += strlen(currLine+lineLen);
91
if( *currLoc == '#' ) {
93
/* Look to see if it is followed by a format statement... */
94
/* if not skip line */
97
while( *currLoc==' ' ) currLoc++;
98
if( !strncasecmp( currLoc, "format:", 7 ) ) {
100
ffpmsg("Format code encountered after reading 1 or more shapes.");
101
*status = PARSE_SYNTAX_ERR;
105
while( *currLoc==' ' ) currLoc++;
106
if( !strncasecmp( currLoc, "pixel", 5 ) ) {
108
} else if( !strncasecmp( currLoc, "degree", 6 ) ) {
110
} else if( !strncasecmp( currLoc, "hhmmss", 6 ) ) {
112
} else if( !strncasecmp( currLoc, "hms", 3 ) ) {
115
ffpmsg("Unknown format code encountered in region file.");
116
*status = PARSE_SYNTAX_ERR;
121
} else if( !strncasecmp( currLoc, "glob", 4 ) ) {
122
/* skip lines that begin with the word 'global' */
126
while( *currLoc != '\0' ) {
132
/* Search for closing parenthesis */
135
while( !done && !*status && *currLoc ) {
140
if( paramPtr ) /* Can't have two '(' in a region! */
148
if( !paramPtr ) /* Can't have a ')' without a '(' first */
156
if( !paramPtr ) /* Allow for a blank line */
168
nParams++; /* Fall through to default */
174
if( *status || !done ) {
175
ffpmsg( "Error reading Region file" );
176
*status = PARSE_SYNTAX_ERR;
180
/* Skip white space in region name */
182
while( *namePtr==' ' ) namePtr++;
184
/* Was this a blank line? Or the end of the current one */
186
if( ! *namePtr && ! paramPtr ) continue;
188
/**************************************************/
189
/* We've apparently found a region... Set it up */
190
/**************************************************/
192
if( !(aRgn->nShapes % 10) ) {
194
tmpShape = (RgnShape *)realloc( aRgn->Shapes,
196
* sizeof(RgnShape) );
198
tmpShape = (RgnShape *) malloc( 10 * sizeof(RgnShape) );
200
aRgn->Shapes = tmpShape;
202
ffpmsg( "Failed to allocate memory for Region data");
203
*status = MEMORY_ALLOCATION;
208
newShape = &aRgn->Shapes[aRgn->nShapes++];
210
newShape->shape = point_rgn;
212
/* Check for format code at beginning of the line */
214
if( !strncasecmp( namePtr, "image;", 6 ) ) {
217
} else if( !strncasecmp( namePtr, "fk4;", 4 ) ) {
220
} else if( !strncasecmp( namePtr, "fk5;", 4 ) ) {
223
} else if( !strncasecmp( namePtr, "icrs;", 5 ) ) {
226
} else if( !strncasecmp( namePtr, "fk5", 3 ) ) {
228
continue; /* supports POW region file format */
229
} else if( !strncasecmp( namePtr, "fk4", 3 ) ) {
231
continue; /* supports POW region file format */
232
} else if( !strncasecmp( namePtr, "icrs", 4 ) ) {
234
continue; /* supports POW region file format */
235
} else if( !strncasecmp( namePtr, "image", 5 ) ) {
237
continue; /* supports POW region file format */
238
} else if( !strncasecmp( namePtr, "galactic;", 9 ) ) {
239
ffpmsg( "Galactic region coordinates not supported" );
241
*status = PARSE_SYNTAX_ERR;
243
} else if( !strncasecmp( namePtr, "ecliptic;", 9 ) ) {
244
ffpmsg( "ecliptic region coordinates not supported" );
246
*status = PARSE_SYNTAX_ERR;
250
while( *namePtr==' ' ) namePtr++;
252
/* Check for the shape's sign */
254
if( *namePtr=='+' ) {
256
} else if( *namePtr=='-' ) {
261
/* Skip white space in region name */
263
while( *namePtr==' ' ) namePtr++;
264
if( *namePtr=='\0' ) {
265
ffpmsg( "Error reading Region file" );
266
*status = PARSE_SYNTAX_ERR;
269
lineLen = strlen( namePtr ) - 1;
270
while( namePtr[lineLen]==' ' ) namePtr[lineLen--] = '\0';
272
/* Now identify the region */
274
if( !strcasecmp( namePtr, "circle" ) ) {
275
newShape->shape = circle_rgn;
277
*status = PARSE_SYNTAX_ERR;
279
} else if( !strcasecmp( namePtr, "annulus" ) ) {
280
newShape->shape = annulus_rgn;
282
*status = PARSE_SYNTAX_ERR;
284
} else if( !strcasecmp( namePtr, "ellipse" ) ) {
285
newShape->shape = ellipse_rgn;
286
if( nParams < 4 || nParams > 5 )
287
*status = PARSE_SYNTAX_ERR;
288
newShape->param.gen.p[4] = 0.0;
290
} else if( !strcasecmp( namePtr, "elliptannulus" ) ) {
291
newShape->shape = elliptannulus_rgn;
292
if( !( nParams==8 || nParams==6 ) )
293
*status = PARSE_SYNTAX_ERR;
294
newShape->param.gen.p[6] = 0.0;
295
newShape->param.gen.p[7] = 0.0;
297
} else if( !strcasecmp( namePtr, "box" )
298
|| !strcasecmp( namePtr, "rotbox" ) ) {
299
newShape->shape = box_rgn;
300
if( nParams < 4 || nParams > 5 )
301
*status = PARSE_SYNTAX_ERR;
302
newShape->param.gen.p[4] = 0.0;
304
} else if( !strcasecmp( namePtr, "rectangle" )
305
|| !strcasecmp( namePtr, "rotrectangle" ) ) {
306
newShape->shape = rectangle_rgn;
307
if( nParams < 4 || nParams > 5 )
308
*status = PARSE_SYNTAX_ERR;
309
newShape->param.gen.p[4] = 0.0;
311
} else if( !strcasecmp( namePtr, "diamond" )
312
|| !strcasecmp( namePtr, "rotdiamond" )
313
|| !strcasecmp( namePtr, "rhombus" )
314
|| !strcasecmp( namePtr, "rotrhombus" ) ) {
315
newShape->shape = diamond_rgn;
316
if( nParams < 4 || nParams > 5 )
317
*status = PARSE_SYNTAX_ERR;
318
newShape->param.gen.p[4] = 0.0;
320
} else if( !strcasecmp( namePtr, "sector" )
321
|| !strcasecmp( namePtr, "pie" ) ) {
322
newShape->shape = sector_rgn;
324
*status = PARSE_SYNTAX_ERR;
326
} else if( !strcasecmp( namePtr, "point" ) ) {
327
newShape->shape = point_rgn;
329
*status = PARSE_SYNTAX_ERR;
331
} else if( !strcasecmp( namePtr, "line" ) ) {
332
newShape->shape = line_rgn;
334
*status = PARSE_SYNTAX_ERR;
336
} else if( !strcasecmp( namePtr, "polygon" ) ) {
337
newShape->shape = poly_rgn;
338
if( nParams < 6 || (nParams&1) )
339
*status = PARSE_SYNTAX_ERR;
342
ffpmsg( "Unrecognized region found in region file:" );
344
*status = PARSE_SYNTAX_ERR;
348
ffpmsg( "Wrong number of parameters found for region" );
353
/* Parse Parameter string... convert to pixels if necessary */
355
if( newShape->shape==poly_rgn ) {
356
newShape->param.poly.Pts = (double *)malloc( nParams
358
if( !newShape->param.poly.Pts ) {
360
"Could not allocate memory to hold polygon parameters" );
361
*status = MEMORY_ALLOCATION;
364
newShape->param.poly.nPts = nParams;
365
coords = newShape->param.poly.Pts;
367
coords = newShape->param.gen.p;
369
/* Parse the initial "WCS?" coordinates */
370
for( i=0; i<nCoords; i+=2 ) {
372
while( *paramPtr!=',' ) paramPtr++;
373
*(paramPtr++) = '\0';
376
while( *paramPtr!=',' && *paramPtr != '\0' ) paramPtr++;
377
*(paramPtr++) = '\0';
379
if( strchr(pX, ':' ) ) {
380
/* Read in special format & convert to decimal degrees */
384
hh = strtol(pX, &endp, 10);
385
if (endp && *endp==':') {
387
mm = strtol(pX, &endp, 10);
388
if (endp && *endp==':') {
393
X = 15. * (hh + mm/60. + ss/3600.); /* convert to degrees */
399
while( *pY==' ' ) pY++;
404
dd = strtol(pY, &endp, 10);
405
if (endp && *endp==':') {
407
mm = strtol(pY, &endp, 10);
408
if (endp && *endp==':') {
414
Y = -dd - mm/60. - ss/3600.; /* convert to degrees */
416
Y = dd + mm/60. + ss/3600.;
422
if (i==0) { /* save 1st coord. in case needed later */
427
if( cFmt!=pixel_fmt ) {
428
/* Convert to pixels */
429
if( wcs==NULL || ! wcs->exists ) {
430
ffpmsg("WCS information needed to convert region coordinates.");
431
*status = NO_WCS_KEY;
435
if( ffxypx( X, Y, wcs->xrefval, wcs->yrefval,
436
wcs->xrefpix, wcs->yrefpix,
437
wcs->xinc, wcs->yinc,
440
ffpmsg("Error converting region to pixel coordinates.");
449
/* Read in remaining parameters... */
451
for( ; i<nParams; i++ ) {
453
while( *paramPtr!=',' && *paramPtr != '\0' ) paramPtr++;
454
*(paramPtr++) = '\0';
455
coords[i] = strtod( pX, &endp );
457
if (endp && *endp=='"') {
458
/* parameter given in arcsec so convert to pixels. */
459
/* Increment first Y coordinate by this amount then calc */
460
/* the distance in pixels from the original coordinate. */
461
/* NOTE: This assumes the pixels are square!! */
463
Y = ysave + coords[i]/3600.; /* don't exceed -90 */
465
Y = ysave - coords[i]/3600.; /* don't exceed +90 */
468
if( ffxypx( X, Y, wcs->xrefval, wcs->yrefval,
469
wcs->xrefpix, wcs->yrefpix,
470
wcs->xinc, wcs->yinc,
473
ffpmsg("Error converting region to pixel coordinates.");
477
coords[i] = sqrt( pow(x-coords[0],2) + pow(y-coords[1],2) );
479
} else if (endp && *endp=='\'') {
480
/* parameter given in arcmin so convert to pixels. */
481
/* Increment first Y coordinate by this amount, then calc */
482
/* the distance in pixels from the original coordinate. */
483
/* NOTE: This assumes the pixels are square!! */
485
Y = ysave + coords[i]/60.; /* don't exceed -90 */
487
Y = ysave - coords[i]/60.; /* don't exceed +90 */
490
if( ffxypx( X, Y, wcs->xrefval, wcs->yrefval,
491
wcs->xrefpix, wcs->yrefpix,
492
wcs->xinc, wcs->yinc,
495
ffpmsg("Error converting region to pixel coordinates.");
499
coords[i] = sqrt( pow(x-coords[0],2) + pow(y-coords[1],2) );
501
} else if (endp && *endp=='d') {
502
/* parameter given in degrees so convert to pixels. */
503
/* Increment first Y coordinate by this amount, then calc */
504
/* the distance in pixels from the original coordinate. */
505
/* NOTE: This assumes the pixels are square!! */
507
Y = ysave + coords[i]; /* don't exceed -90 */
509
Y = ysave - coords[i]; /* don't exceed +90 */
512
if( ffxypx( X, Y, wcs->xrefval, wcs->yrefval,
513
wcs->xrefpix, wcs->yrefpix,
514
wcs->xinc, wcs->yinc,
517
ffpmsg("Error converting region to pixel coordinates.");
521
coords[i] = sqrt( pow(x-coords[0],2) + pow(y-coords[1],2) );
525
/* Perform some useful calculations now to speed up filter later */
527
switch( newShape->shape ) {
529
newShape->param.gen.a = coords[2] * coords[2];
532
newShape->param.gen.a = coords[2] * coords[2];
533
newShape->param.gen.b = coords[3] * coords[3];
536
while( coords[2]> 180.0 ) coords[2] -= 360.0;
537
while( coords[2]<=-180.0 ) coords[2] += 360.0;
538
while( coords[3]> 180.0 ) coords[3] -= 360.0;
539
while( coords[3]<=-180.0 ) coords[3] += 360.0;
542
newShape->param.gen.sinT = sin( myPI * (coords[4] / 180.0) );
543
newShape->param.gen.cosT = cos( myPI * (coords[4] / 180.0) );
545
case elliptannulus_rgn:
546
newShape->param.gen.a = sin( myPI * (coords[6] / 180.0) );
547
newShape->param.gen.b = cos( myPI * (coords[6] / 180.0) );
548
newShape->param.gen.sinT = sin( myPI * (coords[7] / 180.0) );
549
newShape->param.gen.cosT = cos( myPI * (coords[7] / 180.0) );
552
newShape->param.gen.sinT = sin( myPI * (coords[4] / 180.0) );
553
newShape->param.gen.cosT = cos( myPI * (coords[4] / 180.0) );
556
newShape->param.gen.sinT = sin( myPI * (coords[4] / 180.0) );
557
newShape->param.gen.cosT = cos( myPI * (coords[4] / 180.0) );
558
X = 0.5 * ( coords[2]-coords[0] );
559
Y = 0.5 * ( coords[3]-coords[1] );
560
newShape->param.gen.a = fabs( X * newShape->param.gen.cosT
561
+ Y * newShape->param.gen.sinT );
562
newShape->param.gen.b = fabs( Y * newShape->param.gen.cosT
563
- X * newShape->param.gen.sinT );
564
newShape->param.gen.p[5] = 0.5 * ( coords[2]+coords[0] );
565
newShape->param.gen.p[6] = 0.5 * ( coords[3]+coords[1] );
568
newShape->param.gen.sinT = sin( myPI * (coords[4] / 180.0) );
569
newShape->param.gen.cosT = cos( myPI * (coords[4] / 180.0) );
572
X = coords[2] - coords[0];
573
Y = coords[3] - coords[1];
574
R = sqrt( X*X + Y*Y );
575
newShape->param.gen.sinT = ( R ? Y/R : 0.0 );
576
newShape->param.gen.cosT = ( R ? X/R : 1.0 );
577
newShape->param.gen.a = R + 0.5;
582
/* Find bounding box */
583
newShape->param.poly.xmin = coords[0];
584
newShape->param.poly.xmax = coords[0];
585
newShape->param.poly.ymin = coords[1];
586
newShape->param.poly.ymax = coords[1];
587
for( i=2; i<nParams; ) {
588
if( newShape->param.poly.xmin > coords[i] ) /* Min X */
589
newShape->param.poly.xmin = coords[i];
590
if( newShape->param.poly.xmax < coords[i] ) /* Max X */
591
newShape->param.poly.xmax = coords[i];
593
if( newShape->param.poly.ymin > coords[i] ) /* Min Y */
594
newShape->param.poly.ymin = coords[i];
595
if( newShape->param.poly.ymax < coords[i] ) /* Max Y */
596
newShape->param.poly.ymax = coords[i];
602
} /* End of while( *currLoc ) */
604
if (coords)printf("%.8f %.8f %.8f %.8f %.8f\n",
605
coords[0],coords[1],coords[2],coords[3],coords[4]);
607
} /* End of if...else parse line */
608
} /* End of while( fgets(rgnFile) ) */
614
fits_free_region( aRgn );
624
/*---------------------------------------------------------------------------*/
625
int fftrgn( double X,
628
/* Test if the given point is within the region described by Rgn. X and */
629
/* Y are in pixel coordinates. */
630
/*---------------------------------------------------------------------------*/
632
double x, y, dx, dy, xprime, yprime, r;
637
Shapes = Rgn->Shapes;
639
/* if an excluded region is given first, then implicitly */
640
/* assume a previous shape that includes the entire image. */
644
for( i=0; i<Rgn->nShapes; i++, Shapes++ ) {
646
/* only need to test if */
647
/* the point is not already included and this is an include region, */
648
/* or the point is included and this is an excluded region */
650
if ( (!result && Shapes->sign) || (result && !Shapes->sign) ) {
654
switch( Shapes->shape ) {
657
/* Shift origin to center of region */
658
xprime = X - Shapes->param.gen.p[0];
659
yprime = Y - Shapes->param.gen.p[1];
661
/* Rotate point to region's orientation */
662
x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
663
y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
665
dx = 0.5 * Shapes->param.gen.p[2];
666
dy = 0.5 * Shapes->param.gen.p[3];
667
if( (x < -dx) || (x > dx) || (y < -dy) || (y > dy) )
672
/* Shift origin to center of region */
673
xprime = X - Shapes->param.gen.p[5];
674
yprime = Y - Shapes->param.gen.p[6];
676
/* Rotate point to region's orientation */
677
x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
678
y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
680
dx = Shapes->param.gen.a;
681
dy = Shapes->param.gen.b;
682
if( (x < -dx) || (x > dx) || (y < -dy) || (y > dy) )
687
/* Shift origin to center of region */
688
xprime = X - Shapes->param.gen.p[0];
689
yprime = Y - Shapes->param.gen.p[1];
691
/* Rotate point to region's orientation */
692
x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
693
y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
695
dx = 0.5 * Shapes->param.gen.p[2];
696
dy = 0.5 * Shapes->param.gen.p[3];
697
r = fabs(x/dx) + fabs(y/dy);
703
/* Shift origin to center of region */
704
x = X - Shapes->param.gen.p[0];
705
y = Y - Shapes->param.gen.p[1];
708
if ( r > Shapes->param.gen.a )
713
/* Shift origin to center of region */
714
x = X - Shapes->param.gen.p[0];
715
y = Y - Shapes->param.gen.p[1];
718
if ( r < Shapes->param.gen.a || r > Shapes->param.gen.b )
723
/* Shift origin to center of region */
724
x = X - Shapes->param.gen.p[0];
725
y = Y - Shapes->param.gen.p[1];
728
r = atan2( y, x ) * 180.0 / myPI;
729
if( Shapes->param.gen.p[2] <= Shapes->param.gen.p[3] ) {
730
if( r < Shapes->param.gen.p[2] || r > Shapes->param.gen.p[3] )
733
if( r < Shapes->param.gen.p[2] && r > Shapes->param.gen.p[3] )
740
/* Shift origin to center of region */
741
xprime = X - Shapes->param.gen.p[0];
742
yprime = Y - Shapes->param.gen.p[1];
744
/* Rotate point to region's orientation */
745
x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
746
y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
748
x /= Shapes->param.gen.p[2];
749
y /= Shapes->param.gen.p[3];
755
case elliptannulus_rgn:
756
/* Shift origin to center of region */
757
xprime = X - Shapes->param.gen.p[0];
758
yprime = Y - Shapes->param.gen.p[1];
760
/* Rotate point to outer ellipse's orientation */
761
x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
762
y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
764
x /= Shapes->param.gen.p[4];
765
y /= Shapes->param.gen.p[5];
770
/* Repeat test for inner ellipse */
771
x = xprime * Shapes->param.gen.b + yprime * Shapes->param.gen.a;
772
y = -xprime * Shapes->param.gen.a + yprime * Shapes->param.gen.b;
774
x /= Shapes->param.gen.p[2];
775
y /= Shapes->param.gen.p[3];
783
/* Shift origin to first point of line */
784
xprime = X - Shapes->param.gen.p[0];
785
yprime = Y - Shapes->param.gen.p[1];
787
/* Rotate point to line's orientation */
788
x = xprime * Shapes->param.gen.cosT + yprime * Shapes->param.gen.sinT;
789
y = -xprime * Shapes->param.gen.sinT + yprime * Shapes->param.gen.cosT;
791
if( (y < -0.5) || (y >= 0.5) || (x < -0.5)
792
|| (x >= Shapes->param.gen.a) )
797
/* Shift origin to center of region */
798
x = X - Shapes->param.gen.p[0];
799
y = Y - Shapes->param.gen.p[1];
801
if ( (x<-0.5) || (x>=0.5) || (y<-0.5) || (y>=0.5) )
806
if( X<Shapes->param.poly.xmin || X>Shapes->param.poly.xmax
807
|| Y<Shapes->param.poly.ymin || Y>Shapes->param.poly.ymax )
810
result = Pt_in_Poly( X, Y, Shapes->param.poly.nPts,
811
Shapes->param.poly.Pts );
815
if( !Shapes->sign ) result = !result;
823
/*---------------------------------------------------------------------------*/
824
void fffrgn( SAORegion *Rgn )
825
/* Free up memory allocated to hold the region data. */
826
/*---------------------------------------------------------------------------*/
830
for( i=0; i<Rgn->nShapes; i++ )
831
if( Rgn->Shapes[i].shape == poly_rgn )
832
free( Rgn->Shapes[i].param.poly.Pts );
838
/*---------------------------------------------------------------------------*/
839
static int Pt_in_Poly( double x,
843
/* Internal routine for testing whether the coordinate x,y is within the */
844
/* polygon region traced out by the array Pts. */
845
/*---------------------------------------------------------------------------*/
855
for( i=0; i<nPts; i+=2 ) {
862
if( (y>prevY && y>=nextY) || (y<prevY && y<=nextY)
863
|| (x>prevX && x>=nextX) )
866
/* Check to see if x,y lies right on the segment */
868
if( x>=prevX || x>nextX ) {
872
if( fabs(Dy)<1e-10 ) {
879
dx = prevX + ( (nextX-prevX)/(Dy) ) * dy - x;
886
/* There is an intersection! Make sure it isn't a V point. */
891
j = i+1; /* Point to Y component */
897
} while( y == Pts[j] );
899
if( (nextY-y)*(y-Pts[j]) > 0 )