Warning, file /education/kstars/kstars/skycomponents/starcomponent.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2005 Thomas Kabelmann <thomas.kabelmann@gmx.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "starcomponent.h" 0008 0009 #include "binfilehelper.h" 0010 #include "deepstarcomponent.h" 0011 #include "highpmstarlist.h" 0012 #ifndef KSTARS_LITE 0013 #include "kstars.h" 0014 #endif 0015 #include "kstarsdata.h" 0016 #include "kstarssplash.h" 0017 #include "Options.h" 0018 #include "skylabeler.h" 0019 #include "skymap.h" 0020 #include "skymesh.h" 0021 #ifndef KSTARS_LITE 0022 #include "skyqpainter.h" 0023 #endif 0024 #include "htmesh/MeshIterator.h" 0025 #include "projections/projector.h" 0026 0027 #include "kstars_debug.h" 0028 0029 #include <qplatformdefs.h> 0030 0031 #ifdef _WIN32 0032 #include <windows.h> 0033 #endif 0034 0035 #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) 0036 #include <sys/endian.h> 0037 #define bswap_16(x) bswap16(x) 0038 #define bswap_32(x) bswap32(x) 0039 #else 0040 #include "byteorder.h" 0041 #endif 0042 0043 // Qt version calming 0044 #include <qtskipemptyparts.h> 0045 0046 StarComponent *StarComponent::pinstance = nullptr; 0047 0048 StarComponent::StarComponent(SkyComposite *parent) 0049 : ListComponent(parent), m_reindexNum(J2000) 0050 { 0051 m_skyMesh = SkyMesh::Instance(); 0052 m_StarBlockFactory = StarBlockFactory::Instance(); 0053 0054 m_starIndex.reset(new StarIndex()); 0055 for (int i = 0; i < m_skyMesh->size(); i++) 0056 m_starIndex->append(new StarList()); 0057 m_highPMStars.append(new HighPMStarList(840.0)); 0058 m_highPMStars.append(new HighPMStarList(304.0)); 0059 m_reindexInterval = StarObject::reindexInterval(304.0); 0060 0061 for (int i = 0; i <= MAX_LINENUMBER_MAG; i++) 0062 m_labelList[i] = new LabelList; 0063 0064 // Actually load data 0065 emitProgressText(i18n("Loading stars")); 0066 0067 loadStaticData(); 0068 // Load any deep star catalogs that are available 0069 loadDeepStarCatalogs(); 0070 0071 // The following works but can cause crashes sometimes 0072 //QtConcurrent::run(this, &StarComponent::loadDeepStarCatalogs); 0073 0074 //In KStars Lite star images are initialized in SkyMapLite 0075 #ifndef KSTARS_LITE 0076 SkyQPainter::initStarImages(); 0077 #endif 0078 } 0079 0080 StarComponent::~StarComponent() 0081 { 0082 qDeleteAll(*m_starIndex); 0083 m_starIndex->clear(); 0084 qDeleteAll(m_DeepStarComponents); 0085 m_DeepStarComponents.clear(); 0086 qDeleteAll(m_highPMStars); 0087 m_highPMStars.clear(); 0088 for (int i = 0; i <= MAX_LINENUMBER_MAG; i++) 0089 delete m_labelList[i]; 0090 } 0091 0092 StarComponent *StarComponent::Create(SkyComposite *parent) 0093 { 0094 delete pinstance; 0095 pinstance = new StarComponent(parent); 0096 return pinstance; 0097 } 0098 0099 bool StarComponent::selected() 0100 { 0101 return Options::showStars(); 0102 } 0103 0104 bool StarComponent::addDeepStarCatalogIfExists(const QString &fileName, float trigMag, bool staticstars) 0105 { 0106 if (BinFileHelper::testFileExists(fileName)) 0107 { 0108 m_DeepStarComponents.append(new DeepStarComponent(parent(), fileName, trigMag, staticstars)); 0109 return true; 0110 } 0111 return false; 0112 } 0113 0114 int StarComponent::loadDeepStarCatalogs() 0115 { 0116 // Look for the basic unnamed star catalog to mag 8.0 0117 if (!addDeepStarCatalogIfExists("unnamedstars.dat", -5.0, true)) 0118 return 0; 0119 0120 // Look for the Tycho-2 add-on with 2.5 million stars to mag 12.5 0121 if (!addDeepStarCatalogIfExists("tycho2.dat", 8.0) && !addDeepStarCatalogIfExists("deepstars.dat", 8.0)) 0122 return 1; 0123 0124 // Look for the USNO NOMAD 1e8 star catalog add-on with stars to mag 16 0125 if (!addDeepStarCatalogIfExists("USNO-NOMAD-1e8.dat", 11.0)) 0126 return 2; 0127 0128 return 3; 0129 } 0130 0131 //This function is empty for a reason; we override the normal 0132 //update function in favor of JiT updates for stars. 0133 void StarComponent::update(KSNumbers *) 0134 { 0135 } 0136 0137 // We use the update hook to re-index all the stars when the date has changed by 0138 // more than 150 years. 0139 0140 bool StarComponent::reindex(KSNumbers *num) 0141 { 0142 if (!num) 0143 return false; 0144 0145 // for large time steps we re-index all points 0146 if (fabs(num->julianCenturies() - m_reindexNum.julianCenturies()) > m_reindexInterval) 0147 { 0148 reindexAll(num); 0149 return true; 0150 } 0151 0152 bool highPM = true; 0153 0154 // otherwise we just re-index fast movers as needed 0155 for (auto &star : m_highPMStars) 0156 highPM &= !(star->reindex(num, m_starIndex.get())); 0157 0158 return !(highPM); 0159 } 0160 0161 void StarComponent::reindexAll(KSNumbers *num) 0162 { 0163 #if 0 0164 if (0 && !m_reindexSplash) 0165 { 0166 m_reindexSplash = new KStarsSplash(i18n("Please wait while re-indexing stars...")); 0167 QObject::connect(KStarsData::Instance(), SIGNAL(progressText(QString)), m_reindexSplash, 0168 SLOT(setMessage(QString))); 0169 0170 m_reindexSplash->show(); 0171 m_reindexSplash->raise(); 0172 return; 0173 } 0174 #endif 0175 0176 qCInfo(KSTARS) << "Re-indexing Stars to year" << 2000.0 + num->julianCenturies() * 100.0; 0177 0178 m_reindexNum = KSNumbers(*num); 0179 m_skyMesh->setKSNumbers(num); 0180 0181 // clear out the old index 0182 for (auto &item : *m_starIndex) 0183 { 0184 item->clear(); 0185 } 0186 0187 // re-populate it from the objectList 0188 for (auto &object : m_ObjectList) 0189 { 0190 StarObject *star = dynamic_cast<StarObject *>(object); 0191 Trixel trixel = m_skyMesh->indexStar(star); 0192 0193 m_starIndex->at(trixel)->append(star); 0194 } 0195 0196 // Let everyone else know we have re-indexed to num 0197 for (auto &star : m_highPMStars) 0198 { 0199 star->setIndexTime(num); 0200 } 0201 0202 //delete m_reindexSplash; 0203 //m_reindexSplash = 0; 0204 } 0205 0206 float StarComponent::faintMagnitude() const 0207 { 0208 float faintmag = m_FaintMagnitude; 0209 0210 for (auto &component : m_DeepStarComponents) 0211 { 0212 if (faintmag < component->faintMagnitude()) 0213 faintmag = component->faintMagnitude(); 0214 } 0215 return faintmag; 0216 } 0217 0218 float StarComponent::zoomMagnitudeLimit() 0219 { 0220 //adjust maglimit for ZoomLevel 0221 double lgmin = log10(MINZOOM); 0222 double lgz = log10(Options::zoomFactor()); 0223 0224 // Old formula: 0225 // float maglim = ( 2.000 + 2.444 * Options::memUsage() / 10.0 ) * ( lgz - lgmin ) + Options::magLimitDrawStarZoomOut(); 0226 0227 /* 0228 Explanation for the following formula: 0229 -------------------------------------- 0230 Estimates from a sample of 125000 stars shows that, magnitude 0231 limit vs. number of stars follows the formula: 0232 nStars = 10^(.45 * maglim + .95) 0233 (A better formula is available here: https://www.aa.quae.nl/en/antwoorden/magnituden.html 0234 which we do not implement for simplicity) 0235 We want to keep the star density on screen a constant. This is directly proportional to the number of stars 0236 and directly proportional to the area on screen. The area is in turn inversely proportional to the square 0237 of the zoom factor ( zoomFactor / MINZOOM ). This means that (taking logarithms): 0238 0.45 * maglim + 0.95 - 2 * log( ZoomFactor ) - log( Star Density ) - log( Some proportionality constant ) 0239 hence the formula. We've gathered together all the constants and set it to 3.5, so as to set the minimum 0240 possible value of maglim to 3.5 0241 */ 0242 0243 // float maglim = 4.444 * ( lgz - lgmin ) + 2.222 * log10( Options::starDensity() ) + 3.5; 0244 0245 // Reducing the slope w.r.t zoom factor to avoid the extremely fast increase in star density with zoom 0246 // that 4.444 gives us (although that is what the derivation gives us) 0247 0248 return 3.5 + 3.7 * (lgz - lgmin) + 2.222 * log10(static_cast<float>(Options::starDensity())); 0249 } 0250 0251 void StarComponent::draw(SkyPainter *skyp) 0252 { 0253 #ifndef KSTARS_LITE 0254 if (!selected()) 0255 return; 0256 0257 SkyMap *map = SkyMap::Instance(); 0258 const Projector *proj = map->projector(); 0259 KStarsData *data = KStarsData::Instance(); 0260 UpdateID updateID = data->updateID(); 0261 0262 bool checkSlewing = (map->isSlewing() && Options::hideOnSlew()); 0263 m_hideLabels = checkSlewing || !(Options::showStarMagnitudes() || Options::showStarNames()); 0264 0265 //shortcuts to inform whether to draw different objects 0266 bool hideFaintStars = checkSlewing && Options::hideStars(); 0267 double hideStarsMag = Options::magLimitHideStar(); 0268 reindex(data->updateNum()); 0269 0270 double lgmin = log10(MINZOOM); 0271 double lgmax = log10(MAXZOOM); 0272 double lgz = log10(Options::zoomFactor()); 0273 0274 double maglim; 0275 m_zoomMagLimit = maglim = zoomMagnitudeLimit(); 0276 0277 double labelMagLim = Options::starLabelDensity() / 5.0; 0278 labelMagLim += (12.0 - labelMagLim) * (lgz - lgmin) / (lgmax - lgmin); 0279 if (labelMagLim > 8.0) 0280 labelMagLim = 8.0; 0281 0282 //Calculate sizeMagLim 0283 // Old formula: 0284 // float sizeMagLim = ( 2.000 + 2.444 * Options::memUsage() / 10.0 ) * ( lgz - lgmin ) + 5.8; 0285 0286 // Using the maglim to compute the sizes of stars reduces 0287 // discernability between brighter and fainter stars at high zoom 0288 // levels. To fix that, we use an "arbitrary" constant in place of 0289 // the variable star density. 0290 // Not using this formula now. 0291 // float sizeMagLim = 4.444 * ( lgz - lgmin ) + 5.0; 0292 0293 float sizeMagLim = zoomMagnitudeLimit(); 0294 if (sizeMagLim > faintMagnitude() * (1 - 1.5 / 16)) 0295 sizeMagLim = faintMagnitude() * (1 - 1.5 / 16); 0296 skyp->setSizeMagLimit(sizeMagLim); 0297 0298 //Loop for drawing star images 0299 0300 MeshIterator region(m_skyMesh, DRAW_BUF); 0301 magLim = maglim; 0302 0303 // If we are hiding faint stars, then maglim is really the brighter of hideStarsMag and maglim 0304 if (hideFaintStars && maglim > hideStarsMag) 0305 maglim = hideStarsMag; 0306 0307 m_StarBlockFactory->drawID = m_skyMesh->drawID(); 0308 0309 int nTrixels = 0; 0310 0311 while (region.hasNext()) 0312 { 0313 ++nTrixels; 0314 Trixel currentRegion = region.next(); 0315 StarList *starList = m_starIndex->at(currentRegion); 0316 0317 for (auto &star : *starList) 0318 { 0319 if (!star) 0320 continue; 0321 0322 float mag = star->mag(); 0323 0324 // break loop if maglim is reached 0325 if (mag > maglim) 0326 break; 0327 0328 if (star->updateID != updateID) 0329 star->JITupdate(); 0330 0331 bool drawn = skyp->drawPointSource(star, mag, star->spchar()); 0332 0333 //FIXME_SKYPAINTER: find a better way to do this. 0334 if (drawn && !(m_hideLabels || mag > labelMagLim)) 0335 addLabel(proj->toScreen(star), star); 0336 } 0337 } 0338 0339 // Draw focusStar if not null 0340 if (focusStar) 0341 { 0342 if (focusStar->updateID != updateID) 0343 focusStar->JITupdate(); 0344 float mag = focusStar->mag(); 0345 skyp->drawPointSource(focusStar, mag, focusStar->spchar()); 0346 } 0347 0348 // Now draw each of our DeepStarComponents 0349 for (auto &component : m_DeepStarComponents) 0350 { 0351 component->draw(skyp); 0352 } 0353 #else 0354 Q_UNUSED(skyp) 0355 #endif 0356 } 0357 0358 void StarComponent::addLabel(const QPointF &p, StarObject *star) 0359 { 0360 int idx = int(star->mag() * 10.0); 0361 if (idx < 0) 0362 idx = 0; 0363 if (idx > MAX_LINENUMBER_MAG) 0364 idx = MAX_LINENUMBER_MAG; 0365 m_labelList[idx]->append(SkyLabel(p, star)); 0366 } 0367 0368 void StarComponent::drawLabels() 0369 { 0370 if (m_hideLabels) 0371 return; 0372 0373 SkyLabeler *labeler = SkyLabeler::Instance(); 0374 labeler->setPen(QColor(KStarsData::Instance()->colorScheme()->colorNamed("SNameColor"))); 0375 0376 int max = int(m_zoomMagLimit * 10.0); 0377 if (max < 0) 0378 max = 0; 0379 if (max > MAX_LINENUMBER_MAG) 0380 max = MAX_LINENUMBER_MAG; 0381 0382 for (int i = 0; i <= max; i++) 0383 { 0384 LabelList *list = m_labelList[i]; 0385 0386 for (const auto &item : *list) 0387 { 0388 labeler->drawNameLabel(item.obj, item.o); 0389 } 0390 list->clear(); 0391 } 0392 } 0393 0394 bool StarComponent::loadStaticData() 0395 { 0396 // We break from Qt / KDE API and use traditional file handling here, to obtain speed. 0397 // We also avoid C++ constructors for the same reason. 0398 FILE *dataFile, *nameFile; 0399 bool swapBytes = false, named = false, gnamed = false; 0400 BinFileHelper dataReader, nameReader; 0401 QString name, gname, visibleName; 0402 StarObject *star; 0403 0404 if (starsLoaded) 0405 return true; 0406 0407 // prepare to index stars to this date 0408 m_skyMesh->setKSNumbers(&m_reindexNum); 0409 0410 /* Open the data files */ 0411 // TODO: Maybe we don't want to hardcode the filename? 0412 if ((dataFile = dataReader.openFile("namedstars.dat")) == nullptr) 0413 { 0414 qCWarning(KSTARS) << "Could not open data file namedstars.dat"; 0415 return false; 0416 } 0417 0418 if (!(nameFile = nameReader.openFile("starnames.dat"))) 0419 { 0420 qCWarning(KSTARS) << "Could not open data file starnames.dat"; 0421 return false; 0422 } 0423 0424 if (!dataReader.readHeader()) 0425 { 0426 qCWarning(KSTARS) << "Error reading namedstars.dat header : " << dataReader.getErrorNumber() << " : " 0427 << dataReader.getError(); 0428 return false; 0429 } 0430 0431 if (!nameReader.readHeader()) 0432 { 0433 qCWarning(KSTARS) << "Error reading starnames.dat header : " << nameReader.getErrorNumber() << " : " 0434 << nameReader.getError(); 0435 return false; 0436 } 0437 //KDE_fseek(nameFile, nameReader.getDataOffset(), SEEK_SET); 0438 QT_FSEEK(nameFile, nameReader.getDataOffset(), SEEK_SET); 0439 swapBytes = dataReader.getByteSwap(); 0440 0441 long int nstars = 0; 0442 0443 //KDE_fseek(dataFile, dataReader.getDataOffset(), SEEK_SET); 0444 QT_FSEEK(dataFile, dataReader.getDataOffset(), SEEK_SET); 0445 0446 qint16 faintmag; 0447 quint8 htm_level; 0448 quint16 t_MSpT; 0449 int ret = 0; 0450 0451 // Faint Magnitude 0452 ret = fread(&faintmag, 2, 1, dataFile); 0453 if (swapBytes) 0454 faintmag = bswap_16(faintmag); 0455 0456 // HTM Level 0457 ret = fread(&htm_level, 1, 1, dataFile); 0458 0459 // Unused 0460 { 0461 int rc = fread(&t_MSpT, 2, 1, dataFile); 0462 Q_UNUSED(rc) 0463 } 0464 0465 if (faintmag / 100.0 > m_FaintMagnitude) 0466 m_FaintMagnitude = faintmag / 100.0; 0467 0468 if (htm_level != m_skyMesh->level()) 0469 qCWarning(KSTARS) 0470 << "HTM Level in shallow star data file and HTM Level in m_skyMesh do not match. EXPECT TROUBLE" 0471 ; 0472 for (int i = 0; i < m_skyMesh->size(); ++i) 0473 { 0474 Trixel trixel = i; // = ( ( i >= 256 ) ? ( i - 256 ) : ( i + 256 ) ); 0475 for (unsigned long j = 0; j < static_cast<unsigned long>(dataReader.getRecordCount(i)); ++j) 0476 { 0477 if (1 != fread(&stardata, sizeof(StarData), 1, dataFile)) 0478 { 0479 qCCritical(KSTARS) << "FILE FORMAT ERROR: Could not read StarData structure for star #" << j << " under trixel #" 0480 << trixel; 0481 continue; 0482 } 0483 0484 /* Swap Bytes when required */ 0485 if (swapBytes) 0486 byteSwap(&stardata); 0487 0488 named = false; 0489 gnamed = false; 0490 0491 /* Named Star - Read the nameFile */ 0492 if (stardata.flags & 0x01) 0493 { 0494 visibleName = ""; 0495 if (1 != fread(&starname, sizeof(starName), 1, nameFile)) 0496 qCCritical(KSTARS) << "ERROR: fread() call on nameFile failed in trixel " << trixel << " star " << j; 0497 0498 name = QByteArray(starname.longName, 32); 0499 named = !name.isEmpty(); 0500 0501 gname = QByteArray(starname.bayerName, 8); 0502 gnamed = !gname.isEmpty(); 0503 0504 if (gnamed && starname.bayerName[0] != '.') 0505 visibleName = gname; 0506 0507 if (named) 0508 { 0509 // HEV: look up star name in internationalization filesource 0510 name = i18nc("star name", name.toLocal8Bit().data()); 0511 } 0512 else 0513 { 0514 name = i18n("star"); 0515 } 0516 } 0517 else 0518 qCCritical(KSTARS) << "ERROR: Named star file contains unnamed stars! Expect trouble."; 0519 0520 /* Create the new StarObject */ 0521 star = new StarObject; 0522 star->init(&stardata); 0523 //if( star->getHDIndex() != 0 && name == i18n("star")) 0524 if (stardata.HD) 0525 { 0526 m_HDHash.insert(stardata.HD, star); 0527 if (named == false) 0528 { 0529 name = QString("HD %1").arg(stardata.HD); 0530 named = true; 0531 } 0532 } 0533 0534 star->setNames(name, visibleName); 0535 //star->EquatorialToHorizontal( data->lst(), data->geo()->lat() ); 0536 ++nstars; 0537 0538 if (gnamed) 0539 m_genName.insert(gname, star); 0540 0541 //if ( ! name.isEmpty() && name != i18n("star")) 0542 if (named) 0543 { 0544 objectNames(SkyObject::STAR).append(name); 0545 objectLists(SkyObject::STAR).append(QPair<QString, const SkyObject *>(name, star)); 0546 } 0547 0548 if (!visibleName.isEmpty() && gname != name) 0549 { 0550 QString gName = star->gname(false); 0551 objectNames(SkyObject::STAR).append(gName); 0552 objectLists(SkyObject::STAR).append(QPair<QString, const SkyObject *>(gName, star)); 0553 } 0554 0555 appendListObject(star); 0556 0557 m_starIndex->at(trixel)->append(star); 0558 double pm = star->pmMagnitude(); 0559 0560 for (auto &list : m_highPMStars) 0561 { 0562 if (list->append(trixel, star, pm)) 0563 break; 0564 } 0565 } 0566 } 0567 0568 dataReader.closeFile(); 0569 nameReader.closeFile(); 0570 0571 starsLoaded = true; 0572 return true; 0573 } 0574 0575 void StarComponent::appendListObject(SkyObject *object) 0576 { 0577 m_ObjectList.append(object); 0578 m_ObjectHash.insert(object->name().toLower(), object); 0579 m_ObjectHash.insert(object->longname().toLower(), object); 0580 m_ObjectHash.insert(object->name2().toLower(), object); 0581 m_ObjectHash.insert(object->name2().toLower(), object); 0582 m_ObjectHash.insert((dynamic_cast<StarObject *>(object))->gname(false).toLower(), object); 0583 } 0584 0585 SkyObject *StarComponent::findStarByGenetiveName(const QString name) 0586 { 0587 if (name.startsWith(QLatin1String("HD"))) 0588 { 0589 QStringList fields = name.split(' ', Qt::SkipEmptyParts); 0590 bool Ok = false; 0591 unsigned int HDNum = fields[1].toInt(&Ok); 0592 if (Ok) 0593 return findByHDIndex(HDNum); 0594 } 0595 return m_genName.value(name); 0596 } 0597 0598 void StarComponent::objectsInArea(QList<SkyObject *> &list, const SkyRegion ®ion) 0599 { 0600 for (SkyRegion::const_iterator it = region.constBegin(); it != region.constEnd(); ++it) 0601 { 0602 Trixel trixel = it.key(); 0603 StarList *starlist = m_starIndex->at(trixel); 0604 for (int i = 0; starlist && i < starlist->size(); i++) 0605 if (starlist->at(i) && starlist->at(i)->name() != QString("star")) 0606 list.push_back(starlist->at(i)); 0607 } 0608 } 0609 0610 StarObject *StarComponent::findByHDIndex(int HDnum) 0611 { 0612 KStarsData *data = KStarsData::Instance(); 0613 StarObject *o = nullptr; 0614 BinFileHelper hdidxReader; 0615 0616 // First check the hash to see if we have a corresponding StarObject already 0617 if ((o = m_HDHash.value(HDnum, nullptr))) 0618 return o; 0619 // If we don't have the StarObject here, try it in the DeepStarComponents' hashes 0620 if (m_DeepStarComponents.size() >= 1) 0621 if ((o = m_DeepStarComponents.at(0)->findByHDIndex(HDnum))) 0622 return o; 0623 if (m_DeepStarComponents.size() >= 2) 0624 { 0625 qint32 offset = 0; 0626 int ret = 0; 0627 FILE *hdidxFile = hdidxReader.openFile("Henry-Draper.idx"); 0628 FILE *dataFile = nullptr; 0629 0630 if (!hdidxFile) 0631 return nullptr; 0632 //KDE_fseek( hdidxFile, (HDnum - 1) * 4, SEEK_SET ); 0633 QT_FSEEK(hdidxFile, (HDnum - 1) * 4, SEEK_SET); 0634 // TODO: Offsets need to be byteswapped if this is a big endian machine. 0635 // This means that the Henry Draper Index needs a endianness indicator. 0636 ret = fread(&offset, 4, 1, hdidxFile); 0637 if (offset <= 0) 0638 return nullptr; 0639 dataFile = m_DeepStarComponents.at(1)->getStarReader()->getFileHandle(); 0640 //KDE_fseek( dataFile, offset, SEEK_SET ); 0641 QT_FSEEK(dataFile, offset, SEEK_SET); 0642 { 0643 int rc = fread(&stardata, sizeof(StarData), 1, dataFile); 0644 Q_UNUSED(rc) 0645 } 0646 if (m_DeepStarComponents.at(1)->getStarReader()->getByteSwap()) 0647 { 0648 byteSwap(&stardata); 0649 } 0650 m_starObject.init(&stardata); 0651 m_starObject.EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0652 m_starObject.JITupdate(); 0653 focusStar = m_starObject.clone(); 0654 m_HDHash.insert(HDnum, focusStar); 0655 hdidxReader.closeFile(); 0656 return focusStar; 0657 } 0658 0659 return nullptr; 0660 } 0661 0662 // This uses the main star index for looking up nearby stars but then 0663 // filters out objects with the generic name "star". We could easily 0664 // build an index for just the named stars which would make this go 0665 // much faster still. -jbb 0666 // 0667 SkyObject *StarComponent::objectNearest(SkyPoint *p, double &maxrad) 0668 { 0669 m_zoomMagLimit = zoomMagnitudeLimit(); 0670 0671 SkyObject *oBest = nullptr; 0672 0673 MeshIterator region(m_skyMesh, OBJ_NEAREST_BUF); 0674 0675 while (region.hasNext()) 0676 { 0677 Trixel currentRegion = region.next(); 0678 StarList *starList = m_starIndex->at(currentRegion); 0679 0680 for (auto &star : *starList) 0681 { 0682 if (!star) 0683 continue; 0684 if (star->mag() > m_zoomMagLimit) 0685 continue; 0686 0687 double r = star->angularDistanceTo(p).Degrees(); 0688 0689 if (r < maxrad) 0690 { 0691 oBest = star; 0692 maxrad = r; 0693 } 0694 } 0695 } 0696 0697 // Check up with our Deep Star Components too! 0698 double rTry, rBest; 0699 SkyObject *oTry; 0700 // JM 2016-03-30: Multiply rBest by a factor of 0.5 so that named stars are preferred to unnamed stars searched below 0701 rBest = maxrad * 0.5; 0702 rTry = maxrad; 0703 for (auto &component : m_DeepStarComponents) 0704 { 0705 oTry = component->objectNearest(p, rTry); 0706 if (rTry < rBest) 0707 { 0708 rBest = rTry; 0709 oBest = oTry; 0710 } 0711 } 0712 maxrad = rBest; 0713 0714 return oBest; 0715 } 0716 0717 void StarComponent::starsInAperture(QList<StarObject *> &list, const SkyPoint ¢er, float radius, float maglim) 0718 { 0719 // Ensure that we have deprecessed the (RA, Dec) to (RA0, Dec0) 0720 Q_ASSERT(center.ra0().Degrees() >= 0.0); 0721 Q_ASSERT(center.dec0().Degrees() <= 90.0); 0722 0723 m_skyMesh->intersect(center.ra0().Degrees(), center.dec0().Degrees(), radius, static_cast<BufNum>(OBJ_NEAREST_BUF)); 0724 0725 MeshIterator region(m_skyMesh, OBJ_NEAREST_BUF); 0726 0727 if (maglim < -28) 0728 maglim = m_FaintMagnitude; 0729 0730 while (region.hasNext()) 0731 { 0732 Trixel currentRegion = region.next(); 0733 StarList *starList = m_starIndex->at(currentRegion); 0734 0735 for (auto &star : *starList) 0736 { 0737 if (!star) 0738 continue; 0739 if (star->mag() > m_FaintMagnitude) 0740 continue; 0741 if (star->angularDistanceTo(¢er).Degrees() <= radius) 0742 list.append(star); 0743 } 0744 } 0745 0746 // Add stars from the DeepStarComponents as well 0747 for (auto &component : m_DeepStarComponents) 0748 { 0749 component->starsInAperture(list, center, radius, maglim); 0750 } 0751 } 0752 0753 void StarComponent::byteSwap(StarData *stardata) 0754 { 0755 stardata->RA = bswap_32(stardata->RA); 0756 stardata->Dec = bswap_32(stardata->Dec); 0757 stardata->dRA = bswap_32(stardata->dRA); 0758 stardata->dDec = bswap_32(stardata->dDec); 0759 stardata->parallax = bswap_32(stardata->parallax); 0760 stardata->HD = bswap_32(stardata->HD); 0761 stardata->mag = bswap_16(stardata->mag); 0762 stardata->bv_index = bswap_16(stardata->bv_index); 0763 } 0764 /* 0765 void StarComponent::printDebugInfo() { 0766 0767 int nTrixels = 0; 0768 int nBlocks = 0; 0769 long int nStars = 0; 0770 float faintMag = -5.0; 0771 0772 MeshIterator trixels( m_skyMesh, DRAW_BUF ); 0773 Trixel trixel; 0774 0775 while( trixels.hasNext() ) { 0776 trixel = trixels.next(); 0777 nTrixels++; 0778 for(int i = 0; i < m_starBlockList[ trixel ]->getBlockCount(); ++i) { 0779 nBlocks++; 0780 StarBlock *block = m_starBlockList[ trixel ]->block( i ); 0781 for(int j = 0; j < block->getStarCount(); ++j) { 0782 nStars++; 0783 } 0784 if( block->getFaintMag() > faintMag ) { 0785 faintMag = block->getFaintMag(); 0786 } 0787 } 0788 } 0789 0790 printf( "========== UNNAMED STAR MEMORY ALLOCATION INFORMATION ==========\n" ); 0791 printf( "Number of visible trixels = %8d\n", nTrixels ); 0792 printf( "Number of visible StarBlocks = %8d\n", nBlocks ); 0793 printf( "Number of StarBlocks allocated via SBF = %8d\n", m_StarBlockFactory.getBlockCount() ); 0794 printf( "Number of unnamed stars in memory = %8ld\n", nStars ); 0795 printf( "Magnitude of the faintest star in memory = %8.2f\n", faintMag ); 0796 printf( "Target magnitude limit = %8.2f\n", magLim ); 0797 printf( "Size of each StarBlock = %8d bytes\n", sizeof( StarBlock ) ); 0798 printf( "Size of each StarObject = %8d bytes\n", sizeof( StarObject ) ); 0799 printf( "Memory use due to visible unnamed stars = %8.2f MB\n", ( sizeof( StarObject ) * nStars / 1048576.0 ) ); 0800 printf( "Memory use due to visible StarBlocks = %8d bytes\n", sizeof( StarBlock ) * nBlocks ); 0801 printf( "Memory use due to StarBlocks in SBF = %8d bytes\n", sizeof( StarBlock ) * m_StarBlockFactory.getBlockCount() ); 0802 printf( "=============== STAR DRAW LOOP TIMING INFORMATION ==============\n" ); 0803 printf( "Time taken for drawing named stars = %8ld ms\n", t_drawNamed ); 0804 printf( "Time taken for dynamic load of data = %8ld ms\n", t_dynamicLoad ); 0805 printf( "Time taken for updating LRU cache = %8ld ms\n", t_updateCache ); 0806 printf( "Time taken for drawing unnamed stars = %8ld ms\n", t_drawUnnamed ); 0807 printf( "================================================================\n" ); 0808 } 0809 0810 bool StarComponent::verifySBLIntegrity() { 0811 0812 float faintMag = -5.0; 0813 bool integrity = true; 0814 for(Trixel trixel = 0; trixel < m_skyMesh->size(); ++trixel) { 0815 for(int i = 0; i < m_starBlockList[ trixel ]->getBlockCount(); ++i) { 0816 StarBlock *block = m_starBlockList[ trixel ]->block( i ); 0817 if( i == 0 ) 0818 faintMag = block->getBrightMag(); 0819 // NOTE: Assumes 2 decimal places in magnitude field. TODO: Change if it ever does change 0820 if( block->getBrightMag() != faintMag && ( block->getBrightMag() - faintMag ) > 0.016) { 0821 qDebug() << Q_FUNC_INFO << "Trixel " << trixel << ": ERROR: faintMag of prev block = " << faintMag 0822 << ", brightMag of block #" << i << " = " << block->getBrightMag(); 0823 integrity = false; 0824 } 0825 if( i > 1 && ( !block->prev ) ) 0826 qDebug() << Q_FUNC_INFO << "Trixel " << trixel << ": ERROR: Block" << i << "is unlinked in LRU Cache"; 0827 if( block->prev && block->prev->parent == m_starBlockList[ trixel ] 0828 && block->prev != m_starBlockList[ trixel ]->block( i - 1 ) ) { 0829 qDebug() << Q_FUNC_INFO << "Trixel " << trixel << ": ERROR: SBF LRU Cache linked list seems to be broken at before block " << i; 0830 integrity = false; 0831 } 0832 faintMag = block->getFaintMag(); 0833 } 0834 } 0835 return integrity; 0836 } 0837 */