/*
*				refine.c
*
* Deblend sources based on their pixel lists.
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
*	This file part of:	SExtractor
*
*	Copyright:		(C) 1993,1998-2010 IAP/CNRS/UPMC
*				(C) 1994,1997 ESO
*				(C) 1995,1996 Sterrewacht Leiden
*
*	Author:			Emmanuel Bertin (IAP)
*
*	License:		GNU General Public License
*
*	SExtractor is free software: you can redistribute it and/or modify
*	it under the terms of the GNU General Public License as published by
*	the Free Software Foundation, either version 3 of the License, or
*	(at your option) any later version.
*	SExtractor 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 General Public License for more details.
*	You should have received a copy of the GNU General Public License
*	along with SExtractor. If not, see .
*
*	Last modified:		11/10/2010
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef HAVE_CONFIG_H
#include        "config.h"
#endif
#include	
#include	
#include	
#include	"define.h"
#include	"globals.h"
#include	"prefs.h"
#include	"plist.h"
#include	"extract.h"
#ifndef	RAND_MAX
#define	RAND_MAX	2147483647
#endif
#define	NSONMAX			1024	/* max. number per level */
#define	NBRANCH			16	/* starting number per branch */
static objliststruct	*objlist;
static short		*son, *ok;
/******************************** parcelout **********************************
PROTO   parcelout(objliststruct *objlistin, objliststruct *objlistout)
PURPOSE Divide a list of isophotal detections in several parts (deblending).
INPUT   input objlist,
        output objlist,
OUTPUT  RETURN_OK if success, RETURN_FATAL_ERROR otherwise (memory overflow).
NOTES   Even if the object is not deblended, the output objlist threshold is
        recomputed if a variable threshold is used.
AUTHOR  E. Bertin (IAP, Leiden & ESO)
VERSION 15/03/98
 ***/
int	parcelout(objliststruct *objlistin, objliststruct *objlistout)
  {
   objstruct		*obj;
   static objliststruct	debobjlist, debobjlist2;
   double		dthresh, dthresh0, value0;
   int			h,i,j,k,l,m,
			xn,
			nbm = NBRANCH,
			out;
  out = RETURN_OK;
  xn = prefs.deblend_nthresh;
/* ---- initialize lists of objects */
  debobjlist.obj = debobjlist2.obj =  NULL;
  debobjlist.plist = debobjlist2.plist = NULL;
  debobjlist.nobj = debobjlist2.nobj = 0;
  debobjlist.npix = debobjlist2.npix = 0;
  objlistout->thresh = debobjlist2.thresh = objlistin->thresh;
  memset(objlist, 0, (size_t)xn*sizeof(objliststruct));
  for (l=0; lnobj && out==RETURN_OK; l++)
      {
      dthresh0 = objlistin->obj[l].dthresh;
      objlistout->dthresh = debobjlist2.dthresh = dthresh0;
      if ((out = addobj(l, objlistin, &objlist[0])) == RETURN_FATAL_ERROR)
        goto exit_parcelout;
      if ((out = addobj(l, objlistin, &debobjlist2)) == RETURN_FATAL_ERROR)
        goto exit_parcelout;
      value0 = objlist[0].obj[0].fdflux*prefs.deblend_mincont;
      ok[0] = (short)1;
      for (k=1; kobj[l].fdpeak;
        if (dthresh>0.0)
          {
          if (prefs.detect_type == PHOTO)
            debobjlist.dthresh= dthresh0 + (dthresh-dthresh0) * (double)k/xn;
          else
            debobjlist.dthresh = dthresh0 * pow(dthresh/dthresh0,(double)k/xn);
          }
        else
          debobjlist.dthresh = dthresh0;
/*--------- Build tree (bottom->up) */
        if (objlist[k-1].nobj>=NSONMAX)
          {
          out = RETURN_FATAL_ERROR;
          goto exit_parcelout;
          }
        for (i=0; i=NSONMAX)
                {
                out = RETURN_FATAL_ERROR;
                goto exit_parcelout;
                }
              if (h>=nbm-1)
                if (!(son = (short *)realloc(son,
			xn*NSONMAX*(nbm+=16)*sizeof(short))))
                  {
                  out = RETURN_FATAL_ERROR;
                  goto exit_parcelout;
                  }
              son[k-1+xn*(i+NSONMAX*(h++))] = (short)m;
              ok[k+xn*m] = (short)1;
              }
          son[k-1+xn*(i+NSONMAX*h)] = (short)-1;
          }
        }
