/* * The big star catalogue extension to Stellarium: * Author and Copyright: Johannes Gajdosik, 2006, 2007 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #ifdef Q_OS_WIN #include #include #endif #include "ZoneArray.hpp" #include "StelApp.hpp" #include "StelFileMgr.hpp" #include "StelGeodesicGrid.hpp" #include "StelObject.hpp" #include "StelNavigator.hpp" static unsigned int stel_bswap_32(unsigned int val) { return (((val) & 0xff000000) >> 24) | (((val) & 0x00ff0000) >> 8) | (((val) & 0x0000ff00) << 8) | (((val) & 0x000000ff) << 24); } namespace BigStarCatalogExtension { static const Vec3f north(0,0,1); void ZoneArray::initTriangle(int index, const Vec3f &c0, const Vec3f &c1, const Vec3f &c2) { // initialize center,axis0,axis1: ZoneData &z(zones[index]); z.center = c0+c1+c2; z.center.normalize(); z.axis0 = north ^ z.center; z.axis0.normalize(); z.axis1 = z.center ^ z.axis0; // initialize star_position_scale: double mu0,mu1,f,h; mu0 = (c0-z.center)*z.axis0; mu1 = (c0-z.center)*z.axis1; f = 1.0/sqrt(1.0-mu0*mu0-mu1*mu1); h = fabs(mu0)*f; if (star_position_scale < h) star_position_scale = h; h = fabs(mu1)*f; if (star_position_scale < h) star_position_scale = h; mu0 = (c1-z.center)*z.axis0; mu1 = (c1-z.center)*z.axis1; f = 1.0/sqrt(1.0-mu0*mu0-mu1*mu1); h = fabs(mu0)*f; if (star_position_scale < h) star_position_scale = h; h = fabs(mu1)*f; if (star_position_scale < h) star_position_scale = h; mu0 = (c2-z.center)*z.axis0; mu1 = (c2-z.center)*z.axis1; f = 1.0/sqrt(1.0-mu0*mu0-mu1*mu1); h = fabs(mu0)*f; if (star_position_scale < h) star_position_scale = h; h = fabs(mu1)*f; if (star_position_scale < h) star_position_scale = h; } static inline int ReadInt(QFile& file, unsigned int &x) { const int rval = (4 == file.read((char*)&x, 4)) ? 0 : -1; return rval; } #if (!defined(__GNUC__)) #warning Star catalogue loading has only been tested with gcc #endif ZoneArray* ZoneArray::create(const QString& catalogFilePath, bool use_mmap) { QString dbStr; // for debugging output. QFile* file = new QFile(catalogFilePath); if (!file->open(QIODevice::ReadOnly)) { qWarning() << "Error while loading " << catalogFilePath << ": failed to open file."; return 0; } dbStr = "Loading \"" + catalogFilePath + "\": "; unsigned int magic,major,minor,type,level,mag_min,mag_range,mag_steps; if (ReadInt(*file,magic) < 0 || ReadInt(*file,type) < 0 || ReadInt(*file,major) < 0 || ReadInt(*file,minor) < 0 || ReadInt(*file,level) < 0 || ReadInt(*file,mag_min) < 0 || ReadInt(*file,mag_range) < 0 || ReadInt(*file,mag_steps) < 0) { dbStr += "error - file format is bad."; qDebug() << dbStr; return 0; } const bool byte_swap = (magic == FILE_MAGIC_OTHER_ENDIAN); if (byte_swap) { // ok, FILE_MAGIC_OTHER_ENDIAN, must swap if (use_mmap) { dbStr += "warning - must convert catalogue "; #if (!defined(__GNUC__)) dbStr += "to native format "; #endif dbStr += "before mmap loading"; qWarning() << dbStr; use_mmap = false; qWarning() << "Revert to not using mmmap"; //return 0; } dbStr += "byteswap "; type = stel_bswap_32(type); major = stel_bswap_32(major); minor = stel_bswap_32(minor); level = stel_bswap_32(level); mag_min = stel_bswap_32(mag_min); mag_range = stel_bswap_32(mag_range); mag_steps = stel_bswap_32(mag_steps); } else if (magic == FILE_MAGIC) { // ok, FILE_MAGIC #if (!defined(__GNUC__)) if (use_mmap) { // mmap only with gcc: dbStr += "warning - you must convert catalogue " += "to native format before mmap loading"; qDebug(qPrintable(dbStr)); return 0; } #endif } else if (magic == FILE_MAGIC_NATIVE) { // ok, will work for any architecture and any compiler } else { dbStr += "error - not a catalogue file."; qDebug() << dbStr; return 0; } ZoneArray *rval = 0; dbStr += QString("%1_%2v%3_%4; ").arg(level).arg(type).arg(major).arg(minor); switch (type) { case 0: if (major > MAX_MAJOR_FILE_VERSION) { dbStr += "warning - unsupported version "; } else { // When this assertion fails you must redefine Star1 // for your compiler. // Because your compiler does not pack the data, // which is crucial for this application. Q_ASSERT(sizeof(Star1) == 28); rval = new HipZoneArray(file, byte_swap, use_mmap, level, mag_min, mag_range, mag_steps); if (rval == 0) { dbStr += "error - no memory "; } } break; case 1: if (major > MAX_MAJOR_FILE_VERSION) { dbStr += "warning - unsupported version "; } else { // When this assertion fails you must redefine Star2 // for your compiler. // Because your compiler does not pack the data, // which is crucial for this application. Q_ASSERT(sizeof(Star2) == 10); rval = new SpecialZoneArray(file, byte_swap, use_mmap, level, mag_min, mag_range, mag_steps); if (rval == 0) { dbStr += "error - no memory "; } } break; case 2: if (major > MAX_MAJOR_FILE_VERSION) { dbStr += "warning - unsupported version "; } else { // When this assertion fails you must redefine Star3 // for your compiler. // Because your compiler does not pack the data, // which is crucial for this application. Q_ASSERT(sizeof(Star3) == 6); rval = new SpecialZoneArray(file, byte_swap, use_mmap, level, mag_min, mag_range, mag_steps); if (rval == 0) { dbStr += "error - no memory "; } } break; default: dbStr += "error - bad file type "; break; } if (rval && rval->isInitialized()) { dbStr += QString("%1").arg(rval->getNrOfStars()); qDebug() << dbStr; } else { dbStr += " - initialization failed"; qDebug() << dbStr; if (rval) { delete rval; rval = 0; } } return rval; } ZoneArray::ZoneArray(const QString& fname, QFile* file, int level, int mag_min, int mag_range, int mag_steps) : fname(fname), level(level), mag_min(mag_min), mag_range(mag_range), mag_steps(mag_steps), star_position_scale(0.0), zones(0), file(file) { nr_of_zones = StelGeodesicGrid::nrOfZones(level); nr_of_stars = 0; } bool ZoneArray::readFile(QFile& file, void *data, qint64 size) { int parts = 256; int part_size = (size + (parts>>1)) / parts; if (part_size < 64*1024) { part_size = 64*1024; parts = (size + (part_size>>1)) / part_size; } float i = 0.f; i += 1.f; while (size > 0) { const int to_read = (part_size < size) ? part_size : size; const int read_rc = file.read((char*)data, to_read); if (read_rc != to_read) return false; size -= read_rc; data = ((char*)data) + read_rc; i += 1.f; } return true; } void HipZoneArray::updateHipIndex(HipIndexStruct hipIndex[]) const { for (const SpecialZoneData *z=getZones()+(nr_of_zones-1);z>=getZones();z--) { for (const Star1 *s = z->getStars()+z->size-1;s>=z->getStars();s--) { const int hip = s->hip; if (hip < 0 || NR_OF_HIP < hip) { qDebug() << "ERROR: HipZoneArray::updateHipIndex: invalid HIP number:" << hip; exit(1); } if (hip != 0) { hipIndex[hip].a = this; hipIndex[hip].z = z; hipIndex[hip].s = s; } } } } template void SpecialZoneArray::scaleAxis(void) { star_position_scale /= Star::MaxPosVal; for (ZoneData *z=zones+(nr_of_zones-1);z>=zones;z--) { z->axis0 *= star_position_scale; z->axis1 *= star_position_scale; } } template SpecialZoneArray::SpecialZoneArray(QFile* file, bool byte_swap,bool use_mmap, int level, int mag_min, int mag_range, int mag_steps) : ZoneArray(file->fileName(), file, level, mag_min, mag_range, mag_steps), stars(0), mmap_start(0) { if (nr_of_zones > 0) { zones = new SpecialZoneData[nr_of_zones]; if (zones == 0) { qDebug() << "ERROR: SpecialZoneArray(" << level << ")::SpecialZoneArray: no memory (1)"; exit(1); } unsigned int *zone_size = new unsigned int[nr_of_zones]; if (zone_size == 0) { qDebug() << "ERROR: SpecialZoneArray(" << level << ")::SpecialZoneArray: no memory (2)"; exit(1); } if ((qint64)(sizeof(unsigned int)*nr_of_zones) != file->read((char*)zone_size, sizeof(unsigned int)*nr_of_zones)) { qDebug() << "Error reading zones from catalog:" << file->fileName(); delete[] getZones(); zones = 0; nr_of_zones = 0; } else { const unsigned int *tmp = zone_size; for (unsigned int z=0;zmap(file->pos(), sizeof(Star)*nr_of_stars); if (mmap_start == 0) { qDebug() << "ERROR: SpecialZoneArray(" << level << ")::SpecialZoneArray: QFile(" << file->fileName() << ".map(" << file->pos() << ',' << sizeof(Star)*nr_of_stars << ") failed: " << file->errorString(); stars = 0; nr_of_stars = 0; delete[] getZones(); zones = 0; nr_of_zones = 0; } else { stars = (Star*)mmap_start; Star *s = stars; for (unsigned int z=0;zclose(); } else { stars = new Star[nr_of_stars]; if (stars == 0) { qDebug() << "ERROR: SpecialZoneArray(" << level << ")::SpecialZoneArray: no memory (3)"; exit(1); } if (!readFile(*file,stars,sizeof(Star)*nr_of_stars)) { delete[] stars; stars = 0; nr_of_stars = 0; delete[] getZones(); zones = 0; nr_of_zones = 0; } else { Star *s = stars; for (unsigned int z=0;zrepack( #if Q_BYTE_ORDER == Q_BIG_ENDIAN // need for byte_swap on a BE machine means that catalog is LE !byte_swap #else // need for byte_swap on a LE machine means that catalog is BE byte_swap #endif ); } } } file->close(); } } } } template SpecialZoneArray::~SpecialZoneArray(void) { if (stars) { if (mmap_start != 0) { file->unmap(mmap_start); } else { delete[] stars; } delete file; stars = 0; } if (zones) { delete[] getZones(); zones = NULL; } nr_of_zones = 0; nr_of_stars = 0; } template void SpecialZoneArray::draw(StelPainter* sPainter, int index, bool is_inside, const float *rcmag_table, StelCore* core, unsigned int maxMagStarName, float names_brightness) const { StelSkyDrawer* drawer = core->getSkyDrawer(); SpecialZoneData *const z = getZones() + index; Vec3f vf; const Star *const end = z->getStars() + z->size; static const double d2000 = 2451545.0; const double movementFactor = (M_PI/180)*(0.0001/3600) * ((core->getNavigator()->getJDay()-d2000)/365.25) / star_position_scale; const float* tmpRcmag; for (const Star *s=z->getStars();smag; if (*tmpRcmag<=0.f) break; s->getJ2000Pos(z,movementFactor, vf); if (drawer->drawPointSource(sPainter, vf, tmpRcmag, s->bV, !is_inside) && s->hasName() && s->mag < maxMagStarName) { const float offset = *tmpRcmag*0.7f; const Vec3f& colorr = (StelApp::getInstance().getVisionModeNight() ? Vec3f(0.8f, 0.2f, 0.2f) : StelSkyDrawer::indexToColor(s->bV))*0.75f; sPainter->setColor(colorr[0], colorr[1], colorr[2],names_brightness); sPainter->drawText(Vec3d(vf[0], vf[1], vf[2]), s->getNameI18n(), 0, offset, offset, false); } } } template void SpecialZoneArray::searchAround(const StelNavigator* nav, int index, const Vec3d &v, double cosLimFov, QList &result) { static const double d2000 = 2451545.0; const double movementFactor = (M_PI/180.)*(0.0001/3600.) * ((nav->getJDay()-d2000)/365.25)/ star_position_scale; const SpecialZoneData *const z = getZones()+index; Vec3f tmp; Vec3f vf(v[0], v[1], v[2]); for (const Star* s=z->getStars();sgetStars()+z->size;++s) { s->getJ2000Pos(z,movementFactor, tmp); tmp.normalize(); if (tmp*vf >= cosLimFov) { // TODO: do not select stars that are too faint to display result.push_back(s->createStelObject(this,z)); } } } } // namespace BigStarCatalogExtension