//Reimplement draw function so that we have control over the order of //elements, and we can add object labels // //The order in which components are drawn naturally determines the //z-ordering (the layering) of the components. Objects which //should appear "behind" others should be drawn first. void SkyMapComposite::draw( SkyPainter *skyp ) { SkyMap *map = SkyMap::Instance(); KStarsData *data = KStarsData::Instance(); // We delay one draw cycle before re-indexing // we MUST ensure CLines do not get re-indexed while we use DRAW_BUF // so we do it here. m_CLines->reindex( &m_reindexNum ); // This queues re-indexing for the next draw cycle m_reindexNum = KSNumbers( data->updateNum()->julianDay() ); // This ensures that the JIT updates are synchronized for the entire draw // cycle so the sky moves as a single sheet. May not be needed. data->syncUpdateIDs(); // prepare the aperture // FIXME_FOV: We may want to rejigger this to allow // wide-angle views --hdevalence float radius = map->projector()->fov(); if ( radius > 180.0 ) radius = 180.0; if ( m_skyMesh->inDraw() ) { printf("Warning: aborting concurrent SkyMapComposite::draw()\n"); return; } m_skyMesh->inDraw( true ); SkyPoint* focus = map->focus(); m_skyMesh->aperture( focus, radius + 1.0, DRAW_BUF ); // divide by 2 for testing // create the no-precess aperture if needed if ( Options::showEquatorialGrid() || Options::showHorizontalGrid() || Options::showCBounds() || Options::showEquator() ) { m_skyMesh->index( focus, radius + 1.0, NO_PRECESS_BUF ); } // clear marks from old labels and prep fonts m_skyLabeler->reset( map ); m_skyLabeler->useStdFont(); // info boxes have highest label priority // FIXME: REGRESSION. Labeler now know nothing about infoboxes // map->infoBoxes()->reserveBoxes( psky ); if( KStars::Instance() ) { const QList<SkyObject*> obsList = KStarsData::Instance()->observingList()->sessionList(); if( Options::obsListText() ) foreach( SkyObject* obj, obsList ) { SkyLabeler::AddLabel( obj, SkyLabeler::RUDE_LABEL ); } }
void ExportImageDialog::exportSvg(const QString &fileName) { SkyMap *map = m_KStars->map(); // export as SVG QSvgGenerator svgGenerator; svgGenerator.setFileName(fileName); svgGenerator.setTitle(i18n("KStars Exported Sky Image")); svgGenerator.setDescription(i18n("KStars Exported Sky Image")); svgGenerator.setSize(QSize(map->width(), map->height())); svgGenerator.setResolution(qMax(map->logicalDpiX(), map->logicalDpiY())); svgGenerator.setViewBox(QRect(0, 0, map->width(), map->height())); SkyQPainter painter(m_KStars, &svgGenerator); painter.begin(); map->exportSkyImage(&painter); if(m_DialogUI->addLegendCheckBox->isChecked()) { addLegend(&painter); } painter.end(); }
void ConjunctionsTool::slotGoto() { int index = m_SortModel->mapToSource( OutputList->currentIndex() ).row(); // Get the number of the line long double jd = outputJDList.value( index ); KStarsDateTime dt; KStars *ks = KStars::Instance(); KStarsData *data = KStarsData::Instance(); SkyMap *map = ks->map(); // Show conjunction data->setLocation( *geoPlace ); dt.setDJD( jd ); data->changeDateTime( dt ); map->setClickedObject( data->skyComposite()->findByName( m_Model->data( m_Model->index( index, 2 ) ).toString() ) ); map->setClickedPoint( map->clickedObject() ); map->slotCenter(); }
void ExportImageDialog::exportRasterGraphics(const QString &fileName) { //Determine desired image format from filename extension QString ext = fileName.mid(fileName.lastIndexOf(".") + 1); // export as raster graphics const char* format = "PNG"; if(ext.toLower() == "png") {format = "PNG";} else if(ext.toLower() == "jpg" || ext.toLower() == "jpeg" ) { format = "JPG"; } else if(ext.toLower() == "gif") { format = "GIF"; } else if(ext.toLower() == "pnm") { format = "PNM"; } else if(ext.toLower() == "bmp") { format = "BMP"; } else { kWarning() << i18n("Could not parse image format of %1; assuming PNG.", fileName); } int width = m_Size.width(); int height = m_Size.height(); SkyMap *map = m_KStars->map(); QPixmap skyimage(map->width(), map->height()); QPixmap outimage(width, height); outimage.fill(); map->exportSkyImage(&skyimage); qApp->processEvents(); //skyImage is the size of the sky map. The requested image size is w x h. //If w x h is smaller than the skymap, then we simply crop the image. //If w x h is larger than the skymap, pad the skymap image with a white border. if(width == map->width() && height == map->height()) { outimage = skyimage.copy(); } else { int dx(0), dy(0), sx(0), sy(0); int sw(map->width()), sh(map->height()); if(width > map->width()) { dx = (width - map->width())/2; } else { sx = (map->width() - width)/2; sw = width; } if(height > map->height()) { dy = (height - map->height())/2; } else { sy = (map->height() - height)/2; sh = height; } QPainter p; p.begin(&outimage); p.fillRect(outimage.rect(), QBrush( Qt::white)); p.drawImage(dx, dy, skyimage.toImage(), sx, sy, sw, sh); p.end(); } if(m_DialogUI->addLegendCheckBox->isChecked()) { addLegend(&outimage); } if(!outimage.save(fileName, format)) { kDebug() << i18n("Error: Unable to save image: %1 ", fileName); } else { kDebug() << i18n("Image saved to file: %1", fileName); } }
void KSPopupMenu::initPopupMenu( SkyObject *obj, QString name, QString type, QString info, bool showDetails, bool showObsList, bool showFlags ) { KStarsData* data = KStarsData::Instance(); SkyMap * map = SkyMap::Instance(); clear(); bool showLabel = name != i18n("star") && !name.isEmpty(); if( name.isEmpty() ) name = i18n( "Empty sky" ); addFancyLabel( name ); addFancyLabel( type ); addFancyLabel( info ); addFancyLabel( KStarsData::Instance()->skyComposite()->getConstellationBoundary()->constellationName( obj ) ); //Insert Rise/Set/Transit labels SkyObject* o = obj->clone(); addSeparator(); addFancyLabel( riseSetTimeLabel(o, true), -2 ); addFancyLabel( riseSetTimeLabel(o, false), -2 ); addFancyLabel( transitTimeLabel(o), -2 ); addSeparator(); delete o; // Show 'Select this object' item when in object pointing mode and when obj is not empty sky if(map->isInObjectPointingMode() && obj->type() != 21) { addAction( i18n( "Select this object"), map, SLOT(slotObjectSelected())); } //Insert item for centering on object addAction( i18n( "Center && Track" ), map, SLOT( slotCenter() ) ); if ( showFlags ) { //Insert actions for flag operations initFlagActions( obj ); } //Insert item for measuring distances //FIXME: add key shortcut to menu items properly! addAction( i18n( "Angular Distance To... [" ), map, SLOT(slotBeginAngularDistance()) ); addAction( i18n( "Starhop from here to... " ), map, SLOT(slotBeginStarHop()) ); //Insert item for Showing details dialog if ( showDetails ) addAction( i18nc( "Show Detailed Information Dialog", "Details" ), map, SLOT( slotDetail() ) ); //Insert "Add/Remove Label" item if ( showLabel ) { if ( map->isObjectLabeled( obj ) ) { addAction( i18n( "Remove Label" ), map, SLOT( slotRemoveObjectLabel() ) ); } else { addAction( i18n( "Attach Label" ), map, SLOT( slotAddObjectLabel() ) ); } } // Should show observing list if( showObsList ) { if ( data->observingList()->contains( obj ) ) addAction( i18n("Remove From Observing WishList"), data->observingList(), SLOT( slotRemoveObject() ) ); else addAction( i18n("Add to Observing WishList"), data->observingList(), SLOT( slotAddObject() ) ); } // Should we show trail actions TrailObject* t = dynamic_cast<TrailObject*>( obj ); if( t ) { if( t->hasTrail() ) addAction( i18n( "Remove Trail" ), map, SLOT( slotRemovePlanetTrail() ) ); else addAction( i18n( "Add Trail" ), map, SLOT( slotAddPlanetTrail() ) ); } addAction( i18n("Simulate eyepiece view"), map, SLOT( slotEyepieceView() ) ); addSeparator(); #ifdef HAVE_XPLANET if ( obj->isSolarSystem() && obj->type() != SkyObject::COMET ) { // FIXME: We now have asteroids -- so should this not be isMajorPlanet() || Pluto? QMenu *xplanetSubmenu = new QMenu(); xplanetSubmenu->setTitle( i18n( "Print Xplanet view" ) ); xplanetSubmenu->addAction( i18n( "To screen" ), map, SLOT( slotXplanetToScreen() ) ); xplanetSubmenu->addAction( i18n( "To file..." ), map, SLOT( slotXplanetToFile() ) ); addMenu( xplanetSubmenu ); } #endif addSeparator(); addINDI(); }
int main(int argc, char *argv[]) { #ifdef KSTARS_LITE QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QApplication app(argc, argv); #ifdef Q_OS_OSX //Note, this function will return true on OS X if the data directories are good to go. If not, quit with error code 1! if(!KSUtils::copyDataFolderFromAppBundleIfNeeded()){ KMessageBox::sorry(0, i18n("Sorry, without a KStars Data Directory, KStars cannot operate. Exiting program now.")); return 1; } #endif app.setApplicationVersion(KSTARS_VERSION); /** * enable high dpi support */ app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); KLocalizedString::setApplicationDomain("kstars"); #ifndef KSTARS_LITE KCrash::initialize(); KAboutData aboutData( "kstars", i18n("KStars"), KSTARS_VERSION, i18n(description), KAboutLicense::GPL, "2001-" + QString::number(QDate::currentDate().year()) + i18n("(c), The KStars Team"), i18n(notice), "http://edu.kde.org/kstars"); aboutData.addAuthor(i18n("Jason Harris"), i18n("Original Author"), "*****@*****.**", "http://www.30doradus.org"); aboutData.addAuthor(i18n("Jasem Mutlaq"), i18n("Current Maintainer"), "*****@*****.**", "http://www.indilib.org"); // Active developers aboutData.addAuthor(i18n("Akarsh Simha"), QString(), "*****@*****.**", "http://www.ph.utexas.edu/~asimha"); aboutData.addAuthor(i18n("Artem Fedoskin"), i18n("KStars Lite"), "*****@*****.**"); aboutData.addAuthor(i18n("Robert Lancaster"), i18n("FITSViewer Improvements. KStars OSX Port"), "*****@*****.**"); // Inactive developers aboutData.addAuthor(i18n("James Bowlin"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Pablo de Vicente"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Thomas Kabelmann"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Heiko Evermann"),QString(), "*****@*****.**", "http://www.evermann.de"); aboutData.addAuthor(i18n("Carsten Niehaus"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Mark Hollomon"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Alexey Khudyakov"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Médéric Boquien"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Jérôme Sonrier"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Prakash Mohan"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Victor Cărbune"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Henry de Valence"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Samikshan Bairagya"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Rafał Kułaga"), QString(), "*****@*****.**"); aboutData.addAuthor(i18n("Rishab Arora"), QString(), "*****@*****.**"); // Contributors aboutData.addCredit(i18n("Valery Kharitonov"), i18n("Converted labels containing technical terms to links to documentation") ); aboutData.addCredit(i18n("Ana-Maria Constantin"), i18n("Technical documentation on Astronomy and KStars") ); aboutData.addCredit(i18n("Andrew Stepanenko"), i18n("Guiding code based on lin_guider") ); aboutData.addCredit(i18n("Nuno Pinheiro"), i18n("Artwork") ); aboutData.addCredit(i18n("Utkarsh Simha"), i18n("Improvements to observation plan execution, star hopper etc.") ); aboutData.addCredit(i18n("Daniel Holler"), i18n("Extensive testing and suggestions for Ekos/INDI.") ); aboutData.addCredit(i18n("Stephane Lucas"), i18n("Extensive testing and suggestions for Ekos Scheduler.") ); aboutData.addCredit(i18n("Yuri Fabirovsky"), i18n("Splash screen for both regular KStars and KStars Lite.") ); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.setApplicationDescription(aboutData.shortDescription()); parser.addVersionOption(); parser.addHelpOption(); //parser.addHelpOption(INSERT_DESCRIPTION_HERE); parser.addOption(QCommandLineOption(QStringList() << "dump", i18n( "Dump sky image to file" ))); parser.addOption(QCommandLineOption(QStringList() << "script ", i18n( "Script to execute" ))); parser.addOption(QCommandLineOption(QStringList() << "width ", i18n( "Width of sky image" ), "640")); parser.addOption(QCommandLineOption(QStringList() << "height ", i18n( "Height of sky image" ), "480")); parser.addOption(QCommandLineOption(QStringList() << "filename ", i18n( "Filename for sky image" ), "kstars.png")); parser.addOption(QCommandLineOption(QStringList() << "date", i18n( "Date and time" ))); parser.addOption(QCommandLineOption(QStringList() << "paused", i18n( "Start with clock paused" ))); // urls to open parser.addPositionalArgument(QStringLiteral("urls"), i18n("FITS file(s) to open."), QStringLiteral("[urls...]")); parser.process(app); aboutData.processCommandLine(&parser); if ( parser.isSet( "dump" ) ) { qDebug() << "Dumping sky image"; //parse filename and image format const char* format = "PNG"; QString fname = parser.value( "filename" ); QString ext = fname.mid( fname.lastIndexOf(".")+1 ); if ( ext.toLower() == "png" ) { format = "PNG"; } else if ( ext.toLower() == "jpg" || ext.toLower() == "jpeg" ) { format = "JPG"; } else if ( ext.toLower() == "gif" ) { format = "GIF"; } else if ( ext.toLower() == "pnm" ) { format = "PNM"; } else if ( ext.toLower() == "bmp" ) { format = "BMP"; } else { qWarning() << i18n( "Could not parse image format of %1; assuming PNG.", fname ) ; } //parse width and height bool ok(false); int w(0), h(0); w = parser.value( "width" ).toInt( &ok ); if ( ok ) h = parser.value( "height" ).toInt( &ok ); if ( !ok ) { qWarning() << "Unable to parse arguments: " ; qWarning() << "Width: " << parser.value( "width" ) << " Height: " << parser.value( "height" ) << endl; return 1; } KStarsData *dat = KStarsData::Create(); QObject::connect( dat, SIGNAL( progressText(QString) ), dat, SLOT( slotConsoleMessage(QString) ) ); dat->initialize(); //Set Geographic Location dat->setLocationFromOptions(); //Set color scheme dat->colorScheme()->loadFromConfig(); //set clock now that we have a location: //Check to see if user provided a date/time string. If not, use current CPU time QString datestring = parser.value( "date" ); KStarsDateTime kdt; if ( ! datestring.isEmpty() ) { if ( datestring.contains( "-" ) ) { //assume ISODate format if ( datestring.contains( ":" ) ) { //also includes time //kdt = QDateTime::fromString( datestring, QDateTime::ISODate ); kdt = QDateTime::fromString( datestring, Qt::ISODate ); } else { //string probably contains date only //kdt.setDate( QDate::fromString( datestring, Qt::ISODate ) ); kdt.setDate( QDate::fromString( datestring, Qt::ISODate ) ); kdt.setTime( QTime( 0, 0, 0 ) ); } } else { //assume Text format for date string kdt = dat->geo()->LTtoUT( QDateTime::fromString( datestring, Qt::TextDate ) ); } if ( ! kdt.isValid() ) { qWarning() << i18n( "Using CPU date/time instead." ) ; kdt = KStarsDateTime::currentDateTimeUtc(); } } else { kdt = KStarsDateTime::currentDateTimeUtc(); } dat->clock()->setUTC( kdt ); SkyMap *map = SkyMap::Create(); map->resize( w, h ); QPixmap sky( w, h ); dat->setFullTimeUpdate(); dat->updateTime(dat->geo(), map ); SkyPoint dest( Options::focusRA(), Options::focusDec() ); map->setDestination( dest ); map->destination()->EquatorialToHorizontal( dat->lst(), dat->geo()->lat() ); map->setFocus( map->destination() ); map->focus()->EquatorialToHorizontal( dat->lst(), dat->geo()->lat() ); //Execute the specified script QString scriptfile = parser.value( "script" ); if ( ! scriptfile.isEmpty() ) { if ( dat->executeScript( scriptfile, map ) ) { std::cout << i18n( "Script executed." ).toUtf8().data() << std::endl; } else { qWarning() << i18n( "Could not execute script." ) ; } } qApp->processEvents(); map->setupProjector(); map->exportSkyImage( &sky ); qApp->processEvents(); if ( ! sky.save( fname, format ) ) qWarning() << "Unable to save image: " << fname; else qDebug() << "Saved to file: %1" << fname; delete map; delete dat; return 0; } //Try to parse the given date string QString datestring = parser.value( "date" ); if ( ! datestring.isEmpty() && ! KStarsDateTime::fromString( datestring ).isValid() ) { qWarning() << i18n( "Using CPU date/time instead." ) ; datestring.clear(); } #endif // Create writable data dir if it does not exist QDir writableDir; writableDir.mkdir(KSPaths::writableLocation(QStandardPaths::GenericDataLocation)); #ifndef KSTARS_LITE KStars::createInstance( true, ! parser.isSet( "paused" ), datestring ); // no session.. just start up normally const QStringList urls = parser.positionalArguments(); // take arguments if( ! urls.isEmpty() ) { foreach (const QString &url, urls) { const QUrl u = QUrl::fromUserInput(url, QDir::currentPath()); KStars::Instance()->openFITS(u); } }
void StarComponent::draw( SkyPainter *skyp ) { if( !selected() ) return; SkyMap *map = SkyMap::Instance(); const Projector *proj = map->projector(); KStarsData* data = KStarsData::Instance(); UpdateID updateID = data->updateID(); bool checkSlewing = ( map->isSlewing() && Options::hideOnSlew() ); m_hideLabels = checkSlewing || !( Options::showStarMagnitudes() || Options::showStarNames() ); //shortcuts to inform whether to draw different objects bool hideFaintStars = checkSlewing && Options::hideStars(); double hideStarsMag = Options::magLimitHideStar(); reindex( data->updateNum() ); double lgmin = log10(MINZOOM); double lgmax = log10(MAXZOOM); double lgz = log10(Options::zoomFactor()); double maglim; m_zoomMagLimit = maglim = zoomMagnitudeLimit(); double labelMagLim = Options::starLabelDensity() / 5.0; labelMagLim += ( 12.0 - labelMagLim ) * ( lgz - lgmin) / (lgmax - lgmin ); if( labelMagLim > 8.0 ) labelMagLim = 8.0; //Calculate sizeMagLim // Old formula: // float sizeMagLim = ( 2.000 + 2.444 * Options::memUsage() / 10.0 ) * ( lgz - lgmin ) + 5.8; // Using the maglim to compute the sizes of stars reduces // discernability between brighter and fainter stars at high zoom // levels. To fix that, we use an "arbitrary" constant in place of // the variable star density. // Not using this formula now. // float sizeMagLim = 4.444 * ( lgz - lgmin ) + 5.0; float sizeMagLim = zoomMagnitudeLimit(); if( sizeMagLim > faintMagnitude() * ( 1 - 1.5/16 ) ) sizeMagLim = faintMagnitude() * ( 1 - 1.5/16 ); skyp->setSizeMagLimit(sizeMagLim); //Loop for drawing star images MeshIterator region(m_skyMesh, DRAW_BUF); magLim = maglim; // If we are hiding faint stars, then maglim is really the brighter of hideStarsMag and maglim if( hideFaintStars && maglim > hideStarsMag ) maglim = hideStarsMag; m_StarBlockFactory->drawID = m_skyMesh->drawID(); int nTrixels = 0; while( region.hasNext() ) { ++nTrixels; Trixel currentRegion = region.next(); StarList* starList = m_starIndex->at( currentRegion ); for (int i=0; i < starList->size(); ++i) { StarObject *curStar = starList->at( i ); if( !curStar ) continue; float mag = curStar->mag(); // break loop if maglim is reached if ( mag > maglim ) break; if ( curStar->updateID != updateID ) curStar->JITupdate(); bool drawn = skyp->drawPointSource( curStar, mag, curStar->spchar() ); //FIXME_SKYPAINTER: find a better way to do this. if ( drawn && !(m_hideLabels || mag > labelMagLim) ) addLabel( proj->toScreen(curStar), curStar ); } } // Draw focusStar if not null if( focusStar ) { if ( focusStar->updateID != updateID ) focusStar->JITupdate(); float mag = focusStar->mag(); skyp->drawPointSource(focusStar, mag, focusStar->spchar() ); } // Now draw each of our DeepStarComponents for( int i =0; i < m_DeepStarComponents.size(); ++i ) { m_DeepStarComponents.at( i )->draw( skyp ); } }
int main(int argc, char *argv[]) { KAboutData aboutData( "kstars", 0, ki18n("KStars"), KSTARS_VERSION, ki18n(description), KAboutData::License_GPL, ki18n("(c) 2001-2012, The KStars Team"), ki18n(notice), "http://edu.kde.org/kstars"); aboutData.addAuthor(ki18n("Jason Harris"),KLocalizedString(), "*****@*****.**", "http://www.30doradus.org"); aboutData.addAuthor(ki18n("Jasem Mutlaq"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("James Bowlin"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Pablo de Vicente"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Thomas Kabelmann"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Heiko Evermann"),KLocalizedString(), "*****@*****.**", "http://www.evermann.de"); aboutData.addAuthor(ki18n("Carsten Niehaus"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Mark Hollomon"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Alexey Khudyakov"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Médéric Boquien"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Akarsh Simha"), KLocalizedString(), "*****@*****.**", "http://www.ph.utexas.edu/~asimha"); aboutData.addAuthor(ki18n("Jérôme Sonrier"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Prakash Mohan"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Victor Cărbune"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Henry de Valence"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Samikshan Bairagya"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Rafał Kułaga"), KLocalizedString(), "*****@*****.**"); aboutData.addAuthor(ki18n("Rishab Arora"), KLocalizedString(), "*****@*****.**"); aboutData.addCredit(ki18n("Valery Kharitonov"), ki18n("Converted labels containing technical terms to links to documentation") ); aboutData.addCredit(ki18n("Ana-Maria Constantin"), ki18n("Technical documentation on Astronomy and KStars") ); aboutData.addCredit(ki18n("Andrew Stepanenko"), ki18n("Guiding code based on lin_guider") ); aboutData.addCredit(ki18n("Nuno Pinheiro"), ki18n("Artwork") ); KCmdLineArgs::init( argc, argv, &aboutData ); KCmdLineOptions options; options.add("!dump", ki18n( "Dump sky image to file" )); options.add("script ", ki18n( "Script to execute" )); options.add("width ", ki18n( "Width of sky image" ), "640"); options.add("height ", ki18n( "Height of sky image" ), "480"); options.add("filename ", ki18n( "Filename for sky image" ), "kstars.png"); options.add("date ", ki18n( "Date and time" )); options.add("!paused", ki18n( "Start with clock paused" )); KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); KApplication a; if ( args->isSet( "dump" ) ) { kDebug() << i18n( "Dumping sky image" ); //parse filename and image format const char* format = "PNG"; QString fname = args->getOption( "filename" ); QString ext = fname.mid( fname.lastIndexOf(".")+1 ); if ( ext.toLower() == "png" ) { format = "PNG"; } else if ( ext.toLower() == "jpg" || ext.toLower() == "jpeg" ) { format = "JPG"; } else if ( ext.toLower() == "gif" ) { format = "GIF"; } else if ( ext.toLower() == "pnm" ) { format = "PNM"; } else if ( ext.toLower() == "bmp" ) { format = "BMP"; } else { kWarning() << i18n( "Could not parse image format of %1; assuming PNG.", fname ) ; } //parse width and height bool ok(false); int w(0), h(0); w = args->getOption( "width" ).toInt( &ok ); if ( ok ) h = args->getOption( "height" ).toInt( &ok ); if ( !ok ) { kWarning() << "Unable to parse arguments: " ; kWarning() << "Width: " << args->getOption( "width" ) << " Height: " << args->getOption( "height" ) << endl; return 1; } KStarsData *dat = KStarsData::Create(); QObject::connect( dat, SIGNAL( progressText(QString) ), dat, SLOT( slotConsoleMessage(QString) ) ); dat->initialize(); //Set Geographic Location dat->setLocationFromOptions(); //Set color scheme dat->colorScheme()->loadFromConfig(); //set clock now that we have a location: //Check to see if user provided a date/time string. If not, use current CPU time QString datestring = args->getOption( "date" ); KStarsDateTime kdt; if ( ! datestring.isEmpty() ) { if ( datestring.contains( "-" ) ) { //assume ISODate format if ( datestring.contains( ":" ) ) { //also includes time kdt = KDateTime::fromString( datestring, KDateTime::ISODate ); } else { //string probably contains date only kdt.setDate( QDate::fromString( datestring, Qt::ISODate ) ); kdt.setTime( QTime( 0, 0, 0 ) ); } } else { //assume Text format for date string kdt = dat->geo()->LTtoUT( KDateTime::fromString( datestring, KDateTime::QtTextDate ) ); } if ( ! kdt.isValid() ) { kWarning() << i18n( "Using CPU date/time instead." ) ; kdt = KStarsDateTime::currentUtcDateTime(); } } else { kdt = KStarsDateTime::currentUtcDateTime(); } dat->clock()->setUTC( kdt ); KSNumbers num( dat->ut().djd() ); // dat->initGuides(&num); SkyMap *map = SkyMap::Create(); map->resize( w, h ); QPixmap sky( w, h ); dat->setFullTimeUpdate(); dat->updateTime(dat->geo(), map ); SkyPoint dest( Options::focusRA(), Options::focusDec() ); map->setDestination( dest ); map->destination()->EquatorialToHorizontal( dat->lst(), dat->geo()->lat() ); map->setFocus( map->destination() ); map->focus()->EquatorialToHorizontal( dat->lst(), dat->geo()->lat() ); //Execute the specified script QString scriptfile = args->getOption( "script" ); if ( ! scriptfile.isEmpty() ) { if ( dat->executeScript( scriptfile, map ) ) { std::cout << i18n( "Script executed." ).toUtf8().data() << std::endl; } else { kWarning() << i18n( "Could not execute script." ) ; } } qApp->processEvents(); map->setupProjector(); map->exportSkyImage( &sky ); qApp->processEvents(); if ( ! sky.save( fname, format ) ) kWarning() << i18n( "Unable to save image: %1 ", fname ) ; else kDebug() << i18n( "Saved to file: %1", fname ); delete map; delete dat; return 0; } //start up normally in GUI mode //Try to parse the given date string QString datestring = args->getOption( "date" ); //DEBUG kDebug() << "Date string: " << datestring; if ( ! datestring.isEmpty() && ! KStarsDateTime::fromString( datestring ).isValid() ) { kWarning() << i18n( "Using CPU date/time instead." ) ; datestring.clear(); } KStars::createInstance( true, ! args->isSet( "paused" ), datestring ); args->clear(); QObject::connect(kapp, SIGNAL(lastWindowClosed()), kapp, SLOT(quit())); return a.exec(); }
void CoronaRenderer::updateLight(std::shared_ptr<MayaObject> mobj) { std::shared_ptr<mtco_MayaObject> obj(std::static_pointer_cast<mtco_MayaObject>(mobj)); if (obj->lightShader != nullptr) { if (this->context.scene->hasLightShader(obj->lightShader)) this->context.scene->deleteLightShader(obj->lightShader); } if (obj->removed) return; if (MayaTo::getWorldPtr()->renderType == MayaTo::MayaToWorld::WorldRenderType::IPRRENDER) { obj->transformMatrices.clear(); obj->transformMatrices.push_back(obj->dagPath.inclusiveMatrix()); } MFnDependencyNode rGlNode(getRenderGlobalsNode()); MObject coronaGlobals = getRenderGlobalsNode(); std::shared_ptr<RenderGlobals> renderGlobals = MayaTo::getWorldPtr()->worldRenderGlobalsPtr; std::shared_ptr<MayaScene> mayaScene = MayaTo::getWorldPtr()->worldScenePtr; MObjectArray nodeList; MStatus stat; MFnDependencyNode glFn(getRenderGlobalsNode()); Corona::Rgb bgRgb = toCorona(getColorAttr("bgColor", glFn)); int bgType = getEnumInt("bgType", glFn); MayaObject *sunLight = nullptr; MFnDependencyNode depFn(obj->mobject); if (obj->mobject.hasFn(MFn::kPointLight)) { MColor col; getColor("color", depFn, col); float intensity = 1.0f; getFloat("intensity", depFn, intensity); int decay = 0; getEnum(MString("decayRate"), depFn, decay); MMatrix m = obj->transformMatrices[0] * renderGlobals->globalConversionMatrix; Corona::Pos LP(m[3][0], m[3][1], m[3][2]); PointLight *pl = new PointLight; pl->LP = LP; pl->distFactor = 1.0 / renderGlobals->scaleFactor; pl->lightColor = Corona::Rgb(col.r, col.g, col.b); pl->lightIntensity = intensity; getEnum(MString("decayRate"), depFn, pl->decayType); pl->lightRadius = getFloatAttr("lightRadius", depFn, 0.0) * renderGlobals->scaleFactor; pl->doShadows = getBoolAttr("useRayTraceShadows", depFn, true); col = getColorAttr("shadowColor", depFn); pl->shadowColor = Corona::Rgb(col.r, col.g, col.b); for (auto excludedObj : obj->excludedObjects) { pl->excludeList.nodes.push(excludedObj.get()); } this->context.scene->addLightShader(pl); obj->lightShader = pl; } if (obj->mobject.hasFn(MFn::kSpotLight)) { MVector lightDir(0, 0, -1); MColor col; getColor("color", depFn, col); float intensity = 1.0f; getFloat("intensity", depFn, intensity); MMatrix m = obj->transformMatrices[0] * renderGlobals->globalConversionMatrix; lightDir *= obj->transformMatrices[0] * renderGlobals->globalConversionMatrix; lightDir.normalize(); Corona::Pos LP(m[3][0], m[3][1], m[3][2]); SpotLight *sl = new SpotLight; sl->LP = LP; sl->lightColor = Corona::Rgb(col.r, col.g, col.b); sl->lightIntensity = intensity; sl->LD = Corona::Dir(lightDir.x, lightDir.y, lightDir.z); sl->angle = 45.0f; sl->distFactor = 1.0 / renderGlobals->scaleFactor; getEnum(MString("decayRate"), depFn, sl->decayType); getFloat("coneAngle", depFn, sl->angle); getFloat("penumbraAngle", depFn, sl->penumbraAngle); getFloat("dropoff", depFn, sl->dropoff); sl->lightRadius = getFloatAttr("lightRadius", depFn, 0.0) * renderGlobals->scaleFactor; sl->doShadows = getBoolAttr("useRayTraceShadows", depFn, true); col = getColorAttr("shadowColor", depFn); sl->shadowColor = Corona::Rgb(col.r, col.g, col.b); for (auto excludedObj : obj->excludedObjects) { sl->excludeList.nodes.push(excludedObj.get()); } Corona::AffineTm tm; setTransformationMatrix(sl->lightWorldInverseMatrix, m); ShadingNetwork network(obj->mobject); sl->lightColorMap = defineAttribute(MString("color"), depFn, network, oslRenderer); this->context.scene->addLightShader(sl); obj->lightShader = sl; } if (obj->mobject.hasFn(MFn::kDirectionalLight)) { if (getBoolAttr("mtco_useAsSun", depFn, false)) { if (sunLight != nullptr) { Logging::error(MString("A sun light is already defined, ignoring ") + obj->shortName); return; } sunLight = obj.get(); MVector lightDir(0, 0, 1); // default dir light dir lightDir *= obj->transformMatrices[0]; lightDir *= renderGlobals->globalConversionMatrix; lightDir.normalize(); MColor sunColor(1); MFnDependencyNode sunNode(obj->mobject); getColor("color", sunNode, sunColor); sunColor *= getFloatAttr("intensity", sunNode, 1.0f); //float colorMultiplier colorMultiplier = getFloatAttr("mtco_sun_multiplier", sunNode, 1.0f); const float intensityFactor = (1.f - cos(Corona::SUN_PROJECTED_HALF_ANGLE)) / (1.f - cos(getFloatAttr("sunSizeMulti", rGlNode, 1.0f) * Corona::SUN_PROJECTED_HALF_ANGLE)); sunColor *= intensityFactor * 1.0;// 2000000; Corona::Sun sun; Corona::ColorOrMap bgCoMap = this->context.scene->getBackground(); SkyMap *sky = dynamic_cast<SkyMap *>(bgCoMap.getMap()); Corona::Rgb avgColor(1, 1, 1); if (sky != nullptr) { avgColor = sky->sc(); } Corona::Rgb sColor(sunColor.r, sunColor.g, sunColor.b); sun.color = sColor * avgColor; sun.active = true; sun.dirTo = Corona::Dir(lightDir.x, lightDir.y, lightDir.z).getNormalized(); //sun.color = Corona::Rgb(sunColor.r,sunColor.g,sunColor.b); sun.visibleDirect = true; sun.visibleReflect = true; sun.visibleRefract = true; sun.sizeMultiplier = getFloatAttr("sunSizeMulti", rGlNode, 1.0); this->context.scene->getSun() = sun; if (sky != nullptr) { sky->initSky(); this->context.scene->setBackground(bgCoMap); avgColor = sky->sc(); this->context.scene->getSun().color = sColor * avgColor; } } else{ MVector lightDir(0, 0, -1); MVector lightDirTangent(1, 0, 0); MVector lightDirBiTangent(0, 1, 0); MColor col; getColor("color", depFn, col); float intensity = 1.0f; getFloat("intensity", depFn, intensity); MMatrix m = obj->transformMatrices[0] * renderGlobals->globalConversionMatrix; lightDir *= m; lightDirTangent *= m; lightDirBiTangent *= m; lightDir.normalize(); Corona::Pos LP(m[3][0], m[3][1], m[3][2]); DirectionalLight *dl = new DirectionalLight; dl->LP = LP; dl->lightColor = Corona::Rgb(col.r, col.g, col.b); dl->lightIntensity = intensity; dl->LD = Corona::Dir(lightDir.x, lightDir.y, lightDir.z); dl->LT = Corona::Dir(lightDirTangent.x, lightDirTangent.y, lightDirTangent.z); dl->LBT = Corona::Dir(lightDirBiTangent.x, lightDirBiTangent.y, lightDirBiTangent.z); dl->lightAngle = getFloatAttr("lightAngle", depFn, 0.0); dl->doShadows = getBoolAttr("useRayTraceShadows", depFn, true); col = getColorAttr("shadowColor", depFn); dl->shadowColor = Corona::Rgb(col.r, col.g, col.b); for (auto excludedObj : obj->excludedObjects) { dl->excludeList.nodes.push(excludedObj.get()); } this->context.scene->addLightShader(dl); obj->lightShader = dl; } } if (obj->mobject.hasFn(MFn::kAreaLight)) { MMatrix m = obj->transformMatrices[0] * renderGlobals->globalConversionMatrix; if ( obj->geom == nullptr) obj->geom = defineStdPlane(); obj->geom->deleteAllInstances(); Corona::AnimatedAffineTm atm; this->setAnimatedTransformationMatrix(atm, obj); obj->instance = obj->geom->addInstance(atm, nullptr, nullptr); if (getBoolAttr("mtco_envPortal", depFn, false)) { Corona::EnviroPortalMtlData data; Corona::SharedPtr<Corona::IMaterial> mat = data.createMaterial(); Corona::IMaterialSet ms = Corona::IMaterialSet(mat); obj->instance->addMaterial(ms); } else{ Corona::NativeMtlData data; MColor lightColor = getColorAttr("color", depFn); float intensity = getFloatAttr("intensity", depFn, 1.0f); lightColor *= intensity; Corona::ColorOrMap com; // experimental direct corona texture if (getBoolAttr("mtco_noOSL", depFn, false)) { MObject fileNode = getConnectedInNode(obj->mobject, "color"); if ((fileNode != MObject::kNullObj) && (fileNode.hasFn(MFn::kFileTexture))) { MFnDependencyNode fileDep(fileNode); mtco_MapLoader loader(fileNode); Corona::SharedPtr<Corona::Abstract::Map> texmap = loader.loadBitmap(""); com = Corona::ColorOrMap(bgRgb, texmap); } } else { com = defineAttribute(MString("color"), obj->mobject, oslRenderer); OSLMap *oslmap = (OSLMap *)com.getMap(); if (oslmap != nullptr) { oslmap->multiplier = intensity; } else{ Corona::Rgb col = com.getConstantColor() * intensity; com.setColor(col); } } data.emission.color = com; data.castsShadows = getBoolAttr("mtco_castShadows", depFn, false); for (auto excludedObj : obj->excludedObjects) { data.emission.excluded.nodes.push(excludedObj.get()); } data.emission.disableSampling = false; data.emission.useTwoSidedEmission = getBoolAttr("mtco_doubleSided", depFn, false); Corona::SharedPtr<Corona::IMaterial> mat = data.createMaterial(); Corona::IMaterialSet ms = Corona::IMaterialSet(mat); ms.visibility.direct = getBoolAttr("mtco_areaVisible", depFn, true); ms.visibility.reflect = getBoolAttr("mtco_visibleInReflection", depFn, true); ms.visibility.refract = getBoolAttr("mtco_visibleInRefraction", depFn, true); obj->instance->addMaterial(ms); } } }
// TODO: Optimize draw, if it is worth it. void DeepStarComponent::draw( SkyPainter *skyp ) { #ifndef KSTARS_LITE if ( !fileOpened ) return; #ifdef PROFILE_SINCOS long trig_calls_here = - dms::trig_function_calls; long trig_redundancy_here = - dms::redundant_trig_function_calls; long cachingdms_bad_uses = -CachingDms::cachingdms_bad_uses; dms::seconds_in_trig = 0.; #endif #ifdef PROFILE_UPDATECOORDS StarObject::updateCoordsCpuTime = 0.; StarObject::starsUpdated = 0; #endif SkyMap *map = SkyMap::Instance(); KStarsData* data = KStarsData::Instance(); UpdateID updateID = data->updateID(); //FIXME_FOV -- maybe not clamp like that... float radius = map->projector()->fov(); if ( radius > 90.0 ) radius = 90.0; if ( m_skyMesh != SkyMesh::Instance() && m_skyMesh->inDraw() ) { printf("Warning: aborting concurrent DeepStarComponent::draw()"); } bool checkSlewing = ( map->isSlewing() && Options::hideOnSlew() ); //shortcuts to inform whether to draw different objects bool hideFaintStars( checkSlewing && Options::hideStars() ); double hideStarsMag = Options::magLimitHideStar(); //adjust maglimit for ZoomLevel // double lgmin = log10(MINZOOM); // double lgmax = log10(MAXZOOM); // double lgz = log10(Options::zoomFactor()); // TODO: Enable hiding of faint stars float maglim = StarComponent::zoomMagnitudeLimit(); if( maglim < triggerMag ) return; m_zoomMagLimit = maglim; m_skyMesh->inDraw( true ); SkyPoint* focus = map->focus(); m_skyMesh->aperture( focus, radius + 1.0, DRAW_BUF ); // divide by 2 for testing MeshIterator region(m_skyMesh, DRAW_BUF); magLim = maglim; // If we are to hide the fainter stars (eg: while slewing), we set the magnitude limit to hideStarsMag. if( hideFaintStars && maglim > hideStarsMag ) maglim = hideStarsMag; StarBlockFactory *m_StarBlockFactory = StarBlockFactory::Instance(); // m_StarBlockFactory->drawID = m_skyMesh->drawID(); // qDebug() << "Mesh size = " << m_skyMesh->size() << "; drawID = " << m_skyMesh->drawID(); QTime t; int nTrixels = 0; t_dynamicLoad = 0; t_updateCache = 0; t_drawUnnamed = 0; visibleStarCount = 0; t.start(); // Mark used blocks in the LRU Cache. Not required for static stars if( !staticStars ) { while( region.hasNext() ) { Trixel currentRegion = region.next(); for( int i = 0; i < m_starBlockList.at( currentRegion )->getBlockCount(); ++i ) { StarBlock *prevBlock = ( ( i >= 1 ) ? m_starBlockList.at( currentRegion )->block( i - 1 ) : NULL ); StarBlock *block = m_starBlockList.at( currentRegion )->block( i ); if( i == 0 && !m_StarBlockFactory->markFirst( block ) ) qDebug() << "markFirst failed in trixel" << currentRegion; if( i > 0 && !m_StarBlockFactory->markNext( prevBlock, block ) ) qDebug() << "markNext failed in trixel" << currentRegion << "while marking block" << i; if( i < m_starBlockList.at( currentRegion )->getBlockCount() && m_starBlockList.at( currentRegion )->block( i )->getFaintMag() < maglim ) break; } } t_updateCache = t.restart(); region.reset(); } while ( region.hasNext() ) { ++nTrixels; Trixel currentRegion = region.next(); // NOTE: We are guessing that the last 1.5/16 magnitudes in the catalog are just additions and the star catalog // is actually supposed to reach out continuously enough only to mag m_FaintMagnitude * ( 1 - 1.5/16 ) // TODO: Is there a better way? We may have to change the magnitude tolerance if the catalog changes // Static stars need not execute fillToMag if( !staticStars && !m_starBlockList.at( currentRegion )->fillToMag( maglim ) && maglim <= m_FaintMagnitude * ( 1 - 1.5/16 ) ) { qDebug() << "SBL::fillToMag( " << maglim << " ) failed for trixel " << currentRegion << " !"<< endl; } t_dynamicLoad += t.restart(); // qDebug() << "Drawing SBL for trixel " << currentRegion << ", SBL has " // << m_starBlockList[ currentRegion ]->getBlockCount() << " blocks" << endl; // REMARK: The following should never carry state, except for const parameters like updateID and maglim std::function<void( StarBlock * )> mapFunction = [&updateID, &maglim]( StarBlock *myBlock ) { for ( StarObject &star : myBlock->contents() ) { if ( star.updateID != updateID ) star.JITupdate(); if ( star.mag() > maglim ) break; } }; QtConcurrent::blockingMap( m_starBlockList.at( currentRegion )->contents(), mapFunction ); for( int i = 0; i < m_starBlockList.at( currentRegion )->getBlockCount(); ++i ) { StarBlock *block = m_starBlockList.at( currentRegion )->block( i ); // qDebug() << "---> Drawing stars from block " << i << " of trixel " << // currentRegion << ". SB has " << block->getStarCount() << " stars" << endl; for( int j = 0; j < block->getStarCount(); j++ ) { StarObject *curStar = block->star( j ); // qDebug() << "We claim that he's from trixel " << currentRegion //<< ", and indexStar says he's from " << m_skyMesh->indexStar( curStar ); float mag = curStar->mag(); if ( mag > maglim ) break; if( skyp->drawPointSource(curStar, mag, curStar->spchar() ) ) visibleStarCount++; } } // DEBUG: Uncomment to identify problems with Star Block Factory / preservation of Magnitude Order in the LRU Cache // verifySBLIntegrity(); t_drawUnnamed += t.restart(); } m_skyMesh->inDraw( false ); #ifdef PROFILE_SINCOS trig_calls_here += dms::trig_function_calls; trig_redundancy_here += dms::redundant_trig_function_calls; cachingdms_bad_uses += CachingDms::cachingdms_bad_uses; qDebug() << "Spent " << dms::seconds_in_trig << " seconds doing " << trig_calls_here << " trigonometric function calls amounting to an average of " << 1000.0 * dms::seconds_in_trig/double( trig_calls_here ) << " ms per call"; qDebug() << "Redundancy of trig calls in this draw: " << double( trig_redundancy_here ) / double( trig_calls_here ) * 100. << "%"; qDebug() << "CachedDms constructor calls so far: " << CachingDms::cachingdms_constructor_calls; qDebug() << "Caching has prevented " << CachingDms::cachingdms_delta << " redundant trig function calls"; qDebug() << "Bad cache uses in this draw: " << cachingdms_bad_uses; #endif #ifdef PROFILE_UPDATECOORDS qDebug() << "Spent " << StarObject::updateCoordsCpuTime << " seconds updating " << StarObject::starsUpdated << " stars' coordinates (StarObject::updateCoords) for an average of " << double( StarObject::updateCoordsCpuTime )/double( StarObject::starsUpdated ) * 1.e6 << " us per star."; #endif #else Q_UNUSED(skyp) #endif }