double seg2segdistsq(int *x1, int *y1, int *x2, int *y2) { double d1 = distsq(x1[0], y1[0], x1[1], y1[1], x2[0], y2[0]); double d2 = distsq(x1[0], y1[0], x1[1], y1[1], x2[1], y2[1]); double d3 = distsq(x2[0], y2[0], x2[1], y2[1], x1[0], y1[0]); double d4 = distsq(x2[0], y2[0], x2[1], y2[1], x1[1], y1[1]); return min(min(d1, d2), min(d3, d4)); }
int KDTree::GetClosestFattyCell(float *pnt, KDTreeNode **nodeOut ) { int dim = 0; // First, iterate along the path to the point, // and find the one associated with this point // on the line struct KDTreeNode *n = m_Root; for (;;) { // Is this a leaf node if (n->pntidx >= 0) { *nodeOut = n; break; } if (n->key > pnt[dim]) n = m_Root + n->leftIdx; else n = m_Root + n->rightIdx;; dim = (dim + 1) % ndim; } int idx = (int)(n-m_Root); float ndistsq = distsq( pnt, points + idx*ndim ); // Search for possible other nearest neighbors // by examining adjoining nodes whos children may // be closer CheckNeighborFattyCells(0, 0, pnt, ndistsq, nodeOut); return 0; }
int KDTree::GetClosestPoint(float *pnt, int &idx, bool approx) { int dim = 0; // First, iterate along the path to the point, // and find the one associated with this point // on the line struct KDTreeNode *n = m_Root; idx = -1; for (;;) { // Is this a leaf node if (n->pntidx >= 0) { idx = n->pntidx; break; } if (n->key > pnt[dim]) n = m_Root + n->leftIdx; else n = m_Root + n->rightIdx;; dim = (dim + 1) % ndim; } // Are we getting an approximate value? if(approx == true) return 0; float ndistsq = distsq(pnt,points+idx*ndim); // Search for possible other nearest neighbors // by examining adjoining nodes whos children may // be closer check_border_distance(0, 0, pnt, ndistsq, idx); return 0; } // end of GetClosestPoint
int KDTree::GetClosestPoints(float *pnt, multimap< float, int > &sortedPoints, float &distancesquared ) { int dim = 0; // First, iterate along the path to the point, // and find the one associated with this point // on the line struct KDTreeNode *n = m_Root; int idx = -1; for (;;) { // Is this a leaf node if (n->pntidx >= 0) { idx = n->pntidx; break; } if (n->key > pnt[dim]) n = m_Root + n->leftIdx; else n = m_Root + n->rightIdx;; dim = (dim + 1) % ndim; } float ndistsq = distsq(pnt,points+idx*ndim); sortedPoints.insert( pair< float, int >( ndistsq, idx ) ); // Search for possible other nearest neighbors // by examining adjoining nodes whos children may // be closer check_border_distance_sort(0, 0, pnt, distancesquared, sortedPoints); return 0; }
double distsq_between_radecdeg(double ra1, double dec1, double ra2, double dec2) { double xyz1[3]; double xyz2[3]; radecdeg2xyzarr(ra1, dec1, xyz1); radecdeg2xyzarr(ra2, dec2, xyz2); return distsq(xyz1, xyz2, 3); }
/** This callback gets called when we've reached a node in the Y tree and a node in the X tree (one or both may be leaves), and it's time to look at individual data points. */ static void rs_handle_result(void* vparams, kdtree_t* xtree, int xnode, kdtree_t* ytree, int ynode) { int xl, xr, yl, yr; int x, y; rs_params* p = (rs_params*)vparams; int D = ytree->ndim; double checkd2; xl = kdtree_left (xtree, xnode); xr = kdtree_right(xtree, xnode); yl = kdtree_left (ytree, ynode); yr = kdtree_right(ytree, ynode); for (y=yl; y<=yr; y++) { void* py = kdtree_get_data(ytree, y); if (p->count_in_range) { checkd2 = p->d2; } else { p->nearest_d2[y] = MIN(p->nearest_d2[y], p->node_nearest_d2[ynode]); checkd2 = p->nearest_d2[y]; } // check if we can eliminate the whole x node for this y point... if (kdtree_node_point_mindist2_exceeds(xtree, xnode, py, checkd2)) continue; for (x=xl; x<=xr; x++) { double d2; void* px; if (p->notself && (y == x)) continue; px = kdtree_get_data(xtree, x); d2 = distsq(px, py, D); if (p->count_in_range) { if (d2 < p->d2) { p->count_in_range[y]++; } } if (d2 > p->nearest_d2[y]) continue; p->nearest_d2[y] = d2; p->nearest_ind[y] = x; } } }
void convexhull() { int i,hix=-INF,loy=-INF,ix=-1; int atx,aty; double pi=2*acos(0),dir,a,best,bestd; point_t t; for(i=0;i<n;i++) if(hix<p[i].x || (hix==p[i].x && loy>p[i].y)) hix=p[i].x,loy=p[i].y,ix=i; t=p[0],p[0]=p[ix],p[ix]=t; hn=ix=0; dir=pi/2; do { atx=p[ix].x; aty=p[ix].y; h[hn++]=p[ix]; best=1e100; bestd=1e100; ix=-1; for(i=0;i<n;i++) if(p[i].x!=atx || p[i].y!=aty) { a=atan2(p[i].y-aty,p[i].x-atx); while(a+EPS<dir) a+=2*pi; if(fabs(best-a)<EPS && bestd>distsq(p[i].x,p[i].y,atx,aty)) best=a,ix=i,bestd=distsq(p[i].x,p[i].y,atx,aty); else if(fabs(best-a)>=EPS && best>a) best=a,bestd=distsq(p[i].x,p[i].y,atx,aty),ix=i; } if(ix<0) puts("error"); dir=best; } while(ix); }
void printoctreesearchsphere(const std::string& str, const double *xp, const double *yp, const double *zp, const double& search_x, const double& search_y, const double& search_z, const double& search_radius, const std::deque<int>& nbrlist) { std::ofstream octreesearch_file; octreesearch_file.open(str.c_str()); octreesearch_file<<"Number of neighbours detected are "<<nbrlist.size() <<std::endl; octreesearch_file<<"\n\nSearch point is " <<search_x<<"\t" <<search_y<<"\t" <<search_z <<std::endl; octreesearch_file<<"Search Radius is " <<search_radius <<std::endl; octreesearch_file<<"\nIn the table below POSN indicates the position of the neighbours in the XYZ arrays used while building the octree.\n"<<std::endl; octreesearch_file<<"\n-------------------------------------------------------------------- " << std::endl; octreesearch_file<<" OCTREE SEARCH NEIGHBOURS " <<std::endl; octreesearch_file<<"\n------------------------------------------------------------------" << std::endl; octreesearch_file<<"#\tPOSN\tXCD\tYCD\tZCD\t\tDISTANCE TO SEARCHPT" << std::endl; octreesearch_file<<"-------------------------------------------------------------------- " << std::endl; for (unsigned int i = 0; i < nbrlist.size(); ++i) { octreesearch_file << std::setprecision(3) << i <<"\t" << nbrlist[i] <<"\t" << xp[nbrlist[i]] <<"\t" << yp[nbrlist[i]] <<"\t" << zp[nbrlist[i]] <<"\t\t" << sqrt( distsq( xp[nbrlist[i]], yp[nbrlist[i]], zp[nbrlist[i]], search_x, search_y, search_z) )<<std::endl; }//end for octreesearch_file<<"-------------------------------------------------------------------- " << std::endl; octreesearch_file.close(); }
int KDTree::CheckNeighborFattyCells( int nodeIdx, int dim, float *pnt, float &cdistsq, KDTreeNode ** nodeOut ) { if(!nodeOut || !(*nodeOut) ) return 0; // Are we at a closer leaf node? // If so, check the distance struct KDTreeNode *node = *nodeOut; if (node->pntidx >= 0) { float dsq = distsq(pnt, points+node->pntidx*ndim); if (dsq < cdistsq) { cdistsq = dsq; *nodeOut = node; } return 0; } // The distance squared along the current dimension between the // point and the key float ndistsq = (node->key - pnt[dim])*(node->key - pnt[dim]); // If the distance squared from the key to the current value is // greater than the nearest distance, we need only look // in one direction. if (ndistsq > cdistsq) { if (node->key > pnt[dim]) CheckNeighborFattyCells(node->leftIdx, (dim + 1) % ndim, pnt, cdistsq, &node); else CheckNeighborFattyCells(node->rightIdx, (dim + 1) % ndim, pnt, cdistsq, &node); } // If the distance from the key to the current value is // less than the nearest distance, we still need to look // in both directions. else { CheckNeighborFattyCells(node->leftIdx, (dim + 1) % ndim, pnt, cdistsq, &node); CheckNeighborFattyCells(node->rightIdx, (dim + 1) % ndim, pnt, cdistsq, &node); } return 0; }
int KDTree::check_border_distance(int nodeIdx, int dim, float *pnt, float &cdistsq, int &idx) { if(nodeIdx < 0) return 0; // Are we at a closer leaf node? // If so, check the distance struct KDTreeNode *node = m_Root+nodeIdx; if (node->pntidx >= 0) { float dsq = distsq(pnt, points+node->pntidx*ndim); if (dsq < cdistsq) { cdistsq = dsq; idx = node->pntidx; } return 0; } // The distance squared along the current dimension between the // point and the key float ndistsq = (node->key - pnt[dim])*(node->key - pnt[dim]); // If the distance squared from the key to the current value is // greater than the nearest distance, we need only look // in one direction. if (ndistsq > cdistsq) { if (node->key > pnt[dim]) check_border_distance(node->leftIdx, (dim + 1) % ndim, pnt, cdistsq, idx); else check_border_distance(node->rightIdx, (dim + 1) % ndim, pnt, cdistsq, idx); } // If the distance from the key to the current value is // less than the nearest distance, we still need to look // in both directions. else { check_border_distance(node->leftIdx, (dim + 1) % ndim, pnt, cdistsq, idx); check_border_distance(node->rightIdx, (dim + 1) % ndim, pnt, cdistsq, idx); } return 0; } // end of check_border_distance
static void check_scale(quadbuilder_t* qb, pquad_t* pq) { double *sA, *sB; double s2; double Bx=0, By=0; double invscale; double ABx, ABy; Unused anbool ok; if (!(qb->check_scale_low || qb->check_scale_high)) return; sA = qb->starxyz + pq->iA * 3; sB = qb->starxyz + pq->iB * 3; // s2: squared AB dist s2 = distsq(sA, sB, 3); pq->scale_ok = TRUE; if (qb->check_scale_low && s2 < qb->quadd2_low) pq->scale_ok = FALSE; if (pq->scale_ok && qb->check_scale_high && s2 > qb->quadd2_high) pq->scale_ok = FALSE; if (!pq->scale_ok) { qb->nbadscale++; return; } star_midpoint(pq->midAB, sA, sB); pq->scale_ok = TRUE; pq->staridA = qb->starinds[pq->iA]; pq->staridB = qb->starinds[pq->iB]; ok = star_coords(sA, pq->midAB, TRUE, &pq->Ay, &pq->Ax); assert(ok); ok = star_coords(sB, pq->midAB, TRUE, &By, &Bx); assert(ok); ABx = Bx - pq->Ax; ABy = By - pq->Ay; invscale = 1.0 / (ABx*ABx + ABy*ABy); pq->costheta = (ABy + ABx) * invscale; pq->sintheta = (ABy - ABx) * invscale; //nabok++; }
void bruteforcesphere(const double *xp, const double *yp, const double *zp, int numpoints, const double& search_x, const double& search_y, const double& search_z, const double& radius, std::deque<int>& nbrlist ) { for (int i = 0; i < numpoints; ++i) { double distance_squared_to_search_pt = distsq( xp[i] , yp[i], zp[i], search_x, search_y, search_z); //Check if point lies within the sphere. Ensure that the point does not count itself as its own neighbour! if ( (distance_squared_to_search_pt < radius*radius) && (distance_squared_to_search_pt > 0) ) { nbrlist.push_back(i); } }//end for }//end function bruteforce sphere.
// ************************************************************************ // Takes a line specified by a point and slope and // returns the end points of the line segment that is inside // a specified clipping rectangle. // Assumes clip[0].x < clip[1].x and clip[0].y < clip[1].y // Assumes the line passes through the clipping rectangle. // ************************************************************************ void extend_line(Fpoint origin, // A point on the line Fpoint slope, // The slope of the line Fpoint *clip, // Two corners of clipping rectangle Fpoint *endpts) // Returns the two end points { int i; int endindex = 0; // Prepare to find up to four end points. (If the line passes // through two opposite corners of the clip rectangle, we find // each end point twice.) Fpoint end[4]; // First, deal with special cases of vertical and horizontal lines. if (slope.x == 0){ endpts[0].x = endpts[1].x = origin.x; endpts[0].y = clip[0].y; endpts[1].y = clip[1].y; return; } if (slope.y == 0){ endpts[0].y = endpts[1].y = origin.y; endpts[0].x = clip[0].x; endpts[1].x = clip[1].x; return; } // Now deal with the general case. float xcut, ycut; for (i=0; i<2; i++){ xcut = origin.x + (clip[i].y - origin.y) * slope.x / slope.y; if (xcut >= clip[0].x && xcut <= clip[1].x){ // Line crosses the y clip line between the x clip lines. end[endindex].x = xcut; end[endindex].y = clip[i].y; endindex++; } ycut = origin.y + (clip[i].x - origin.x) * slope.y / slope.x; if (ycut >= clip[0].y && ycut <= clip[1].y){ end[endindex].x = clip[i].x; end[endindex].y = ycut; endindex++; } } if (endindex == 0){ // Line does not intersect clip rectangle. msgerr_print("Internal error in extend_line()"); end[0].x = end[0].y = 0; } endpts[0] = end[0]; if (endindex <= 1){ endpts[1] = endpts[0]; }else{ // We have found more than one end point. // We will return the first one, and the one that is farthest from // that one. float t; endpts[1] = end[1]; float d = distsq(end[0], end[1]); for (i=2; i<endindex; i++){ if ( (t=distsq(end[0], end[i])) > d){ d = t; endpts[1] = end[i]; } } } return; }
int main(int argc, char** args) { int argchar; char* basename; char* outfn = NULL; index_t* index; quadfile* qf; rdlist_t* rdls; startree_t* skdt = NULL; anbool addradius = FALSE; int i; int radcolumn = -1; while ((argchar = getopt (argc, args, OPTIONS)) != -1) switch (argchar) { case 'R': addradius = TRUE; break; case 'r': outfn = optarg; break; case 'h': print_help(args[0]); exit(0); } if (!outfn || (optind == argc)) { print_help(args[0]); exit(-1); } rdls = rdlist_open_for_writing(outfn); if (!rdls) { fprintf(stderr, "Failed to open RDLS file %s for output.\n", outfn); exit(-1); } if (rdlist_write_primary_header(rdls)) { fprintf(stderr, "Failed to write RDLS header.\n"); exit(-1); } if (addradius) { radcolumn = rdlist_add_tagalong_column(rdls, fitscolumn_double_type(), 1, fitscolumn_double_type(), "QUADRADIUS", "deg"); } for (; optind<argc; optind++) { //int Nstars; int dimquads; basename = args[optind]; printf("Reading files with basename %s\n", basename); index = index_load(basename, 0, NULL); if (!index) { fprintf(stderr, "Failed to read index with base name \"%s\"\n", basename); exit(-1); } qf = index->quads; skdt = index->starkd; //Nstars = startree_N(skdt); if (rdlist_write_header(rdls)) { fprintf(stderr, "Failed to write new RDLS field header.\n"); exit(-1); } dimquads = quadfile_dimquads(qf); printf("Reading quads...\n"); for (i=0; i<qf->numquads; i++) { unsigned int stars[dimquads]; double axyz[3], bxyz[3]; double midab[3]; double radec[2]; if (!(i % 200000)) { printf("."); fflush(stdout); } quadfile_get_stars(qf, i, stars); startree_get(skdt, stars[0], axyz); startree_get(skdt, stars[1], bxyz); star_midpoint(midab, axyz, bxyz); xyzarr2radecdegarr(midab, radec); if (rdlist_write_one_radec(rdls, radec[0], radec[1])) { fprintf(stderr, "Failed to write a RA,Dec entry.\n"); exit(-1); } if (addradius) { double rad = arcsec2deg(distsq2arcsec(distsq(midab, axyz, 3))); if (rdlist_write_tagalong_column(rdls, radcolumn, i, 1, &rad, 0)) { fprintf(stderr, "Failed to write quad radius.\n"); exit(-1); } } } printf("\n"); index_close(index); if (rdlist_fix_header(rdls)) { fprintf(stderr, "Failed to fix RDLS field header.\n"); exit(-1); } rdlist_next_field(rdls); } if (rdlist_fix_primary_header(rdls) || rdlist_close(rdls)) { fprintf(stderr, "Failed to close RDLS file.\n"); exit(-1); } return 0; }
int main(int argc, char** args) { int c; char* xylsfn = NULL; char* wcsfn = NULL; char* rdlsfn = NULL; xylist_t* xyls = NULL; rdlist_t* rdls = NULL; sip_t sip; int i, j; int W, H; //double xyzcenter[3]; //double fieldrad2; double pixeljitter = 1.0; int loglvl = LOG_MSG; double wcsscale; char* bgfn = NULL; //double nsigma = 3.0; fits_use_error_system(); while ((c = getopt(argc, args, OPTIONS)) != -1) { switch (c) { case 'I': bgfn = optarg; break; case 'j': pixeljitter = atof(optarg); break; case 'h': print_help(args[0]); exit(0); case 'r': rdlsfn = optarg; break; case 'x': xylsfn = optarg; break; case 'w': wcsfn = optarg; break; case 'v': loglvl++; break; } } if (optind != argc) { print_help(args[0]); exit(-1); } if (!xylsfn || !wcsfn || !rdlsfn) { print_help(args[0]); exit(-1); } log_init(loglvl); // read WCS. logmsg("Trying to parse SIP header from %s...\n", wcsfn); if (!sip_read_header_file(wcsfn, &sip)) { logmsg("Failed to parse SIP header from %s.\n", wcsfn); } // image W, H W = sip.wcstan.imagew; H = sip.wcstan.imageh; if ((W == 0.0) || (H == 0.0)) { logmsg("WCS file %s didn't contain IMAGEW and IMAGEH headers.\n", wcsfn); // FIXME - use bounds of xylist? exit(-1); } wcsscale = sip_pixel_scale(&sip); logmsg("WCS scale: %g arcsec/pixel\n", wcsscale); // read XYLS. xyls = xylist_open(xylsfn); if (!xyls) { logmsg("Failed to read an xylist from file %s.\n", xylsfn); exit(-1); } // read RDLS. rdls = rdlist_open(rdlsfn); if (!rdls) { logmsg("Failed to read an rdlist from file %s.\n", rdlsfn); exit(-1); } // Find field center and radius. /* sip_pixelxy2xyzarr(&sip, W/2, H/2, xyzcenter); fieldrad2 = arcsec2distsq(sip_pixel_scale(&sip) * hypot(W/2, H/2)); */ { // (x,y) positions of field stars. double* fieldpix; int Nfield; double* indexpix; starxy_t* xy; rd_t* rd; int Nindex; xy = xylist_read_field(xyls, NULL); if (!xy) { logmsg("Failed to read xyls entries.\n"); exit(-1); } Nfield = starxy_n(xy); fieldpix = starxy_to_xy_array(xy, NULL); logmsg("Found %i field objects\n", Nfield); // Project RDLS into pixel space. rd = rdlist_read_field(rdls, NULL); if (!rd) { logmsg("Failed to read rdls entries.\n"); exit(-1); } Nindex = rd_n(rd); logmsg("Found %i indx objects\n", Nindex); indexpix = malloc(2 * Nindex * sizeof(double)); for (i=0; i<Nindex; i++) { anbool ok; double ra = rd_getra(rd, i); double dec = rd_getdec(rd, i); ok = sip_radec2pixelxy(&sip, ra, dec, indexpix + i*2, indexpix + i*2 + 1); assert(ok); } logmsg("CRPIX is (%g,%g)\n", sip.wcstan.crpix[0], sip.wcstan.crpix[1]); /* // ?? // Look for index-field pairs that are (a) close together; and (b) close to CRPIX. // Split the image into 3x3, 5x5 or so, and in each, look for a // (small) rotation and log(scale), then (bigger) shift, using histogram // cross-correlation. // Are the rotations and scales really going to be big enough that this // is required, or can we get away with doing shift first, then fine-tuning // rotation and scale? { // NxN blocks int NB = 3; int b; // HACK - use histogram2d machinery to split image into blocks. histogram2d* blockhist = histogram2d_new_nbins(0, W, NB, 0, H, NB); int* fieldi = malloc(Nfield * sizeof(int)); int* indexi = malloc(Nindex * sizeof(int)); // rotation bins int NR = 100; // scale bins (ie, log(radius) bins) double minrad = 1.0; double maxrad = 200.0; int NS = 100; histogram2d* rsfield = histogram2d_new_nbins(-M_PI, M_PI, NR, log(minrad), log(maxrad), NS); histogram2d* rsindex = histogram2d_new_nbins(-M_PI, M_PI, NR, log(minrad), log(maxrad), NS); histogram2d_set_y_edges(rsfield, HIST2D_DISCARD); histogram2d_set_y_edges(rsindex, HIST2D_DISCARD); for (b=0; b<(NB*NB); b++) { int bin; int NF, NI; double dx, dy; NF = NI = 0; for (i=0; i<Nfield; i++) { bin = histogram2d_add(blockhist, fieldpix[2*i], fieldpix[2*i+1]); if (bin != b) continue; fieldi[NF] = i; NF++; } for (i=0; i<Nindex; i++) { bin = histogram2d_add(blockhist, indexpix[2*i], indexpix[2*i+1]); if (bin != b) continue; indexi[NI] = i; NI++; } logmsg("bin %i has %i field and %i index stars.\n", b, NF, NI); logmsg("histogramming field rotation/scale\n"); for (i=0; i<NF; i++) { for (j=0; j<i; j++) { dx = fieldpix[2*fieldi[i]] - fieldpix[2*fieldi[j]]; dy = fieldpix[2*fieldi[i]+1] - fieldpix[2*fieldi[j]+1]; histogram2d_add(rsfield, atan2(dy, dx), log(sqrt(dx*dx + dy*dy))); } } logmsg("histogramming index rotation/scale\n"); for (i=0; i<NI; i++) { for (j=0; j<i; j++) { dx = indexpix[2*indexi[i]] - fieldpix[2*indexi[j]]; dy = indexpix[2*indexi[i]+1] - fieldpix[2*indexi[j]+1]; histogram2d_add(rsindex, atan2(dy, dx), log(sqrt(dx*dx + dy*dy))); } } } histogram2d_free(rsfield); histogram2d_free(rsindex); free(fieldi); free(indexi); histogram2d_free(blockhist); } */ { double* fieldsigma2s = malloc(Nfield * sizeof(double)); int besti; int* theta; double logodds; double Q2, R2; double qc[2]; double gamma; // HACK -- quad radius-squared Q2 = square(100.0); qc[0] = sip.wcstan.crpix[0]; qc[1] = sip.wcstan.crpix[1]; // HACK -- variance growth rate wrt radius. gamma = 1.0; for (i=0; i<Nfield; i++) { R2 = distsq(qc, fieldpix + 2*i, 2); fieldsigma2s[i] = square(pixeljitter) * (1.0 + gamma * R2/Q2); } logodds = verify_star_lists(indexpix, Nindex, fieldpix, fieldsigma2s, Nfield, W*H, 0.25, log(1e-100), log(1e100), &besti, NULL, &theta, NULL, NULL); logmsg("Logodds: %g\n", logodds); if (bgfn) { plot_args_t pargs; plotimage_t* img; cairo_t* cairo; char outfn[32]; j = 0; plotstuff_init(&pargs); pargs.outformat = PLOTSTUFF_FORMAT_PNG; sprintf(outfn, "tweak-%03i.png", j); pargs.outfn = outfn; img = plotstuff_get_config(&pargs, "image"); //img->format = PLOTSTUFF_FORMAT_JPG; // guess plot_image_set_filename(img, bgfn); plot_image_setsize(&pargs, img); plotstuff_run_command(&pargs, "image"); cairo = pargs.cairo; // red circles around every field star. cairo_set_color(cairo, "red"); for (i=0; i<Nfield; i++) { cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_CIRCLE, fieldpix[2*i+0], fieldpix[2*i+1], 2.0 * sqrt(fieldsigma2s[i])); cairo_stroke(cairo); } // green crosshairs at every index star. cairo_set_color(cairo, "green"); for (i=0; i<Nindex; i++) { cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_XCROSSHAIR, indexpix[2*i+0], indexpix[2*i+1], 3); cairo_stroke(cairo); } // thick white circles for corresponding field stars. cairo_set_line_width(cairo, 2); for (i=0; i<Nfield; i++) { if (theta[i] < 0) continue; cairo_set_color(cairo, "white"); cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_CIRCLE, fieldpix[2*i+0], fieldpix[2*i+1], 2.0 * sqrt(fieldsigma2s[i])); cairo_stroke(cairo); // thick cyan crosshairs for corresponding index stars. cairo_set_color(cairo, "cyan"); cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_XCROSSHAIR, indexpix[2*theta[i]+0], indexpix[2*theta[i]+1], 3); cairo_stroke(cairo); } plotstuff_output(&pargs); } free(theta); free(fieldsigma2s); } free(fieldpix); free(indexpix); } if (xylist_close(xyls)) { logmsg("Failed to close XYLS file.\n"); } return 0; }
int main(int argc, char** args) { int c; char* xylsfn = NULL; char* wcsfn = NULL; char* rdlsfn = NULL; char* plotfn = NULL; xylist_t* xyls = NULL; rdlist_t* rdls = NULL; sip_t sip; int i; int W, H; double pixeljitter = 1.0; int loglvl = LOG_MSG; double wcsscale; fits_use_error_system(); while ((c = getopt(argc, args, OPTIONS)) != -1) { switch (c) { case 'p': plotfn = optarg; break; case 'j': pixeljitter = atof(optarg); break; case 'h': print_help(args[0]); exit(0); case 'r': rdlsfn = optarg; break; case 'x': xylsfn = optarg; break; case 'w': wcsfn = optarg; break; case 'v': loglvl++; break; } } if (optind != argc) { print_help(args[0]); exit(-1); } if (!xylsfn || !wcsfn || !rdlsfn) { print_help(args[0]); exit(-1); } log_init(loglvl); // read WCS. logmsg("Trying to parse SIP header from %s...\n", wcsfn); if (!sip_read_header_file(wcsfn, &sip)) { logmsg("Failed to parse SIP header from %s.\n", wcsfn); } // image W, H W = sip.wcstan.imagew; H = sip.wcstan.imageh; if ((W == 0.0) || (H == 0.0)) { logmsg("WCS file %s didn't contain IMAGEW and IMAGEH headers.\n", wcsfn); // FIXME - use bounds of xylist? exit(-1); } wcsscale = sip_pixel_scale(&sip); logmsg("WCS scale: %g arcsec/pixel\n", wcsscale); // read XYLS. xyls = xylist_open(xylsfn); if (!xyls) { logmsg("Failed to read an xylist from file %s.\n", xylsfn); exit(-1); } // read RDLS. rdls = rdlist_open(rdlsfn); if (!rdls) { logmsg("Failed to read an rdlist from file %s.\n", rdlsfn); exit(-1); } { // (x,y) positions of field stars. double* fieldpix; int Nfield; double* indexpix; starxy_t* xy; rd_t* rd; int Nindex; xy = xylist_read_field(xyls, NULL); if (!xy) { logmsg("Failed to read xyls entries.\n"); exit(-1); } Nfield = starxy_n(xy); fieldpix = starxy_to_xy_array(xy, NULL); logmsg("Found %i field objects\n", Nfield); // Project RDLS into pixel space. rd = rdlist_read_field(rdls, NULL); if (!rd) { logmsg("Failed to read rdls entries.\n"); exit(-1); } Nindex = rd_n(rd); logmsg("Found %i indx objects\n", Nindex); indexpix = malloc(2 * Nindex * sizeof(double)); for (i=0; i<Nindex; i++) { anbool ok; double ra = rd_getra(rd, i); double dec = rd_getdec(rd, i); ok = sip_radec2pixelxy(&sip, ra, dec, indexpix + i*2, indexpix + i*2 + 1); assert(ok); } logmsg("CRPIX is (%g,%g)\n", sip.wcstan.crpix[0], sip.wcstan.crpix[1]); { double* fieldsigma2s = malloc(Nfield * sizeof(double)); int besti; int* theta; double logodds; double Q2, R2; double qc[2]; double gamma; // HACK -- quad radius-squared Q2 = square(100.0); qc[0] = sip.wcstan.crpix[0]; qc[1] = sip.wcstan.crpix[1]; // HACK -- variance growth rate wrt radius. gamma = 1.0; for (i=0; i<Nfield; i++) { R2 = distsq(qc, fieldpix + 2*i, 2); fieldsigma2s[i] = square(pixeljitter) * (1.0 + gamma * R2/Q2); } logodds = verify_star_lists(indexpix, Nindex, fieldpix, fieldsigma2s, Nfield, W*H, 0.25, log(1e-100), log(1e100), &besti, NULL, &theta, NULL); logmsg("Logodds: %g\n", logodds); if (TRUE) { for (i=0; i<Nfield; i++) { if (theta[i] < 0) continue; printf("%g %g %g %g\n", fieldpix[2*i+0], fieldpix[2*i+1], rd_getra(rd, theta[i]), rd_getdec(rd, theta[i])); } } if (plotfn) { plot_args_t pargs; plotimage_t* img; cairo_t* cairo; plotstuff_init(&pargs); pargs.outformat = PLOTSTUFF_FORMAT_PNG; pargs.outfn = plotfn; img = plotstuff_get_config(&pargs, "image"); img->format = PLOTSTUFF_FORMAT_JPG; plot_image_set_filename(img, "1.jpg"); plot_image_setsize(&pargs, img); plotstuff_run_command(&pargs, "image"); cairo = pargs.cairo; // red circles around every field star. cairo_set_color(cairo, "red"); for (i=0; i<Nfield; i++) { cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_CIRCLE, fieldpix[2*i+0], fieldpix[2*i+1], 2.0 * sqrt(fieldsigma2s[i])); cairo_stroke(cairo); } // green crosshairs at every index star. cairo_set_color(cairo, "green"); for (i=0; i<Nindex; i++) { cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_XCROSSHAIR, indexpix[2*i+0], indexpix[2*i+1], 3); cairo_stroke(cairo); } // thick white circles for corresponding field stars. cairo_set_line_width(cairo, 2); for (i=0; i<Nfield; i++) { if (theta[i] < 0) continue; cairo_set_color(cairo, "white"); cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_CIRCLE, fieldpix[2*i+0], fieldpix[2*i+1], 2.0 * sqrt(fieldsigma2s[i])); cairo_stroke(cairo); // thick cyan crosshairs for corresponding index stars. cairo_set_color(cairo, "cyan"); cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_XCROSSHAIR, indexpix[2*theta[i]+0], indexpix[2*theta[i]+1], 3); cairo_stroke(cairo); } plotstuff_output(&pargs); } free(theta); free(fieldsigma2s); } free(fieldpix); free(indexpix); } if (xylist_close(xyls)) { logmsg("Failed to close XYLS file.\n"); } return 0; }
int main(int argc, char *argv[]) { int argchar; char* progname = argv[0]; sl* infns = sl_new(16); char* outfnpat = NULL; char* racol = "RA"; char* deccol = "DEC"; char* tempdir = "/tmp"; anbool gzip = FALSE; sl* cols = sl_new(16); int loglvl = LOG_MSG; int nside = 1; double margin = 0.0; int NHP; double md; char* backref = NULL; fitstable_t* intable; fitstable_t** outtables; char** myargs; int nmyargs; int i; while ((argchar = getopt (argc, argv, OPTIONS)) != -1) switch (argchar) { case 'b': backref = optarg; break; case 't': tempdir = optarg; break; case 'c': sl_append(cols, optarg); break; case 'g': gzip = TRUE; break; case 'o': outfnpat = optarg; break; case 'r': racol = optarg; break; case 'd': deccol = optarg; break; case 'n': nside = atoi(optarg); break; case 'm': margin = atof(optarg); break; case 'v': loglvl++; break; case '?': fprintf(stderr, "Unknown option `-%c'.\n", optopt); case 'h': printHelp(progname); return 0; default: return -1; } if (sl_size(cols) == 0) { sl_free2(cols); cols = NULL; } nmyargs = argc - optind; myargs = argv + optind; for (i=0; i<nmyargs; i++) sl_append(infns, myargs[i]); if (!sl_size(infns)) { printHelp(progname); printf("Need input filenames!\n"); exit(-1); } log_init(loglvl); fits_use_error_system(); NHP = 12 * nside * nside; logmsg("%i output healpixes\n", NHP); outtables = calloc(NHP, sizeof(fitstable_t*)); assert(outtables); md = deg2dist(margin); /** About the mincaps/maxcaps: These have a center and radius-squared, describing the region inside a small circle on the sphere. The "mincaps" describe the regions that are definitely owned by a single healpix -- ie, more than MARGIN distance from any edge. That is, the mincap is the small circle centered at (0.5, 0.5) in the healpix and with radius = the distance to the closest healpix boundary, MINUS the margin distance. Below, we first check whether a new star is within the "mincap" of any healpix. If so, we stick it in that healpix and continue. Otherwise, we check all the "maxcaps" -- these are the healpixes it could *possibly* be in. We then refine with healpix_within_range_of_xyz. The maxcap distance is the distance to the furthest boundary point, PLUS the margin distance. */ cap_t* mincaps = malloc(NHP * sizeof(cap_t)); cap_t* maxcaps = malloc(NHP * sizeof(cap_t)); for (i=0; i<NHP; i++) { // center double r2; double xyz[3]; double* cxyz; double step = 1e-3; double v; double r2b, r2a; cxyz = mincaps[i].xyz; healpix_to_xyzarr(i, nside, 0.5, 0.5, mincaps[i].xyz); memcpy(maxcaps[i].xyz, cxyz, 3 * sizeof(double)); logverb("Center of HP %i: (%.3f, %.3f, %.3f)\n", i, cxyz[0], cxyz[1], cxyz[2]); // radius-squared: // max is the easy one: max of the four corners (I assume) r2 = 0.0; healpix_to_xyzarr(i, nside, 0.0, 0.0, xyz); logverb(" HP %i corner 1: (%.3f, %.3f, %.3f), distsq %.3f\n", i, xyz[0], xyz[1], xyz[2], distsq(xyz, cxyz, 3)); r2 = MAX(r2, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, 1.0, 0.0, xyz); logverb(" HP %i corner 1: (%.3f, %.3f, %.3f), distsq %.3f\n", i, xyz[0], xyz[1], xyz[2], distsq(xyz, cxyz, 3)); r2 = MAX(r2, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, 0.0, 1.0, xyz); logverb(" HP %i corner 1: (%.3f, %.3f, %.3f), distsq %.3f\n", i, xyz[0], xyz[1], xyz[2], distsq(xyz, cxyz, 3)); r2 = MAX(r2, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, 1.0, 1.0, xyz); logverb(" HP %i corner 1: (%.3f, %.3f, %.3f), distsq %.3f\n", i, xyz[0], xyz[1], xyz[2], distsq(xyz, cxyz, 3)); r2 = MAX(r2, distsq(xyz, cxyz, 3)); logverb(" max distsq: %.3f\n", r2); logverb(" margin dist: %.3f\n", md); maxcaps[i].r2 = square(sqrt(r2) + md); logverb(" max cap distsq: %.3f\n", maxcaps[i].r2); r2a = r2; r2 = 1.0; r2b = 0.0; for (v=0; v<=1.0; v+=step) { healpix_to_xyzarr(i, nside, 0.0, v, xyz); r2 = MIN(r2, distsq(xyz, cxyz, 3)); r2b = MAX(r2b, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, 1.0, v, xyz); r2 = MIN(r2, distsq(xyz, cxyz, 3)); r2b = MAX(r2b, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, v, 0.0, xyz); r2 = MIN(r2, distsq(xyz, cxyz, 3)); r2b = MAX(r2b, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, v, 1.0, xyz); r2 = MIN(r2, distsq(xyz, cxyz, 3)); r2b = MAX(r2b, distsq(xyz, cxyz, 3)); } mincaps[i].r2 = square(MAX(0, sqrt(r2) - md)); logverb("\nhealpix %i: min rad %g\n", i, sqrt(r2)); logverb("healpix %i: max rad %g\n", i, sqrt(r2a)); logverb("healpix %i: max rad(b) %g\n", i, sqrt(r2b)); assert(r2a >= r2b); } if (backref) { fitstable_t* tab = fitstable_open_for_writing(backref); int maxlen = 0; char* buf; for (i=0; i<sl_size(infns); i++) { char* infn = sl_get(infns, i); maxlen = MAX(maxlen, strlen(infn)); } fitstable_add_write_column_array(tab, fitscolumn_char_type(), maxlen, "filename", NULL); fitstable_add_write_column(tab, fitscolumn_i16_type(), "index", NULL); if (fitstable_write_primary_header(tab) || fitstable_write_header(tab)) { ERROR("Failed to write header of backref table \"%s\"", backref); exit(-1); } buf = malloc(maxlen+1); assert(buf); for (i=0; i<sl_size(infns); i++) { char* infn = sl_get(infns, i); int16_t ind; memset(buf, 0, maxlen); strcpy(buf, infn); ind = i; if (fitstable_write_row(tab, buf, &ind)) { ERROR("Failed to write row %i of backref table: %s = %i", i, buf, ind); exit(-1); } } if (fitstable_fix_header(tab) || fitstable_close(tab)) { ERROR("Failed to fix header & close backref table"); exit(-1); } logmsg("Wrote backref table %s\n", backref); free(buf); } for (i=0; i<sl_size(infns); i++) { char* infn = sl_get(infns, i); char* originfn = infn; int r, NR; tfits_type any, dubl; il* hps = NULL; bread_t* rowbuf; int R; char* tempfn = NULL; char* padrowdata = NULL; int ii; logmsg("Reading input \"%s\"...\n", infn); if (gzip) { char* cmd; int rtn; tempfn = create_temp_file("hpsplit", tempdir); asprintf_safe(&cmd, "gunzip -cd %s > %s", infn, tempfn); logmsg("Running: \"%s\"\n", cmd); rtn = run_command_get_outputs(cmd, NULL, NULL); if (rtn) { ERROR("Failed to run command: \"%s\"", cmd); exit(-1); } free(cmd); infn = tempfn; } intable = fitstable_open(infn); if (!intable) { ERROR("Couldn't read catalog %s", infn); exit(-1); } NR = fitstable_nrows(intable); logmsg("Got %i rows\n", NR); any = fitscolumn_any_type(); dubl = fitscolumn_double_type(); fitstable_add_read_column_struct(intable, dubl, 1, 0, any, racol, TRUE); fitstable_add_read_column_struct(intable, dubl, 1, sizeof(double), any, deccol, TRUE); fitstable_use_buffered_reading(intable, 2*sizeof(double), 1000); R = fitstable_row_size(intable); rowbuf = buffered_read_new(R, 1000, NR, refill_rowbuffer, intable); if (fitstable_read_extension(intable, 1)) { ERROR("Failed to find RA and DEC columns (called \"%s\" and \"%s\" in the FITS file)", racol, deccol); exit(-1); } for (r=0; r<NR; r++) { int hp = -1; double ra, dec; int j; double* rd; void* rowdata; void* rdata; if (r && ((r % 100000) == 0)) { logmsg("Reading row %i of %i\n", r, NR); } //printf("reading RA,Dec for row %i\n", r); rd = fitstable_next_struct(intable); ra = rd[0]; dec = rd[1]; logverb("row %i: ra,dec %g,%g\n", r, ra, dec); if (margin == 0) { hp = radecdegtohealpix(ra, dec, nside); logverb(" --> healpix %i\n", hp); } else { double xyz[3]; anbool gotit = FALSE; double d2; if (!hps) hps = il_new(4); radecdeg2xyzarr(ra, dec, xyz); for (j=0; j<NHP; j++) { d2 = distsq(xyz, mincaps[j].xyz, 3); if (d2 <= mincaps[j].r2) { logverb(" -> in mincap %i (dist %g vs %g)\n", j, sqrt(d2), sqrt(mincaps[j].r2)); il_append(hps, j); gotit = TRUE; break; } } if (!gotit) { for (j=0; j<NHP; j++) { d2 = distsq(xyz, maxcaps[j].xyz, 3); if (d2 <= maxcaps[j].r2) { logverb(" -> in maxcap %i (dist %g vs %g)\n", j, sqrt(d2), sqrt(maxcaps[j].r2)); if (healpix_within_range_of_xyz(j, nside, xyz, margin)) { logverb(" -> and within range.\n"); il_append(hps, j); } } } } //hps = healpix_rangesearch_radec(ra, dec, margin, nside, hps); logverb(" --> healpixes: ["); for (j=0; j<il_size(hps); j++) logverb(" %i", il_get(hps, j)); logverb(" ]\n"); } //printf("Reading rowdata for row %i\n", r); rowdata = buffered_read(rowbuf); assert(rowdata); j=0; while (1) { if (hps) { if (j >= il_size(hps)) break; hp = il_get(hps, j); j++; } assert(hp < NHP); assert(hp >= 0); if (!outtables[hp]) { char* outfn; fitstable_t* out; // MEMLEAK the output filename. You'll live. asprintf_safe(&outfn, outfnpat, hp); logmsg("Opening output file \"%s\"...\n", outfn); out = fitstable_open_for_writing(outfn); if (!out) { ERROR("Failed to open output table \"%s\"", outfn); exit(-1); } // Set the output table structure. if (cols) { fitstable_add_fits_columns_as_struct3(intable, out, cols, 0); } else fitstable_add_fits_columns_as_struct2(intable, out); if (backref) { tfits_type i16type; tfits_type i32type; // R = fitstable_row_size(intable); int off = R; i16type = fitscolumn_i16_type(); i32type = fitscolumn_i32_type(); fitstable_add_read_column_struct(out, i16type, 1, off, i16type, "backref_file", TRUE); off += sizeof(int16_t); fitstable_add_read_column_struct(out, i32type, 1, off, i32type, "backref_index", TRUE); } //printf("Output table:\n"); //fitstable_print_columns(out); if (fitstable_write_primary_header(out) || fitstable_write_header(out)) { ERROR("Failed to write output file headers for \"%s\"", outfn); exit(-1); } outtables[hp] = out; } if (backref) { int16_t brfile; int32_t brind; if (!padrowdata) { padrowdata = malloc(R + sizeof(int16_t) + sizeof(int32_t)); assert(padrowdata); } // convert to FITS endian brfile = htons(i); brind = htonl(r); // add backref data to rowdata memcpy(padrowdata, rowdata, R); memcpy(padrowdata + R, &brfile, sizeof(int16_t)); memcpy(padrowdata + R + sizeof(int16_t), &brind, sizeof(int32_t)); rdata = padrowdata; } else { rdata = rowdata; } if (cols) { if (fitstable_write_struct_noflip(outtables[hp], rdata)) { ERROR("Failed to copy a row of data from input table \"%s\" to output healpix %i", infn, hp); } } else { if (fitstable_write_row_data(outtables[hp], rdata)) { ERROR("Failed to copy a row of data from input table \"%s\" to output healpix %i", infn, hp); } } if (!hps) break; } if (hps) il_remove_all(hps); } buffered_read_free(rowbuf); // wack... buffered_read_free() just frees its internal buffer, // not the "rowbuf" struct itself. // who wrote this crazy code? Oh, me of 5 years ago. Jerk. free(rowbuf); fitstable_close(intable); il_free(hps); if (tempfn) { logverb("Removing temp file %s\n", tempfn); if (unlink(tempfn)) { SYSERROR("Failed to unlink() temp file \"%s\"", tempfn); } tempfn = NULL; } // fix headers so that the files are valid at this point. for (ii=0; ii<NHP; ii++) { if (!outtables[ii]) continue; off_t offset = ftello(outtables[ii]->fid); if (fitstable_fix_header(outtables[ii])) { ERROR("Failed to fix header for healpix %i after reading input file \"%s\"", ii, originfn); exit(-1); } fseeko(outtables[ii]->fid, offset, SEEK_SET); } if (padrowdata) { free(padrowdata); padrowdata = NULL; } } for (i=0; i<NHP; i++) { if (!outtables[i]) continue; if (fitstable_fix_header(outtables[i]) || fitstable_fix_primary_header(outtables[i]) || fitstable_close(outtables[i])) { ERROR("Failed to close output table for healpix %i", i); exit(-1); } } free(outtables); sl_free2(infns); sl_free2(cols); free(mincaps); free(maxcaps); return 0; }
static void plot_constellations(cairo_t* cairo, plot_args_t* pargs, plotann_t* ann) { int i, N; double ra,dec,radius; double xyzf[3]; // Find the field center and radius anwcs_get_radec_center_and_radius(pargs->wcs, &ra, &dec, &radius); logverb("Plotting constellations: field center %g,%g, radius %g\n", ra, dec, radius); radecdeg2xyzarr(ra, dec, xyzf); radius = deg2dist(radius); N = constellations_n(); for (i=0; i<N; i++) { int j, k; // Find the approximate center and radius of this constellation // and see if it overlaps with the field. il* stars = constellations_get_unique_stars(i); double xyzj[3]; double xyzc[3]; double maxr2 = 0; dl* rds; xyzc[0] = xyzc[1] = xyzc[2] = 0.0; xyzj[0] = xyzj[1] = xyzj[2] = 0.0; for (j=0; j<il_size(stars); j++) { constellations_get_star_radec(il_get(stars, j), &ra, &dec); radecdeg2xyzarr(ra, dec, xyzj); for (k=0; k<3; k++) xyzc[k] += xyzj[k]; } normalize_3(xyzc); for (j=0; j<il_size(stars); j++) { constellations_get_star_radec(il_get(stars, j), &ra, &dec); maxr2 = MAX(maxr2, distsq(xyzc, xyzj, 3)); } il_free(stars); maxr2 = square(sqrt(maxr2) + radius); if (distsq(xyzf, xyzc, 3) > maxr2) { xyzarr2radecdeg(xyzc, &ra, &dec); logverb("Constellation %s (center %g,%g, radius %g) out of bounds\n", constellations_get_shortname(i), ra, dec, dist2deg(sqrt(maxr2) - radius)); logverb(" dist from field center to constellation center is %g deg\n", distsq2deg(distsq(xyzf, xyzc, 3))); logverb(" max radius: %g\n", distsq2deg(maxr2)); continue; } if (ann->constellation_pastel) { float r,g,b; xyzarr2radecdeg(xyzc, &ra, &dec); color_for_radec(ra, dec, &r,&g,&b); plotstuff_set_rgba2(pargs, r,g,b, 0.8); plotstuff_builtin_apply(cairo, pargs); } // Phew, plot it. if (ann->constellation_lines) { rds = constellations_get_lines_radec(i); logverb("Constellation %s: plotting %zu lines\n", constellations_get_shortname(i), dl_size(rds)/4); for (j=0; j<dl_size(rds)/4; j++) { double r1,d1,r2,d2; double r3,d3,r4,d4; double off = ann->constellation_lines_offset; r1 = dl_get(rds, j*4+0); d1 = dl_get(rds, j*4+1); r2 = dl_get(rds, j*4+2); d2 = dl_get(rds, j*4+3); if (anwcs_find_discontinuity(pargs->wcs, r1, d1, r2, d2, &r3, &d3, &r4, &d4)) { logverb("Discontinuous: %g,%g -- %g,%g\n", r1, d1, r2, d2); logverb(" %g,%g == %g,%g\n", r3,d3, r4,d4); plot_offset_line_rd(NULL, pargs, r1,d1,r3,d3, off, 0.); plot_offset_line_rd(NULL, pargs, r4,d4,r2,d2, 0., off); } else { plot_offset_line_rd(NULL, pargs, r1,d1,r2,d2, off, off); } plotstuff_stroke(pargs); } dl_free(rds); } if (ann->constellation_labels || ann->constellation_markers) { // Put the label at the center of mass of the stars that // are in-bounds int Nin = 0; stars = constellations_get_unique_stars(i); xyzc[0] = xyzc[1] = xyzc[2] = 0.0; logverb("Labeling %s: %zu stars\n", constellations_get_shortname(i), il_size(stars)); for (j=0; j<il_size(stars); j++) { constellations_get_star_radec(il_get(stars, j), &ra, &dec); if (!anwcs_radec_is_inside_image(pargs->wcs, ra, dec)) continue; if (ann->constellation_markers) plotstuff_marker_radec(pargs, ra, dec); radecdeg2xyzarr(ra, dec, xyzj); for (k=0; k<3; k++) xyzc[k] += xyzj[k]; Nin++; } logverb(" %i stars in-bounds\n", Nin); if (ann->constellation_labels && Nin) { const char* label; normalize_3(xyzc); xyzarr2radecdeg(xyzc, &ra, &dec); if (ann->constellation_labels_long) label = constellations_get_longname(i); else label = constellations_get_shortname(i); plotstuff_text_radec(pargs, ra, dec, label); } il_free(stars); } } }
sip_t* tweak2(const double* fieldxy, int Nfield, double fieldjitter, int W, int H, const double* indexradec, int Nindex, double indexjitter, const double* quadcenter, double quadR2, double distractors, double logodds_bail, int sip_order, int sip_invorder, const sip_t* startwcs, sip_t* destwcs, int** newtheta, double** newodds, double* crpix, double* p_logodds, int* p_besti, int* testperm, int startorder) { int order; sip_t* sipout; int* indexin; double* indexpix; double* fieldsigma2s; double* weights; double* matchxyz; double* matchxy; int i, Nin=0; double logodds = 0; int besti = -1; int* theta = NULL; double* odds = NULL; int* refperm = NULL; double qc[2]; memcpy(qc, quadcenter, 2*sizeof(double)); if (destwcs) sipout = destwcs; else sipout = sip_create(); indexin = malloc(Nindex * sizeof(int)); indexpix = malloc(2 * Nindex * sizeof(double)); fieldsigma2s = malloc(Nfield * sizeof(double)); weights = malloc(Nfield * sizeof(double)); matchxyz = malloc(Nfield * 3 * sizeof(double)); matchxy = malloc(Nfield * 2 * sizeof(double)); // FIXME --- hmmm, how do the annealing steps and iterating up to // higher orders interact? assert(startwcs); memcpy(sipout, startwcs, sizeof(sip_t)); logverb("tweak2: starting orders %i, %i\n", sipout->a_order, sipout->ap_order); if (!sipout->wcstan.imagew) sipout->wcstan.imagew = W; if (!sipout->wcstan.imageh) sipout->wcstan.imageh = H; logverb("Tweak2: starting from WCS:\n"); if (log_get_level() >= LOG_VERB) sip_print_to(sipout, stdout); for (order=startorder; order <= sip_order; order++) { int step; int STEPS = 100; // variance growth rate wrt radius. double gamma = 1.0; //logverb("Starting tweak2 order=%i\n", order); for (step=0; step<STEPS; step++) { double iscale; double ijitter; double ra, dec; double R2; int Nmatch; int nmatch, nconf, ndist; double pix2; double totalweight; // clean up from last round (we do it here so that they're // valid when we leave the loop) free(theta); free(odds); free(refperm); // Anneal gamma = pow(0.9, step); if (step == STEPS-1) gamma = 0.0; logverb("Annealing: order %i, step %i, gamma = %g\n", order, step, gamma); debug("Using input WCS:\n"); if (log_get_level() > LOG_VERB) sip_print_to(sipout, stdout); // Project reference sources into pixel space; keep the ones inside image bounds. Nin = 0; for (i=0; i<Nindex; i++) { anbool ok; double x,y; ra = indexradec[2*i + 0]; dec = indexradec[2*i + 1]; ok = sip_radec2pixelxy(sipout, ra, dec, &x, &y); if (!ok) continue; if (!sip_pixel_is_inside_image(sipout, x, y)) continue; indexpix[Nin*2+0] = x; indexpix[Nin*2+1] = y; indexin[Nin] = i; Nin++; } logverb("%i reference sources within the image.\n", Nin); //logverb("CRPIX is (%g,%g)\n", sip.wcstan.crpix[0], sip.wcstan.crpix[1]); if (Nin == 0) { sip_free(sipout); free(matchxy); free(matchxyz); free(weights); free(fieldsigma2s); free(indexpix); free(indexin); return NULL; } iscale = sip_pixel_scale(sipout); ijitter = indexjitter / iscale; //logverb("With pixel scale of %g arcsec/pixel, index adds jitter of %g pix.\n", iscale, ijitter); /* CHECK for (i=0; i<Nin; i++) { double x,y; int ii = indexin[i]; sip_radec2pixelxy(sipout, indexradec[2*ii+0], indexradec[2*ii+1], &x, &y); logverb("indexin[%i]=%i; (%.1f,%.1f) -- (%.1f,%.1f)\n", i, ii, indexpix[i*2+0], indexpix[i*2+1], x, y); } */ for (i=0; i<Nfield; i++) { R2 = distsq(qc, fieldxy + 2*i, 2); fieldsigma2s[i] = (square(fieldjitter) + square(ijitter)) * (1.0 + gamma * R2/quadR2); } if (order == 1 && step == 0 && TWEAK_DEBUG_PLOTS) { TWEAK_DEBUG_PLOT("init", W, H, Nfield, fieldxy, fieldsigma2s, Nin, indexpix, *p_besti, *newtheta, sipout->wcstan.crpix, testperm, qc); } /* logodds = verify_star_lists(indexpix, Nin, fieldxy, fieldsigma2s, Nfield, W*H, distractors, logodds_bail, HUGE_VAL, &besti, &odds, &theta, NULL, &testperm); */ pix2 = square(fieldjitter); logodds = verify_star_lists_ror(indexpix, Nin, fieldxy, fieldsigma2s, Nfield, pix2, gamma, qc, quadR2, W, H, distractors, logodds_bail, HUGE_VAL, &besti, &odds, &theta, NULL, &testperm, &refperm); logverb("Logodds: %g\n", logodds); verify_count_hits(theta, besti, &nmatch, &nconf, &ndist); logverb("%i matches, %i distractors, %i conflicts (at best log-odds); %i field sources, %i index sources\n", nmatch, ndist, nconf, Nfield, Nin); verify_count_hits(theta, Nfield-1, &nmatch, &nconf, &ndist); logverb("%i matches, %i distractors, %i conflicts (all sources)\n", nmatch, ndist, nconf); if (log_get_level() >= LOG_VERB) { matchobj_log_hit_miss(theta, testperm, besti+1, Nfield, LOG_VERB, "Hit/miss: "); } /* logverb("\nAfter verify():\n"); for (i=0; i<Nin; i++) { double x,y; int ii = indexin[refperm[i]]; sip_radec2pixelxy(sipout, indexradec[2*ii+0], indexradec[2*ii+1], &x, &y); logverb("indexin[%i]=%i; (%.1f,%.1f) -- (%.1f,%.1f)\n", i, ii, indexpix[i*2+0], indexpix[i*2+1], x, y); } */ if (TWEAK_DEBUG_PLOTS) { char name[32]; sprintf(name, "o%is%02ipre", order, step); TWEAK_DEBUG_PLOT(name, W, H, Nfield, fieldxy, fieldsigma2s, Nin, indexpix, besti, theta, sipout->wcstan.crpix, testperm, qc); } Nmatch = 0; debug("Weights:"); for (i=0; i<Nfield; i++) { double ra,dec; if (theta[i] < 0) continue; assert(theta[i] < Nin); int ii = indexin[refperm[theta[i]]]; assert(ii < Nindex); assert(ii >= 0); ra = indexradec[ii*2+0]; dec = indexradec[ii*2+1]; radecdeg2xyzarr(ra, dec, matchxyz + Nmatch*3); memcpy(matchxy + Nmatch*2, fieldxy + i*2, 2*sizeof(double)); weights[Nmatch] = verify_logodds_to_weight(odds[i]); debug(" %.2f", weights[Nmatch]); Nmatch++; /* logverb("match img (%.1f,%.1f) -- ref (%.1f, %.1f), odds %g, wt %.3f\n", fieldxy[i*2+0], fieldxy[i*2+1], indexpix[theta[i]*2+0], indexpix[theta[i]*2+1], odds[i], weights[Nmatch-1]); double xx,yy; sip_radec2pixelxy(sipout, ra, dec, &xx, &yy); logverb("check: (%.1f, %.1f)\n", xx, yy); */ } debug("\n"); if (Nmatch < 2) { logverb("No matches -- aborting tweak attempt\n"); free(theta); sip_free(sipout); free(matchxy); free(matchxyz); free(weights); free(fieldsigma2s); free(indexpix); free(indexin); return NULL; } // Update the "quad center" to be the weighted average matched star posn. qc[0] = qc[1] = 0.0; totalweight = 0.0; for (i=0; i<Nmatch; i++) { qc[0] += (weights[i] * matchxy[2*i+0]); qc[1] += (weights[i] * matchxy[2*i+1]); totalweight += weights[i]; } qc[0] /= totalweight; qc[1] /= totalweight; logverb("Moved quad center to (%.1f, %.1f)\n", qc[0], qc[1]); // sipout->a_order = sipout->b_order = order; sipout->ap_order = sipout->bp_order = sip_invorder; logverb("tweak2: setting orders %i, %i\n", sipout->a_order, sipout->ap_order); if (crpix) { tan_t temptan; logverb("Moving tangent point to given CRPIX (%g,%g)\n", crpix[0], crpix[1]); fit_tan_wcs_move_tangent_point_weighted(matchxyz, matchxy, weights, Nmatch, crpix, &sipout->wcstan, &temptan); fit_tan_wcs_move_tangent_point_weighted(matchxyz, matchxy, weights, Nmatch, crpix, &temptan, &sipout->wcstan); } int doshift = 1; fit_sip_wcs(matchxyz, matchxy, weights, Nmatch, &(sipout->wcstan), order, sip_invorder, doshift, sipout); debug("Got SIP:\n"); if (log_get_level() > LOG_VERB) sip_print_to(sipout, stdout); sipout->wcstan.imagew = W; sipout->wcstan.imageh = H; } } //logverb("Final logodds: %g\n", logodds); // Now, recompute final logodds after turning 'gamma' on again (?) // FIXME -- this counts the quad stars in the logodds... { double gamma = 1.0; double iscale; double ijitter; double ra, dec; double R2; int nmatch, nconf, ndist; double pix2; free(theta); free(odds); free(refperm); gamma = 1.0; // Project reference sources into pixel space; keep the ones inside image bounds. Nin = 0; for (i=0; i<Nindex; i++) { anbool ok; double x,y; ra = indexradec[2*i + 0]; dec = indexradec[2*i + 1]; ok = sip_radec2pixelxy(sipout, ra, dec, &x, &y); if (!ok) continue; if (!sip_pixel_is_inside_image(sipout, x, y)) continue; indexpix[Nin*2+0] = x; indexpix[Nin*2+1] = y; indexin[Nin] = i; Nin++; } logverb("%i reference sources within the image.\n", Nin); iscale = sip_pixel_scale(sipout); ijitter = indexjitter / iscale; for (i=0; i<Nfield; i++) { R2 = distsq(qc, fieldxy + 2*i, 2); fieldsigma2s[i] = (square(fieldjitter) + square(ijitter)) * (1.0 + gamma * R2/quadR2); } pix2 = square(fieldjitter); logodds = verify_star_lists_ror(indexpix, Nin, fieldxy, fieldsigma2s, Nfield, pix2, gamma, qc, quadR2, W, H, distractors, logodds_bail, HUGE_VAL, &besti, &odds, &theta, NULL, &testperm, &refperm); logverb("Logodds: %g\n", logodds); verify_count_hits(theta, besti, &nmatch, &nconf, &ndist); logverb("%i matches, %i distractors, %i conflicts (at best log-odds); %i field sources, %i index sources\n", nmatch, ndist, nconf, Nfield, Nin); verify_count_hits(theta, Nfield-1, &nmatch, &nconf, &ndist); logverb("%i matches, %i distractors, %i conflicts (all sources)\n", nmatch, ndist, nconf); if (log_get_level() >= LOG_VERB) { matchobj_log_hit_miss(theta, testperm, besti+1, Nfield, LOG_VERB, "Hit/miss: "); } if (TWEAK_DEBUG_PLOTS) { TWEAK_DEBUG_PLOT("final", W, H, Nfield, fieldxy, fieldsigma2s, Nin, indexpix, besti, theta, sipout->wcstan.crpix, testperm, qc); } } if (newtheta) { // undo the "indexpix" inside-image-bounds cut. (*newtheta) = malloc(Nfield * sizeof(int)); for (i=0; i<Nfield; i++) { int nt; if (theta[i] < 0) nt = theta[i]; else nt = indexin[refperm[theta[i]]]; (*newtheta)[i] = nt; } } free(theta); free(refperm); if (newodds) *newodds = odds; else free(odds); logverb("Tweak2: final WCS:\n"); if (log_get_level() >= LOG_VERB) sip_print_to(sipout, stdout); if (p_logodds) *p_logodds = logodds; if (p_besti) *p_besti = besti; free(indexin); free(indexpix); free(fieldsigma2s); free(weights); free(matchxyz); free(matchxy); return sipout; }