void radec_derivatives(double ra, double dec, double* dra, double* ddec) { double cosd = cos(deg2rad(dec)); double cosra = cos(deg2rad(ra)); double sinra = sin(deg2rad(ra)); if (dra) { dra[0] = cosd * -sinra; dra[1] = cosd * cosra; dra[2] = 0.0; normalize_3(dra); } if (ddec) { double sind = sin(deg2rad(dec)); ddec[0] = -sind * cosra; ddec[1] = -sind * sinra; ddec[2] = cosd; normalize_3(ddec); } }
void tan_iwc2xyzarr(const tan_t* tan, double x, double y, double *xyz) { double rx, ry, rz; double ix,iy,norm; double jx,jy,jz; // Mysterious factor of -1 correcting for vector directions below. x = -deg2rad(x); y = deg2rad(y); // Take r to be the threespace vector of crval radecdeg2xyz(tan->crval[0], tan->crval[1], &rx, &ry, &rz); // printf("rx=%lf ry=%lf rz=%lf\n",rx,ry,rz); // Form i = r cross north pole (0,0,1) ix = ry; iy = -rx; // iz = 0 norm = hypot(ix, iy); ix /= norm; iy /= norm; // printf("ix=%lf iy=%lf iz=0.0\n",ix,iy); // printf("r.i = %lf\n",ix*rx+iy*ry); // Form j = i cross r; iz=0 so some terms drop out jx = iy * rz; jy = - ix * rz; jz = ix * ry - iy * rx; // norm should already be 1, but normalize anyway normalize(&jx, &jy, &jz); // printf("jx=%lf jy=%lf jz=%lf\n",jx,jy,jz); // printf("r.j = %lf\n",jx*rx+jy*ry+jz*rz); // printf("i.j = %lf\n",ix*jx+iy*jy); if (tan->sin) { assert((x*x + y*y) < 1.0); // Figure out what factor of r we have to add in to make the resulting length = 1 double rfrac = sqrt(1.0 - (x*x + y*y)); // Don't scale the projected x,y positions, just add in the right amount of r to // bring it onto the unit sphere xyz[0] = ix*x + jx*y + rx * rfrac; xyz[1] = iy*x + jy*y + ry * rfrac; xyz[2] = jz*y + rz * rfrac; // iz = 0 } else { // Form the point on the tangent plane relative to observation point, xyz[0] = ix*x + jx*y + rx; xyz[1] = iy*x + jy*y + ry; xyz[2] = jz*y + rz; // iz = 0 // and normalize back onto the unit sphere normalize_3(xyz); } }
static int fit_tan_wcs_solve(const double* starxyz, const double* fieldxy, const double* weights, int N, const double* crpix, const tan_t* tanin, tan_t* tanout, double* p_scale) { int i, j, k; double field_cm[2] = {0, 0}; double cov[4] = {0, 0, 0, 0}; double R[4] = {0, 0, 0, 0}; double scale; // projected star coordinates double* p; // relative field coordinates double* f; double pcm[2] = {0, 0}; double w = 0; double totalw; gsl_matrix* A; gsl_matrix* U; gsl_matrix* V; gsl_vector* S; gsl_vector* work; gsl_matrix_view vcov; gsl_matrix_view vR; double crxyz[3]; double star_cm[3] = {0, 0, 0}; assert(((tanin != NULL) && (crpix != NULL)) || ((tanin == NULL) && (crpix == NULL))); if (tanin) { // default vals... memcpy(tanout, tanin, sizeof(tan_t)); } else { memset(tanout, 0, sizeof(tan_t)); } // -allocate and fill "p" and "f" arrays. ("projected" and "field") p = malloc(N * 2 * sizeof(double)); f = malloc(N * 2 * sizeof(double)); // -get field center-of-mass totalw = 0.0; for (i=0; i<N; i++) { w = (weights ? weights[i] : 1.0); field_cm[0] += w * fieldxy[i*2 + 0]; field_cm[1] += w * fieldxy[i*2 + 1]; totalw += w; } field_cm[0] /= totalw; field_cm[1] /= totalw; // Subtract it out. for (i=0; i<N; i++) { f[2*i+0] = fieldxy[2*i+0] - field_cm[0]; f[2*i+1] = fieldxy[2*i+1] - field_cm[1]; } if (tanin) { // Use original WCS to set the center of projection to the new crpix. tan_pixelxy2xyzarr(tanin, crpix[0], crpix[1], crxyz); for (i=0; i<N; i++) { Unused anbool ok; // -project the stars around crval ok = star_coords(starxyz + i*3, crxyz, TRUE, p + 2*i, p + 2*i + 1); assert(ok); } } else { // -get the star center-of-mass (this will become the tangent point CRVAL) for (i=0; i<N; i++) { w = (weights ? weights[i] : 1.0); star_cm[0] += w * starxyz[i*3 + 0]; star_cm[1] += w * starxyz[i*3 + 1]; star_cm[2] += w * starxyz[i*3 + 2]; } normalize_3(star_cm); // -project the stars around their center of mass for (i=0; i<N; i++) { Unused anbool ok; ok = star_coords(starxyz + i*3, star_cm, TRUE, p + 2*i, p + 2*i + 1); assert(ok); } } // -compute the center of mass of the projected stars and subtract it out. for (i=0; i<N; i++) { w = (weights ? weights[i] : 1.0); pcm[0] += w * p[2*i + 0]; pcm[1] += w * p[2*i + 1]; } pcm[0] /= totalw; pcm[1] /= totalw; for (i=0; i<N; i++) { p[2*i + 0] -= pcm[0]; p[2*i + 1] -= pcm[1]; } // -compute the covariance between field positions and projected // positions of the corresponding stars. for (i=0; i<N; i++) for (j=0; j<2; j++) for (k=0; k<2; k++) cov[j*2 + k] += p[i*2 + k] * f[i*2 + j]; for (i=0; i<4; i++) assert(isfinite(cov[i])); // -run SVD V = gsl_matrix_alloc(2, 2); S = gsl_vector_alloc(2); work = gsl_vector_alloc(2); vcov = gsl_matrix_view_array(cov, 2, 2); vR = gsl_matrix_view_array(R, 2, 2); A = &(vcov.matrix); // The Jacobi version doesn't always compute an orthonormal U if S has zeros. //gsl_linalg_SV_decomp_jacobi(A, V, S); gsl_linalg_SV_decomp(A, V, S, work); // the U result is written to A. U = A; gsl_vector_free(S); gsl_vector_free(work); // R = V U' gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1.0, V, U, 0.0, &(vR.matrix)); gsl_matrix_free(V); for (i=0; i<4; i++) assert(isfinite(R[i])); // -compute scale: make the variances equal. { double pvar, fvar; pvar = fvar = 0.0; for (i=0; i<N; i++) { w = (weights ? weights[i] : 1.0); for (j=0; j<2; j++) { pvar += w * square(p[i*2 + j]); fvar += w * square(f[i*2 + j]); } } scale = sqrt(pvar / fvar); } // -compute WCS parameters. scale = rad2deg(scale); tanout->cd[0][0] = R[0] * scale; // CD1_1 tanout->cd[0][1] = R[1] * scale; // CD1_2 tanout->cd[1][0] = R[2] * scale; // CD2_1 tanout->cd[1][1] = R[3] * scale; // CD2_2 assert(isfinite(tanout->cd[0][0])); assert(isfinite(tanout->cd[0][1])); assert(isfinite(tanout->cd[1][0])); assert(isfinite(tanout->cd[1][1])); if (tanin) { // CRPIX is fixed. tanout->crpix[0] = crpix[0]; tanout->crpix[1] = crpix[1]; // Set CRVAL temporarily... tan_pixelxy2radec(tanin, crpix[0], crpix[1], tanout->crval+0, tanout->crval+1); // Shift CRVAL so that the center of the quad is in the right place. { double ix,iy; double dx,dy; double dxyz[3]; tan_pixelxy2iwc(tanout, field_cm[0], field_cm[1], &ix, &iy); dx = rad2deg(pcm[0]) - ix; dy = rad2deg(pcm[1]) - iy; tan_iwc2xyzarr(tanout, dx, dy, dxyz); xyzarr2radecdeg(dxyz, tanout->crval + 0, tanout->crval + 1); } } else { tanout->crpix[0] = field_cm[0]; tanout->crpix[1] = field_cm[1]; xyzarr2radecdegarr(star_cm, tanout->crval); // FIXME -- we ignore pcm. It should get added back in (after // multiplication by CD in the appropriate units) to either crval or // crpix. It's a very small correction probably of the same size // as the other approximations we're making. } if (p_scale) *p_scale = scale; free(p); free(f); return 0; }
static void plot_targets(cairo_t* cairo, plot_args_t* pargs, plotann_t* ann) { int i; double cra, cdec; plotstuff_get_radec_center_and_radius(pargs, &cra, &cdec, NULL); for (i=0; i<bl_size(ann->targets); i++) { target_t* tar = bl_access(ann->targets, i); double px,py; double cx,cy; double dx,dy, r; double ex,ey; double ly, ry, tx, bx; double distdeg; anbool okquadrant; char* txt; logverb("Target: \"%s\" at (%g,%g)\n", tar->name, tar->ra, tar->dec); okquadrant = plotstuff_radec2xy(pargs, tar->ra, tar->dec, &px, &py); px -= 1; py -= 1; if (okquadrant && px >= 0 && px < pargs->W && py >= 0 && py < pargs->H) { // inside the image! logverb("Target \"%s\" is inside the image, at pixel (%g,%g)\n", tar->name, px, py); plotstuff_stack_marker(pargs, px, py); plotstuff_stack_text(pargs, cairo, tar->name, px, py); continue; } // outside the image: find intersection point. cx = pargs->W / 2.0; cy = pargs->H / 2.0; if (okquadrant) { logverb("Target \"%s\" is outside the image, at pixel (%g,%g)\n", tar->name, px, py); dx = px - cx; dy = py - cy; } else { double cxyz[3]; double txyz[3]; double vec[3]; int j; double ra,dec; logverb("Target \"%s\" is way outside the image.\n", tar->name); // fallback. radecdeg2xyzarr(cra, cdec, cxyz); radecdeg2xyzarr(tar->ra, tar->dec, txyz); for (j=0; j<3; j++) vec[j] = cxyz[j] + 0.1 * txyz[j]; normalize_3(vec); xyzarr2radecdeg(vec, &ra, &dec); okquadrant = plotstuff_radec2xy(pargs, ra, dec, &px, &py); assert(okquadrant); dx = px - cx; dy = py - cy; if ((dx*dx + dy*dy) < (cx*cx + cy*cy)) { double scale = 3.0 * sqrt(cx*cx + cy*cy) / sqrt(dx*dx + dy*dy); dx *= scale; dy *= scale; } } ly = (-(pargs->W/2.0) / dx) * dy + cy; ry = ( (pargs->W/2.0) / dx) * dy + cy; bx = (-(pargs->H/2.0) / dy) * dx + cx; tx = ( (pargs->H/2.0) / dy) * dx + cx; logverb("ly %g, ry %g, bx %g, tx %g\n", ly, ry, bx, tx); if (px < cx && ly >= 0 && ly < pargs->H) { ex = 0.0; ey = ly; } else if (px >= cx && ry >= 0 && ry < pargs->H) { ex = pargs->W - 1; ey = ry; } else if (py < cy && bx >= 0 && bx < pargs->W) { ex = bx; ey = 0; } else if (py >= cy && tx >= 0 && tx < pargs->W) { ex = tx; ey = pargs->H - 1; } else { logverb("None of the edges are in bounds: px,py=(%g,%g); ly=%g, ry=%g, bx=%g, tx=%g\n", px,py,ly,ry,bx,tx); continue; } dx = ex - cx; dy = ey - cy; r = sqrt(dx*dx + dy*dy); px = (r-100.0) / r * dx + cx; py = (r-100.0) / r * dy + cy; plotstuff_stack_arrow(pargs, px, py, ex, ey); logverb("Arrow from (%g,%g) to (%g,%g)\n", px, py, ex, ey); distdeg = deg_between_radecdeg(cra, cdec, tar->ra, tar->dec); asprintf_safe(&txt, "%s: %.1f deg", tar->name, distdeg); plotstuff_stack_text(pargs, cairo, txt, px, py); } }
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); } } }