Kstars

nomadbinfile2mysql.cpp
1 /*
2  SPDX-FileCopyrightText: 2011 Akarsh Simha <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 /*
8  * NOTE: I modified nomadbinfiletester.c to do this -- Akarsh
9  */
10 
11 /*
12  * TODO: VERY UGLY CODE. Please fix it some day. Preferably now. This
13  * file was created from a modified C file, and needs to be recast
14  * into the C++ way of writing stuff, i.e. with classes etc.
15  */
16 
17 #include "nomadbinfile2mysql.h"
18 #include "binfile.h"
19 #include "angconversion.h"
20 #include "MeshIterator.h"
21 #include <iostream>
22 #include <string.h>
23 #include <stdio.h>
24 
25 using namespace std;
26 
27 NOMADStarDataWriter::NOMADStarDataWriter(FILE *f, int HTMLevel, MYSQL *link, char *_db_tbl)
28 {
29  m_MySQLLink = link;
30  DataFile = f;
31  // Create a new shiny HTMesh
32  m_Mesh = new HTMesh(HTMLevel, HTMLevel);
33  strcpy(db_tbl, _db_tbl);
34  m_HeaderRead = false;
35 }
36 
38 {
39  delete m_Mesh;
40 }
41 
43 {
44  stardata->RA = bswap_32(stardata->RA);
45  stardata->Dec = bswap_32(stardata->Dec);
46  stardata->dRA = bswap_16(stardata->dRA);
47  stardata->dDec = bswap_16(stardata->dDec);
48  stardata->B = bswap_16(stardata->B);
49  stardata->V = bswap_16(stardata->V);
50 }
51 
52 /**
53  *@short Create the table
54  */
55 bool NOMADStarDataWriter::createTable()
56 {
57  // TODO: This is not working. Investigate.
58  char create_query[2048];
59  sprintf(create_query,
60  "CREATE TABLE IF NOT EXISTS `%s` (`Trixel` int(32) NOT NULL COMMENT 'Trixel Number', `RA` double NOT NULL "
61  "COMMENT 'RA Hours', `Dec` double NOT NULL COMMENT 'Declination Degrees', `dRA` double NOT NULL COMMENT "
62  "'Proper Motion along RA', `dDec` double NOT NULL COMMENT 'Proper Motion along Dec', `PM` double NOT NULL "
63  "COMMENT 'Proper Motion (magnitude)', `V` float NOT NULL COMMENT 'Visual Magnitude', `B` float NOT NULL "
64  "COMMENT 'Blue Magnitude', `Mag` float NOT NULL COMMENT 'Magnitude for sorting', `UID` int(64) NOT NULL "
65  "auto_increment COMMENT 'Unique ID', `Copies` tinyint(8) NOT NULL COMMENT 'Number of Copies of the star', "
66  "PRIMARY KEY (`UID`), UNIQUE KEY `UID` (`UID`), KEY `Trixel` (`Trixel`,`PM`,`Mag`)) ENGINE=MyISAM DEFAULT "
67  "CHARSET=latin1 AUTO_INCREMENT=1",
68  db_tbl);
69 
70  if (mysql_query(m_MySQLLink, create_query))
71  {
72  cerr << "ERROR: Table creation failed!" << endl;
73  return false;
74  }
75  return true;
76 }
77 
78 /**
79  *@short Calculate the final destination RA and Dec of a star with the
80  *given initial RA, Dec and proper motion rates after 'years' number
81  *of years
82  */
83 void NOMADStarDataWriter::calculatePMCoords(double startRA, double startDec, double dRA, double dDec, double *endRA,
84  double *endDec, float years)
85 {
86  // (Translated from Perl)
87  double theta0 = hour2rad(startRA);
88  double lat0 = deg2rad(startDec);
89 
90  double PMperyear = sqrt(dRA * dRA + dDec * dDec);
91 
92  double dir0 = (years > 0.0) ? atan2(dRA, dDec) : atan2(-dRA, -dDec); // If years < 0, we're precessing backwards
93  double PM = PMperyear * fabs(years);
94 
95  double dst = deg2rad(arcsec2deg(PM / 1000.0)); // Milliarcsecond -> radian
96 
97  double phi0 = M_PI / 2.0 - lat0;
98 
99  double lat1 = asin(sin(lat0) * cos(dst) + cos(lat0) * sin(dst) * cos(dir0)); // Cosine rule on a sphere
100  double dtheta = atan2(sin(dir0) * sin(dst) * cos(lat0), cos(dst) - sin(lat0) * sin(lat1));
101 
102  *endRA = rad2hour(theta0 + dtheta);
103  *endDec = rad2deg(lat1);
104 }
105 
106 /**
107  *@short Do some calculations and insert the star data into the database
108  */
109 bool NOMADStarDataWriter::insertStarData(unsigned int trixel, const DeepStarData *const data)
110 {
111  char query[2048];
112  float mag;
113  float B, V, RA, Dec, dRA, dDec;
114 
115  // Rescale the data from the structure
116  B = ((double)data->B) / 1000.0;
117  V = ((double)data->V) / 1000.0;
118  RA = ((double)data->RA) / 1000000.0;
119  Dec = ((double)data->Dec) / 100000.0;
120  dRA = ((double)data->dRA) / 1000.0;
121  dDec = ((double)data->dDec) / 1000.0;
122 
123  // Check if the supplied trixel is really the trixel in which the
124  // star is in according to its RA and Dec. If that's not the case,
125  // this star is a duplicate and must be ignored
126  unsigned int originalTrixelID = m_Mesh->index(RA, Dec);
127  if (trixel != originalTrixelID)
128  return true; // Ignore this star.
129 
130  // Magnitude for sorting.
131  if (V == 30.0 && B != 30.0)
132  {
133  mag = B - 1.6;
134  }
135  else
136  {
137  mag = V;
138  }
139 
140  // Compute the proper motion
141  double RA1, Dec1, RA2, Dec2;
142  double PM; // Magnitude of the proper motion in milliarcseconds per year
143 
144  PM = sqrt(dRA * dRA + dDec * dDec);
145 
146  calculatePMCoords(RA, Dec, dRA, dDec, &RA1, &Dec1, PM_MILLENIA * -1000.);
147  calculatePMCoords(RA, Dec, dRA, dDec, &RA2, &Dec2, PM_MILLENIA * 1000.);
148 
149  unsigned int TrixelList[900];
150  int ntrixels = 0;
151 
152  double separation = sqrt(hour2deg(RA1 - RA2) * hour2deg(RA1 - RA2) +
153  (Dec1 - Dec2) * (Dec1 - Dec2)); // Separation in degrees // ugly.
154  if (separation > 50.0 / 60.0) // 50 arcminutes
155  {
156  m_Mesh->intersect(RA1, Dec1, RA2, Dec2);
157  MeshIterator trixels(m_Mesh);
158  while (trixels.hasNext())
159  {
160  TrixelList[ntrixels] = trixels.next();
161  ntrixels++;
162  }
163  }
164  else
165  {
166  TrixelList[0] = originalTrixelID;
167  ntrixels = 1;
168  }
169 
170  if (ntrixels == 0)
171  {
172  cerr << "Ntrixels is zero in trixel " << originalTrixelID;
173  return false;
174  }
175 
176  for (int i = 0; i < ntrixels; ++i)
177  {
178  sprintf(query,
179  "INSERT INTO `%s` (`Trixel`, `RA`, `Dec`, `dRA`, `dDec`, `B`, `V`, `mag`, `PM`, `Copies`) VALUES "
180  "(\'%d\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%u\')",
181  db_tbl, TrixelList[i], RA, Dec, dRA, dDec, B, V, mag, PM,
182  ((TrixelList[i] == originalTrixelID) ?
183  ntrixels :
184  0) // Duplicates get a 'Copies' value of 0. The real star gets the actual value.
185  );
186  if (mysql_query(m_MySQLLink, query))
187  {
188  cerr << "MySQL INSERT INTO failed! Query was: " << endl << query << endl;
189  return false;
190  }
191  }
192  return true;
193 }
194 
195 bool NOMADStarDataWriter::truncateTable()
196 {
197  // Truncate table. TODO: Issue warning etc
198  char query[60];
199  sprintf(query, "TRUNCATE TABLE `%s`", db_tbl);
200  if (mysql_query(m_MySQLLink, query))
201  {
202  cerr << "Truncate table query \"" << query << "\" failed!" << endl;
203  return false;
204  }
205  return true;
206 }
207 
208 /**
209  *@short Write star data to the database
210  */
211 bool NOMADStarDataWriter::writeStarDataToDB()
212 {
213  int8_t HTM_Level;
214  u_int16_t MSpT;
215  u_int32_t nstars;
216  u_int32_t offset;
217  unsigned int trixel;
218  DeepStarData data;
219  int16_t mag;
220 
221  /*
222  // TODO: FIX THIS // FIXME
223  // We must at least check if the HTM level matches
224  fseek( DataFile, m_IndexOffset - 3, SEEK_SET );
225  fread( &HTM_Level, 1, 1, DataFile );
226  fprintf( stdout, "HTMesh Level: %d\n", HTM_Level );
227  if( HTM_Level != m_Mesh->level() ) {
228  cerr << "ERROR: HTMesh Level in file (" << HTM_Level << ") and HTM_LEVEL in program (" << m_Mesh->level() << ") differ." << endl
229  << "Please set the define directive for HTM_LEVEL in the header file correctly and rebuild."
230  << endl;
231  return false;
232  }
233  */
234 
235  for (trixel = 0; trixel < ntrixels; ++trixel)
236  {
237  fseek(DataFile, m_IndexOffset + trixel * INDEX_ENTRY_SIZE + 4, SEEK_SET);
238  fread(&offset, 4, 1, DataFile);
239  fread(&nstars, 4, 1, DataFile);
240 
241  /* If offset > 2^31 - 1, do the fseek in two steps */
242  if (offset > (unsigned)(pow2(31) - 1))
243  {
244  fseek(DataFile, pow2(31) - 1, SEEK_SET);
245  fseek(DataFile, offset - pow2(31) + 1, SEEK_CUR);
246  }
247  else
248  fseek(DataFile, offset, SEEK_SET);
249 
250  for (int i = 0; i < nstars; ++i)
251  {
252  fread(&data, sizeof(DeepStarData), 1, DataFile);
253  if (byteswap)
254  bswap_stardata(&data);
255 
256  /** CODE FROM INSERTSTARDATA PASTED HERE FOR SPEED */
257  {
258  char query[2048];
259  float mag;
260  float B, V, RA, Dec, dRA, dDec;
261 
262  // Rescale the data from the structure
263  B = ((double)data.B) / 1000.0;
264  V = ((double)data.V) / 1000.0;
265  RA = ((double)data.RA) / 1000000.0;
266  Dec = ((double)data.Dec) / 100000.0;
267  dRA = ((double)data.dRA) / 1000.0;
268  dDec = ((double)data.dDec) / 1000.0;
269 
270  // Check if the supplied trixel is really the trixel in which the
271  // star is in according to its RA and Dec. If that's not the case,
272  // this star is a duplicate and must be ignored
273  unsigned int originalTrixelID = m_Mesh->index(hour2deg(RA), Dec);
274  if (trixel != originalTrixelID)
275  {
276  cout << "Trixel = " << trixel << ", but this is the original Trixel ID: " << originalTrixelID
277  << ". Skipping" << endl;
278  cout << "Skipped star has (RA, Dec) = " << RA << Dec << "; (dRA, dDec) = " << dRA << dDec
279  << "; and (B, V) = " << B << V << "." << endl;
280  cout << "This suspected duplicate is star " << i << "in trixel " << trixel;
281  continue;
282  }
283 
284  // Magnitude for sorting.
285  if (V == 30.0 && B != 30.0)
286  {
287  mag = B - 1.6;
288  }
289  else
290  {
291  mag = V;
292  }
293 
294  // Compute the proper motion
295  double RA1, Dec1, RA2, Dec2, RA1deg, RA2deg;
296  double PM; // Magnitude of the proper motion in milliarcseconds per year
297 
298  PM = sqrt(dRA * dRA + dDec * dDec);
299 
300  calculatePMCoords(RA, Dec, dRA, dDec, &RA1, &Dec1, PM_MILLENIA * -1000.);
301  calculatePMCoords(RA, Dec, dRA, dDec, &RA2, &Dec2, PM_MILLENIA * 1000.);
302  RA1deg = hour2deg(RA1);
303  RA2deg = hour2deg(RA2);
304 
305  unsigned int TrixelList[60];
306  int nt = 0;
307 
308  double separationsqr = (RA1deg - RA2deg) * (RA1deg - RA2deg) +
309  (Dec1 - Dec2) * (Dec1 - Dec2); // Separation in degrees // ugly.
310  if (separationsqr >
311  0.69) // 50 arcminutes converted to degrees, squared and rounded below = 0.69. (This has nothing to do with sex positions.)
312  {
313  m_Mesh->intersect(RA1deg, Dec1, RA2deg, Dec2);
314  MeshIterator trixels(m_Mesh);
315  while (trixels.hasNext())
316  {
317  TrixelList[nt] = trixels.next();
318  nt++;
319  }
320  }
321  else
322  {
323  TrixelList[0] = originalTrixelID;
324  nt = 1;
325  }
326 
327  if (nt == 0)
328  {
329  cerr << "# of trixels is zero in trixel " << originalTrixelID;
330  return false;
331  }
332 
333  for (int i = 0; i < nt; ++i)
334  {
335  sprintf(query,
336  "INSERT INTO `%s` (`Trixel`, `RA`, `Dec`, `dRA`, `dDec`, `B`, `V`, `mag`, `PM`, `Copies`) "
337  "VALUES (\'%d\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', "
338  "\'%u\')",
339  db_tbl, TrixelList[i], RA, Dec, dRA, dDec, B, V, mag, PM,
340  ((TrixelList[i] == originalTrixelID) ?
341  nt :
342  0) // Duplicates get a 'Copies' value of 0. The real star gets the actual value.
343  );
344  if (mysql_query(m_MySQLLink, query))
345  {
346  cerr << "MySQL INSERT INTO failed! Query was: " << endl << query << endl;
347  return false;
348  }
349  }
350  }
351  }
352  if (trixel % 100 == 0)
353  cout << "Finished trixel " << trixel << endl;
354  }
355 
356  return true;
357 }
358 
359 bool NOMADStarDataWriter::readFileHeader()
360 {
361  int i;
362  int16_t endian_id;
363  char ASCII_text[125];
364  u_int8_t version_no;
365  u_int16_t nfields;
366 
367  if (!DataFile)
368  return false;
369 
370  fread(ASCII_text, 124, 1, DataFile);
371  ASCII_text[124] = '\0';
372  printf("%s", ASCII_text);
373 
374  fread(&endian_id, 2, 1, DataFile);
375  if (endian_id != 0x4B53)
376  {
377  fprintf(stdout, "Byteswapping required\n");
378  byteswap = 1;
379  }
380  else
381  {
382  fprintf(stdout, "Byteswapping not required\n");
383  byteswap = 0;
384  }
385 
386  fread(&version_no, 1, 1, DataFile);
387  fprintf(stdout, "Version number: %d\n", version_no);
388 
389  fread(&nfields, 2, 1, DataFile);
390 
391  // Just to read those many bytes
392  // TODO: Don't waste time and memory. fseek.
393  dataElement de;
394  for (i = 0; i < nfields; ++i)
395  fread(&de, sizeof(struct dataElement), 1, DataFile);
396 
397  fread(&ntrixels, 4, 1, DataFile);
398  if (byteswap)
399  ntrixels = bswap_32(ntrixels);
400  fprintf(stdout, "Number of trixels reported = %d\n", ntrixels);
401 
402  m_IndexOffset = ftell(DataFile);
403 
404  m_HeaderRead = true;
405 
406  return true;
407 }
408 
410 {
411  if (!readFileHeader())
412  return false;
413  if (!createTable())
414  return false;
415  truncateTable();
416  if (!writeStarDataToDB())
417  return false;
418 }
419 
420 int main(int argc, char *argv[])
421 {
422  MYSQL link;
423  FILE *f;
424  char db_tbl[20];
425  char db_name[20];
426 
427  if (argc <= 5)
428  {
429  fprintf(stderr, "USAGE: %s <NOMAD bin file> <MySQL DB User> <Password> <DB Name> <Table Name>\n", argv[0]);
430  return 1;
431  }
432 
433  strcpy(db_tbl, argv[5]);
434  strcpy(db_name, argv[4]);
435 
436  f = fopen(argv[1], "r");
437 
438  if (f == nullptr)
439  {
440  fprintf(stderr, "ERROR: Could not open file %s for binary read.\n", argv[1]);
441  return 1;
442  }
443 
444  /* Open the Database */
445  if (mysql_init(&link) == nullptr)
446  {
447  fprintf(stderr, "ERROR: Failed to initialize MySQL connection!\n");
448  return 1;
449  }
450  MYSQL *ret;
451  ret = mysql_real_connect(&link, "localhost", argv[2], argv[3], db_name, 0, nullptr, 0);
452 
453  if (!ret)
454  {
455  fprintf(stderr, "ERROR: MySQL connect failed for the following reason: %s\n", mysql_error(&link));
456  fcloseall();
457  return 1;
458  }
459 
460  if (mysql_select_db(&link, db_name))
461  {
462  fprintf(stderr, "ERROR: Could not select MySQL database %s. MySQL said: %s", db_name, mysql_error(&link));
463  fcloseall();
464  mysql_close(&link);
465  return 1;
466  }
467 
468  NOMADStarDataWriter writer(f, HTM_LEVEL, &link, db_tbl);
469 
470  writer.write();
471 
472  fclose(f);
473  mysql_close(&link);
474  return 0;
475 }
QTextStream & endl(QTextStream &stream)
bool write()
Writes the star data into the DB by calling multiple functions.
static void bswap_stardata(DeepStarData *stardata)
Byteswaps the DeepStarData structure.
Definition: HTMesh.h:56
Writes NOMAD star data.
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
FILE * fopen(const QString &pathname, const char *mode)
NOMADStarDataWriter(FILE *f, int HTMLevel, MYSQL *link, char *_db_tbl)
Constructor.
A 16-byte structure that holds star data for really faint stars.
A structure describing a data field in the binary file.
Definition: binfilehelper.h:19
static void calculatePMCoords(double startRA, double startDec, double dRA, double dDec, double *endRA, double *endDec, float years)
Computes the (unprecessed) coordinates of a star after accounting for proper motion.
~NOMADStarDataWriter()
Destructor.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Aug 8 2022 04:13:23 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.