diff --git a/kstars/auxiliary/ksutils.cpp b/kstars/auxiliary/ksutils.cpp --- a/kstars/auxiliary/ksutils.cpp +++ b/kstars/auxiliary/ksutils.cpp @@ -1114,6 +1114,13 @@ else return snap + "/usr/bin/solve-field"; } + else if (option == "SextractorBinary") + { +#if defined(Q_OS_OSX) + return "/usr/local/bin/sex"; +#endif + return "/usr/bin/sextractor"; + } else if (option == "AstrometryWCSInfo") { #if defined(Q_OS_OSX) diff --git a/kstars/ekos/align/align.cpp b/kstars/ekos/align/align.cpp --- a/kstars/ekos/align/align.cpp +++ b/kstars/ekos/align/align.cpp @@ -2475,6 +2475,25 @@ if (optionsMap.contains("downsample")) solver_args << "--downsample" << QString::number(optionsMap.value("downsample", 2).toInt()); + if(Options::useSextractor()) + { + qDebug()<<"Is there an image width"; + if (optionsMap.contains("image_width")) + qDebug()<<"Yes there is: " << QString::number(optionsMap.value("image_width").toInt()); + else + qDebug()<<"no not really"; + //Sextractor needs all these parameters in order to solve an xylist of stars + if (optionsMap.contains("image_width")) + solver_args << "--width" << QString::number(optionsMap.value("image_width").toInt()); + if (optionsMap.contains("image_height")) + solver_args << "--height" << QString::number(optionsMap.value("image_height").toInt()); + solver_args << "--x-column X_IMAGE --y-column Y_IMAGE --sort-column MAG_AUTO --sort-ascending"; + + //Note This set of items is NOT NEEDED for Sextractor, it is needed to avoid python usage + //This may need to be changed later, but since the goal for using sextractor is to avoid python, this is placed here. + solver_args << "--no-remove-lines --uniformize 0"; + } + // image scale low if (optionsMap.contains("scaleL")) solver_args << "-L" << QString::number(optionsMap.value("scaleL").toDouble()); @@ -2584,6 +2603,11 @@ optionsMap["downsample"] = Options::astrometryDownsample(); } + //Options needed for Sextractor + int bin = Options::solverBinningIndex() + 1; + optionsMap["image_width"] = ccd_width / bin; + optionsMap["image_height"] = ccd_height / bin; + if (Options::astrometryUseImageScale() && fov_x > 0 && fov_y > 0) { QString units = ImageScales[Options::astrometryImageScaleUnits()]; @@ -2661,12 +2685,15 @@ #ifdef Q_OS_OSX if(solverBackendGroup->checkedId() == SOLVER_OFFLINE) { - if(Options::useDefaultPython()) + if(!Options::useSextractor()) { - if( !opsAlign->astropyInstalled() || !opsAlign->pythonInstalled() ) + if(Options::useDefaultPython()) { - KSNotification::error(i18n("Astrometry.net uses python3 and the astropy package for plate solving images offline. These were not detected on your system. Please go into the Align Options and either click the setup button to install them or uncheck the default button and enter the path to python3 on your system and manually install astropy.")); - return false; + if( !opsAlign->astropyInstalled() || !opsAlign->pythonInstalled() ) + { + KSNotification::error(i18n("Astrometry.net uses python3 and the astropy package for plate solving images offline. These were not detected on your system. Please go into the Align Options and either click the setup button to install them or uncheck the default button and enter the path to python3 on your system and manually install astropy.")); + return false; + } } } } @@ -3081,6 +3108,11 @@ if (Options::astrometryUseDownsample()) optionsMap["downsample"] = Options::astrometryDownsample(); + //Options needed for Sextractor + int bin = Options::solverBinningIndex() + 1; + optionsMap["image_width"] = ccd_width / bin; + optionsMap["image_height"] = ccd_height / bin; + solverArgs = generateOptions(optionsMap, solverBackendGroup->checkedId()); } else if (rc == KMessageBox::No) @@ -4570,17 +4602,20 @@ bool Align::loadAndSlew(QString fileURL) { #ifdef Q_OS_OSX - if(solverBackendGroup->checkedId() == SOLVER_OFFLINE) - { - if(Options::useDefaultPython()) + if(solverBackendGroup->checkedId() == SOLVER_OFFLINE) { - if( !opsAlign->astropyInstalled() || !opsAlign->pythonInstalled() ) + if(!Options::useSextractor()) { - KSNotification::error(i18n("Astrometry.net uses python3 and the astropy package for plate solving images offline. These were not detected on your system. Please go into the Align Options and either click the setup button to install them or uncheck the default button and enter the path to python3 on your system and manually install astropy.")); - return false; + if(Options::useDefaultPython()) + { + if( !opsAlign->astropyInstalled() || !opsAlign->pythonInstalled() ) + { + KSNotification::error(i18n("Astrometry.net uses python3 and the astropy package for plate solving images offline. These were not detected on your system. Please go into the Align Options and either click the setup button to install them or uncheck the default button and enter the path to python3 on your system and manually install astropy.")); + return false; + } + } } } - } #endif if (fileURL.isEmpty()) @@ -4918,6 +4953,14 @@ solver_args = generateOptions(optionsMap, SOLVER_ASTROMETRYNET); } + //Needed for Sextractor, let us figure out the image size and regenerate options + if(Options::useSextractor()) + { + optionsMap["image_width"] = fits_ccd_width; + optionsMap["image_height"] = fits_ccd_height; + solver_args = generateOptions(optionsMap, SOLVER_ASTROMETRYNET); + } + bool coord_ok = true; status = 0; diff --git a/kstars/ekos/align/offlineastrometryparser.h b/kstars/ekos/align/offlineastrometryparser.h --- a/kstars/ekos/align/offlineastrometryparser.h +++ b/kstars/ekos/align/offlineastrometryparser.h @@ -52,6 +52,7 @@ QMap astrometryIndex; QString parity; QPointer solver; + QPointer sextractorProcess; QProcess wcsinfo; QTime solverTimer; QString fitsFile; diff --git a/kstars/ekos/align/offlineastrometryparser.cpp b/kstars/ekos/align/offlineastrometryparser.cpp --- a/kstars/ekos/align/offlineastrometryparser.cpp +++ b/kstars/ekos/align/offlineastrometryparser.cpp @@ -218,13 +218,16 @@ solverArgs << "--config" << confPath; QString solutionFile = QDir::tempPath() + "/solution.wcs"; - solverArgs << "-W" << solutionFile << filename; - - fitsFile = filename; + solverArgs << "-W" << solutionFile; solver.clear(); solver = new QProcess(this); + sextractorProcess.clear(); + sextractorProcess = new QProcess(this); + + QString sextractorBinaryPath=Options::sextractorBinary(); + #ifdef Q_OS_OSX QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QString path = env.value("PATH", ""); @@ -239,15 +242,87 @@ { env.insert("PATH", pythonExecPath + ":/usr/local/bin:" + path); } + if(Options::sextractorIsInternal()) + sextractorBinaryPath=QCoreApplication::applicationDirPath() + "/astrometry/bin/sex"; solver->setProcessEnvironment(env); + sextractorProcess->setProcessEnvironment(env); if (Options::alignmentLogging()) { align->appendLogText("export PATH=" + env.value("PATH", "")); } #endif + fitsFile = filename; + + //These commands use sextractor to make a list of stars to feed into astrometry.net + if(Options::useSextractor()) + { + //Sets up the Temp file for the xy list of stars + QString sextractorFilePath = QDir::tempPath() + "/SextractorList.xyls"; + QFile sextractorFile(sextractorFilePath); + if(sextractorFile.exists()) + sextractorFile.remove(); + + //Configuration arguments for sextractor + QStringList sextractorArgs; + sextractorArgs << "-CATALOG_NAME" << sextractorFilePath; + sextractorArgs << "-CATALOG_TYPE" << "FITS_1.0"; + sextractorArgs << filename; + + //sextractor needs a default.param file in the working directory + //This creates that file with the options we need for astrometry.net + + QString paramPath = QDir::tempPath() + "/default.param"; + QFile paramFile(paramPath); + if(!paramFile.exists()) + { + if (paramFile.open(QIODevice::WriteOnly) == false) + KSNotification::error(i18n("Sextractor file write error.")); + else + { + QTextStream out(¶mFile); + out << "MAG_AUTO Kron-like elliptical aperture magnitude [mag]\n"; + out << "X_IMAGE Object position along x [pixel]\n"; + out << "Y_IMAGE Object position along y [pixel]\n"; + paramFile.close(); + } + } + + //sextractor needs a default.conv file in the working directory + //This creates the default one + + QString convPath = QDir::tempPath() + "/default.conv"; + QFile convFile(convPath); + if(!convFile.exists()) + { + if (convFile.open(QIODevice::WriteOnly) == false) + KSNotification::error(i18n("Sextractor file write error.")); + else + { + QTextStream out(&convFile); + out << "CONV NORM\n"; + out << "1 2 1\n"; + out << "2 4 2\n"; + out << "1 2 1\n"; + convFile.close(); + } + } + sextractorProcess->setWorkingDirectory(QDir::tempPath()); + sextractorProcess->start(sextractorBinaryPath, sextractorArgs); + align->appendLogText(i18n("Starting sextractor...")); + align->appendLogText(sextractorBinaryPath + " " + sextractorArgs.join(' ')); + sextractorProcess->waitForFinished(); + if (Options::alignmentLogging()) + align->appendLogText(sextractorProcess->readAllStandardError().trimmed()); + solverArgs << sextractorFilePath; + } + else + { + solverArgs << fitsFile; + } + connect(solver, SIGNAL(finished(int)), this, SLOT(solverComplete(int))); solver->setProcessChannelMode(QProcess::MergedChannels); connect(solver, SIGNAL(readyReadStandardOutput()), this, SLOT(logSolver())); diff --git a/kstars/ekos/align/opsalign.h b/kstars/ekos/align/opsalign.h --- a/kstars/ekos/align/opsalign.h +++ b/kstars/ekos/align/opsalign.h @@ -37,6 +37,7 @@ void setupPython(); void toggleConfigInternal(); void toggleWCSInternal(); + void toggleSextractorInternal(); void slotApply(); void togglePythonDefault(); diff --git a/kstars/ekos/align/opsalign.cpp b/kstars/ekos/align/opsalign.cpp --- a/kstars/ekos/align/opsalign.cpp +++ b/kstars/ekos/align/opsalign.cpp @@ -51,13 +51,19 @@ if (Options::astrometryWCSIsInternal()) kcfg_AstrometryWCSInfo->setEnabled(false); + connect(kcfg_SextractorIsInternal, SIGNAL(clicked()), this, SLOT(toggleSextractorInternal())); + kcfg_SextractorIsInternal->setToolTip(i18n("Internal or External sextractor?")); + if (Options::sextractorIsInternal()) + kcfg_SextractorBinary->setEnabled(false); + connect(kcfg_UseDefaultPython, SIGNAL(clicked()), this, SLOT(togglePythonDefault())); kcfg_PythonExecPath->setVisible(!Options::useDefaultPython()); SetupPython->setVisible(Options::useDefaultPython()); #else kcfg_AstrometrySolverIsInternal->setVisible(false); kcfg_AstrometryWCSIsInternal->setVisible(false); + kcfg_SextractorIsInternal->setVisible(false); kcfg_UseDefaultPython->setVisible(false); pythonLabel->setVisible(false); @@ -183,6 +189,15 @@ kcfg_AstrometryWCSInfo->setText(KSUtils::getDefaultPath("AstrometryWCSInfo")); } +void OpsAlign::toggleSextractorInternal() +{ + kcfg_SextractorBinary->setEnabled(!kcfg_SextractorIsInternal->isChecked()); + if (kcfg_SextractorIsInternal->isChecked()) + kcfg_SextractorBinary->setText("*Internal Sextractor*"); + else + kcfg_SextractorBinary->setText(KSUtils::getDefaultPath("SextractorBinary")); +} + void OpsAlign::togglePythonDefault() { bool defaultPython = kcfg_UseDefaultPython->isChecked(); diff --git a/kstars/ekos/align/opsalign.ui b/kstars/ekos/align/opsalign.ui --- a/kstars/ekos/align/opsalign.ui +++ b/kstars/ekos/align/opsalign.ui @@ -7,12 +7,69 @@ 0 0 422 - 202 + 235 + + + + Time out: + + + + + + + Rotator: + + + + + + + <html><head/><body><p>On Load &amp; Slew, solve the image and slew the mount to the target location and then rotate the camera to match the orientation of the FITS image.</p></body></html> + + + + + + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Script to setup homebrew python3 and required packages for astrometry.net + + + Setup + + + + + + + Path to Python3 bin folder + + + + + @@ -23,54 +80,78 @@ + + + + API URL: + + + + + + + <html><head/><body><p>Rotator threshold in arc-minutes when using Load &amp; Slew. If the difference between measured position angle and FITS position angle is below this value, the Load &amp; Slew operation is considered successful.</p></body></html> + + + python: + + + + config: + + + - + - Timeout in seconds to wait for astrometry solver to complete - - - 30 + API Key - - 600 + + - - + + - + wcsinfo: - - - - Time out: + + + + Timeout in seconds to wait for astrometry solver to complete + + + 30 + + + 600 - - + + - Astrometry.net configuration file + API URL - - + + - Astrometry.net configuration file + Astrometry.net solver binary is internal to the application bundle @@ -84,119 +165,100 @@ - - + + + + Astromebry config file is internal to the application bundle + - API Key: + - - + + - Astrometry.net wcsinfo binary + WCS Info file is internal to the Application Bundle - - + + - <html><head/><body><p>Rotator threshold in arc-minutes when using Load &amp; Slew. If the difference between measured position angle and FITS position angle is below this value, the Load &amp; Slew operation is considered successful.</p></body></html> + Use the Default python in homebrew - - - - - API URL: + - - + + - config: + API Key: - - - - + + + + Astrometry.net wcsinfo binary - - - - - - + + - <html><head/><body><p>On Load &amp; Slew, solve the image and slew the mount to the target location and then rotate the camera to match the orientation of the FITS image.</p></body></html> + Path to Sextractor binary file - - + + - wcsinfo: + sextractor: - - + + - Astrometry.net configuration file + Sextractor binary file is internal to the application bundle - - + + + + Astrometry.net configuration file + - - + + + + This allows you to use sextractor to make xylists to avoid using python with astrometry.net + - Rotator: + Use Sextractor not python - - - - 0 - - - 0 - - - - - Setup - - - - - - - - diff --git a/kstars/ekos/align/opsastrometry.cpp b/kstars/ekos/align/opsastrometry.cpp --- a/kstars/ekos/align/opsastrometry.cpp +++ b/kstars/ekos/align/opsastrometry.cpp @@ -123,41 +123,6 @@ Options::setAstrometryPositionDE(DE.Degrees()); } - QVariantMap optionsMap; - - if (kcfg_AstrometryUseNoVerify->isChecked()) - optionsMap["noverify"] = true; - - if (kcfg_AstrometryUseResort->isChecked()) - optionsMap["resort"] = true; - - if (kcfg_AstrometryUseNoFITS2FITS->isChecked()) - optionsMap["nofits2fits"] = true; - - if (kcfg_AstrometryUseImageScale->isChecked() && kcfg_AstrometryImageScaleLow->value() > 0 && kcfg_AstrometryImageScaleHigh->value() > 0) - { - optionsMap["scaleL"] = kcfg_AstrometryImageScaleLow->value(); - optionsMap["scaleH"] = kcfg_AstrometryImageScaleHigh->value(); - optionsMap["scaleUnits"] = kcfg_AstrometryImageScaleUnits->currentText(); - } - - if (kcfg_AstrometryUsePosition->isChecked()) - { - optionsMap["ra"] = RA.Degrees(); - optionsMap["de"] = DE.Degrees(); - optionsMap["radius"] = kcfg_AstrometryRadius->value(); - } - - if (kcfg_AstrometryUseDownsample->isChecked()) - optionsMap["downsample"] = kcfg_AstrometryDownsample->value(); - - if (kcfg_AstrometryCustomOptions->text().isEmpty() == false) - optionsMap["custom"] = kcfg_AstrometryCustomOptions->text(); - - QStringList solverArgs = Align::generateOptions(optionsMap); - - QString options = solverArgs.join(" "); - alignModule->solverOptions->setText(options); - alignModule->solverOptions->setToolTip(options); + alignModule->generateArgs(); } } diff --git a/kstars/indi/opsindi.ui b/kstars/indi/opsindi.ui --- a/kstars/indi/opsindi.ui +++ b/kstars/indi/opsindi.ui @@ -6,8 +6,8 @@ 0 0 - 443 - 333 + 555 + 411 @@ -36,6 +36,9 @@ + + INDI Server binary is internal to the application bundle + @@ -53,6 +56,9 @@ + + Path to the indiserver binary + /usr/bin/indiserver @@ -67,6 +73,9 @@ + + INDI Drivers are internal to the application bundle + @@ -84,6 +93,9 @@ + + path to the INDI drivers xml directory + /usr/share/indi diff --git a/kstars/kstars.kcfg b/kstars/kstars.kcfg --- a/kstars/kstars.kcfg +++ b/kstars/kstars.kcfg @@ -2016,6 +2016,20 @@ /usr/local/opt/python/libexec/bin + + + false + + + + false + + + + Path to the Sextractor executable. + KSUtils::getDefaultPath("SextractorBinary") + + Key to access astrometry.net online web services. You must register with astrometry.net to obtain a key. diff --git a/kstars/xplanet/opsxplanet.ui b/kstars/xplanet/opsxplanet.ui --- a/kstars/xplanet/opsxplanet.ui +++ b/kstars/xplanet/opsxplanet.ui @@ -41,6 +41,9 @@ + + Xplanet binary is internal to the application bundle +