/*------- cut the right branches (top->down) */
      for (k = xn-2; k>=0; k--)
        {
        obj = objlist[k+1].obj;
        for (i=0; i value0)
              m++;
            ok[k+xn*i] &= ok[k+1+xn*j];
            }
          if (m>1)	
            {
            for (h=0; (j=(int)son[k+xn*(i+NSONMAX*h)])!=-1; h++)
              if (ok[k+1+xn*j] && obj[j].fdflux-obj[j].dthresh*obj[j].fdnpix
			> value0)
                {
                objlist[k+1].obj[j].flag |= OBJ_MERGED	/* Merge flag on */
			| ((OBJ_ISO_PB|OBJ_APERT_PB|OBJ_OVERFLOW)
			&debobjlist2.obj[0].flag);
                if ((out = addobj(j, &objlist[k+1], &debobjlist2))
			== RETURN_FATAL_ERROR)
                  goto exit_parcelout;
                }
            ok[k+xn*i] = (short)0;
            }
          }
        }
      if (ok[0])
        out = addobj(0, &debobjlist2, objlistout);
      else
        out = gatherup(&debobjlist2, objlistout);
exit_parcelout:
      free(debobjlist2.obj);
      free(debobjlist2.plist);
      for (k=0; kobj, *objout, *objt;
   pliststruct	*pixelin = objlistin->plist, *pixelout, *pixt,*pixt2;
   int		i,k,l, *n, iclst, npix, bmwidth,
		nobj = objlistin->nobj, xs,ys, x,y, out;
  out = RETURN_OK;
  objlistout->dthresh = objlistin->dthresh;
  objlistout->thresh = objlistin->thresh;
  QMALLOC(amp, float, nobj);
  QMALLOC(p, float, nobj);
  QMALLOC(n, int, nobj);
  for (i=1; ixmax - (xs=objin->xmin) + 1;
  npix = bmwidth * (objin->ymax - (ys=objin->ymin) + 1);
  if (!(bmp = (char *)calloc(1, npix*sizeof(char))))
    {
    bmp = 0;
    out = RETURN_FATAL_ERROR;
    goto exit_gatherup;
    }
  for (objt = objin+(i=1); idthresh = objlistin->dthresh;
    objt->thresh = objlistin->thresh;
/* ------------	flag pixels which are already allocated */
    for (pixt=pixelin+objin[i].firstpix; pixt>=pixelin;
	pixt=pixelin+PLIST(pixt,nextpix))
      bmp[(PLIST(pixt,x)-xs) + (PLIST(pixt,y)-ys)*bmwidth] = '\1';
    if ((n[i] = addobj(i, objlistin, objlistout)) == RETURN_FATAL_ERROR)
      {
      out = RETURN_FATAL_ERROR;
      goto exit_gatherup;
      }
    dist = objt->fdnpix/(2*PI*objt->abcor*objt->a*objt->b);
    amp[i] = dist<70.0? objt->dthresh*expf(dist) : 4.0*objt->fdpeak;
/* ------------ limitate expansion ! */
    if (amp[i]>4.0*objt->fdpeak)
      amp[i] = 4.0*objt->fdpeak;
    }
  objout = objlistout->obj;		/* DO NOT MOVE !!! */
  if (!(pixelout=(pliststruct *)realloc(objlistout->plist,
	(objlistout->npix + npix)*plistsize)))
    {
    out = RETURN_FATAL_ERROR;
    goto exit_gatherup;
    }
  objlistout->plist = pixelout;
  k = objlistout->npix;
  iclst = 0;				/* To avoid gcc -Wall warnings */
  for (pixt=pixelin+objin->firstpix; pixt>=pixelin;
	pixt=pixelin+PLIST(pixt,nextpix))
    {
    x = PLIST(pixt,x);
    y = PLIST(pixt,y);
    if (!bmp[(x-xs) + (y-ys)*bmwidth])
      {
      pixt2 = pixelout + (l=(k++*plistsize));
      memcpy(pixt2, pixt, (size_t)plistsize);
      PLIST(pixt2, nextpix) = -1;
      distmin = 1e+31;
      for (objt = objin+(i=1); imx;
        dy = y - objt->my;
        dist=0.5*(objt->cxx*dx*dx+objt->cyy*dy*dy+objt->cxy*dx*dy)/objt->abcor;
        p[i] = p[i-1] + (dist<70.0?amp[i]*expf(-dist) : 0.0);
        if (dist 1.0e-31)
        {
        drand = p[nobj-1]*rand()/RAND_MAX;
        for (i=1; inpix = k;
  if (!(objlistout->plist = (pliststruct *)realloc(pixelout,
	objlistout->npix*plistsize)))
    error (-1, "Not enough memory to update pixel list in ", "gatherup()");
exit_gatherup:
  free(bmp);
  free(amp);
  free(p);
  free(n);
  return out;
  }