File indexing completed on 2024-04-28 03:43:53

0001 /*
0002     This file is part of SEP
0003 
0004     SPDX-FileCopyrightText: 1993-2011 Emmanuel Bertin -- IAP /CNRS/UPMC
0005     SPDX-FileCopyrightText: 2014 SEP developers
0006 
0007     SPDX-License-Identifier: LGPL-3.0-or-later
0008 */
0009 
0010 #include <math.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <string.h>
0014 #include "sep.h"
0015 #include "sepcore.h"
0016 #include "overlap.h"
0017 
0018 #define FLUX_RADIUS_BUFSIZE 64
0019 
0020 #define WINPOS_NITERMAX 16      /* Maximum number of steps */
0021 #define WINPOS_NSIG     4       /* Measurement radius */
0022 #define WINPOS_STEPMIN  0.0001  /* Minimum change in position for continuing */
0023 #define WINPOS_FAC      2.0     /* Centroid offset factor (2 for a Gaussian) */
0024 
0025 /*
0026   Adding (void *) pointers is a GNU C extension, not part of standard C. 
0027   When compiling on Windows with MS VIsual C compiler need to cast the
0028   (void *) to something the size of one byte.
0029 */
0030 #if defined(_MSC_VER)
0031   #define MSVC_VOID_CAST (char *)
0032 #else
0033   #define MSVC_VOID_CAST
0034 #endif
0035 
0036 /****************************************************************************/
0037 /* conversions between ellipse representations */
0038 
0039 /* return ellipse semi-major and semi-minor axes and position angle, given
0040    representation: cxx*x^2 + cyy*y^2 + cxy*x*y = 1
0041    derived from http://mathworld.wolfram.com/Ellipse.html
0042 
0043    Input requirements:
0044    cxx*cyy - cxy*cxy/4. > 0.
0045    cxx + cyy > 0.
0046 */
0047 int sep_ellipse_axes(double cxx, double cyy, double cxy,
0048                      double *a, double *b, double *theta)
0049 {
0050   double p, q, t;
0051 
0052   p = cxx + cyy;
0053   q = cxx - cyy;
0054   t = sqrt(q*q + cxy*cxy);
0055 
0056   /* Ensure that parameters actually describe an ellipse. */
0057   if ((cxx*cyy - cxy*cxy/4. <= 0.) || (p <= 0.))
0058     return NON_ELLIPSE_PARAMS;
0059 
0060   *a = sqrt(2. / (p - t));
0061   *b = sqrt(2. / (p + t));
0062 
0063   /* theta = 0 if cxy == 0, else (1/2) acot(q/cxy) */
0064   *theta = (cxy == 0.) ? 0. : (q == 0. ? 0. : atan(cxy/q))/2.;
0065   if (cxx>cyy)
0066     *theta += PI/2.;
0067   if (*theta > PI/2.)
0068     *theta -= PI;
0069 
0070   return RETURN_OK;
0071 }
0072 
0073 void sep_ellipse_coeffs(double a, double b, double theta,
0074                         double *cxx, double *cyy, double *cxy)
0075 {
0076   double costheta, sintheta;
0077 
0078   costheta = cos(theta);
0079   sintheta = sin(theta);
0080 
0081   *cxx = costheta*costheta/(a*a) + sintheta*sintheta/(b*b);
0082   *cyy = sintheta*sintheta/(a*a) + costheta*costheta/(b*b);
0083   *cxy = 2.*costheta*sintheta * (1./(a*a) - 1./(b*b));
0084 }
0085 
0086 /*****************************************************************************/
0087 /* Helper functions for aperture functions */
0088 
0089 /* determine the extent of the box that just contains the circle with
0090  * parameters x, y, r. xmin is inclusive and xmax is exclusive.
0091  * Ensures that box is within image bound and sets a flag if it is not.
0092  */
0093 static void boxextent(double x, double y, double rx, double ry, int w, int h,
0094                       int *xmin, int *xmax, int *ymin, int *ymax,
0095                       short *flag)
0096 {
0097   *xmin = (int)(x - rx + 0.5);
0098   *xmax = (int)(x + rx + 1.4999999);
0099   *ymin = (int)(y - ry + 0.5);
0100   *ymax = (int)(y + ry + 1.4999999);
0101   if (*xmin < 0)
0102     {
0103       *xmin = 0;
0104       *flag |= SEP_APER_TRUNC;
0105     }
0106   if (*xmax > w)
0107     {
0108       *xmax = w;
0109       *flag |= SEP_APER_TRUNC;
0110     }
0111   if (*ymin < 0)
0112     {
0113       *ymin = 0;
0114       *flag |= SEP_APER_TRUNC;
0115     }
0116   if (*ymax > h)
0117     {
0118       *ymax = h;
0119       *flag |= SEP_APER_TRUNC;
0120     }
0121 }
0122 
0123 
0124 static void boxextent_ellipse(double x, double y,
0125                               double cxx, double cyy, double cxy, double r,
0126                               int w, int h,
0127                               int *xmin, int *xmax, int *ymin, int *ymax,
0128                               short *flag)
0129 {
0130   double dxlim, dylim;
0131 
0132   dxlim = cxx - cxy*cxy/(4.0*cyy);
0133   dxlim = dxlim>0.0 ? r/sqrt(dxlim) : 0.0;
0134   dylim = cyy - cxy*cxy/(4.0*cxx);
0135   dylim = dylim > 0.0 ? r/sqrt(dylim) : 0.0;
0136   boxextent(x, y, dxlim, dylim, w, h, xmin, xmax, ymin, ymax, flag);
0137 }
0138 
0139 /* determine oversampled annulus for a circle */
0140 static void oversamp_ann_circle(double r, double *r_in2, double *r_out2)
0141 {
0142    *r_in2 = r - 0.7072;
0143    *r_in2 = (*r_in2 > 0.0) ? (*r_in2)*(*r_in2) : 0.0;
0144    *r_out2 = r + 0.7072;
0145    *r_out2 = (*r_out2) * (*r_out2);
0146 }
0147 
0148 /* determine oversampled "annulus" for an ellipse */
0149 static void oversamp_ann_ellipse(double r, double b, double *r_in2,
0150                                  double *r_out2)
0151 {
0152    *r_in2 = r - 0.7072/b;
0153    *r_in2 = (*r_in2 > 0.0) ? (*r_in2)*(*r_in2) : 0.0;
0154    *r_out2 = r + 0.7072/b;
0155    *r_out2 = (*r_out2) * (*r_out2);
0156 }
0157 
0158 /*****************************************************************************/
0159 /* circular aperture */
0160 
0161 #define APER_NAME sep_sum_circle
0162 #define APER_ARGS double r
0163 #define APER_DECL double r2, r_in2, r_out2
0164 #define APER_CHECKS                             \
0165   if (r < 0.0)                                  \
0166     return ILLEGAL_APER_PARAMS
0167 #define APER_INIT                               \
0168   r2 = r*r;                                     \
0169   oversamp_ann_circle(r, &r_in2, &r_out2)
0170 #define APER_BOXEXTENT boxextent(x, y, r, r, im->w, im->h,              \
0171                                  &xmin, &xmax, &ymin, &ymax, flag)
0172 #define APER_EXACT circoverlap(dx-0.5, dy-0.5, dx+0.5, dy+0.5, r)
0173 #define APER_RPIX2 dx*dx + dy*dy
0174 #define APER_RPIX2_SUBPIX dx1*dx1 + dy2
0175 #define APER_COMPARE1 rpix2 < r_out2
0176 #define APER_COMPARE2 rpix2 > r_in2
0177 #define APER_COMPARE3 rpix2 < r2
0178 #include "aperture.i"
0179 #undef APER_NAME
0180 #undef APER_ARGS
0181 #undef APER_DECL
0182 #undef APER_CHECKS
0183 #undef APER_INIT
0184 #undef APER_BOXEXTENT
0185 #undef APER_EXACT
0186 #undef APER_RPIX2
0187 #undef APER_RPIX2_SUBPIX
0188 #undef APER_COMPARE1
0189 #undef APER_COMPARE2
0190 #undef APER_COMPARE3
0191 
0192 /*****************************************************************************/
0193 /* elliptical aperture */
0194 
0195 #define APER_NAME sep_sum_ellipse
0196 #define APER_ARGS double a, double b, double theta, double r
0197 #define APER_DECL double cxx, cyy, cxy, r2, r_in2, r_out2
0198 #define APER_CHECKS                                                     \
0199   if (!(r >= 0.0 && b >= 0.0 && a >= b &&                               \
0200         theta >= -PI/2. && theta <= PI/2.))                             \
0201     return ILLEGAL_APER_PARAMS
0202 #define APER_INIT                                               \
0203   r2 = r*r;                                                     \
0204   oversamp_ann_ellipse(r, b, &r_in2, &r_out2);                  \
0205   sep_ellipse_coeffs(a, b, theta, &cxx, &cyy, &cxy);            \
0206   a *= r;                                                       \
0207   b *= r
0208 #define APER_BOXEXTENT boxextent_ellipse(x, y, cxx, cyy, cxy, r, im->w, im->h, \
0209                                          &xmin, &xmax, &ymin, &ymax, flag)
0210 #define APER_EXACT ellipoverlap(dx-0.5, dy-0.5, dx+0.5, dy+0.5, a, b, theta)
0211 #define APER_RPIX2 cxx*dx*dx + cyy*dy*dy + cxy*dx*dy
0212 #define APER_RPIX2_SUBPIX cxx*dx1*dx1 + cyy*dy2 + cxy*dx1*dy
0213 #define APER_COMPARE1 rpix2 < r_out2
0214 #define APER_COMPARE2 rpix2 > r_in2
0215 #define APER_COMPARE3 rpix2 < r2
0216 #include "aperture.i"
0217 #undef APER_NAME
0218 #undef APER_ARGS
0219 #undef APER_DECL
0220 #undef APER_CHECKS
0221 #undef APER_INIT
0222 #undef APER_BOXEXTENT
0223 #undef APER_EXACT
0224 #undef APER_RPIX2
0225 #undef APER_RPIX2_SUBPIX
0226 #undef APER_COMPARE1
0227 #undef APER_COMPARE2
0228 #undef APER_COMPARE3
0229 
0230 /*****************************************************************************/
0231 /* circular annulus aperture */
0232 
0233 #define APER_NAME sep_sum_circann
0234 #define APER_ARGS double rin, double rout
0235 #define APER_DECL double rin2, rin_in2, rin_out2, rout2, rout_in2, rout_out2
0236 #define APER_CHECKS                             \
0237   if (!(rin >= 0.0 && rout >= rin))             \
0238     return ILLEGAL_APER_PARAMS
0239 #define APER_INIT                                       \
0240   rin2 = rin*rin;                                       \
0241   oversamp_ann_circle(rin, &rin_in2, &rin_out2);        \
0242   rout2 = rout*rout;                                    \
0243   oversamp_ann_circle(rout, &rout_in2, &rout_out2)
0244 #define APER_BOXEXTENT boxextent(x, y, rout, rout, im->w, im->h, \
0245                                  &xmin, &xmax, &ymin, &ymax, flag)
0246 #define APER_EXACT (circoverlap(dx-0.5, dy-0.5, dx+0.5, dy+0.5, rout) - \
0247                     circoverlap(dx-0.5, dy-0.5, dx+0.5, dy+0.5, rin))
0248 #define APER_RPIX2 dx*dx + dy*dy
0249 #define APER_RPIX2_SUBPIX dx1*dx1 + dy2
0250 #define APER_COMPARE1 (rpix2 < rout_out2) && (rpix2 > rin_in2)
0251 #define APER_COMPARE2 (rpix2 > rout_in2) || (rpix2 < rin_out2)
0252 #define APER_COMPARE3 (rpix2 < rout2) && (rpix2 > rin2)
0253 #include "aperture.i"
0254 #undef APER_NAME
0255 #undef APER_ARGS
0256 #undef APER_DECL
0257 #undef APER_CHECKS
0258 #undef APER_INIT
0259 #undef APER_BOXEXTENT
0260 #undef APER_EXACT
0261 #undef APER_RPIX2
0262 #undef APER_RPIX2_SUBPIX
0263 #undef APER_COMPARE1
0264 #undef APER_COMPARE2
0265 #undef APER_COMPARE3
0266 
0267 /*****************************************************************************/
0268 /* elliptical annulus aperture */
0269 
0270 #define APER_NAME sep_sum_ellipann
0271 #define APER_ARGS double a, double b, double theta, double rin, double rout
0272 #define APER_DECL                                               \
0273   double cxx, cyy, cxy;                                         \
0274   double rin2, rin_in2, rin_out2, rout2, rout_in2, rout_out2
0275 #define APER_CHECKS                                         \
0276   if (!(rin >= 0.0 && rout >= rin && b >= 0.0 && a >= b &&  \
0277         theta >= -PI/2. && theta <= PI/2.))                 \
0278     return ILLEGAL_APER_PARAMS
0279 #define APER_INIT                                               \
0280   rin2 = rin*rin;                                               \
0281   oversamp_ann_ellipse(rin, b, &rin_in2, &rin_out2);            \
0282   rout2 = rout*rout;                                            \
0283   oversamp_ann_ellipse(rout, b, &rout_in2, &rout_out2);         \
0284   sep_ellipse_coeffs(a, b, theta, &cxx, &cyy, &cxy)
0285 #define APER_BOXEXTENT boxextent_ellipse(x, y, cxx, cyy, cxy, rout, im->w, im->h, \
0286                                          &xmin, &xmax, &ymin, &ymax, flag)
0287 #define APER_EXACT                                                      \
0288   (ellipoverlap(dx-0.5, dy-0.5, dx+0.5, dy+0.5, a*rout, b*rout, theta) - \
0289    ellipoverlap(dx-0.5, dy-0.5, dx+0.5, dy+0.5, a*rin, b*rin, theta))
0290 #define APER_RPIX2 cxx*dx*dx + cyy*dy*dy + cxy*dx*dy
0291 #define APER_RPIX2_SUBPIX cxx*dx1*dx1 + cyy*dy2 + cxy*dx1*dy
0292 #define APER_COMPARE1 (rpix2 < rout_out2) && (rpix2 > rin_in2)
0293 #define APER_COMPARE2 (rpix2 > rout_in2) || (rpix2 < rin_out2)
0294 #define APER_COMPARE3 (rpix2 < rout2) && (rpix2 > rin2)
0295 #include "aperture.i"
0296 #undef APER_NAME
0297 #undef APER_ARGS
0298 #undef APER_DECL
0299 #undef APER_CHECKS
0300 #undef APER_INIT
0301 #undef APER_BOXEXTENT
0302 #undef APER_EXACT
0303 #undef APER_RPIX2
0304 #undef APER_RPIX2_SUBPIX
0305 #undef APER_COMPARE1
0306 #undef APER_COMPARE2
0307 #undef APER_COMPARE3
0308 
0309 
0310 /*****************************************************************************/
0311 /*
0312  * This is just different enough from the other aperture functions
0313  * that it doesn't quite make sense to use aperture.i.
0314  */
0315 int sep_sum_circann_multi(sep_image *im,
0316                           double x, double y, double rmax, int n, int subpix,
0317                           short inflag,
0318                           double *sum, double *sumvar, double *area,
0319                           double *maskarea, short *flag)
0320 {
0321   PIXTYPE pix, varpix;
0322   double dx, dy, dx1, dy2, offset, scale, scale2, tmp, rpix2;
0323   int ix, iy, xmin, xmax, ymin, ymax, sx, sy, status, size, esize, msize;
0324   long pos;
0325   short errisarray, errisstd;
0326   BYTE *datat, *errort, *maskt;
0327   converter convert, econvert, mconvert;
0328   double rpix, r_out, r_out2, d, prevbinmargin, nextbinmargin, step, stepdens;
0329   int j, ismasked;
0330 
0331   /* input checks */
0332   if (rmax < 0.0 || n < 1)
0333     return ILLEGAL_APER_PARAMS;
0334   if (subpix < 1)
0335     return ILLEGAL_SUBPIX;
0336 
0337   /* clear results arrays */
0338   memset(sum, 0, (size_t)(n*sizeof(double)));
0339   memset(sumvar, 0, (size_t)(n*sizeof(double)));
0340   memset(area, 0, (size_t)(n*sizeof(double)));
0341   if (im->mask)
0342     memset(maskarea, 0, (size_t)(n*sizeof(double)));
0343 
0344   /* initializations */
0345   size = esize = msize = 0;
0346   datat = maskt = NULL;
0347   errort = im->noise;
0348   *flag = 0;
0349   varpix = 0.0;
0350   scale = 1.0/subpix;
0351   scale2 = scale*scale;
0352   offset = 0.5*(scale-1.0);
0353 
0354   r_out = rmax + 1.5; /* margin for interpolation */
0355   r_out2 = r_out * r_out;
0356   step = rmax/n;
0357   stepdens = 1.0/step;
0358   prevbinmargin = 0.7072;
0359   nextbinmargin = step - 0.7072;
0360   j = 0;
0361   d = 0.;
0362   ismasked = 0;
0363   errisarray = 0;
0364   errisstd = 0;
0365 
0366   /* get data converter(s) for input array(s) */
0367   if ((status = get_converter(im->dtype, &convert, &size)))
0368     return status;
0369   if (im->mask && (status = get_converter(im->mdtype, &mconvert, &msize)))
0370     return status;
0371 
0372   /* get image noise */
0373   if (im->noise_type != SEP_NOISE_NONE)
0374     {
0375       errisstd = (im->noise_type == SEP_NOISE_STDDEV);
0376       if (im->noise)
0377         {
0378           errisarray = 1;
0379           if ((status = get_converter(im->ndtype, &econvert, &esize)))
0380             return status;
0381         }
0382       else
0383         {
0384           varpix = (errisstd)?  im->noiseval * im->noiseval: im->noiseval;
0385         }
0386     }
0387 
0388 
0389   /* get extent of box */
0390   boxextent(x, y, r_out, r_out, im->w, im->h, &xmin, &xmax, &ymin, &ymax,
0391             flag);
0392 
0393   /* loop over rows in the box */
0394   for (iy=ymin; iy<ymax; iy++)
0395     {
0396       /* set pointers to the start of this row */
0397       pos = (iy % im->h) * im->w + xmin;
0398       datat = MSVC_VOID_CAST im->data + pos*size;
0399       if (errisarray)
0400         errort = MSVC_VOID_CAST im->noise + pos*esize;
0401       if (im->mask)
0402         maskt = MSVC_VOID_CAST im->mask + pos*msize;
0403 
0404       /* loop over pixels in this row */
0405       for (ix=xmin; ix<xmax; ix++)
0406         {
0407           dx = ix - x;
0408           dy = iy - y;
0409           rpix2 = dx*dx + dy*dy;
0410           if (rpix2 < r_out2)
0411             {
0412               /* get pixel values */
0413               pix = convert(datat);
0414               if (errisarray)
0415                 {
0416                   varpix = econvert(errort);
0417                   if (errisstd)
0418                     varpix *= varpix;
0419                 }
0420               if (im->mask)
0421                 {
0422                   if (mconvert(maskt) > im->maskthresh)
0423                     {
0424                       *flag |= SEP_APER_HASMASKED;
0425                       ismasked = 1;
0426                     }
0427                   else
0428                     ismasked = 0;
0429                 }
0430 
0431               /* check if oversampling is needed (close to bin boundary?) */
0432               rpix = sqrt(rpix2);
0433               d = fmod(rpix, step);
0434               if (d < prevbinmargin || d > nextbinmargin)
0435                 {
0436                   dx += offset;
0437                   dy += offset;
0438                   for (sy=subpix; sy--; dy+=scale)
0439                     {
0440                       dx1 = dx;
0441                       dy2 = dy*dy;
0442                       for (sx=subpix; sx--; dx1+=scale)
0443                         {
0444                           j = (int)(sqrt(dx1*dx1+dy2)*stepdens);
0445                           if (j < n)
0446                             {
0447                               if (ismasked)
0448                                 maskarea[j] += scale2;
0449                               else
0450                                 {
0451                                   sum[j] += scale2*pix;
0452                                   sumvar[j] += scale2*varpix;
0453                                 }
0454                               area[j] += scale2;
0455                             }
0456                         }
0457                     }
0458                 }
0459               else
0460                 /* pixel not close to bin boundary */
0461                 {
0462                   j = (int)(rpix*stepdens);
0463                   if (j < n)
0464                     {
0465                       if (ismasked)
0466                         maskarea[j] += 1.0;
0467                       else
0468                         {
0469                           sum[j] += pix;
0470                           sumvar[j] += varpix;
0471                         }
0472                       area[j] += 1.0;
0473                     }
0474                 }
0475             } /* closes "if pixel might be within aperture" */
0476 
0477           /* increment pointers by one element */
0478           datat += size;
0479           if (errisarray)
0480             errort += esize;
0481           maskt += msize;
0482         }
0483     }
0484 
0485 
0486   /* correct for masked values */
0487   if (im->mask)
0488     {
0489       if (inflag & SEP_MASK_IGNORE)
0490         for (j=n; j--;)
0491           area[j] -= maskarea[j];
0492       else
0493         {
0494           for (j=n; j--;)
0495             {
0496               tmp = area[j] == maskarea[j]? 0.0: area[j]/(area[j]-maskarea[j]);
0497               sum[j] *= tmp;
0498               sumvar[j] *= tmp;
0499             }
0500         }
0501     }
0502 
0503   /* add poisson noise, only if gain > 0 */
0504   if (im->gain > 0.0)
0505     for (j=n; j--;)
0506       if (sum[j] > 0.0)
0507         sumvar[j] += sum[j] / im->gain;
0508 
0509   return status;
0510 }
0511 
0512 
0513 /* for use in flux_radius */
0514 static double inverse(double xmax, double *y, int n, double ytarg)
0515 {
0516   double step;
0517   int i;
0518 
0519   step = xmax/n;
0520   i = 0;
0521 
0522   /* increment i until y[i] is >= to ytarg */
0523   while (i < n && y[i] < ytarg)
0524     i++;
0525 
0526   if (i == 0)
0527     {
0528       if (ytarg <= 0. || y[0] == 0.)
0529         return 0.;
0530       return step * ytarg/y[0];
0531     }
0532   if (i == n)
0533     return xmax;
0534 
0535   /* note that y[i-1] corresponds to x=step*i. */
0536   return step * (i + (ytarg - y[i-1])/(y[i] - y[i-1]));
0537 }
0538 
0539 int sep_flux_radius(sep_image *im,
0540                     double x, double y, double rmax, int subpix, short inflag,
0541                     double *fluxtot, double *fluxfrac, int n, double *r,
0542                     short *flag)
0543 {
0544   int status;
0545   int i;
0546   double f;
0547   double sumbuf[FLUX_RADIUS_BUFSIZE] = {0.};
0548   double sumvarbuf[FLUX_RADIUS_BUFSIZE];
0549   double areabuf[FLUX_RADIUS_BUFSIZE];
0550   double maskareabuf[FLUX_RADIUS_BUFSIZE];
0551 
0552   /* measure FLUX_RADIUS_BUFSIZE annuli out to rmax. */
0553   status = sep_sum_circann_multi(im, x, y, rmax,
0554                                  FLUX_RADIUS_BUFSIZE, subpix, inflag,
0555                                  sumbuf, sumvarbuf, areabuf, maskareabuf,
0556                                  flag);
0557 
0558   /* sum up sumbuf array */
0559   for (i=1; i<FLUX_RADIUS_BUFSIZE; i++)
0560     sumbuf[i] += sumbuf[i-1];
0561 
0562   /* if given, use "total flux", else, use sum within rmax. */
0563   f = fluxtot? *fluxtot : sumbuf[FLUX_RADIUS_BUFSIZE-1];
0564 
0565   /* Use inverse to get the radii corresponding to the requested flux fracs */
0566   for (i=0; i<n; i++)
0567     r[i] = inverse(rmax, sumbuf, FLUX_RADIUS_BUFSIZE, fluxfrac[i] * f);
0568 
0569   return status;
0570 }
0571 
0572 /*****************************************************************************/
0573 /* calculate Kron radius from pixels within an ellipse. */
0574 int sep_kron_radius(sep_image *im, double x, double y,
0575                     double cxx, double cyy, double cxy, double r,
0576                     double *kronrad, short *flag)
0577 {
0578   float pix;
0579   double r1, v1, r2, area, rpix2, dx, dy;
0580   int ix, iy, xmin, xmax, ymin, ymax, status, size, msize;
0581   long pos;
0582   BYTE *datat, *maskt;
0583   converter convert, mconvert;
0584 
0585   r2 = r*r;
0586   r1 = v1 = 0.0;
0587   area = 0.0;
0588   *flag = 0;
0589   datat = maskt = NULL;
0590   size = msize = 0;
0591 
0592   /* get data converter(s) for input array(s) */
0593   if ((status = get_converter(im->dtype, &convert, &size)))
0594     return status;
0595   if (im->mask && (status = get_converter(im->mdtype, &mconvert, &msize)))
0596       return status;
0597 
0598 
0599   /* get extent of ellipse in x and y */
0600   boxextent_ellipse(x, y, cxx, cyy, cxy, r, im->w, im->h,
0601                     &xmin, &xmax, &ymin, &ymax, flag);
0602 
0603   /* loop over rows in the box */
0604   for (iy=ymin; iy<ymax; iy++)
0605     {
0606       /* set pointers to the start of this row */
0607       pos = (iy % im->h) * im->w + xmin;
0608       datat = MSVC_VOID_CAST im->data + pos*size;
0609       if (im->mask)
0610         maskt = MSVC_VOID_CAST im->mask + pos*msize;
0611 
0612       /* loop over pixels in this row */
0613       for (ix=xmin; ix<xmax; ix++)
0614         {
0615           dx = ix - x;
0616           dy = iy - y;
0617           rpix2 = cxx*dx*dx + cyy*dy*dy + cxy*dx*dy;
0618           if (rpix2 <= r2)
0619             {
0620               pix = convert(datat);
0621               if ((pix < -BIG) || (im->mask && mconvert(maskt) > im->maskthresh))
0622                 {
0623                   *flag |= SEP_APER_HASMASKED;
0624                 }
0625               else
0626                 {
0627                   r1 += sqrt(rpix2)*pix;
0628                   v1 += pix;
0629                   area++;
0630                 }
0631             }
0632 
0633           /* increment pointers by one element */
0634           datat += size;
0635           maskt += msize;
0636         }
0637     }
0638 
0639   if (area == 0)
0640     {
0641       *flag |= SEP_APER_ALLMASKED;
0642       *kronrad = 0.0;
0643     }
0644   else if (r1 <= 0.0 || v1 <= 0.0)
0645     {
0646       *flag |= SEP_APER_NONPOSITIVE;
0647       *kronrad = 0.0;
0648     }
0649   else
0650     {
0651       *kronrad = r1 / v1;
0652     }
0653 
0654   return RETURN_OK;
0655 }
0656 
0657 
0658 /* set array values within an ellipse (uc = unsigned char array) */
0659 void sep_set_ellipse(unsigned char *arr, int w, int h,
0660                      double x, double y, double cxx, double cyy, double cxy,
0661                      double r, unsigned char val)
0662 {
0663   unsigned char *arrt;
0664   int xmin, xmax, ymin, ymax, xi, yi;
0665   double r2, dx, dy, dy2;
0666   short flag; /* not actually used, but input to boxextent */
0667 
0668   flag = 0;
0669   r2 = r*r;
0670 
0671   boxextent_ellipse(x, y, cxx, cyy, cxy, r, w, h,
0672                     &xmin, &xmax, &ymin, &ymax, &flag);
0673 
0674   for (yi=ymin; yi<ymax; yi++)
0675     {
0676       arrt = arr + (yi*w + xmin);
0677       dy = yi - y;
0678       dy2 = dy*dy;
0679       for (xi=xmin; xi<xmax; xi++, arrt++)
0680         {
0681           dx = xi - x;
0682           if ((cxx*dx*dx + cyy*dy2 + cxy*dx*dy) <= r2)
0683             *arrt = val;
0684         }
0685     }
0686 }
0687 
0688 /*****************************************************************************/
0689 /*
0690  * As with `sep_sum_circann_multi`, this is different enough from the other
0691  * aperture functions that it doesn't quite make sense to use aperture.i.
0692  *
0693  * To reproduce SExtractor:
0694  * - use sig = obj.hl_radius * 2/2.35.
0695  * - use obj.posx/posy for initial position
0696  *
0697  */
0698 
0699 int sep_windowed(sep_image *im,
0700                  double x, double y, double sig, int subpix, short inflag,
0701                  double *xout, double *yout, int *niter, short *flag)
0702 {
0703   PIXTYPE pix, varpix;
0704   double dx, dy, dx1, dy2, offset, scale, scale2, tmp, dxpos, dypos, weight;
0705   double maskarea, maskweight, maskdxpos, maskdypos;
0706   double r, tv, twv, sigtv, totarea, overlap, rpix2, invtwosig2;
0707   double wpix;
0708   int i, ix, iy, xmin, xmax, ymin, ymax, sx, sy, status, size, esize, msize;
0709   long pos;
0710   short errisarray, errisstd;
0711   BYTE *datat, *errort, *maskt;
0712   converter convert, econvert, mconvert;
0713   double r2, r_in2, r_out2;
0714 
0715   /* input checks */
0716   if (sig < 0.0)
0717     return ILLEGAL_APER_PARAMS;
0718   if (subpix < 0)
0719     return ILLEGAL_SUBPIX;
0720 
0721   /* initializations */
0722   size = esize = msize = 0;
0723   tv = sigtv = 0.0;
0724   overlap = totarea = maskweight = 0.0;
0725   datat = maskt = NULL;
0726   errort = im->noise;
0727   *flag = 0;
0728   varpix = 0.0;
0729   scale = 1.0/subpix;
0730   scale2 = scale*scale;
0731   offset = 0.5*(scale-1.0);
0732   invtwosig2 = 1.0/(2.0*sig*sig);
0733   errisarray = 0;
0734   errisstd = 0;
0735 
0736   /* Integration radius */
0737   r = WINPOS_NSIG*sig;
0738 
0739   /* calculate oversampled annulus */
0740   r2 = r*r;
0741   oversamp_ann_circle(r, &r_in2, &r_out2);
0742 
0743   /* get data converter(s) for input array(s) */
0744   if ((status = get_converter(im->dtype, &convert, &size)))
0745     return status;
0746   if (im->mask && (status = get_converter(im->mdtype, &mconvert, &msize)))
0747     return status;
0748 
0749   /* get image noise */
0750   if (im->noise_type != SEP_NOISE_NONE)
0751     {
0752       errisstd = (im->noise_type == SEP_NOISE_STDDEV);
0753       if (im->noise)
0754         {
0755           errisarray = 1;
0756           if ((status = get_converter(im->ndtype, &econvert, &esize)))
0757             return status;
0758         }
0759       else
0760         {
0761           varpix = (errisstd)?  im->noiseval * im->noiseval: im->noiseval;
0762         }
0763     }
0764 
0765   /* iteration loop */
0766   for (i=0; i<WINPOS_NITERMAX; i++)
0767     {
0768 
0769       /* get extent of box */
0770       boxextent(x, y, r, r, im->w, im->h,
0771                 &xmin, &xmax, &ymin, &ymax, flag);
0772 
0773       /* TODO: initialize values */
0774       /* mx2ph
0775          my2ph
0776         esum, emxy, emx2, emy2, mx2, my2, mxy */
0777       tv = twv = sigtv = 0.0;
0778       overlap = totarea = maskarea = maskweight = 0.0;
0779       dxpos = dypos = 0.0;
0780       maskdxpos = maskdypos = 0.0;
0781 
0782       /* loop over rows in the box */
0783       for (iy=ymin; iy<ymax; iy++)
0784         {
0785           /* set pointers to the start of this row */
0786           pos = (iy % im->h) * im->w + xmin;
0787           datat = MSVC_VOID_CAST im->data + pos*size;
0788           if (errisarray)
0789             errort = MSVC_VOID_CAST im->noise + pos*esize;
0790           if (im->mask)
0791             maskt = MSVC_VOID_CAST im->mask + pos*msize;
0792 
0793           /* loop over pixels in this row */
0794           for (ix=xmin; ix<xmax; ix++)
0795             {
0796               dx = ix - x;
0797               dy = iy - y;
0798               rpix2 = dx*dx + dy*dy;
0799               if (rpix2 < r_out2)
0800                 {
0801                   if (rpix2 > r_in2)  /* might be partially in aperture */
0802                     {
0803                       if (subpix == 0)
0804                         overlap = circoverlap(dx-0.5, dy-0.5, dx+0.5, dy+0.5,
0805                                               r);
0806                       else
0807                         {
0808                           dx += offset;
0809                           dy += offset;
0810                           overlap = 0.0;
0811                           for (sy=subpix; sy--; dy+=scale)
0812                             {
0813                               dx1 = dx;
0814                               dy2 = dy*dy;
0815                               for (sx=subpix; sx--; dx1+=scale)
0816                                 if (dx1*dx1 + dy2 < r2)
0817                                   overlap += scale2;
0818                             }
0819                         }
0820                     }
0821                   else
0822                     /* definitely fully in aperture */
0823                     overlap = 1.0;
0824 
0825                   /* get pixel value and variance value */
0826                   pix = convert(datat);
0827                   if (errisarray)
0828                     {
0829                       varpix = econvert(errort);
0830                       if (errisstd)
0831                         varpix *= varpix;
0832                     }
0833 
0834                   /* offset of this pixel from center */
0835                   dx = ix - x; 
0836                   dy = iy - y;
0837 
0838                   /* weight by gaussian */
0839                   weight = exp(-rpix2*invtwosig2);
0840 
0841                   if (im->mask && (mconvert(maskt) > im->maskthresh))
0842                     {
0843                       *flag |= SEP_APER_HASMASKED;
0844                       maskarea += overlap;
0845                       maskweight += overlap * weight;
0846                       maskdxpos += overlap * weight * dx;
0847                       maskdypos += overlap * weight * dy;
0848                     }
0849                   else
0850                     {
0851                       tv += pix * overlap;
0852                       wpix = pix * overlap * weight;
0853                       twv += wpix;
0854                       dxpos += wpix * dx;
0855                       dypos += wpix * dy;
0856                     }
0857 
0858                   totarea += overlap;
0859 
0860                 } /* closes "if pixel might be within aperture" */
0861 
0862               /* increment pointers by one element */
0863               datat += size;
0864               if (errisarray)
0865                 errort += esize;
0866               maskt += msize;
0867             } /* closes loop over x */
0868         } /* closes loop over y */
0869 
0870       /* we're done looping over pixels for this iteration.
0871        * Our summary statistics are:
0872        *
0873        * tv : total value
0874        * twv : total weighted value
0875        * dxpos : weighted dx
0876        * dypos : weighted dy
0877        */
0878 
0879       /* Correct for masked values: This effectively makes it as if
0880        * the masked pixels had the value of the average unmasked value
0881        * in the aperture.
0882        */
0883       if (im->mask)
0884         {
0885           /* this option will probably not yield accurate values */
0886           if (inflag & SEP_MASK_IGNORE)
0887             totarea -= maskarea;
0888           else
0889             {
0890               tmp = tv/(totarea-maskarea); /* avg unmasked pixel value */
0891               twv += tmp * maskweight;
0892               dxpos += tmp * maskdxpos;
0893               dypos += tmp * maskdypos;
0894             }
0895         }
0896 
0897       /* update center */
0898       if (twv>0.0)
0899         {
0900           x += (dxpos /= twv) * WINPOS_FAC;
0901           y += (dypos /= twv) * WINPOS_FAC;
0902         }
0903       else
0904         break;
0905 
0906       /* Stop here if position does not change */
0907       if (dxpos*dxpos+dypos*dypos < WINPOS_STEPMIN*WINPOS_STEPMIN)
0908         break;
0909 
0910     } /* closes loop over interations */
0911 
0912   /* assign output results */
0913   *xout = x;
0914   *yout = y;
0915   *niter = i+1;
0916 
0917   return status;
0918 }