// Copyright (C) 1999-2017 // Smithsonian Astrophysical Observatory, Cambridge, MA, USA // For conditions of distribution and use, see copyright notice in "copyright" #include "context.h" #include "base.h" #include "fitsimage.h" #include "fvcontour.h" #include "sigbus.h" #ifdef INTERP #undef INTERP #endif #define INTERP (((Base*)parent_)->interp) static const char* methodName_[] = { "smooth", "block" }; // It is a modified version of contour code found in Fv 2.4 // Fv may be obtained from the HEASARC (High Energy Astrophysics Science // Archive Research Center) FTOOLS Web site at: // http://heasarc.gsfc.nasa.gov/ftools/fv.html // The original author is unknown. FVContour::FVContour() { parent_ =NULL; colorName_ = dupstr("green"); lineWidth_ =1; dash_ =0; dlist_[0] =8; dlist_[1] =3; method_ = BLOCK; smooth_ =4; numLevel_ =5; level_ =NULL; scale_ =NULL; } FVContour::~FVContour() { if (colorName_) delete [] colorName_; if (level_) delete [] level_; if (scale_) delete scale_; } void FVContour::create(Base* pp, FitsImage* fits, FrScale* fr, const char* cc, int ww, int dd, Method mm, int nn, int rr, const char* ll) { lcontourlevel_.deleteAll(); parent_ = pp; colorName_ = dupstr(cc); lineWidth_ = ww; dash_ = dd; method_ = mm; smooth_ = rr; numLevel_ = nn; frScale_ = *fr; level_ = dupstr(ll); if (level_ && strlen(level_)>0) { int cnt = 0; double levels[100]; string x(level_); istringstream str(x); while ((cnt<100) && (str >> levels[cnt])) cnt++; scale_ = new InverseScale(cnt, levels); } else buildScale(fits); append(fits); } void FVContour::buildScale(FitsImage* fits) { switch (frScale_.colorScaleType()) { case FrScale::LINEARSCALE: scale_ = new LinearInverseScale(numLevel_, frScale_.low(), frScale_.high()); break; case FrScale::LOGSCALE: scale_ = new LogInverseScale(numLevel_, frScale_.low(), frScale_.high(), frScale_.expo()); break; case FrScale::POWSCALE: scale_ = new PowInverseScale(numLevel_, frScale_.low(), frScale_.high(), frScale_.expo()); break; case FrScale::SQRTSCALE: scale_ = new SqrtInverseScale(numLevel_, frScale_.low(), frScale_.high()); break; case FrScale::SQUAREDSCALE: scale_ = new SquaredInverseScale(numLevel_, frScale_.low(), frScale_.high()); break; case FrScale::ASINHSCALE: scale_ = new AsinhInverseScale(numLevel_, frScale_.low(), frScale_.high()); break; case FrScale::SINHSCALE: scale_ = new SinhInverseScale(numLevel_, frScale_.low(), frScale_.high()); break; case FrScale::HISTEQUSCALE: scale_ = new HistEquInverseScale(numLevel_, frScale_.low(), frScale_.high(), frScale_.histequ(fits), HISTEQUSIZE); break; case FrScale::IISSCALE: scale_ = new IISInverseScale(numLevel_, frScale_.low(), frScale_.high(), fits->iisz()); break; } } void FVContour::update(FitsImage* fits) { lcontourlevel_.deleteAll(); switch (frScale_.clipScope()) { case FrScale::GLOBAL: break; case FrScale::LOCAL: if (scale_) delete scale_; buildScale(fits); if (level_) delete [] level_; { ostringstream str; str << *scale_ << ends; level_ = dupstr(str.str().c_str()); } break; } append(fits); } const char* FVContour::methodName() { return methodName_[method_]; } void FVContour::append(FitsImage* fits) { if (smooth_ == 1) unity(fits); else switch (method_) { case SMOOTH: nobin(fits); break; case BLOCK: bin(fits); break; } } void FVContour::unity(FitsImage* fits) { FitsBound* params = fits->getDataParams(((Base*)parent_)->currentContext->secMode()); long width = fits->width(); long height = fits->height(); // blank img long size = width*height; double* img = new double[size]; if (!img) { internalError("FVContour could not allocate enough memory"); return; } for (long ii=0; iiymin; jjymax; jj++) { for(long ii=params->xmin; iixmax; ii++) { long kk = jj*width + ii; double vv = fits->getValueDouble(kk); if (isfinite(vv)) img[kk] = vv; } } CLEARSIGBUS // do contours build(width, height, img, fits->dataToRef); // clean up delete [] img; } void FVContour::nobin(FitsImage* fits) { long width = fits->width(); long height = fits->height(); // blank img long size = width*height; double* img = new double[size]; if (!img) { internalError("FVContour could not allocate enough memory"); return; } for (long ii=0; iidataToRef); // cleanup delete kernal; delete [] img; } void FVContour::convolve(FitsImage* fits, double* kernal, double* dest, int r) { FitsBound* params = fits->getDataParams(((Base*)parent_)->currentContext->secMode()); long width = fits->width(); int rr = 2*r+1; SETSIGBUS for (long jj=params->ymin; jjymax; jj++) { for (long ii=params->xmin; iixmax; ii++) { long ir = ii-r; long irr = ii+r; long jr = jj-r; long jrr = jj+r; for (long n=jr, nn=0; n<=jrr; n++, nn++) { if (n>=params->ymin && nymax) { for (long m=ir, mm=0; m<=irr; m++, mm++) { if (m>=params->xmin && mxmax) { double vv = fits->getValueDouble(n*width+m); if (isfinite(vv)) { double kk = kernal[nn*rr+mm]; double* ptr = dest+(jj*width+ii); if (*ptr == FLT_MIN) *ptr = vv*kk; else *ptr += vv*kk; } } } } } } } CLEARSIGBUS } double* FVContour::tophat(int r) { int rr = 2*r+1; int ksz = rr*rr; double* kernal = new double[ksz]; memset(kernal, 0, ksz*sizeof(double)); double kt = 0; for (int yy=-r; yy<=r; yy++) { for (int xx=-r; xx<=r; xx++) { if ((xx*xx + yy*yy) <= r*r) { kernal[(yy+r)*rr+(xx+r)] = 1; kt++; } } } // normalize kernal for (int aa=0; aagetDataParams(((Base*)parent_)->currentContext->secMode()); long width = fits->width(); long height = fits->height(); int rr = smooth_; long w2 = (long)(width/rr); long h2 = (long)(height/rr); Matrix m = Translate((Vector(-width,-height)/2).floor()) * Scale(1./rr) * Translate((Vector(w2,h2)/2).floor()); Matrix n = m.invert(); double* mm = m.mm(); double* img = new double[w2 * h2]; { for (long jj=0; jjymin; jjymax; jj++) { for (long ii=params->xmin; iixmax; ii++) { double xx = ii*mm[0] + jj*mm[3] + mm[6]; double yy = ii*mm[1] + jj*mm[4] + mm[7]; if (xx >= 0 && xx < w2 && yy >= 0 && yy < h2) { long kk = (long(yy)*w2 + long(xx)); double v = fits->getValueDouble(jj*width + ii); if (isfinite(v)) { if (count[kk]) img[kk] += v; else img[kk] = v; count[kk]++; } } } } for (long kk=0; kkdataToRef; build(w2, h2, img, w); delete [] img; } void FVContour::build(long xdim, long ydim, double *image, Matrix& mx) { long nelem = xdim*ydim; char* usedGrid = new char[nelem]; double** rows = new double*[ydim]; for (long jj=0; jjsize(); c++) { double cntour = scale_->level(c); ContourLevel* cl =new ContourLevel(parent_, cntour, colorName_, lineWidth_, dash_, dlist_); memset(usedGrid,0,nelem); // Search outer edge long ii,jj; // Search top for (jj=0, ii=0; ii=0; ii--) if (rows[jj][ii+1]=0; jj--) if (rows[jj+1][ii]lcontour().isEmpty()) lcontourlevel_.append(cl); } delete [] usedGrid; delete [] rows; } void FVContour::trace(long xdim, long ydim, double cntr, long xCell, long yCell, int side, double** rows, char* usedGrid, Matrix& mx, ContourLevel* cl) { long ii = xCell; long jj = yCell; int origSide = side; int init = 1; int done = (ii<0 || ii>=xdim-1 || (jj<0 && jj>=ydim-1)); Contour* cc = new Contour(cl); while (!done) { int flag = 0; double a = rows[jj][ii]; double b = rows[jj][ii+1]; double c = rows[jj+1][ii+1]; double d = rows[jj+1][ii]; double X, Y; if (init) { init = 0; switch (side) { case top: X = (cntr-a) / (b-a) + ii; Y = jj; break; case right: X = ii+1; Y = (cntr-b) / (c-b) + jj; break; case bottom: X = (cntr-c) / (d-c) + ii; Y = jj+1; break; case left: X = ii; Y = (cntr-a) / (d-a) + jj; break; } } else { if (side==top) usedGrid[jj*xdim + ii] = 1; do { if (++side == none) side = top; switch (side) { case top: if (a>=cntr && cntr>b) { flag = 1; X = (cntr-a) / (b-a) + ii; Y = jj; jj--; } break; case right: if( b>=cntr && cntr>c ) { flag = 1; X = ii+1; Y = (cntr-b) / (c-b) + jj; ii++; } break; case bottom: if( c>=cntr && cntr>d ) { flag = 1; X = (cntr-d) / (c-d) + ii; Y = jj+1; jj++; } break; case left: if( d>=cntr && cntr>a ) { flag = 1; X = ii; Y = (cntr-a) / (d-a) + jj; ii--; } break; } } while (!flag); if (++side == none) side = top; if (++side == none) side = top; if (ii==xCell && jj==yCell && side==origSide) done = 1; if (ii<0 || ii>=xdim-1 || jj<0 || jj>=ydim-1) done = 1; } cc->lvertex().append(new Vertex(Vector(X+.5,Y+.5)*mx)); } if (!cc->lvertex().isEmpty()) cl->lcontour().append(cc); else delete cc; }