VIRCAM Pipeline  1.3.3
vircam/vircam_platesol.c
1 /* $Id: vircam_platesol.c,v 1.32 2013-10-15 16:50:51 jim Exp $
2  *
3  * This file is part of the VIRCAM Pipeline
4  * Copyright (C) 2005 Cambridge Astronomy Survey Unit
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jim $
23  * $Date: 2013-10-15 16:50:51 $
24  * $Revision: 1.32 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 /* Includes */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <cpl.h>
35 #include <math.h>
36 
37 #include "vircam_mods.h"
38 #include "vircam_utils.h"
39 #include "vircam_wcsutils.h"
40 #include "vircam_stats.h"
41 #include "vircam_pfits.h"
42 
43 static double *work = NULL;
44 static unsigned char *iwork = NULL;
45 
46 static int vircam_plate6(double *xpos, double *ypos, double *xi, double *eta,
47  unsigned char *flag, int nstds, double *a, double *b,
48  double *c, double *d, double *e, double *f);
49 static int vircam_plate4(double *xpos, double *ypos, double *xi, double *eta,
50  unsigned char *flag, int nstds, double *a, double *b,
51  double *c, double *d, double *e, double *f);
52 static void tidy(void);
53 
56 /*---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------*/
130 
131 extern int vircam_platesol(cpl_propertylist *plist, cpl_propertylist *tlist,
132  cpl_table *matchedstds, int nconst, int shiftan,
133  int *status) {
134  int nstds,nc2,i,niter,nrej,ngood,nreq=6,xcol,ycol;
135  long n1,n2;
136  const char *fctid = "vircam_platesol";
137  float *tptr;
138  double *xptr,*yptr,*xptr2,*yptr2,*ra,*dec,*xiptr,*etaptr,*wptr,averr;
139  double r1,r2,d1,d2,newcrval1,newcrval2,a,b,c,d,e,f,xifit,etafit,dxi,deta;
140  double crpix1,crpix2,xi,eta,rac_before,rac_after,decc_before,decc_after;
141  double xcen,ycen,oldtheta,scale,oldcrpix1,oldcrpix2;
142  const double *crdata;
143  unsigned char *isbad,*wptr2;
144  const char *reqcols[] = {"X_coordinate","Y_coordinate","xpredict",
145  "ypredict","RA","Dec"};
146  char key[9];
147  cpl_wcs *wcs;
148  const cpl_array *cr;
149  const cpl_matrix *crm;
150 
151  /* Inherited status */
152 
153  if (*status != VIR_OK)
154  return(*status);
155 
156  /* Check the value of nconst */
157 
158  if (nconst != 4 && nconst != 6) {
159  cpl_msg_error(fctid,
160  "Value of nconst = %" CPL_SIZE_FORMAT " is unsupported",
161  (cpl_size)nconst);
162  FATAL_ERROR
163  }
164 
165  /* How many standards are in the input matched standards table? */
166 
167  nstds = (int)cpl_table_get_nrow(matchedstds);
168  nc2 = nconst/2;
169  if (nstds < nc2) {
170  cpl_msg_error(fctid,
171  "Too few standards (%" CPL_SIZE_FORMAT ") in table for %" CPL_SIZE_FORMAT " coefficient fit",
172  (cpl_size)nstds,(cpl_size)nconst);
173  FATAL_ERROR
174  }
175 
176  /* Check that the matched standards table has all the required columns */
177 
178  for (i = 0; i < nreq; i++) {
179  if (cpl_table_has_column(matchedstds,reqcols[i]) != 1) {
180  cpl_msg_error(fctid,"Matched standards table missing column %s\n",
181  reqcols[i]);
182  FATAL_ERROR
183  }
184  }
185 
186  /* Get some workspace now */
187 
188  work = cpl_malloc(10*nstds*sizeof(*work));
189  iwork = cpl_calloc(3*nstds,sizeof(*isbad));
190  xptr = work;
191  yptr = work + nstds;
192  xptr2 = work + 2*nstds;
193  yptr2 = work + 3*nstds;
194  ra = work + 4*nstds;
195  dec = work + 5*nstds;
196  xiptr = work + 6*nstds;
197  etaptr = work + 7*nstds;
198  wptr = work + 8*nstds;
199  isbad = iwork;
200  wptr2 = iwork + nstds;
201 
202  /* Get the data from the table and put it all into double precision
203  arrays */
204 
205  tptr = cpl_table_get_data_float(matchedstds,"X_coordinate");
206  for (i = 0; i < nstds; i++)
207  xptr[i] = (double)tptr[i];
208  tptr = cpl_table_get_data_float(matchedstds,"Y_coordinate");
209  for (i = 0; i < nstds; i++)
210  yptr[i] = (double)tptr[i];
211  tptr = cpl_table_get_data_float(matchedstds,"xpredict");
212  for (i = 0; i < nstds; i++)
213  xptr2[i] = (double)tptr[i];
214  tptr = cpl_table_get_data_float(matchedstds,"ypredict");
215  for (i = 0; i < nstds; i++)
216  yptr2[i] = (double)tptr[i];
217  tptr = cpl_table_get_data_float(matchedstds,"RA");
218  for (i = 0; i < nstds; i++)
219  ra[i] = (double)tptr[i];
220  tptr = cpl_table_get_data_float(matchedstds,"Dec");
221  for (i = 0; i < nstds; i++)
222  dec[i] = (double)tptr[i];
223 
224  /* If you want to shift the RA and Dec of the tangent point, then
225  do that now */
226 
227  newcrval1 = 0.0;
228  newcrval2 = 0.0;
229  if (shiftan) {
230  wcs = cpl_wcs_new_from_propertylist(plist);
231  cr = cpl_wcs_get_crval(wcs);
232  crdata = cpl_array_get_data_double_const(cr);
233  for (i = 0; i < nstds; i++) {
234  vircam_xytoradec(wcs,xptr[i],yptr[i],&r1,&d1);
235  vircam_xytoradec(wcs,xptr2[i],yptr2[i],&r2,&d2);
236  xiptr[i] = r2 - r1;
237  etaptr[i] = d2 - d1;
238  }
239  r1 = vircam_dmed(xiptr,NULL,nstds);
240  d1 = vircam_dmed(etaptr,NULL,nstds);
241  newcrval1 = crdata[0] + r1;
242  newcrval2 = crdata[1] + d1;
243  cpl_propertylist_update_double(plist,"CRVAL1",newcrval1);
244  cpl_propertylist_update_double(plist,"CRVAL2",newcrval2);
245  cpl_wcs_delete(wcs);
246  }
247 
248  /* Calculate the central RA and Dec */
249 
250  wcs = cpl_wcs_new_from_propertylist(plist);
251  (void)vircam_pfits_get_naxis1(plist,&n1);
252  (void)vircam_pfits_get_naxis2(plist,&n2);
253  cr = cpl_wcs_get_crpix(wcs);
254  crdata = cpl_array_get_data_double_const(cr);
255  oldcrpix1 = crdata[0];
256  oldcrpix2 = crdata[1];
257  xcen = 0.5*(double)n1;
258  ycen = 0.5*(double)n2;
259  vircam_xytoradec(wcs,xcen,ycen,&rac_before,&decc_before);
260 
261  /* Right, calculate xi and eta for each of the standards */
262 
263  for (i = 0; i < nstds; i++) {
264  vircam_radectoxieta(wcs,ra[i],dec[i],&xi,&eta);
265  xiptr[i] = xi;
266  etaptr[i] = eta;
267  }
268 
269  /* Right, now loop for maximum number of iterations or until
270  convergence */
271 
272  niter = 0;
273  while (niter >= 0) {
274 
275  /* Do a plate solution */
276 
277  switch (nconst) {
278  case 6:
279  *status = vircam_plate6(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
280  &c,&e,&d,&f);
281  break;
282  case 4:
283  *status = vircam_plate4(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
284  &c,&e,&d,&f);
285  break;
286  default:
287  *status = vircam_plate6(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
288  &c,&e,&d,&f);
289  break;
290  }
291  if (*status != VIR_OK) {
292  cpl_msg_error(fctid,"Plate constant solution failed");
293  tidy();
294  FATAL_ERROR
295  }
296 
297  /* Now look at the residuals and see if any should be rejected */
298 
299  for (i = 0; i < nstds; i++) {
300  xifit = xptr[i]*a + yptr[i]*b + c;
301  etafit = xptr[i]*d + yptr[i]*e + f;
302  dxi = fabs(xifit - xiptr[i]);
303  deta = fabs(etafit - etaptr[i]);
304  wptr[i*2] = dxi;
305  wptr[i*2+1] = deta;
306  wptr2[i*2] = isbad[i];
307  wptr2[i*2+1] = isbad[i];
308  }
309  averr = vircam_dmed(wptr,wptr2,2*nstds);
310  averr *= 1.48;
311  if (niter == 3)
312  break;
313  nrej = 0;
314  ngood = 0;
315  for (i = 0; i < nstds; i++) {
316  if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) nrej++;
317  if (!isbad[i])
318  ngood++;
319  }
320  ngood -= nrej;
321  if (nrej == 0 || ngood < nconst)
322  break;
323  for (i = 0; i < nstds; i++) {
324  if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) isbad[i] = 1;
325  }
326  niter++;
327  }
328 
329  /* Convert values to degrees now */
330 
331  crpix1 = (e*c - b*f)/(d*b - e*a);
332  crpix2 = (a*f - d*c)/(d*b - e*a);
333  a *= DEGRAD;
334  b *= DEGRAD;
335  d *= DEGRAD;
336  e *= DEGRAD;
337 
338  /* Number of good points fit and average error in arcsec*/
339 
340  ngood = 0;
341  for (i = 0; i < nstds; i++)
342  if (! isbad[i])
343  ngood++;
344  averr *= DEGRAD*3600.0;
345 
346  /* Right, now update the header */
347 
348  cpl_propertylist_update_double(plist,"CRPIX1",crpix1);
349  cpl_propertylist_update_double(plist,"CRPIX2",crpix2);
350  cpl_propertylist_update_double(plist,"CD1_1",a);
351  cpl_propertylist_update_double(plist,"CD1_2",b);
352  cpl_propertylist_update_double(plist,"CD2_1",d);
353  cpl_propertylist_update_double(plist,"CD2_2",e);
354  cpl_propertylist_update_int(plist,"ESO DRS NUMBRMS",ngood);
355  cpl_propertylist_set_comment(plist,"ESO DRS NUMBRMS",
356  "Number of stars in WCS fit");
357  cpl_propertylist_update_double(plist,"ESO DRS STDCRMS",averr);
358  cpl_propertylist_set_comment(plist,"ESO DRS STDCRMS",
359  "[arcsec] Average error in WCS fit");
360 
361  /* Calculate the central RA and Dec again */
362 
363  crm = cpl_wcs_get_cd(wcs);
364  crdata = cpl_matrix_get_data_const(crm);
365  oldtheta = 0.5*(fabs(atan2(crdata[1],crdata[0])) +
366  fabs(atan2(crdata[2],crdata[3])));
367  cpl_wcs_delete(wcs);
368  wcs = cpl_wcs_new_from_propertylist(plist);
369  vircam_xytoradec(wcs,xcen,ycen,&rac_after,&decc_after);
370  xcen = 3600.0*(rac_after - rac_before);
371  ycen = 3600.0*(decc_after - decc_before);
372  cpl_propertylist_update_double(plist,"ESO DRS WCSRAOFF",xcen);
373  cpl_propertylist_set_comment(plist,"ESO DRS WCSRAOFF",
374  "[arcsec] cenpix RA_after - RA_before)");
375  cpl_propertylist_update_double(plist,"ESO DRS WCSDECOFF",ycen);
376  cpl_propertylist_set_comment(plist,"ESO DRS WCSDECOFF",
377  "[arcsec] cenpix Dec_after - Dec_before)");
378 
379  /* Update the table header */
380 
381  if (tlist != NULL) {
382  xcol = vircam_findcol(tlist,"X");
383  ycol = vircam_findcol(tlist,"Y");
384  if (xcol != -1 && ycol != -1) {
385  snprintf(key,9,"TCRPX%d",xcol);
386  cpl_propertylist_update_double(tlist,key,crpix1);
387  snprintf(key,9,"TCRPX%d",ycol);
388  cpl_propertylist_update_double(tlist,key,crpix2);
389  if (shiftan) {
390  snprintf(key,9,"TCRVL%d",xcol);
391  cpl_propertylist_update_double(tlist,key,newcrval1);
392  snprintf(key,9,"TCRVL%d",ycol);
393  cpl_propertylist_update_double(tlist,key,newcrval2);
394  }
395  snprintf(key,9,"TC%d_%d",xcol,xcol);
396  cpl_propertylist_update_double(tlist,key,a);
397  snprintf(key,9,"TC%d_%d",xcol,ycol);
398  cpl_propertylist_update_double(tlist,key,b);
399  snprintf(key,9,"TC%d_%d",ycol,xcol);
400  cpl_propertylist_update_double(tlist,key,d);
401  snprintf(key,9,"TC%d_%d",ycol,ycol);
402  cpl_propertylist_update_double(tlist,key,e);
403  cpl_propertylist_update_int(tlist,"ESO DRS NUMBRMS",ngood);
404  cpl_propertylist_set_comment(tlist,"ESO DRS NUMBRMS",
405  "Number of stars in WCS fit");
406  cpl_propertylist_update_double(tlist,"ESO DRS STDCRMS",averr);
407  cpl_propertylist_set_comment(tlist,"ESO DRS STDCRMS",
408  "[arcsec] Average error in WCS fit");
409  cpl_propertylist_update_double(tlist,"ESO DRS WCSRAOFF",xcen);
410  cpl_propertylist_set_comment(tlist,"ESO DRS WCSRAOFF",
411  "[arcsec] cenpix RA_after - RA_before)");
412  cpl_propertylist_update_double(tlist,"ESO DRS WCSDECOFF",ycen);
413  cpl_propertylist_set_comment(tlist,"ESO DRS WCSDECOFF",
414  "[arcsec] cenpix Dec_after - Dec_before)");
415  }
416  }
417 
418  /* Back-calculate a crval for the old value of crpix. Compare to the
419  WCS crval and write to QC header */
420 
421  cr = cpl_wcs_get_crval(wcs);
422  crdata = cpl_array_get_data_double_const(cr);
423  vircam_xytoradec(wcs,oldcrpix1,oldcrpix2,&rac_after,&decc_after);
424  rac_after -= crdata[0];
425  decc_after -= crdata[1];
426  cpl_propertylist_update_double(plist,"ESO QC WCS_DCRVAL1",rac_after);
427  cpl_propertylist_set_comment(plist,"ESO QC WCS_DCRVAL1",
428  "[deg] change in crval1");
429  cpl_propertylist_update_double(plist,"ESO QC WCS_DCRVAL2",decc_after);
430  cpl_propertylist_set_comment(plist,"ESO QC WCS_DCRVAL2",
431  "[deg] change in crval2");
432 
433  /* Work out the change in the rotation */
434 
435  crm = cpl_wcs_get_cd(wcs);
436  crdata = cpl_matrix_get_data_const(crm);
437  oldtheta = 0.5*(fabs(atan2(crdata[1],crdata[0])) +
438  fabs(atan2(crdata[2],crdata[3]))) - oldtheta;
439  oldtheta *= DEGRAD;
440  cpl_propertylist_update_double(plist,"ESO QC WCS_DTHETA",oldtheta);
441  cpl_propertylist_set_comment(plist,"ESO QC WCS_DTHETA",
442  "[deg] change in rotation");
443 
444  /* Work out the mean plate scale */
445 
446  scale = 1800.0*(sqrt(pow(crdata[0],2.0) + pow(crdata[1],2.0)) +
447  sqrt(pow(crdata[2],2.0) + pow(crdata[3],2.0)));
448  cpl_propertylist_update_double(plist,"ESO QC WCS_SCALE",scale);
449  cpl_propertylist_set_comment(plist,"ESO QC WCS_SCALE",
450  "[arcsec] mean plate scale");
451 
452  /* Work out the shear of this new WCS */
453 
454  oldtheta = fabs(atan2(crdata[1],crdata[0])) -
455  fabs(atan2(crdata[2],crdata[3]));
456  cpl_propertylist_update_double(plist,"ESO QC WCS_SHEAR",oldtheta);
457  cpl_propertylist_set_comment(plist,"ESO QC WCS_SHEAR",
458  "[deg] abs(xrot) - abs(yrot)");
459 
460  /* Now just add in the RMS */
461 
462  cpl_propertylist_update_double(plist,"ESO QC WCS_RMS",averr);
463  cpl_propertylist_set_comment(plist,"ESO QC WCS_RMS",
464  "[arcsec] Average error in WCS fit");
465 
466  /* Right, get out of here now... */
467 
468  cpl_wcs_delete(wcs);
469  tidy();
470  GOOD_STATUS
471 }
472 
473 /*---------------------------------------------------------------------------*/
512 /*---------------------------------------------------------------------------*/
513 
514 extern int vircam_platexy(cpl_table *matchedxy, int nconst, cpl_array **coefs,
515  int *status) {
516  const char *fctid = "vircam_platexy";
517  int nxy,nc2,i,niter,nrej,ngood;
518  unsigned char *isbad,*wptr2;
519  double *xptr1,*xptr2,*yptr1,*yptr2,*wptr,a,b,c,d,e,f,*cc,xfit,yfit;
520  double dx,dy,averr;
521  float *tptr;
522  int nreq = 4;
523  const char *reqcols[] = {"X_coordinate_1","Y_coordinate_1","X_coordinate_2",
524  "Y_coordinate_2"};
525 
526  /* Inherited status */
527 
528  *coefs = NULL;
529  if (*status != VIR_OK)
530  return(*status);
531 
532  /* Check the value of nconst */
533 
534  if (nconst != 4 && nconst != 6) {
535  cpl_msg_error(fctid,
536  "Value of nconst = %" CPL_SIZE_FORMAT " is unsupported",
537  (cpl_size)nconst);
538  FATAL_ERROR
539  }
540 
541  /* How many objects are in the input table? */
542 
543  nxy = (int)cpl_table_get_nrow(matchedxy);
544  nc2 = nconst/2;
545  if (nxy < nc2) {
546  cpl_msg_error(fctid,
547  "Too few objects (%" CPL_SIZE_FORMAT ") in table for %" CPL_SIZE_FORMAT " coefficient fit",
548  (cpl_size)nxy,(cpl_size)nconst);
549  FATAL_ERROR
550  }
551 
552  /* Check that the matched standards table has all the required columns */
553 
554  for (i = 0; i < nreq; i++) {
555  if (cpl_table_has_column(matchedxy,reqcols[i]) != 1) {
556  cpl_msg_error(fctid,"Input table missing column %s\n",reqcols[i]);
557  FATAL_ERROR
558  }
559  }
560 
561  /* Get some workspace now */
562 
563  work = cpl_malloc(6*nxy*sizeof(*work));
564  iwork = cpl_calloc(3*nxy,sizeof(*isbad));
565  xptr1 = work;
566  yptr1 = work + nxy;
567  xptr2 = work + 2*nxy;
568  yptr2 = work + 3*nxy;
569  wptr = work + 4*nxy;
570  isbad = iwork;
571  wptr2 = iwork + nxy;
572 
573  /* Get the data from the table and put it all into double precision
574  arrays */
575 
576  tptr = cpl_table_get_data_float(matchedxy,"X_coordinate_1");
577  for (i = 0; i < nxy; i++)
578  xptr1[i] = (double)tptr[i];
579  tptr = cpl_table_get_data_float(matchedxy,"Y_coordinate_1");
580  for (i = 0; i < nxy; i++)
581  yptr1[i] = (double)tptr[i];
582  tptr = cpl_table_get_data_float(matchedxy,"X_coordinate_2");
583  for (i = 0; i < nxy; i++)
584  xptr2[i] = (double)tptr[i];
585  tptr = cpl_table_get_data_float(matchedxy,"Y_coordinate_2");
586  for (i = 0; i < nxy; i++)
587  yptr2[i] = (double)tptr[i];
588 
589  /* Right, now loop for maximum number of iterations or until
590  convergence */
591 
592  niter = 0;
593  while (niter >= 0) {
594 
595  /* Do a plate solution */
596 
597  switch (nconst) {
598  case 6:
599  *status = vircam_plate6(xptr2,yptr2,xptr1,yptr1,isbad,nxy,&a,&b,
600  &c,&e,&d,&f);
601  break;
602  case 4:
603  *status = vircam_plate4(xptr2,yptr2,xptr1,yptr1,isbad,nxy,&a,&b,
604  &c,&e,&d,&f);
605  break;
606  default:
607  *status = vircam_plate6(xptr2,yptr2,xptr1,yptr1,isbad,nxy,&a,&b,
608  &c,&e,&d,&f);
609  break;
610  }
611  if (*status != VIR_OK) {
612  cpl_msg_error(fctid,"Plate constant solution failed");
613  tidy();
614  FATAL_ERROR
615  }
616 
617  /* Now look at the residuals and see if any should be rejected */
618 
619  for (i = 0; i < nxy; i++) {
620  xfit = xptr2[i]*a + yptr2[i]*b + c;
621  yfit = xptr2[i]*d + yptr2[i]*e + f;
622  dx = fabs(xfit - xptr1[i]);
623  dy = fabs(yfit - yptr1[i]);
624  wptr[i*2] = dx;
625  wptr[i*2+1] = dy;
626  wptr2[i*2] = isbad[i];
627  wptr2[i*2+1] = isbad[i];
628  }
629  averr = vircam_dmed(wptr,wptr2,2*nxy);
630  averr *= 1.48;
631  if (niter == 3)
632  break;
633  nrej = 0;
634  ngood = 0;
635  for (i = 0; i < nxy; i++) {
636  if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) nrej++;
637  if (!isbad[i])
638  ngood++;
639  }
640  ngood -= nrej;
641  if (nrej == 0 || ngood < nconst)
642  break;
643  for (i = 0; i < nxy; i++) {
644  if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) isbad[i] = 1;
645  }
646  niter++;
647  }
648 
649  /* Set the output array */
650 
651  *coefs = cpl_array_new(6,CPL_TYPE_DOUBLE);
652  cc = cpl_array_get_data_double(*coefs);
653  cc[0] = a;
654  cc[1] = b;
655  cc[2] = c;
656  cc[3] = d;
657  cc[4] = e;
658  cc[5] = f;
659 
660  /* Right, get out of here now... */
661 
662  tidy();
663  GOOD_STATUS
664 }
665 
666 /*---------------------------------------------------------------------------*/
700 /*---------------------------------------------------------------------------*/
701 
702 static int vircam_plate6(double *xpos, double *ypos, double *xi, double *eta,
703  unsigned char *flag, int nstds, double *a, double *b,
704  double *c, double *d, double *e, double *f) {
705  double sx1sq,sy1sq,sx1y1,sx1x2,sy1x2;
706  double sy1y2,sx1y2,xposmean,yposmean,ximean,etamean,xx1,yy1,xx2,yy2;
707  int i,ngood,nbad;
708 
709  /* Is it worthwhile even being here? */
710 
711  (void)vircam_sumbpm(flag,nstds,&nbad);
712  ngood = nstds - nbad;
713  if (ngood < 2)
714  return(VIR_FATAL);
715 
716  /* Initialise all the counters and summations */
717 
718  sx1sq = 0.0;
719  sy1sq = 0.0;
720  sx1y1 = 0.0;
721  sx1x2 = 0.0;
722  sy1x2 = 0.0;
723  sy1y2 = 0.0;
724  sx1y2 = 0.0;
725  xposmean = 0.0;
726  yposmean = 0.0;
727  ximean = 0.0;
728  etamean = 0.0;
729 
730  /* Find means in each coordinate system */
731 
732  xposmean = vircam_dmean(xpos,flag,nstds);
733  yposmean = vircam_dmean(ypos,flag,nstds);
734  ximean = vircam_dmean(xi,flag,nstds);
735  etamean = vircam_dmean(eta,flag,nstds);
736 
737  /* Now accumulate the sums */
738 
739  for (i = 0; i < nstds; i++) {
740  if (!flag[i]) {
741  xx1 = xpos[i] - xposmean;
742  yy1 = ypos[i] - yposmean;
743  xx2 = xi[i] - ximean;
744  yy2 = eta[i] - etamean;
745  sx1sq += xx1*xx1;
746  sy1sq += yy1*yy1;
747  sx1y1 += xx1*yy1;
748  sx1x2 += xx1*xx2;
749  sy1x2 += yy1*xx2;
750  sy1y2 += yy1*yy2;
751  sx1y2 += xx1*yy2;
752  }
753  }
754 
755  /* Do solution for X */
756 
757  *a = (sx1y1*sy1x2 - sx1x2*sy1sq)/(sx1y1*sx1y1 - sx1sq*sy1sq);
758  *b = (sx1x2*sx1y1 - sx1sq*sy1x2)/(sx1y1*sx1y1 - sx1sq*sy1sq);
759  *c = -xposmean*(*a) - yposmean*(*b) + ximean;
760 
761  /* Now the solution for Y */
762 
763  *d = (sx1y1*sx1y2 - sy1y2*sx1sq)/(sx1y1*sx1y1 - sy1sq*sx1sq);
764  *e = (sy1y2*sx1y1 - sy1sq*sx1y2)/(sx1y1*sx1y1 - sy1sq*sx1sq);
765  *f = -xposmean*(*e) - yposmean*(*d) + etamean;
766 
767  /* Get outta here */
768 
769  return(VIR_OK);
770 }
771 
772 /*---------------------------------------------------------------------------*/
806 /*---------------------------------------------------------------------------*/
807 
808 static int vircam_plate4(double *xpos, double *ypos, double *xi, double *eta,
809  unsigned char *flag, int nstds, double *a, double *b,
810  double *c, double *d, double *e, double *f) {
811  double sx1sq,sy1sq,sx1x2,sy1x2,sy1y2,sx1y2,xposmean,yposmean;
812  double ximean,etamean,xx1,yy1,xx2,yy2,det,num,denom,theta,mag;
813  double stheta,ctheta;
814  int i,ngood,nbad;
815 
816  /* Is it worthwhile even being here? */
817 
818  (void)vircam_sumbpm(flag,nstds,&nbad);
819  ngood = nstds - nbad;
820  if (ngood < 2)
821  return(VIR_FATAL);
822 
823  /* Initialise all the counters and summations */
824 
825  sx1sq = 0.0;
826  sy1sq = 0.0;
827  sx1x2 = 0.0;
828  sy1x2 = 0.0;
829  sy1y2 = 0.0;
830  sx1y2 = 0.0;
831  xposmean = 0.0;
832  yposmean = 0.0;
833  ximean = 0.0;
834  etamean = 0.0;
835 
836  /* Find means in each coordinate system */
837 
838  xposmean = vircam_dmean(xpos,flag,nstds);
839  yposmean = vircam_dmean(ypos,flag,nstds);
840  ximean = vircam_dmean(xi,flag,nstds);
841  etamean = vircam_dmean(eta,flag,nstds);
842 
843  /* Now accumulate the sums */
844 
845  for (i = 0; i < nstds; i++) {
846  if (!flag[i]) {
847  xx1 = xpos[i] - xposmean;
848  yy1 = ypos[i] - yposmean;
849  xx2 = xi[i] - ximean;
850  yy2 = eta[i] - etamean;
851  sx1sq += xx1*xx1;
852  sy1sq += yy1*yy1;
853  sx1x2 += xx1*xx2;
854  sy1x2 += yy1*xx2;
855  sy1y2 += yy1*yy2;
856  sx1y2 += xx1*yy2;
857  }
858  }
859 
860  /* Compute the rotation angle */
861 
862  det = sx1x2*sy1y2 - sy1x2*sx1y2;
863  if (det < 0.0) {
864  num = sy1x2 + sx1y2;
865  denom = -sx1x2 + sy1y2;
866  } else {
867  num = sy1x2 - sx1y2;
868  denom = sx1x2 + sy1y2;
869  }
870  if (num == 0.0 && denom == 0.0) {
871  theta = 0.0;
872  } else {
873  theta = atan2(num,denom);
874  if (theta < 0.0)
875  theta += CPL_MATH_2PI;
876  }
877 
878  /* Compute magnification factor */
879 
880  ctheta = cos(theta);
881  stheta = sin(theta);
882  num = denom*ctheta + num*stheta;
883  denom = sx1sq + sy1sq;
884  if (denom <= 0.0) {
885  mag = 1.0;
886  } else {
887  mag = num/denom;
888  }
889 
890  /* Compute coeffs */
891 
892  if (det < 0.0) {
893  *a = -mag*ctheta;
894  *e = mag*stheta;
895  } else {
896  *a = mag*ctheta;
897  *e = -mag*stheta;
898  }
899  *b = mag*stheta;
900  *d = mag*ctheta;
901  *c = -xposmean*(*a) - yposmean*(*b) + ximean;
902  *f = -xposmean*(*e) - yposmean*(*d) + etamean;
903 
904  /* Get outta here */
905 
906  return(VIR_OK);
907 }
908 
909 static void tidy(void) {
910 
911  freespace(work);
912  freespace(iwork);
913 }
914 
918 /*
919 
920 $Log: not supported by cvs2svn $
921 Revision 1.31 2012/01/15 17:40:09 jim
922 Minor modifications to take into accout the changes in cpl API for v6
923 
924 Revision 1.30 2010/06/30 12:42:00 jim
925 A few fixes to stop compiler compaints
926 
927 Revision 1.29 2010/06/07 12:42:40 jim
928 Modifications to get rid of compiler gripes
929 
930 Revision 1.28 2009/12/11 06:53:35 jim
931 Minor changes to documentation
932 
933 Revision 1.27 2009/09/09 09:47:55 jim
934 uses CPL defined macros for constants
935 
936 Revision 1.26 2009/05/20 12:21:01 jim
937 Fixed to update TCRVL values when the tangent point is shifted
938 
939 Revision 1.25 2008/11/25 06:22:33 jim
940 Added prologue for vircam_platexy
941 
942 Revision 1.24 2008/11/21 10:12:10 jim
943 Added vircam_platexy
944 
945 Revision 1.23 2008/10/21 08:42:28 jim
946 Fixed some declarations to make them constant
947 
948 Revision 1.22 2008/07/10 13:05:53 jim
949 Modified to use v4.2 version of cpl_wcs
950 
951 Revision 1.21 2008/05/06 08:40:10 jim
952 Modified to use cpl_wcs interface
953 
954 Revision 1.20 2008/01/22 19:46:10 jim
955 Fixed sign error in plate4
956 
957 Revision 1.19 2007/10/25 17:34:01 jim
958 Modified to remove lint warnings
959 
960 Revision 1.18 2007/05/03 11:15:33 jim
961 Fixed little problem with table wcs
962 
963 Revision 1.17 2007/05/02 09:12:30 jim
964 Modified to update table header WCS keywords
965 
966 Revision 1.16 2007/03/29 12:19:39 jim
967 Little changes to improve documentation
968 
969 Revision 1.15 2007/03/01 12:42:42 jim
970 Modified slightly after code checking
971 
972 Revision 1.14 2007/01/17 23:54:01 jim
973 Plugged some memory leaks
974 
975 Revision 1.13 2007/01/08 19:12:03 jim
976 Fixed shear comment so that it doesn't overflow
977 
978 Revision 1.12 2006/10/02 13:43:50 jim
979 Added missing .h file
980 
981 Revision 1.11 2006/08/11 12:45:41 jim
982 Modified to use wcslib
983 
984 Revision 1.10 2006/06/14 14:33:31 jim
985 Fixed units of WCS_SCALE
986 
987 Revision 1.9 2006/06/13 14:09:38 jim
988 Made some of the QC header values single precision
989 
990 Revision 1.8 2006/06/09 11:26:26 jim
991 Small changes to keep lint happy
992 
993 Revision 1.7 2006/05/26 15:05:46 jim
994 Fixed column names for input table
995 
996 Revision 1.6 2006/03/23 21:18:53 jim
997 Minor changes mainly to comment headers
998 
999 Revision 1.5 2006/03/22 14:05:37 jim
1000 fixed a little bug
1001 
1002 Revision 1.4 2006/03/22 13:58:32 jim
1003 Cosmetic fixes to keep lint happy
1004 
1005 Revision 1.3 2006/03/15 10:43:41 jim
1006 Fixed a few things
1007 
1008 Revision 1.2 2006/02/22 14:19:52 jim
1009 Modified to check for the existence of the columns in the matched standards
1010 table.
1011 
1012 Revision 1.1 2006/02/18 11:52:34 jim
1013 new file
1014 
1015 
1016 */