Kstars

nomadbinfile2mysql.cpp
1/*
2 SPDX-FileCopyrightText: 2011 Akarsh Simha <akarshsimha@gmail.com>
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
25using namespace std;
26
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
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 */
55bool NOMADStarDataWriter::createTable()
56{
57 // TODO: This is not working. Investigate.
58 char create_query[2048];
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 */
83void 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 */
109bool 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 {
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,
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
195bool 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 */
211bool NOMADStarDataWriter::writeStarDataToDB()
212{
213 int8_t HTM_Level;
214 u_int16_t MSpT;
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 {
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,
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
359bool 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.
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
420int 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}
HTMesh was originally intended to be a simple interface to the HTM library for the KStars project tha...
Definition HTMesh.h:57
Trixel index(double ra, double dec) const
returns the index of the trixel that contains the specified point.
Definition HTMesh.cpp:72
void intersect(double ra, double dec, double radius, BufNum bufNum=0)
NOTE: The intersect() routines below are all used to find the trixels needed to cover a geometric obj...
Definition HTMesh.cpp:104
MeshIterator is a very lightweight class used to iterate over the result set of an HTMesh intersectio...
Writes NOMAD star data.
static void bswap_stardata(DeepStarData *stardata)
Byteswaps the DeepStarData structure.
NOMADStarDataWriter(FILE *f, int HTMLevel, MYSQL *link, char *_db_tbl)
Constructor.
bool write()
Writes the star data into the DB by calling multiple functions.
~NOMADStarDataWriter()
Destructor.
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.
std::optional< QSqlQuery > query(const QString &queryStatement)
QTextStream & endl(QTextStream &stream)
A 16-byte structure that holds star data for really faint stars.
A structure describing a data field in the binary file.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:48:25 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.