diff --git a/kstars/CMakeLists.txt b/kstars/CMakeLists.txt index fc504685d..b75c0400b 100644 --- a/kstars/CMakeLists.txt +++ b/kstars/CMakeLists.txt @@ -1,1036 +1,1037 @@ add_subdirectory( data ) add_subdirectory( icons ) add_subdirectory( htmesh ) if (${KF5_VERSION} VERSION_EQUAL 5.18.0 OR ${KF5_VERSION} VERSION_GREATER 5.18.0) SET(HAVE_KF5WIT 1) if(NOT BUILD_KSTARS_LITE) add_subdirectory( tools/whatsinteresting/qml) endif(NOT BUILD_KSTARS_LITE) else() SET(HAVE_KF5WIT 0) endif() Find_package(ZLIB REQUIRED) Find_package(Threads REQUIRED) if(MSVC) add_definitions(-D_USE_MATH_DEFINES=1) add_definitions(-DNOMINMAX) endif() include_directories( ${kstars_SOURCE_DIR}/kstars/skyobjects ${kstars_SOURCE_DIR}/kstars/skycomponents ${kstars_SOURCE_DIR}/kstars/auxiliary ${kstars_SOURCE_DIR}/kstars/time ) if(BUILD_KSTARS_LITE) include_directories( ${kstars_SOURCE_DIR}/kstars/triangle ) else(BUILD_KSTARS_LITE) include_directories( ${kstars_SOURCE_DIR}/kstars/tools ) endif(BUILD_KSTARS_LITE) if(NOT BUILD_KSTARS_LITE) if (CFITSIO_FOUND) set (fits_SRCS fitsviewer/fitshistogram.cpp fitsviewer/fitsdata.cpp fitsviewer/fitsview.cpp fitsviewer/fitslabel.cpp fitsviewer/fitsviewer.cpp fitsviewer/fitstab.cpp fitsviewer/fitsdebayer.cpp fitsviewer/bayer.c fitsviewer/opsfits.cpp ) set (fitsui_SRCS fitsviewer/fitsheaderdialog.ui fitsviewer/statform.ui fitsviewer/fitsdebayer.ui indi/streamform.ui indi/recordingoptions.ui fitsviewer/fitshistogramui.ui fitsviewer/opsfits.ui ) include_directories(${CFITSIO_INCLUDE_DIR}) endif(CFITSIO_FOUND) endif(NOT BUILD_KSTARS_LITE) if (INDI_FOUND) if(BUILD_KSTARS_LITE) set (fits_SRCS fitsviewer/fitsdata.cpp fitsviewer/bayer.c ) include_directories(${CFITSIO_INCLUDE_DIR}) include_directories(${NOVA_INCLUDE_DIR}) set (indi_SRCS indi/clientmanagerlite.cpp indi/inditelescopelite.cpp kstarslite/skyitems/skynodes/crosshairnode.cpp kstarslite/skyitems/telescopesymbolsitem.cpp ) else(BUILD_KSTARS_LITE) set(indiui_SRCS indi/streamform.ui indi/drivermanager.ui indi/opsindi.ui indi/indihostconf.ui indi/telescopewizard.ui ) set(indi_SRCS indi/drivermanager.cpp indi/servermanager.cpp indi/clientmanager.cpp indi/guimanager.cpp indi/driverinfo.cpp indi/deviceinfo.cpp indi/indidevice.cpp indi/indigroup.cpp indi/indiproperty.cpp indi/indielement.cpp indi/indistd.cpp indi/indilistener.cpp indi/inditelescope.cpp indi/indiccd.cpp indi/indifocuser.cpp indi/indifilter.cpp indi/indidome.cpp indi/indiweather.cpp indi/indicap.cpp indi/indilightbox.cpp indi/indidbus.cpp indi/opsindi.cpp indi/telescopewizardprocess.cpp indi/streamwg.cpp indi/videowg.cpp indi/indiwebmanager.cpp ) if (CFITSIO_FOUND) set(ekosui_SRCS ekos/opsekos.ui ekos/ekosmanager.ui ekos/profileeditor.ui ekos/profilewizard.ui # Scheduler ekos/scheduler/scheduler.ui ekos/scheduler/mosaic.ui # Capture ekos/capture/capture.ui ekos/capture/calibrationoptions.ui ekos/capture/dslrinfo.ui # Align ekos/align/align.ui ekos/align/opsekos.ui ekos/align/opsastrometry.ui ekos/align/opsalign.ui ekos/align/opsastrometrycfg.ui ekos/align/opsastrometryindexfiles.ui ekos/align/mountmodel.ui # Focus ekos/focus/focus.ui # Mount ekos/mount/mount.ui # Guide ekos/guide/guide.ui ekos/guide/opscalibration.ui ekos/guide/opsguide.ui #TODO remove from GIT #ekos/guide/guider.ui #ekos/guide/rcalibration.ui ) set(ekos_SRCS ekos/ekos.cpp ekos/ekosmanager.cpp ekos/profileeditor.cpp ekos/profilewizard.cpp ekos/opsekos.cpp # Auxiliary ekos/auxiliary/dome.cpp ekos/auxiliary/weather.cpp ekos/auxiliary/dustcap.cpp ekos/auxiliary/darklibrary.cpp # Capture ekos/capture/capture.cpp ekos/capture/sequencejob.cpp ekos/capture/dslrinfodialog.cpp # Scheduler ekos/scheduler/schedulerjob.cpp ekos/scheduler/scheduler.cpp ekos/scheduler/mosaic.cpp # Focus ekos/focus/focus.cpp # Mount ekos/mount/mount.cpp # Align ekos/align/align.cpp ekos/align/alignview.cpp ekos/align/astrometryparser.cpp ekos/align/opsastrometry.cpp ekos/align/opsalign.cpp ekos/align/opsastrometrycfg.cpp ekos/align/opsastrometryindexfiles.cpp ekos/align/offlineastrometryparser.cpp ekos/align/onlineastrometryparser.cpp ekos/align/remoteastrometryparser.cpp # Guide ekos/guide/guide.cpp ekos/guide/guideinterface.cpp ekos/guide/opscalibration.cpp ekos/guide/opsguide.cpp # Internal Guide ekos/guide/internalguide/gmath.cpp ekos/guide/internalguide/internalguider.cpp #ekos/guide/internalguide/guider.cpp ekos/guide/internalguide/matr.cpp #ekos/guide/internalguide/rcalibration.cpp ekos/guide/internalguide/vect.cpp + ekos/guide/internalguide/imageautoguiding.cpp # External Guide ekos/guide/externalguide/phd2.cpp ekos/guide/externalguide/linguider.cpp ) endif(CFITSIO_FOUND) endif(BUILD_KSTARS_LITE) include_directories(${INDI_INCLUDE_DIR}) endif (INDI_FOUND) if(NOT BUILD_KSTARS_LITE) if(WCSLIB_FOUND) include_directories( ${WCSLIB_INCLUDE_DIR} ) endif(WCSLIB_FOUND) if(XPLANET_FOUND) set(xplanet_SRCS xplanet/opsxplanet.cpp ) set(xplanetui_SRCS xplanet/opsxplanet.ui ) endif(XPLANET_FOUND) ########### next target ############### set(libkstarstools_SRCS tools/altvstime.cpp tools/avtplotwidget.cpp tools/calendarwidget.cpp tools/conjunctions.cpp # tools/jmoontool.cpp tools/ksconjunct.cpp tools/eqplotwidget.cpp tools/astrocalc.cpp tools/modcalcangdist.cpp tools/modcalcapcoord.cpp tools/modcalcaltaz.cpp tools/modcalcdaylength.cpp tools/modcalceclipticcoords.cpp tools/modcalcvizequinox.cpp tools/modcalcgalcoord.cpp tools/modcalcgeodcoord.cpp tools/modcalcjd.cpp tools/modcalcplanets.cpp tools/modcalcsidtime.cpp tools/modcalcvlsr.cpp tools/observinglist.cpp tools/obslistpopupmenu.cpp tools/sessionsortfilterproxymodel.cpp tools/obslistwizard.cpp tools/planetviewer.cpp tools/pvplotwidget.cpp tools/scriptargwidgets.cpp tools/scriptbuilder.cpp tools/scriptfunction.cpp tools/skycalendar.cpp tools/wutdialog.cpp tools/flagmanager.cpp tools/horizonmanager.cpp tools/nameresolver.cpp #FIXME Port to KF5 #tools/moonphasetool.cpp tools/starhopper.cpp tools/eyepiecefield.cpp tools/exporteyepieceview.cpp tools/starhopperdialog.cpp tools/adddeepskyobject.cpp ) if(${KF5_VERSION} VERSION_EQUAL 5.18.0 OR ${KF5_VERSION} VERSION_GREATER 5.18.0) set(libkstarstools_SRCS ${libkstarstools_SRCS} tools/whatsinteresting/skyobjlistmodel.cpp tools/whatsinteresting/wiview.cpp tools/whatsinteresting/modelmanager.cpp tools/whatsinteresting/skyobjitem.cpp tools/whatsinteresting/wilpsettings.cpp tools/whatsinteresting/wiequipsettings.cpp tools/whatsinteresting/obsconditions.cpp tools/whatsinteresting/skyobjdescription.cpp ) endif() ki18n_wrap_ui(libkstarstools_SRCS tools/altvstime.ui tools/argchangeviewoption.ui tools/argexportimage.ui tools/argloadcolorscheme.ui tools/arglooktoward.ui tools/argfindobject.ui tools/argprintimage.ui tools/argsetaltaz.ui tools/argsetcolor.ui tools/argsetgeolocation.ui tools/argsetlocaltime.ui tools/argsetradec.ui tools/argsettrack.ui tools/argtimescale.ui tools/argwaitfor.ui tools/argwaitforkey.ui tools/argzoom.ui tools/conjunctions.ui tools/modcalcangdist.ui tools/modcalcapcoord.ui tools/modcalcaltaz.ui tools/modcalcdaylength.ui tools/modcalceclipticcoords.ui tools/modcalcvizequinox.ui tools/modcalcgalcoord.ui tools/modcalcgeod.ui tools/modcalcjd.ui tools/modcalcplanets.ui tools/modcalcsidtime.ui tools/modcalcvlsr.ui tools/observinglist.ui tools/obslistwizard.ui tools/optionstreeview.ui tools/planetviewer.ui tools/scriptbuilder.ui tools/scriptnamedialog.ui tools/skycalendar.ui tools/wutdialog.ui tools/flagmanager.ui tools/starhopperdialog.ui tools/horizonmanager.ui tools/adddeepskyobject.ui ) if (${KF5_VERSION} VERSION_EQUAL 5.18.0 OR ${KF5_VERSION} VERSION_GREATER 5.18.0) ki18n_wrap_ui(libkstarstools_SRCS tools/whatsinteresting/wilpsettings.ui tools/whatsinteresting/wiequipsettings.ui ) endif() set(libkstarswidgets_SRCS widgets/clicklabel.cpp widgets/dmsbox.cpp widgets/draglistbox.cpp widgets/fovwidget.cpp widgets/logedit.cpp widgets/magnitudespinbox.cpp widgets/mapcanvas.cpp widgets/thumbimage.cpp widgets/timespinbox.cpp widgets/timestepbox.cpp widgets/timeunitbox.cpp widgets/infoboxwidget.cpp # widgets/genericcalendarwidget.cpp # widgets/moonphasecalendarwidget.cpp widgets/kshelplabel.cpp widgets/unitspinboxwidget.cpp ) ki18n_wrap_ui(libkstarswidgets_SRCS # widgets/genericcalendarwidget.ui widgets/unitspinboxwidget.ui ) set(kstars_KCFG_SRCS Options.kcfgc) set(kstars_options_SRCS options/opsadvanced.cpp options/opscatalog.cpp options/opscolors.cpp options/opsguides.cpp options/opssolarsystem.cpp options/opssatellites.cpp options/opssupernovae.cpp ) set(kstars_optionsui_SRCS options/opsadvanced.ui options/opscatalog.ui options/opscolors.ui options/opsguides.ui options/opssolarsystem.ui options/opssatellites.ui options/opssupernovae.ui ) set(kstars_dialogs_SRCS dialogs/addcatdialog.cpp dialogs/addlinkdialog.cpp dialogs/detaildialog.cpp dialogs/finddialog.cpp dialogs/focusdialog.cpp dialogs/fovdialog.cpp dialogs/locationdialog.cpp dialogs/timedialog.cpp dialogs/exportimagedialog.cpp ) set(kstars_dialogsui_SRCS dialogs/addcatdialog.ui dialogs/addlinkdialog.ui dialogs/details_database.ui dialogs/details_data.ui dialogs/details_data_comet.ui dialogs/details_links.ui dialogs/details_log.ui dialogs/details_position.ui dialogs/finddialog.ui dialogs/focusdialog.ui dialogs/fovdialog.ui dialogs/locationdialog.ui dialogs/wizwelcome.ui dialogs/wizlocation.ui dialogs/wizdownload.ui dialogs/wizdata.ui dialogs/wizastrometry.ui dialogs/newfov.ui dialogs/exportimagedialog.ui ) set(oal_SRCS oal/log.cpp oal/observer.cpp oal/site.cpp oal/session.cpp oal/scope.cpp oal/eyepiece.cpp oal/filter.cpp oal/observation.cpp oal/lens.cpp oal/equipmentwriter.cpp oal/observeradd.cpp oal/execute.cpp ) set(printing_SRCS printing/detailstable.cpp printing/finderchart.cpp printing/foveditordialog.cpp printing/fovsnapshot.cpp printing/kstarsdocument.cpp printing/legend.cpp printing/loggingform.cpp printing/printingwizard.cpp printing/pwizchartconfig.cpp printing/pwizchartcontents.cpp printing/pwizfovbrowse.cpp printing/pwizfovconfig.cpp printing/pwizfovmanual.cpp printing/pwizfovsh.cpp printing/pwizfovtypeselection.cpp printing/pwizobjectselection.cpp printing/pwizprint.cpp printing/shfovexporter.cpp printing/simplefovexporter.cpp ) set(printingui_SRCS printing/foveditordialog.ui printing/pwizchartconfig.ui printing/pwizchartcontents.ui printing/pwizfovbrowse.ui printing/pwizfovconfig.ui printing/pwizfovmanual.ui printing/pwizfovsh.ui printing/pwizfovtypeselection.ui printing/pwizobjectselection.ui printing/pwizprint.ui printing/pwizwelcome.ui ) set(oal_SRCS oal/log.cpp oal/observer.cpp oal/site.cpp oal/session.cpp oal/scope.cpp oal/eyepiece.cpp oal/filter.cpp oal/observation.cpp oal/lens.cpp oal/equipmentwriter.cpp oal/observeradd.cpp oal/execute.cpp ) set(printing_SRCS printing/detailstable.cpp printing/finderchart.cpp printing/foveditordialog.cpp printing/fovsnapshot.cpp printing/kstarsdocument.cpp printing/legend.cpp printing/loggingform.cpp printing/printingwizard.cpp printing/pwizchartconfig.cpp printing/pwizchartcontents.cpp printing/pwizfovbrowse.cpp printing/pwizfovconfig.cpp printing/pwizfovmanual.cpp printing/pwizfovsh.cpp printing/pwizfovtypeselection.cpp printing/pwizobjectselection.cpp printing/pwizprint.cpp printing/shfovexporter.cpp printing/simplefovexporter.cpp ) set(printingui_SRCS printing/foveditordialog.ui printing/pwizchartconfig.ui printing/pwizchartcontents.ui printing/pwizfovbrowse.ui printing/pwizfovconfig.ui printing/pwizfovmanual.ui printing/pwizfovsh.ui printing/pwizfovtypeselection.ui printing/pwizobjectselection.ui printing/pwizprint.ui printing/pwizwelcome.ui ) endif(NOT BUILD_KSTARS_LITE) set( kstars_KCFG_SRCS Options.kcfgc ) set(libkstarscomponents_SRCS skycomponents/skylabeler.cpp skycomponents/highpmstarlist.cpp skycomponents/skymapcomposite.cpp skycomponents/skymesh.cpp skycomponents/linelistindex.cpp skycomponents/linelistlabel.cpp skycomponents/noprecessindex.cpp skycomponents/listcomponent.cpp skycomponents/pointlistcomponent.cpp skycomponents/solarsystemsinglecomponent.cpp skycomponents/solarsystemlistcomponent.cpp skycomponents/asteroidscomponent.cpp skycomponents/cometscomponent.cpp skycomponents/planetmoonscomponent.cpp skycomponents/solarsystemcomposite.cpp skycomponents/satellitescomponent.cpp skycomponents/starcomponent.cpp skycomponents/deepstarcomponent.cpp skycomponents/deepskycomponent.cpp skycomponents/catalogcomponent.cpp skycomponents/syncedcatalogcomponent.cpp skycomponents/constellationartcomponent.cpp skycomponents/constellationboundarylines.cpp skycomponents/constellationlines.cpp skycomponents/constellationnamescomponent.cpp skycomponents/supernovaecomponent.cpp skycomponents/coordinategrid.cpp skycomponents/equatorialcoordinategrid.cpp skycomponents/horizontalcoordinategrid.cpp skycomponents/ecliptic.cpp skycomponents/equator.cpp skycomponents/artificialhorizoncomponent.cpp skycomponents/horizoncomponent.cpp skycomponents/milkyway.cpp skycomponents/skycomponent.cpp skycomponents/skycomposite.cpp skycomponents/starblock.cpp skycomponents/starblocklist.cpp skycomponents/starblockfactory.cpp skycomponents/culturelist.cpp skycomponents/flagcomponent.cpp skycomponents/targetlistcomponent.cpp ) if(NOT BUILD_KSTARS_LITE) LIST(APPEND libkstarscomponents_SRCS #skycomponents/notifyupdatesui.cpp ) else(NOT BUILD_KSTARS_LITE) set(libkstarstools_SRCS tools/nameresolver.cpp ) endif(NOT BUILD_KSTARS_LITE) set(kstars_skyobjects_SRCS skyobjects/constellationsart.cpp skyobjects/deepskyobject.cpp # skyobjects/jupitermoons.cpp # skyobjects/planetmoons.cpp skyobjects/ksasteroid.cpp skyobjects/kscomet.cpp skyobjects/ksmoon.cpp skyobjects/ksplanetbase.cpp skyobjects/ksplanet.cpp #skyobjects/kspluto.cpp skyobjects/kssun.cpp skyobjects/skyline.cpp skyobjects/skyobject.cpp skyobjects/skypoint.cpp skyobjects/starobject.cpp skyobjects/trailobject.cpp skyobjects/satellite.cpp skyobjects/satellitegroup.cpp skyobjects/supernova.cpp ) set(kstars_projection_SRCS projections/projector.cpp projections/lambertprojector.cpp projections/gnomonicprojector.cpp projections/stereographicprojector.cpp projections/orthographicprojector.cpp projections/azimuthalequidistantprojector.cpp projections/equirectangularprojector.cpp ) set(kstars_extra_SRCS auxiliary/colorscheme.cpp auxiliary/dms.cpp auxiliary/cachingdms.cpp auxiliary/geolocation.cpp auxiliary/ksfilereader.cpp auxiliary/ksuserdb.cpp auxiliary/binfilehelper.cpp auxiliary/ksutils.cpp auxiliary/ksdssimage.cpp auxiliary/ksdssdownloader.cpp auxiliary/profileinfo.cpp auxiliary/filedownloader.cpp auxiliary/kspaths.cpp auxiliary/QRoundProgressBar.cpp auxiliary/skyobjectlistmodel.cpp auxiliary/ksnotification.cpp auxiliary/QProgressIndicator.cpp time/simclock.cpp time/kstarsdatetime.cpp time/timezonerule.cpp ksnumbers.cpp kstarsdata.cpp texturemanager.cpp #to minimize number of indef KSTARS_LITE skypainter.cpp ) if(NOT BUILD_KSTARS_LITE) LIST(APPEND kstars_extra_SRCS auxiliary/imageviewer.cpp auxiliary/fov.cpp auxiliary/thumbnailpicker.cpp auxiliary/thumbnaileditor.cpp auxiliary/imageexporter.cpp auxiliary/kswizard.cpp auxiliary/qcustomplot.cpp kstarsdbus.cpp kspopupmenu.cpp ksalmanac.cpp kstarsactions.cpp kstarsinit.cpp kstars.cpp kstarssplash.cpp skymap.cpp skymapdrawabstract.cpp skymapqdraw.cpp skymapevents.cpp skyqpainter.cpp ) endif(NOT BUILD_KSTARS_LITE) if(BUILD_KSTARS_LITE) #Temporary solution to allow use of qml files from source dir DELETE add_definitions( -DSOURCE_DIR=\"${kstars_SOURCE_DIR}\" ) add_definitions(-DQML_IMPORT="${CMAKE_CURRENT_SOURCE_DIR}") set(kstarslite_SRCS kstarslite.cpp kstarsliteinit.cpp skymaplite.cpp skymapliteevents.cpp #Wrappers kstarslite/skypointlite.cpp kstarslite/skyobjectlite.cpp #ImageProvider kstarslite/imageprovider.cpp #Dialogs kstarslite/dialogs/detaildialoglite.cpp kstarslite/dialogs/finddialoglite.cpp kstarslite/dialogs/locationdialoglite.cpp #RootNode kstarslite/skyitems/rootnode.cpp kstarslite/skyitems/skyopacitynode.cpp kstarslite/skyitems/typedeflite.h #SkyItems kstarslite/skyitems/skyitem.cpp kstarslite/skyitems/planetsitem.cpp kstarslite/skyitems/asteroidsitem.cpp kstarslite/skyitems/cometsitem.cpp kstarslite/skyitems/horizonitem.cpp kstarslite/skyitems/labelsitem.cpp kstarslite/skyitems/constellationnamesitem.cpp kstarslite/skyitems/staritem.cpp kstarslite/skyitems/deepstaritem.cpp kstarslite/skyitems/deepskyitem.cpp kstarslite/skyitems/constellationartitem.cpp kstarslite/skyitems/satellitesitem.cpp kstarslite/skyitems/supernovaeitem.cpp kstarslite/skyitems/fovitem.cpp kstarslite/skyitems/syncedcatalogitem.cpp #Line kstarslite/skyitems/lines/linesitem.cpp kstarslite/skyitems/lines/equatoritem.cpp kstarslite/skyitems/lines/eclipticitem.cpp kstarslite/skyitems/lines/milkywayitem.cpp #SkyNodes kstarslite/skyitems/skynodes/planetnode.cpp kstarslite/skyitems/skynodes/skynode.cpp kstarslite/skyitems/skynodes/pointsourcenode.cpp kstarslite/skyitems/skynodes/planetmoonsnode.cpp kstarslite/skyitems/skynodes/horizonnode.cpp kstarslite/skyitems/skynodes/labelnode.cpp kstarslite/skyitems/skynodes/guidelabelnode.cpp kstarslite/skyitems/skynodes/deepskynode.cpp kstarslite/skyitems/skynodes/dsosymbolnode.cpp kstarslite/skyitems/skynodes/skypolygonnode.cpp kstarslite/skyitems/skynodes/constellationartnode.cpp kstarslite/skyitems/skynodes/satellitenode.cpp kstarslite/skyitems/skynodes/supernovanode.cpp kstarslite/skyitems/skynodes/trixelnode.cpp kstarslite/skyitems/skynodes/fovsymbolnode.cpp #Nodes kstarslite/skyitems/skynodes/nodes/pointnode.cpp kstarslite/skyitems/skynodes/nodes/polynode.cpp kstarslite/skyitems/skynodes/nodes/linenode.cpp kstarslite/skyitems/skynodes/nodes/ellipsenode.cpp kstarslite/skyitems/skynodes/nodes/rectnode.cpp #Other kstarslite/deviceorientation.cpp #libtess libtess/dict.c libtess/geom.c libtess/gluos.h libtess/memalloc.c libtess/mesh.c libtess/normal.c libtess/priorityq-sort.h libtess/priorityq.c libtess/render.c libtess/sweep.c libtess/tess.c libtess/tessmono.c libtess/priorityq-heap.c libtess/dict-list.h libtess/glu.h libtess/tessellate.c ) #Qml files will be probably moved to user's data dir, but for use #with QtCreator it is more convenient to have them here set(kstarsliteqml_SRCS kstarslite/qml/main.qml kstarslite/qml/constants/Constants.qml kstarslite/qml/modules/SkyMapLiteWrapper.qml kstarslite/qml/modules/BottomMenu.qml kstarslite/qml/modules/KSPage.qml kstarslite/qml/modules/KSListView.qml kstarslite/qml/modules/KSLabel.qml kstarslite/qml/modules/KSText.qml kstarslite/qml/modules/KSTabButton.qml kstarslite/qml/modules/KSTab.qml kstarslite/qml/modules/KSTabBarArrow.qml kstarslite/qml/modules/KSTextField.qml kstarslite/qml/modules/KSButton.qml kstarslite/qml/modules/TopMenu.qml kstarslite/qml/modules/helpers/TopMenuButton.qml kstarslite/qml/modules/helpers/BottomMenuButton.qml kstarslite/qml/modules/Splash.qml kstarslite/qml/modules/helpers/TimeSpinBox.qml kstarslite/qml/modules/TimePage.qml #Popups kstarslite/qml/modules/popups/ProjectionsPopup.qml kstarslite/qml/modules/popups/FOVPopup.qml kstarslite/qml/modules/popups/ColorSchemePopup.qml #Menus kstarslite/qml/modules/menus/ContextMenu.qml #Helpers kstarslite/qml/modules/helpers/PassiveNotification.qml kstarslite/qml/modules/helpers/KSMenuItem.qml kstarslite/qml/modules/helpers/TelescopeControl.qml #Dialogs kstarslite/qml/dialogs/FindDialog.qml kstarslite/qml/dialogs/LocationDialog.qml kstarslite/qml/dialogs/DetailsDialog.qml kstarslite/qml/dialogs/helpers/DetailsItem.qml kstarslite/qml/dialogs/helpers/DetailsAddLink.qml kstarslite/qml/dialogs/helpers/LocationEdit.qml kstarslite/qml/dialogs/helpers/LocationLoading.qml kstarslite/qml/dialogs/menus/DetailsLinkMenu.qml kstarslite/qml/dialogs/menus/LocationsGeoMenu.qml #INDI kstarslite/qml/indi/INDIControlPanel.qml kstarslite/qml/indi/DevicePanel.qml kstarslite/qml/indi/ImagePreview.qml kstarslite/qml/indi/modules/MotionControl.qml kstarslite/qml/indi/modules/Led.qml kstarslite/qml/indi/modules/KSLed.qml kstarslite/qml/indi/modules/Property.qml kstarslite/qml/indi/modules/KSComboBox.qml kstarslite/qml/indi/modules/KSButtonSwitch.qml kstarslite/qml/indi/modules/KSCheckBox.qml kstarslite/qml/indi/modules/KSINDIText.qml kstarslite/qml/indi/modules/KSINDITextField.qml kstarslite/qml/indi/modules/KSButtonsSwitchRow.qml #Tutorial kstarslite/qml/modules/tutorial/TutorialPopup.qml kstarslite/qml/modules/tutorial/TutorialExitPopup.qml kstarslite/qml/modules/tutorial/TutorialStep1.qml kstarslite/qml/modules/tutorial/TutorialStep2.qml kstarslite/qml/modules/tutorial/TutorialStep3.qml kstarslite/qml/modules/tutorial/TutorialStep4.qml kstarslite/qml/modules/tutorial/TutorialStep5.qml kstarslite/qml/modules/tutorial/TutorialPane.qml ) add_subdirectory(kstarslite/qml) ADD_CUSTOM_TARGET(kstarsliteqml SOURCES ${kstarsliteqml_SRCS}) if(ANDROID) add_subdirectory(kstarslite/res) endif(ANDROID) endif(BUILD_KSTARS_LITE) set(kstars_SRCS ${indi_SRCS} ${fits_SRCS} ${ekos_SRCS} ${onlineparser_SRCS} ${libkstarswidgets_SRCS} ${libkstarscomponents_SRCS} ${libkstarstools_SRCS} ${kstars_extra_SRCS} ${kstars_gl_SRCS} ${kstars_projection_SRCS} ${xplanet_SRCS} ${kstars_options_SRCS} ${kstars_skyobjects_SRCS} ${kstars_dialogs_SRCS} ${oal_SRCS} ${printing_SRCS} #KStars Lite ${kstarslite_SRCS} ${indi_lite_SRCS} ) kconfig_add_kcfg_files(kstars_SRCS ${kstars_KCFG_SRCS}) if(NOT BUILD_KSTARS_LITE) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.xml kstars.h KStars) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.SimClock.xml simclock.h SimClock) if (INDI_FOUND) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.INDI.xml indi/indidbus.h INDIDBus) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.xml ekos/ekosmanager.h EkosManager) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Capture.xml ekos/capture/capture.h Ekos::Capture) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Focus.xml ekos/focus/focus.h Ekos::Focus) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Guide.xml ekos/guide/guide.h Ekos::Guide) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Align.xml ekos/align/align.h Ekos::Align) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Mount.xml ekos/mount/mount.h Ekos::Mount) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Dome.xml ekos/auxiliary/dome.h Ekos::Dome) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Weather.xml ekos/auxiliary/weather.h Ekos::Weather) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.DustCap.xml ekos/auxiliary/dustcap.h Ekos::DustCap) qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Scheduler.xml ekos/scheduler/scheduler.h Ekos::Scheduler) endif(INDI_FOUND) ki18n_wrap_ui(kstars_SRCS ${indiui_SRCS} ${ui_SRCS} ${fitsui_SRCS} ${ekosui_SRCS} ${xplanetui_SRCS} ${kstars_optionsui_SRCS} ${kstars_dialogsui_SRCS} ${printingui_SRCS} auxiliary/thumbnailpicker.ui auxiliary/thumbnaileditor.ui oal/observeradd.ui oal/equipmentwriter.ui oal/execute.ui #skycomponents/notifyupdatesui.ui ) endif(NOT BUILD_KSTARS_LITE) add_library(KStarsLib STATIC ${kstars_SRCS}) if(BUILD_KSTARS_LITE) target_link_libraries(KStarsLib LibKSDataHandlers htmesh KF5::I18n KF5::Plotting KF5::ConfigGui Qt5::Gui Qt5::Sql Qt5::Qml Qt5::Quick Qt5::QuickControls2 Qt5::Positioning Qt5::Concurrent ${ZLIB_LIBRARIES} ${QT_EXTRA_LIBRARIES} ) if(INDI_FOUND) if(ANDROID) #RAWExtractor is needed for converting RAW photos to JPEG in INDI Lite add_library(RAWExtractor SHARED IMPORTED) include_directories(${BUILD_KSTARSLITE_DIR}/include/libraw) set_property(TARGET RAWExtractor PROPERTY IMPORTED_LOCATION ${BUILD_KSTARSLITE_DIR}/android_libs/${ANDROID_ARCHITECTURE}/libRAWExtractor.so) target_link_libraries(KStarsLib RAWExtractor) endif(ANDROID) endif(INDI_FOUND) else(BUILD_KSTARS_LITE) target_link_libraries(KStarsLib LibKSDataHandlers htmesh KF5::Crash KF5::I18n KF5::NewStuff KF5::KIOFileWidgets KF5::WidgetsAddons KF5::Plotting Qt5::Gui Qt5::PrintSupport Qt5::Sql Qt5::Svg Qt5::Qml Qt5::Quick Qt5::Network Qt5::Concurrent ${ZLIB_LIBRARIES} ) if (KF5NotifyConfig_FOUND) target_link_libraries(KStarsLib KF5::NotifyConfig) endif(KF5NotifyConfig_FOUND) endif(BUILD_KSTARS_LITE) if(NOT WIN32) target_link_libraries(KStarsLib m) endif(NOT WIN32) if (CFITSIO_FOUND) target_link_libraries(KStarsLib ${CFITSIO_LIBRARIES}) endif(CFITSIO_FOUND) if(INDI_FOUND) find_package(Nova REQUIRED) include_directories(${NOVA_INCLUDE_DIR}) ## Support Multiple Platforms. All Require INDI + libnova ## WIN32 Desktop: Requires INDI Qt5 Client + GSL ## WIN32 Lite: Requires INDI Qt5 Client ## Linux + MacOS Desktop: Requires INDI Client + GSL ## Linux + MacOS Lite: Requires INDI Qt5 Client ## Android: Requires INDI Qt5 Client built for Android #if(BUILD_KSTARS_LITE) #target_link_libraries(KStarsLib ${CMAKE_THREAD_LIBS_INIT}) #else(BUILD_KSTARS_LITE) if(NOT BUILD_KSTARS_LITE) find_package(GSL REQUIRED) include_directories(${GSL_INCLUDE_DIRS}) target_link_libraries(KStarsLib ${GSL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} KF5::Notifications) endif(NOT BUILD_KSTARS_LITE) if(WIN32 OR ANDROID) add_definitions(-DUSE_QT5_INDI) if(ANDROID) target_link_libraries(KStarsLib ${INDI_CLIENT_ANDROID_LIBRARIES} ${NOVA_LIBRARIES}) else(ANDROID) target_link_libraries(KStarsLib ${INDI_CLIENT_QT_LIBRARIES} ${NOVA_LIBRARIES}) endif(ANDROID) else(WIN32 OR ANDROID) if(BUILD_KSTARS_LITE) add_definitions(-DUSE_QT5_INDI) target_link_libraries(KStarsLib ${INDI_CLIENT_QT_LIBRARIES} ${NOVA_LIBRARIES} z) else(BUILD_KSTARS_LITE) target_link_libraries(KStarsLib ${INDI_CLIENT_LIBRARIES} ${NOVA_LIBRARIES} z) endif(BUILD_KSTARS_LITE) endif(WIN32 OR ANDROID) endif(INDI_FOUND) if(WCSLIB_FOUND) target_link_libraries(KStarsLib ${WCSLIB_LIBRARIES}) endif (WCSLIB_FOUND) if(LibRaw_FOUND) if(NOT BUILD_KSTARS_LITE) target_link_libraries(KStarsLib ${LibRaw_LIBRARIES}) endif(NOT BUILD_KSTARS_LITE) endif (LibRaw_FOUND) #FIXME Enable OpenGL Later #if( OPENGL_FOUND ) # target_link_libraries(KStarsLib # ${OPENGL_LIBRARIES} # ${QT_QTOPENGL_LIBRARY} # ) #endif( OPENGL_FOUND ) set (KSTARS_APP_SRCS main.cpp ) if(NOT BUILD_KSTARS_LITE) # add icon to application sources ecm_add_app_icon(KSTARS_APP_SRCS ICONS ${CMAKE_CURRENT_SOURCE_DIR}/icons/16-apps-kstars.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/32-apps-kstars.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/48-apps-kstars.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/64-apps-kstars.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/128-apps-kstars.png ) qt5_add_resources(KSTARS_APP_SRCS data/kstars.qrc) endif(NOT BUILD_KSTARS_LITE) add_executable(kstars ${KSTARS_APP_SRCS}) target_link_libraries(kstars KStarsLib) if(NOT BUILD_KSTARS_LITE) install(TARGETS kstars ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(PROGRAMS org.kde.kstars.desktop DESTINATION ${KDE_INSTALL_APPDIR}) install(FILES kstars.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR}) install(FILES kstars.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR}) endif(NOT BUILD_KSTARS_LITE) diff --git a/kstars/ekos/guide/guide.cpp b/kstars/ekos/guide/guide.cpp index 9bf2b7ef5..d765530b5 100644 --- a/kstars/ekos/guide/guide.cpp +++ b/kstars/ekos/guide/guide.cpp @@ -1,2245 +1,2263 @@ /* Ekos Copyright (C) 2012 Jasem Mutlaq This application 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. */ #include "guide.h" #include #include #include #include #include #include #include #include "Options.h" #include "opscalibration.h" #include "opsguide.h" #include "internalguide/internalguider.h" #include "externalguide/phd2.h" #include "externalguide/linguider.h" #include "ekos/auxiliary/darklibrary.h" #include "auxiliary/QProgressIndicator.h" #include "indi/driverinfo.h" #include "indi/clientmanager.h" #include "fitsviewer/fitsviewer.h" #include "fitsviewer/fitsview.h" #include "guideadaptor.h" #include "kspaths.h" #include "kstarsdata.h" #include "auxiliary/qcustomplot.h" #define driftGraph_WIDTH 200 #define driftGraph_HEIGHT 200 #define MAX_GUIDE_STARS 10 namespace Ekos { Guide::Guide() : QWidget() { setupUi(this); new GuideAdaptor(this); QDBusConnection::sessionBus().registerObject("/KStars/Ekos/Guide", this); // Devices currentCCD = NULL; currentTelescope = NULL; guider = NULL; // AO Driver AODriver= NULL; // ST4 Driver GuideDriver=NULL; // Auto Star autoStarCaptured = false; // Subframe subFramed = false; // To do calibrate + guide in one command autoCalibrateGuide = false; guideView = new FITSView(guideWidget, FITS_GUIDE); guideView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); guideView->setBaseSize(guideWidget->size()); guideView->createFloatingToolBar(); QVBoxLayout * vlayout = new QVBoxLayout(); vlayout->addWidget(guideView); guideWidget->setLayout(vlayout); connect(guideView, SIGNAL(trackingStarSelected(int,int)), this, SLOT(setTrackingStar(int,int))); ccdPixelSizeX = ccdPixelSizeY = mountAperture = mountFocalLength = pixScaleX = pixScaleY = -1; guideDeviationRA = guideDeviationDEC = 0; useGuideHead = false; //rapidGuideReticleSet = false; // Guiding Rate - Advisory only connect( spinBox_GuideRate, SIGNAL(valueChanged(double)), this, SLOT(onInfoRateChanged(double)) ); // Load all settings loadSettings(); // Image Filters foreach(QString filter, FITSViewer::filterTypes) filterCombo->addItem(filter); // Progress Indicator pi = new QProgressIndicator(this); controlLayout->addWidget(pi, 0, 1, 1, 1); showFITSViewerB->setIcon(QIcon::fromTheme("kstars_fitsviewer", QIcon(":/icons/breeze/default/kstars_fitsviewer.svg"))); connect(showFITSViewerB, SIGNAL(clicked()), this, SLOT(showFITSViewer())); // Exposure connect(exposureIN, SIGNAL(editingFinished()), this, SLOT(saveDefaultGuideExposure())); // Guiding Box Size connect(boxSizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTrackingBoxSize(int))); // Guider CCD Selection //connect(guiderCombo, SIGNAL(activated(QString)), this, SLOT(setDefaultCCD(QString))); connect(guiderCombo, static_cast(&QComboBox::activated), this, [&](const QString & ccd) { Options::setDefaultGuideCCD(ccd); }); connect(guiderCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(checkCCD(int))); // Dark Frame Check connect(darkFrameCheck, SIGNAL(toggled(bool)), this, SLOT(setDarkFrameEnabled(bool))); // Subframe check connect(subFrameCheck, SIGNAL(toggled(bool)), this, SLOT(setSubFrameEnabled(bool))); // ST4 Selection connect(ST4Combo, SIGNAL(currentIndexChanged(int)), this, SLOT(setST4(int))); //connect(ST4Combo, SIGNAL(activated(QString)), this, SLOT(setDefaultST4(QString))); //connect(ST4Combo, static_cast(&QComboBox::activated), this, [&](const QString & st4){Options::setDefaultST4Driver(st4);}); // Binning Combo Selection connect(binningCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateCCDBin(int))); // RA/DEC Enable directions connect( checkBox_DirRA, SIGNAL(toggled(bool)), this, SLOT(onEnableDirRA(bool)) ); connect( checkBox_DirDEC, SIGNAL(toggled(bool)), this, SLOT(onEnableDirDEC(bool)) ); // N/W and W/E direction enable connect( northControlCheck, SIGNAL(toggled(bool)), this, SLOT(onControlDirectionChanged(bool))); connect( southControlCheck, SIGNAL(toggled(bool)), this, SLOT(onControlDirectionChanged(bool))); connect( westControlCheck, SIGNAL(toggled(bool)), this, SLOT(onControlDirectionChanged(bool))); connect( eastControlCheck, SIGNAL(toggled(bool)), this, SLOT(onControlDirectionChanged(bool))); // Declination Swap connect(swapCheck, SIGNAL(toggled(bool)), this, SLOT(setDECSwap(bool))); // PID Control - Proportional Gain connect( spinBox_PropGainRA, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); connect( spinBox_PropGainDEC, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); // PID Control - Integral Gain connect( spinBox_IntGainRA, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); connect( spinBox_IntGainDEC, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); // PID Control - Derivative Gain connect( spinBox_DerGainRA, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); connect( spinBox_DerGainDEC, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); // Max Pulse Duration (ms) connect( spinBox_MaxPulseRA, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); connect( spinBox_MaxPulseDEC, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); // Min Pulse Duration (ms) connect( spinBox_MinPulseRA, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); connect( spinBox_MinPulseDEC, SIGNAL(editingFinished()), this, SLOT(onInputParamChanged()) ); // Capture connect(captureB, SIGNAL(clicked()), this, SLOT(capture())); // Stop connect(stopB, SIGNAL(clicked()), this, SLOT(abort())); // Calibrate connect(calibrateB, SIGNAL(clicked()), this, SLOT(calibrate())); // Guide connect(guideB, SIGNAL(clicked()), this, SLOT(guide())); // Connect External Guide connect(externalConnectB, &QPushButton::clicked, this, [&]() { guider->Connect(); }); connect(externalDisconnectB, &QPushButton::clicked, this, [&]() { guider->Disconnect(); }); // Pulse Timer pulseTimer.setSingleShot(true); connect(&pulseTimer, SIGNAL(timeout()), this, SLOT(capture())); // Drift Graph driftGraph->setBackground(QBrush(Qt::black)); driftGraph->xAxis->setBasePen(QPen(Qt::white, 1)); driftGraph->yAxis->setBasePen(QPen(Qt::white, 1)); driftGraph->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); driftGraph->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); driftGraph->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); driftGraph->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); driftGraph->xAxis->grid()->setZeroLinePen(Qt::NoPen); driftGraph->yAxis->grid()->setZeroLinePen(Qt::NoPen); driftGraph->xAxis->setBasePen(QPen(Qt::white, 1)); driftGraph->yAxis->setBasePen(QPen(Qt::white, 1)); driftGraph->xAxis->setTickPen(QPen(Qt::white, 1)); driftGraph->yAxis->setTickPen(QPen(Qt::white, 1)); driftGraph->xAxis->setSubTickPen(QPen(Qt::white, 1)); driftGraph->yAxis->setSubTickPen(QPen(Qt::white, 1)); driftGraph->xAxis->setTickLabelColor(Qt::white); driftGraph->yAxis->setTickLabelColor(Qt::white); driftGraph->xAxis->setLabelColor(Qt::white); driftGraph->yAxis->setLabelColor(Qt::white); driftGraph->xAxis->setRange(0, 120, Qt::AlignRight); driftGraph->legend->setVisible(true); driftGraph->legend->setFont(QFont("Helvetica",9)); driftGraph->legend->setTextColor(Qt::white); driftGraph->legend->setBrush(QBrush(Qt::black)); // RA Curve driftGraph->addGraph(); driftGraph->graph(0)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"))); driftGraph->graph(0)->setName("RA"); driftGraph->graph(0)->setLineStyle(QCPGraph::lsStepLeft); // DE Curve driftGraph->addGraph(); driftGraph->graph(1)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"))); driftGraph->graph(1)->setName("DE"); driftGraph->graph(1)->setLineStyle(QCPGraph::lsStepLeft); QSharedPointer timeTicker(new QCPAxisTickerTime); timeTicker->setTimeFormat("%m:%s"); driftGraph->xAxis->setTicker(timeTicker); driftGraph->axisRect()->setupFullAxesBox(); driftGraph->yAxis->setRange(-3, 3); // make left and bottom axes transfer their ranges to right and top axes: connect(driftGraph->xAxis, SIGNAL(rangeChanged(QCPRange)), driftGraph->xAxis2, SLOT(setRange(QCPRange))); connect(driftGraph->yAxis, SIGNAL(rangeChanged(QCPRange)), driftGraph->yAxis2, SLOT(setRange(QCPRange))); driftGraph->setInteractions(QCP::iRangeZoom); driftGraph->setInteraction(QCP::iRangeDrag, true); connect(driftGraph, SIGNAL(mouseMove(QMouseEvent *)), this, SLOT(driftMouseOverLine(QMouseEvent *))); connect(driftGraph, SIGNAL(mousePress(QMouseEvent *)), this, SLOT(driftMouseClicked(QMouseEvent *))); // Init Internal Guider always internalGuider = new InternalGuider(); KConfigDialog * dialog = new KConfigDialog(this, "guidesettings", Options::self()); opsCalibration = new OpsCalibration(internalGuider); dialog->addPage(opsCalibration, i18n("Calibration Settings")); opsGuide = new OpsGuide(); dialog->addPage(opsGuide, i18n("Guide Settings")); connect(guideOptionsB, SIGNAL(clicked()), dialog, SLOT(show())); connect(opsGuide, SIGNAL(guiderTypeChanged(int)), this, SLOT(setGuiderType(int))); internalGuider->setGuideView(guideView); state = GUIDE_IDLE; // Set current guide type setGuiderType(-1); } Guide::~Guide() { delete guider; } void Guide::addCCD(ISD::GDInterface * newCCD) { ISD::CCD * ccd = static_cast(newCCD); if (CCDs.contains(ccd)) return; CCDs.append(ccd); guiderCombo->addItem(ccd->getDeviceName()); /* * * Check if this is necessary to save bandwidth if (guideType == GUIDE_INTERNAL) { // Receive BLOBs from the driver currentCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_ALSO, currentCCD->getDeviceName(), useGuideHead ? "CCD2" : "CCD1"); } else // Do NOT Receive BLOBs from the driver currentCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_NEVER, currentCCD->getDeviceName(), useGuideHead ? "CCD2" : "CCD1"); */ //checkCCD(CCDs.count()-1); //guiderCombo->setCurrentIndex(CCDs.count()-1); // setGuiderProcess(Options::useEkosGuider() ? GUIDE_INTERNAL : GUIDE_PHD2); } void Guide::addGuideHead(ISD::GDInterface * newCCD) { ISD::CCD * ccd = static_cast (newCCD); CCDs.append(ccd); QString guiderName = ccd->getDeviceName() + QString(" Guider"); if (guiderCombo->findText(guiderName) == -1) { guiderCombo->addItem(guiderName); //CCDs.append(static_cast (newCCD)); } //checkCCD(CCDs.count()-1); //guiderCombo->setCurrentIndex(CCDs.count()-1); //setGuiderProcess(Options::useEkosGuider() ? GUIDE_INTERNAL : GUIDE_PHD2); } void Guide::setTelescope(ISD::GDInterface * newTelescope) { currentTelescope = (ISD::Telescope *) newTelescope; syncTelescopeInfo(); } bool Guide::setCCD(QString device) { for (int i=0; i < guiderCombo->count(); i++) if (device == guiderCombo->itemText(i)) { guiderCombo->setCurrentIndex(i); return true; } return false; } void Guide::checkCCD(int ccdNum) { if (ccdNum == -1) { ccdNum = guiderCombo->currentIndex(); if (ccdNum == -1) return; } if (ccdNum <= CCDs.count()) { currentCCD = CCDs.at(ccdNum); //connect(currentCCD, SIGNAL(FITSViewerClosed()), this, SLOT(viewerClosed()), Qt::UniqueConnection); connect(currentCCD, SIGNAL(numberUpdated(INumberVectorProperty *)), this, SLOT(processCCDNumber(INumberVectorProperty *)), Qt::UniqueConnection); connect(currentCCD, SIGNAL(newExposureValue(ISD::CCDChip *,double,IPState)), this, SLOT(checkExposureValue(ISD::CCDChip *,double,IPState)), Qt::UniqueConnection); // If guider is external and already connected and remote images option was disabled AND it was already // disabled, then let's go ahead and disable it. #if 0 if (guiderType != GUIDE_INTERNAL && Options::guideRemoteImagesEnabled() == false && guider->isConnected()) { for (int i=0; i < CCDs.count(); i++) { ISD::CCD * oneCCD = CCDs[i]; if (i == ccdNum && oneCCD->getDriverInfo()->getClientManager()->getBLOBMode(oneCCD->getDeviceName(), "CCD1") != B_NEVER) { appendLogText(i18n("Disabling remote image reception from %1", oneCCD->getDeviceName())); oneCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_NEVER, oneCCD->getDeviceName(), "CCD1"); oneCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_NEVER, oneCCD->getDeviceName(), "CCD2"); } // If it was already disabled, enable it back else if (i != ccdNum && oneCCD->getDriverInfo()->getClientManager()->getBLOBMode(oneCCD->getDeviceName(), "CCD1") == B_NEVER) { appendLogText(i18n("Enabling remote image reception from %1", oneCCD->getDeviceName())); oneCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_ALSO, oneCCD->getDeviceName(), "CCD1"); oneCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_ALSO, oneCCD->getDeviceName(), "CCD2"); } } } #endif if (currentCCD->hasGuideHead() && guiderCombo->currentText().contains("Guider")) useGuideHead=true; else useGuideHead=false; ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); targetChip->setImageView(guideView, FITS_GUIDE); syncCCDInfo(); } } void Guide::syncCCDInfo() { INumberVectorProperty * nvp = NULL; if (currentCCD == NULL) return; if (useGuideHead) nvp = currentCCD->getBaseDevice()->getNumber("GUIDER_INFO"); else nvp = currentCCD->getBaseDevice()->getNumber("CCD_INFO"); if (nvp) { INumber * np = IUFindNumber(nvp, "CCD_PIXEL_SIZE_X"); if (np) ccdPixelSizeX = np->value; np = IUFindNumber(nvp, "CCD_PIXEL_SIZE_Y"); if (np) ccdPixelSizeY = np->value; np = IUFindNumber(nvp, "CCD_PIXEL_SIZE_Y"); if (np) ccdPixelSizeY = np->value; } updateGuideParams(); } void Guide::syncTelescopeInfo() { if (currentTelescope == NULL) return; INumberVectorProperty * nvp = currentTelescope->getBaseDevice()->getNumber("TELESCOPE_INFO"); if (nvp) { INumber * np = IUFindNumber(nvp, "GUIDER_APERTURE"); if (np && np->value != 0) mountAperture = np->value; else { np = IUFindNumber(nvp, "TELESCOPE_APERTURE"); if (np) mountAperture = np->value; } np = IUFindNumber(nvp, "GUIDER_FOCAL_LENGTH"); if (np && np->value != 0) mountFocalLength = np->value; else { np = IUFindNumber(nvp, "TELESCOPE_FOCAL_LENGTH"); if (np) mountFocalLength = np->value; } } updateGuideParams(); } void Guide::updateGuideParams() { if (currentCCD == NULL) return; if (currentCCD->hasGuideHead() == false) useGuideHead = false; ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); if (targetChip == NULL) { appendLogText(i18n("Connection to the guide CCD is lost.")); return; } binningCombo->setEnabled(targetChip->canBin() && (guiderType == GUIDE_INTERNAL)); int subBinX=1,subBinY=1; if (targetChip->canBin()) { int maxBinX, maxBinY; targetChip->getBinning(&subBinX, &subBinY); targetChip->getMaxBin(&maxBinX, &maxBinY); binningCombo->blockSignals(true); binningCombo->clear(); for (int i=1; i <= maxBinX; i++) binningCombo->addItem(QString("%1x%2").arg(i).arg(i)); binningCombo->setCurrentIndex(subBinX-1); binningCombo->blockSignals(false); } if (frameSettings.contains(targetChip) == false) { int x,y,w,h; if (targetChip->getFrame(&x, &y, &w, &h)) { if (w > 0 && h > 0) { QVariantMap settings; settings["x"] = x; settings["y"] = y; settings["w"] = w; settings["h"] = h; settings["binx"] = subBinX; settings["biny"] = subBinY; frameSettings[targetChip] = settings; } } } if (ccdPixelSizeX != -1 && ccdPixelSizeY != -1 && mountAperture != -1 && mountFocalLength != -1) { guider->setGuiderParams(ccdPixelSizeX, ccdPixelSizeY, mountAperture, mountFocalLength); emit guideChipUpdated(targetChip); int x,y,w,h; if (targetChip->getFrame(&x,&y,&w,&h)) { guider->setFrameParams(x,y,w,h, subBinX, subBinY); } l_Focal->setText(QString::number(mountFocalLength, 'f', 1)); l_Aperture->setText(QString::number(mountAperture, 'f', 1)); l_FbyD->setText(QString::number(mountFocalLength/mountAperture, 'f', 1)); // Pixel scale in arcsec/pixel pixScaleX = 206264.8062470963552 * ccdPixelSizeX / 1000.0 / mountFocalLength; pixScaleY = 206264.8062470963552 * ccdPixelSizeY / 1000.0 / mountFocalLength; // FOV in arcmin double fov_w = (w*pixScaleX)/60.0; double fov_h = (h*pixScaleY)/60.0; l_FOV->setText(QString("%1x%2").arg(QString::number(fov_w, 'f', 1)).arg(QString::number(fov_h, 'f', 1))); } } void Guide::addST4(ISD::ST4 * newST4) { foreach(ISD::ST4 * guidePort, ST4List) { if (!strcmp(guidePort->getDeviceName(),newST4->getDeviceName())) return; } ST4List.append(newST4); ST4Combo->blockSignals(true); ST4Combo->addItem(newST4->getDeviceName()); ST4Combo->blockSignals(false); // Always set the ST4Driver to the first added driver. If the default driver // is at another index, setST4(device) will be called from Ekos which will set a new index and that will then // trigger setST4(index) to update the final ST4 driver. ST4Driver=GuideDriver=ST4List[0]; } bool Guide::setST4(QString device) { for (int i=0; i < ST4List.count(); i++) if (ST4List.at(i)->getDeviceName() == device) { ST4Combo->setCurrentIndex(i); return true; } return false; } void Guide::setST4(int index) { if (ST4List.empty() || index >= ST4List.count()) return; ST4Driver = ST4List.at(index); GuideDriver = ST4Driver; Options::setDefaultST4Driver(ST4Driver->getDeviceName()); } void Guide::setAO(ISD::ST4 * newAO) { AODriver = newAO; //guider->setAO(true); } bool Guide::capture() { buildOperationStack(GUIDE_CAPTURE); return executeOperationStack(); } bool Guide::captureOneFrame() { if (currentCCD == NULL) return false; if (currentCCD->isConnected() == false) { appendLogText(i18n("Error: Lost connection to CCD.")); return false; } double seqExpose = exposureIN->value(); ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); targetChip->setCaptureMode(FITS_GUIDE); targetChip->setFrameType(FRAME_LIGHT); if (darkFrameCheck->isChecked()) targetChip->setCaptureFilter(FITS_NONE); else targetChip->setCaptureFilter((FITSScale) filterCombo->currentIndex()); guideView->setBaseSize(guideWidget->size()); setBusy(true); if (frameSettings.contains(targetChip)) { QVariantMap settings = frameSettings[targetChip]; targetChip->setFrame(settings["x"].toInt(), settings["y"].toInt(), settings["w"].toInt(), settings["h"].toInt()); } #if 0 switch (state) { case GUIDE_GUIDING: if (Options::rapidGuideEnabled() == false) connect(currentCCD, SIGNAL(BLOBUpdated(IBLOB *)), this, SLOT(newFITS(IBLOB *)), Qt::UniqueConnection); targetChip->capture(seqExpose); return true; break; default: break; } #endif currentCCD->setTransformFormat(ISD::CCD::FORMAT_FITS); connect(currentCCD, SIGNAL(BLOBUpdated(IBLOB *)), this, SLOT(newFITS(IBLOB *)), Qt::UniqueConnection); if (Options::guideLogging()) qDebug() << "Guide: Capturing frame..."; targetChip->capture(seqExpose); return true; } bool Guide::abort() { if (currentCCD && guiderType == GUIDE_INTERNAL) { pulseTimer.stop(); ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); if (targetChip->isCapturing()) targetChip->abortExposure(); } setBusy(false); switch (state) { case GUIDE_IDLE: case GUIDE_CONNECTED: break; case GUIDE_DISCONNECTED: #if 0 if (currentCCD && guiderType != GUIDE_INTERNAL && Options::guideRemoteImagesEnabled() == false) { currentCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_ALSO, currentCCD->getDeviceName(), "CCD1"); currentCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_ALSO, currentCCD->getDeviceName(), "CCD2"); } #endif break; case GUIDE_CALIBRATING: case GUIDE_DITHERING: case GUIDE_STAR_SELECT: case GUIDE_CAPTURE: case GUIDE_GUIDING: guider->abort(); default: break; } return true; } void Guide::setBusy(bool enable) { if (enable && pi->isAnimated()) return; else if (enable == false && pi->isAnimated() == false) return; if (enable) { calibrateB->setEnabled(false); guideB->setEnabled(false); captureB->setEnabled(false); darkFrameCheck->setEnabled(false); subFrameCheck->setEnabled(false); stopB->setEnabled(true); pi->startAnimation(); //disconnect(guideView, SIGNAL(trackingStarSelected(int,int)), this, SLOT(setTrackingStar(int,int))); } else { if (guiderType == GUIDE_INTERNAL) { captureB->setEnabled(true); darkFrameCheck->setEnabled(true); subFrameCheck->setEnabled(true); } // All can calibrate except for PHD2 if (guiderType != GUIDE_PHD2) calibrateB->setEnabled(true); if (calibrationComplete || guiderType != GUIDE_INTERNAL) guideB->setEnabled(true); stopB->setEnabled(false); pi->stopAnimation(); connect(guideView, SIGNAL(trackingStarSelected(int,int)), this, SLOT(setTrackingStar(int,int)), Qt::UniqueConnection); } } void Guide::newFITS(IBLOB * bp) { INDI_UNUSED(bp); disconnect(currentCCD, SIGNAL(BLOBUpdated(IBLOB *)), this, SLOT(newFITS(IBLOB *))); if (Options::guideLogging()) qDebug() << "Guide: received guide frame."; ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); int subBinX=1, subBinY=1; targetChip->getBinning(&subBinX, &subBinY); if (starCenter.x() == 0 && starCenter.y() == 0) { int x=0, y=0, w=0,h=0; if (frameSettings.contains(targetChip)) { QVariantMap settings = frameSettings[targetChip]; x = settings["x"].toInt(); y = settings["y"].toInt(); w = settings["w"].toInt(); h = settings["h"].toInt(); } else targetChip->getFrame(&x, &y, &w, &h); starCenter.setX(w/(2*subBinX)); starCenter.setY(h/(2*subBinY)); starCenter.setZ(subBinX); } syncTrackingBoxPosition(); setCaptureComplete(); /*if (operationStack.isEmpty()) setCaptureComplete(); else executeOperationStack();*/ } void Guide::setCaptureComplete() { if (operationStack.isEmpty() == false) { executeOperationStack(); return; } DarkLibrary::Instance()->disconnect(this); switch (state) { case GUIDE_IDLE: case GUIDE_ABORTED: case GUIDE_CONNECTED: case GUIDE_DISCONNECTED: case GUIDE_CALIBRATION_SUCESS: case GUIDE_CALIBRATION_ERROR: case GUIDE_DITHERING_ERROR: setBusy(false); break; case GUIDE_CALIBRATING: guider->calibrate(); break; case GUIDE_GUIDING: guider->guide(); break; case GUIDE_DITHERING: guider->dither(Options::ditherPixels()); break; default: break; } emit newStarPixmap(guideView->getTrackingBoxPixmap()); } void Guide::appendLogText(const QString &text) { logText.insert(0, i18nc("log entry; %1 is the date, %2 is the text", "%1 %2", QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss"), text)); if (Options::guideLogging()) qDebug() << "Guide: " << text; emit newLog(); } void Guide::clearLog() { logText.clear(); emit newLog(); } void Guide::setDECSwap(bool enable) { if (ST4Driver == NULL || guider == NULL) return; if (guiderType == GUIDE_INTERNAL) { dynamic_cast(guider)->setDECSwap(enable); ST4Driver->setDECSwap(enable); } } bool Guide::sendPulse( GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs ) { if (GuideDriver == NULL || (ra_dir == NO_DIR && dec_dir == NO_DIR)) return false; if (state == GUIDE_CALIBRATING) pulseTimer.start( (ra_msecs > dec_msecs ? ra_msecs : dec_msecs) + 100); return GuideDriver->doPulse(ra_dir, ra_msecs, dec_dir, dec_msecs); } bool Guide::sendPulse( GuideDirection dir, int msecs ) { if (GuideDriver == NULL || dir==NO_DIR) return false; if (state == GUIDE_CALIBRATING) pulseTimer.start(msecs+100); return GuideDriver->doPulse(dir, msecs); } QStringList Guide::getST4Devices() { QStringList devices; foreach(ISD::ST4 * driver, ST4List) devices << driver->getDeviceName(); return devices; } #if 0 void Guide::processRapidStarData(ISD::CCDChip * targetChip, double dx, double dy, double fit) { // Check if guide star is lost if (dx == -1 && dy == -1 && fit == -1) { KMessageBox::error(NULL, i18n("Lost track of the guide star. Rapid guide aborted.")); guider->abort(); return; } FITSView * targetImage = targetChip->getImage(FITS_GUIDE); if (targetImage == NULL) { pmath->setImageView(NULL); guider->setImageView(NULL); calibration->setImageView(NULL); } if (rapidGuideReticleSet == false) { // Let's set reticle parameter on first capture to those of the star, then we check if there // is any set double x,y,angle; pmath->getReticleParameters(&x, &y, &angle); pmath->setReticleParameters(dx, dy, angle); rapidGuideReticleSet = true; } pmath->setRapidStarData(dx, dy); if (guider->isDithering()) { pmath->performProcessing(); if (guider->dither() == false) { appendLogText(i18n("Dithering failed. Autoguiding aborted.")); emit newStatus(GUIDE_DITHERING_ERROR); guider->abort(); //emit ditherFailed(); } } else { guider->guide(); capture(); } } void Guide::startRapidGuide() { ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); if (currentCCD->setRapidGuide(targetChip, true) == false) { appendLogText(i18n("The CCD does not support Rapid Guiding. Aborting...")); guider->abort(); return; } rapidGuideReticleSet = false; pmath->setRapidGuide(true); currentCCD->configureRapidGuide(targetChip, true); connect(currentCCD, SIGNAL(newGuideStarData(ISD::CCDChip *,double,double,double)), this, SLOT(processRapidStarData(ISD::CCDChip *,double,double,double))); } void Guide::stopRapidGuide() { ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); pmath->setRapidGuide(false); rapidGuideReticleSet = false; currentCCD->disconnect(SIGNAL(newGuideStarData(ISD::CCDChip *,double,double,double))); currentCCD->configureRapidGuide(targetChip, false, false, false); currentCCD->setRapidGuide(targetChip, false); } #endif bool Guide::calibrate() { // Set status to idle and let the operations change it as they get executed state = GUIDE_IDLE; emit newStatus(state); ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); if (frameSettings.contains(targetChip)) { targetChip->resetFrame(); int x,y,w,h; targetChip->getFrame(&x, &y, &w, &h); QVariantMap settings = frameSettings[targetChip]; settings["x"] = x; settings["y"] = y; settings["w"] = w; settings["h"] = h; frameSettings[targetChip] = settings; subFramed = false; } saveSettings(); buildOperationStack(GUIDE_CALIBRATING); executeOperationStack(); if (Options::guideLogging()) { qDebug() << "Guide: Starting calibration via " << ST4Combo->currentText(); } return true; } bool Guide::guide() { saveSettings(); bool rc = guider->guide(); return rc; } bool Guide::dither() { if (state == GUIDE_DITHERING) return true; if (guiderType == GUIDE_INTERNAL) { if (state != GUIDE_GUIDING) capture(); setStatus(GUIDE_DITHERING); return true; } else return guider->dither(Options::ditherPixels()); } bool Guide::suspend() { if (state == GUIDE_SUSPENDED) return true; else if (state >= GUIDE_CAPTURE) return guider->suspend(); else return false; } bool Guide::resume() { if (state == GUIDE_GUIDING) return true; else if (state == GUIDE_SUSPENDED) return guider->resume(); else return false; } void Guide::setCaptureStatus(CaptureState newState) { switch (newState) { case CAPTURE_DITHERING: dither(); break; default: break; } } void Guide::setMountStatus(ISD::Telescope::TelescopeStatus newState) { switch (newState) { case ISD::Telescope::MOUNT_SLEWING: case ISD::Telescope::MOUNT_PARKING: captureB->setEnabled(false); calibrateB->setEnabled(false); if (newState == ISD::Telescope::MOUNT_PARKING) abort(); break; default: if (pi->isAnimated() == false) { captureB->setEnabled(true); calibrateB->setEnabled(true); } } } void Guide::setExposure(double value) { exposureIN->setValue(value); } void Guide::setImageFilter(const QString &value) { for (int i=0; i < filterCombo->count(); i++) if (filterCombo->itemText(i) == value) { filterCombo->setCurrentIndex(i); break; } } void Guide::setCalibrationTwoAxis(bool enable) { Options::setTwoAxisEnabled(enable); } void Guide::setCalibrationAutoStar(bool enable) { Options::setGuideAutoStarEnabled(enable); } void Guide::setCalibrationAutoSquareSize(bool enable) { Options::setGuideAutoSquareSizeEnabled(enable); } void Guide::setCalibrationPulseDuration(int pulseDuration) { Options::setCalibrationPulseDuration(pulseDuration); } void Guide::setGuideBoxSizeIndex(int index) { Options::setGuideSquareSizeIndex(index); } void Guide::setGuideAlgorithmIndex(int index) { Options::setGuideAlgorithm(index); } void Guide::setSubFrameEnabled(bool enable) { Options::setGuideSubframeEnabled(enable); if (subFrameCheck->isChecked() != enable) subFrameCheck->setChecked(enable); } #if 0 void Guide::setGuideRapidEnabled(bool enable) { //guider->setGuideOptions(guider->getAlgorithm(), guider->useSubFrame() , enable); } #endif void Guide::setDitherSettings(bool enable, double value) { Options::setDitherEnabled(enable); Options::setDitherPixels(value); } QList Guide::getGuidingDeviation() { QList deviation; deviation << guideDeviationRA << guideDeviationDEC; return deviation; } void Guide::startAutoCalibrateGuide() { // A must for auto stuff Options::setGuideAutoStarEnabled(true); calibrationComplete = false; autoCalibrateGuide = true; calibrate(); } void Guide::setStatus(Ekos::GuideState newState) { if (newState == state) return; GuideState previousState = state; state = newState; emit newStatus(state); switch (state) { case GUIDE_CONNECTED: appendLogText(i18n("External guider connected.")); externalConnectB->setEnabled(false); externalDisconnectB->setEnabled(true); if (guiderType == GUIDE_LINGUIDER) calibrateB->setEnabled(true); guideB->setEnabled(true); #if 0 if (currentCCD && guiderType != GUIDE_INTERNAL && Options::guideRemoteImagesEnabled() == false) { appendLogText(i18n("Disabling remote image reception from %1", currentCCD->getDeviceName())); currentCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_NEVER, currentCCD->getDeviceName(), "CCD1"); currentCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_NEVER, currentCCD->getDeviceName(), "CCD2"); } #endif break; case GUIDE_DISCONNECTED: appendLogText(i18n("External guider disconnected.")); externalConnectB->setEnabled(true); externalDisconnectB->setEnabled(false); calibrateB->setEnabled(false); guideB->setEnabled(false); #if 0 if (currentCCD && guiderType != GUIDE_INTERNAL && Options::guideRemoteImagesEnabled() == false) { appendLogText(i18n("Enabling remote image reception from %1", currentCCD->getDeviceName())); currentCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_ALSO, currentCCD->getDeviceName(), "CCD1"); currentCCD->getDriverInfo()->getClientManager()->setBLOBMode(B_ALSO, currentCCD->getDeviceName(), "CCD2"); } #endif break; case GUIDE_CALIBRATION_SUCESS: appendLogText(i18n("Calibration completed.")); calibrationComplete = true; if (autoCalibrateGuide) { autoCalibrateGuide = false; guide(); } else setBusy(false); break; case GUIDE_CALIBRATION_ERROR: setBusy(false); break; case GUIDE_CALIBRATING: appendLogText(i18n("Calibration started.")); setBusy(true); break; case GUIDE_GUIDING: if (previousState == GUIDE_SUSPENDED || previousState == GUIDE_DITHERING_SUCCESS) appendLogText(i18n("Guiding resumed.")); else { appendLogText(i18n("Autoguiding started.")); setBusy(true); driftGraph->graph(0)->data().clear(); driftGraph->graph(1)->data().clear(); guideTimer = QTime::currentTime(); refreshColorScheme(); } break; case GUIDE_ABORTED: appendLogText(i18n("Autoguiding aborted.")); setBusy(false); break; case GUIDE_SUSPENDED: appendLogText(i18n("Guiding suspended.")); break; case GUIDE_DITHERING: appendLogText(i18n("Dithering in progress.")); break; case GUIDE_DITHERING_ERROR: appendLogText(i18n("Dithering failed!")); // LinGuider guide continue after dithering failure if (guiderType != GUIDE_LINGUIDER) { //state = GUIDE_IDLE; state = GUIDE_ABORTED; setBusy(false); } break; case GUIDE_DITHERING_SUCCESS: appendLogText(i18n("Dithering completed successfully.")); // Go back to guiding state immediately setStatus(GUIDE_GUIDING); capture(); break; default: break; } } void Guide::updateCCDBin(int index) { if (currentCCD == NULL && guiderType != GUIDE_INTERNAL) return; ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); targetChip->setBinning(index+1, index+1); QVariantMap settings = frameSettings[targetChip]; settings["binx"] = index+1; settings["biny"] = index+1; frameSettings[targetChip] = settings; } void Guide::processCCDNumber(INumberVectorProperty * nvp) { if (currentCCD == NULL || strcmp(nvp->device, currentCCD->getDeviceName()) || guiderType != GUIDE_INTERNAL) return; if ( (!strcmp(nvp->name, "CCD_BINNING") && useGuideHead == false) || (!strcmp(nvp->name, "GUIDER_BINNING") && useGuideHead) ) { binningCombo->disconnect(); binningCombo->setCurrentIndex(nvp->np[0].value-1); connect(binningCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateCCDBin(int))); } } void Guide::checkExposureValue(ISD::CCDChip * targetChip, double exposure, IPState expState) { if (guiderType != GUIDE_INTERNAL) return; INDI_UNUSED(exposure); if (expState == IPS_ALERT && ( (state == GUIDE_GUIDING) || (state == GUIDE_DITHERING) || (state == GUIDE_CALIBRATING)) ) { appendLogText(i18n("Exposure failed. Restarting exposure...")); currentCCD->setTransformFormat(ISD::CCD::FORMAT_FITS); targetChip->capture(exposureIN->value()); } } void Guide::setDarkFrameEnabled(bool enable) { Options::setGuideDarkFrameEnabled(enable); if (darkFrameCheck->isChecked() != enable) darkFrameCheck->setChecked(enable); } void Guide::saveDefaultGuideExposure() { Options::setGuideExposure(exposureIN->value()); } void Guide::setStarPosition(const QVector3D &newCenter, bool updateNow) { starCenter.setX(newCenter.x()); starCenter.setY(newCenter.y()); if (newCenter.z() > 0) starCenter.setZ(newCenter.z()); if (updateNow) syncTrackingBoxPosition(); } void Guide::syncTrackingBoxPosition() { ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); Q_ASSERT(targetChip); int subBinX=1, subBinY=1; targetChip->getBinning(&subBinX, &subBinY); if (starCenter.isNull() == false) { double boxSize = boxSizeCombo->currentText().toInt(); int x,y,w,h; targetChip->getFrame(&x,&y,&w,&h); // If box size is larger than image size, set it to lower index if (boxSize/subBinX >= w || boxSize/subBinY >= h) { int newIndex = boxSizeCombo->currentIndex()-1; if (newIndex >= 0) boxSizeCombo->setCurrentIndex(newIndex); return; } // If binning changed, update coords accordingly if (subBinX != starCenter.z()) { if (starCenter.z() > 0) { starCenter.setX(starCenter.x() * (starCenter.z()/subBinX)); starCenter.setY(starCenter.y() * (starCenter.z()/subBinY)); } starCenter.setZ(subBinX); } QRect starRect = QRect( starCenter.x()-boxSize/(2*subBinX), starCenter.y()-boxSize/(2*subBinY), boxSize/subBinX, boxSize/subBinY); guideView->setTrackingBoxEnabled(true); guideView->setTrackingBox(starRect); } } bool Guide::setGuiderType(int type) { // Use default guider option if (type == -1) type = Options::guiderType(); else if (type == guiderType) return true; if (state == GUIDE_CALIBRATING || state == GUIDE_GUIDING || state == GUIDE_DITHERING) { appendLogText(i18n("Cannot change guider type while active.")); return false; } if (guider) guider->disconnect(); guiderType = static_cast(type); switch (type) { case GUIDE_INTERNAL: { connect(internalGuider, SIGNAL(newPulse(GuideDirection,int)), this, SLOT(sendPulse(GuideDirection,int))); connect(internalGuider, SIGNAL(newPulse(GuideDirection,int,GuideDirection,int)), this, SLOT(sendPulse(GuideDirection,int,GuideDirection,int))); connect(internalGuider, SIGNAL(DESwapChanged(bool)), swapCheck, SLOT(setChecked(bool))); guider = internalGuider; + internalGuider->setRegionAxis(opsGuide->kcfg_GuideRegionAxis->currentText().toInt()); + calibrateB->setEnabled(true); guideB->setEnabled(false); captureB->setEnabled(true); darkFrameCheck->setEnabled(true); subFrameCheck->setEnabled(true); guiderCombo->setEnabled(true); ST4Combo->setEnabled(true); exposureIN->setEnabled(true); binningCombo->setEnabled(true); boxSizeCombo->setEnabled(true); filterCombo->setEnabled(true); externalConnectB->setEnabled(false); externalDisconnectB->setEnabled(false); controlGroup->setEnabled(true); infoGroup->setEnabled(true); driftGraphicsGroup->setEnabled(true); updateGuideParams(); } break; case GUIDE_PHD2: if (phd2Guider.isNull()) phd2Guider = new PHD2(); guider = phd2Guider; calibrateB->setEnabled(false); captureB->setEnabled(false); darkFrameCheck->setEnabled(false); subFrameCheck->setEnabled(false); guideB->setEnabled(true); externalConnectB->setEnabled(false); controlGroup->setEnabled(false); infoGroup->setEnabled(false); driftGraphicsGroup->setEnabled(false); guiderCombo->setEnabled(false); ST4Combo->setEnabled(false); exposureIN->setEnabled(false); binningCombo->setEnabled(false); boxSizeCombo->setEnabled(false); filterCombo->setEnabled(false); break; case GUIDE_LINGUIDER: if (linGuider.isNull()) linGuider = new LinGuider(); guider = linGuider; calibrateB->setEnabled(true); captureB->setEnabled(false); darkFrameCheck->setEnabled(false); subFrameCheck->setEnabled(false); guideB->setEnabled(true); externalConnectB->setEnabled(true); controlGroup->setEnabled(false); infoGroup->setEnabled(false); driftGraphicsGroup->setEnabled(false); guiderCombo->setEnabled(false); ST4Combo->setEnabled(false); exposureIN->setEnabled(false); binningCombo->setEnabled(false); boxSizeCombo->setEnabled(false); filterCombo->setEnabled(false); break; } connect(guider, SIGNAL(frameCaptureRequested()), this, SLOT(capture())); connect(guider, SIGNAL(newLog(QString)), this, SLOT(appendLogText(QString))); connect(guider, SIGNAL(newStatus(Ekos::GuideState)), this, SLOT(setStatus(Ekos::GuideState))); connect(guider, SIGNAL(newStarPosition(QVector3D,bool)), this, SLOT(setStarPosition(QVector3D,bool))); connect(guider, SIGNAL(newAxisDelta(double,double)), this, SLOT(setAxisDelta(double,double))); connect(guider, SIGNAL(newAxisPulse(double,double)), this, SLOT(setAxisPulse(double,double))); connect(guider, SIGNAL(newAxisSigma(double,double)), this, SLOT(setAxisSigma(double,double))); guider->Connect(); return true; } void Guide::updateTrackingBoxSize(int currentIndex) { if (currentIndex >= 0) { Options::setGuideSquareSizeIndex(currentIndex); syncTrackingBoxPosition(); } } bool Guide::selectAutoStar() { if (currentCCD == NULL) return false; ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); if (targetChip == NULL) return false; FITSView * targetImage = targetChip->getImageView(FITS_GUIDE); if (targetImage == NULL) return false; FITSData * imageData = targetImage->getImageData(); if (imageData == NULL) return false; imageData->findStars(); QList starCenters = imageData->getStarCenters(); if (starCenters.empty()) return false; guideView->setStarsEnabled(true); guideView->updateFrame(); qSort(starCenters.begin(), starCenters.end(), [](const Edge *a, const Edge *b) { return a->width > b->width; }); int maxX = imageData->getWidth(); int maxY = imageData->getHeight(); int scores[MAX_GUIDE_STARS]; int maxIndex = MAX_GUIDE_STARS < starCenters.count() ? MAX_GUIDE_STARS : starCenters.count(); for (int i=0; i < maxIndex; i++) { int score=100; Edge * center = starCenters.at(i); //qDebug() << "#" << i << " X: " << center->x << " Y: " << center->y << " HFR: " << center->HFR << " Width" << center->width; // Severely reject stars close to edges if (center->x < (center->width*5) || center->y < (center->width*5) || center->x > (maxX-center->width*5) || center->y > (maxY-center->width*5)) score-=50; // Moderately favor brighter stars score += center->width*center->width; // Moderately reject stars close to other stars foreach(Edge * edge, starCenters) { if (edge == center) continue; if (abs(center->x - edge->x) < center->width*2 && abs(center->y - edge->y) < center->width*2) { score -= 15; break; } } scores[i] = score; } int maxScore=0; int maxScoreIndex=0; for (int i=0; i < maxIndex; i++) { if (scores[i] > maxScore) { maxScore = scores[i]; maxScoreIndex = i; } } /*if (ui.autoSquareSizeCheck->isEnabled() && ui.autoSquareSizeCheck->isChecked()) { // Select appropriate square size int idealSize = ceil(starCenters[maxScoreIndex]->width * 1.5); if (Options::guideLogging()) qDebug() << "Guide: Ideal calibration box size for star width: " << starCenters[maxScoreIndex]->width << " is " << idealSize << " pixels"; // TODO Set square size in GuideModule }*/ QVector3D newStarCenter(starCenters[maxScoreIndex]->x, starCenters[maxScoreIndex]->y, 0); setStarPosition(newStarCenter, false); return true; } /* void Guide::onXscaleChanged( int i ) { int rx, ry; driftGraphics->getVisibleRanges( &rx, &ry ); driftGraphics->setVisibleRanges( i*driftGraphics->getGridN(), ry ); driftGraphics->update(); } void Guide::onYscaleChanged( int i ) { int rx, ry; driftGraphics->getVisibleRanges( &rx, &ry ); driftGraphics->setVisibleRanges( rx, i*driftGraphics->getGridN() ); driftGraphics->update(); } */ void Guide::onThresholdChanged( int index ) { switch (guiderType) { case GUIDE_INTERNAL: dynamic_cast(guider)->setSquareAlgorithm(index); break; default: break; } } void Guide::onInfoRateChanged( double val ) { Options::setGuidingRate(val); double gain = 0; if( val > 0.01 ) gain = 1000.0 / (val * 15.0); l_RecommendedGain->setText( i18n("P: %1", QString().setNum(gain, 'f', 2 )) ); } void Guide::onEnableDirRA(bool enable) { Options::setRAGuideEnabled(enable); } void Guide::onEnableDirDEC(bool enable) { Options::setDECGuideEnabled(enable); } void Guide::onInputParamChanged() { QSpinBox * pSB; QDoubleSpinBox * pDSB; QObject * obj = sender(); if( (pSB = dynamic_cast(obj)) ) { if( pSB == spinBox_MaxPulseRA ) Options::setRAMaximumPulse(pSB->value()); else if ( pSB == spinBox_MaxPulseDEC ) Options::setDECMaximumPulse(pSB->value()); else if ( pSB == spinBox_MinPulseRA ) Options::setRAMinimumPulse(pSB->value()); else if( pSB == spinBox_MinPulseDEC ) Options::setDECMinimumPulse(pSB->value()); } else if( (pDSB = dynamic_cast(obj)) ) { if( pDSB == spinBox_PropGainRA ) Options::setRAProportionalGain(pDSB->value()); else if ( pDSB == spinBox_PropGainDEC ) Options::setDECProportionalGain(pDSB->value()); else if ( pDSB == spinBox_IntGainRA ) Options::setRAIntegralGain(pDSB->value()); else if( pDSB == spinBox_IntGainDEC ) Options::setDECIntegralGain(pDSB->value()); else if( pDSB == spinBox_DerGainRA ) Options::setRADerivativeGain(pDSB->value()); else if( pDSB == spinBox_DerGainDEC ) Options::setDECDerivativeGain(pDSB->value()); } } void Guide::onControlDirectionChanged(bool enable) { QObject * obj = sender(); if (northControlCheck == dynamic_cast(obj)) { Options::setNorthDECGuideEnabled(enable); } else if (southControlCheck == dynamic_cast(obj)) { Options::setSouthDECGuideEnabled(enable); } else if (westControlCheck == dynamic_cast(obj)) { Options::setWestRAGuideEnabled(enable); } else if (eastControlCheck == dynamic_cast(obj)) { Options::setEastRAGuideEnabled(enable); } } #if 0 void Guide::onRapidGuideChanged(bool enable) { if (m_isStarted) { guideModule->appendLogText(i18n("You must stop auto guiding before changing this setting.")); return; } m_useRapidGuide = enable; if (m_useRapidGuide) { guideModule->appendLogText(i18n("Rapid Guiding is enabled. Guide star will be determined automatically by the CCD driver. No frames are sent to Ekos unless explicitly enabled by the user in the CCD driver settings.")); } else guideModule->appendLogText(i18n("Rapid Guiding is disabled.")); } #endif void Guide::loadSettings() { // Exposure exposureIN->setValue(Options::guideExposure()); // Box Size boxSizeCombo->setCurrentIndex(Options::guideSquareSizeIndex()); // Dark frame? darkFrameCheck->setChecked(Options::guideDarkFrameEnabled()); // Subframed? subFrameCheck->setChecked(Options::guideSubframeEnabled()); // Guiding Rate spinBox_GuideRate->setValue(Options::guidingRate()); // RA/DEC enabled? checkBox_DirRA->setChecked(Options::rAGuideEnabled()); checkBox_DirDEC->setChecked(Options::dECGuideEnabled()); // N/S enabled? northControlCheck->setChecked(Options::northDECGuideEnabled()); southControlCheck->setChecked(Options::southDECGuideEnabled()); // W/E enabled? westControlCheck->setChecked(Options::westRAGuideEnabled()); eastControlCheck->setChecked(Options::eastRAGuideEnabled()); // PID Control - Proportional Gain spinBox_PropGainRA->setValue(Options::rAProportionalGain()); spinBox_PropGainDEC->setValue(Options::dECProportionalGain()); // PID Control - Integral Gain spinBox_IntGainRA->setValue(Options::rAIntegralGain()); spinBox_IntGainDEC->setValue(Options::dECIntegralGain()); // PID Control - Derivative Gain spinBox_DerGainRA->setValue(Options::rADerivativeGain()); spinBox_DerGainDEC->setValue(Options::dECDerivativeGain()); // Max Pulse Duration (ms) spinBox_MaxPulseRA->setValue(Options::rAMaximumPulse()); spinBox_MaxPulseDEC->setValue(Options::dECMaximumPulse()); // Min Pulse Duration (ms) spinBox_MinPulseRA->setValue(Options::rAMinimumPulse()); spinBox_MinPulseDEC->setValue(Options::dECMinimumPulse()); } void Guide::saveSettings() { // Exposure Options::setGuideExposure(exposureIN->value()); // Box Size Options::setGuideSquareSizeIndex(boxSizeCombo->currentIndex()); // Dark frame? Options::setGuideDarkFrameEnabled(darkFrameCheck->isChecked()); // Subframed? Options::setGuideSubframeEnabled(subFrameCheck->isChecked()); // Guiding Rate? Options::setGuidingRate(spinBox_GuideRate->value()); // RA/DEC enabled? Options::setRAGuideEnabled(checkBox_DirRA->isChecked()); Options::setDECGuideEnabled(checkBox_DirDEC->isChecked()); // N/S enabled? Options::setNorthDECGuideEnabled(northControlCheck->isChecked()); Options::setSouthDECGuideEnabled(southControlCheck->isChecked()); // W/E enabled? Options::setWestRAGuideEnabled(westControlCheck->isChecked()); Options::setEastRAGuideEnabled(eastControlCheck->isChecked()); // PID Control - Proportional Gain Options::setRAProportionalGain(spinBox_PropGainRA->value()); Options::setDECProportionalGain(spinBox_PropGainDEC->value()); // PID Control - Integral Gain Options::setRAIntegralGain(spinBox_IntGainRA->value()); Options::setDECIntegralGain(spinBox_IntGainDEC->value()); // PID Control - Derivative Gain Options::setRADerivativeGain(spinBox_DerGainRA->value()); Options::setDECDerivativeGain(spinBox_DerGainDEC->value()); // Max Pulse Duration (ms) Options::setRAMaximumPulse(spinBox_MaxPulseRA->value()); Options::setDECMaximumPulse(spinBox_MaxPulseDEC->value()); // Min Pulse Duration (ms) Options::setRAMinimumPulse(spinBox_MinPulseRA->value()); Options::setDECMinimumPulse(spinBox_MinPulseDEC->value()); } void Guide::setTrackingStar(int x, int y) { QVector3D newStarPosition(x,y, -1); setStarPosition(newStarPosition, true); /*if (state == GUIDE_STAR_SELECT) { guider->setStarPosition(newStarPosition); guider->calibrate(); }*/ if (operationStack.isEmpty() == false) executeOperationStack(); } void Guide::setAxisDelta(double ra, double de) { // Time since timer started. double key = guideTimer.elapsed()/1000.0; driftGraph->graph(0)->addData(key, ra); driftGraph->graph(1)->addData(key, de); // Expand range if it doesn't fit already if (driftGraph->yAxis->range().contains(ra) == false) driftGraph->yAxis->setRange(-1.25*ra, 1.25*ra); if (driftGraph->yAxis->range().contains(de) == false) driftGraph->yAxis->setRange(-1.25*de, 1.25*de); // Show last 120 seconds //driftGraph->xAxis->setRange(key, 120, Qt::AlignRight); driftGraph->xAxis->setRange(key, driftGraph->xAxis->range().size(), Qt::AlignRight); driftGraph->replot(); l_DeltaRA->setText(QString::number(ra, 'f', 2)); l_DeltaDEC->setText(QString::number(de, 'f', 2)); emit newAxisDelta(ra,de); profilePixmap = driftGraph->grab(QRect(QPoint(0, 50), QSize(driftGraph->width(), 150))); emit newProfilePixmap(profilePixmap); } void Guide::setAxisSigma(double ra, double de) { l_ErrRA->setText(QString::number(ra, 'f', 2)); l_ErrDEC->setText(QString::number(de, 'f', 2)); emit sigmasUpdated(ra,de); } void Guide::setAxisPulse(double ra, double de) { l_PulseRA->setText(QString::number(static_cast(ra))); l_PulseDEC->setText(QString::number(static_cast(de))); } void Guide::refreshColorScheme() { // Drift color legend driftGraph->graph(0)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"))); driftGraph->graph(1)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"))); } void Guide::driftMouseClicked(QMouseEvent * event) { if (event->buttons() & Qt::RightButton) { driftGraph->yAxis->setRange(-3, 3); } } void Guide::driftMouseOverLine(QMouseEvent * event) { double key = driftGraph->xAxis->pixelToCoord(event->localPos().x()); if (driftGraph->xAxis->range().contains(key)) { QCPGraph * graph = qobject_cast(driftGraph->plottableAt(event->pos(), false)); if(graph) { int raIndex = driftGraph->graph(0)->findBegin(key); int deIndex = driftGraph->graph(1)->findBegin(key); double raDelta = driftGraph->graph(0)->dataMainValue(raIndex); double deDelta = driftGraph->graph(1)->dataMainValue(deIndex); // Compute time value: QTime localTime = guideTimer; localTime = localTime.addSecs(key); QToolTip::hideText(); QToolTip::showText(event->globalPos(), i18nc("Drift graphics tooltip; %1 is local time; %2 is RA deviation; %3 is DE deviation in arcseconds", "" "" "" "" "
LT: %1
RA: %2 \"
DE: %3 \"
", localTime.toString("hh:mm:ss AP"), QString::number(raDelta, 'f', 2), QString::number(deDelta, 'f', 2))); } else QToolTip::hideText(); driftGraph->replot(); } } void Guide::buildOperationStack(GuideState operation) { operationStack.clear(); switch (operation) { case GUIDE_CAPTURE: if (Options::guideDarkFrameEnabled()) operationStack.push(GUIDE_DARK); operationStack.push(GUIDE_CAPTURE); operationStack.push(GUIDE_SUBFRAME); break; case GUIDE_CALIBRATING: operationStack.push(GUIDE_CALIBRATING); if (guiderType == GUIDE_INTERNAL && (starCenter.isNull() || (Options::guideAutoStarEnabled()))) { if (Options::guideDarkFrameEnabled()) operationStack.push(GUIDE_DARK); // If subframe is enabled and we need to auto select a star, then we need to make the final capture // of the subframed image. This is only done if we aren't already subframed. if (subFramed == false && Options::guideSubframeEnabled() && Options::guideAutoStarEnabled()) operationStack.push(GUIDE_CAPTURE); - operationStack.push(GUIDE_SUBFRAME); - operationStack.push(GUIDE_STAR_SELECT); + // Do not subframe and auto-select star on Image Guiding mode + if (Options::imageGuidingEnabled() == false) + { + operationStack.push(GUIDE_SUBFRAME); + operationStack.push(GUIDE_STAR_SELECT); + } + operationStack.push(GUIDE_CAPTURE); // If we are being ask to go full frame, let's do that first if (subFramed == true && Options::guideSubframeEnabled() == false) operationStack.push(GUIDE_SUBFRAME); } break; default: break; } } bool Guide::executeOperationStack() { if (operationStack.isEmpty()) return false; GuideState nextOperation = operationStack.pop(); bool actionRequired = false; switch (nextOperation) { case GUIDE_SUBFRAME: actionRequired = executeOneOperation(nextOperation); break; case GUIDE_DARK: actionRequired = executeOneOperation(nextOperation); break; case GUIDE_CAPTURE: actionRequired = captureOneFrame(); break; case GUIDE_STAR_SELECT: actionRequired = executeOneOperation(nextOperation); break; case GUIDE_CALIBRATING: if (guiderType == GUIDE_INTERNAL) + { guider->setStarPosition(starCenter); + dynamic_cast(guider)->setImageGuideEnabled(Options::imageGuidingEnabled()); + + // No need to calibrate + if (Options::imageGuidingEnabled()) + { + setStatus(GUIDE_CALIBRATION_SUCESS); + break; + } + } + if (guider->calibrate()) { if (guiderType == GUIDE_INTERNAL) disconnect(guideView, SIGNAL(trackingStarSelected(int,int)), this, SLOT(setTrackingStar(int,int))); setBusy(true); } else { emit newStatus(GUIDE_CALIBRATION_ERROR); state = GUIDE_IDLE; appendLogText(i18n("Calibration failed to start!")); setBusy(false); } break; default: break; } // If an additional action is required, return return and continue later if (actionRequired) return true; // Othereise, continue processing the stack else return executeOperationStack(); } bool Guide::executeOneOperation(GuideState operation) { bool actionRequired = false; ISD::CCDChip * targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD); int subBinX, subBinY; targetChip->getBinning(&subBinX, &subBinY); switch (operation) { case GUIDE_SUBFRAME: { // Do not subframe if we are capturing calibration frame if (subFramed == false && Options::guideSubframeEnabled() == true && targetChip->canSubframe()) { int minX, maxX, minY, maxY, minW, maxW, minH, maxH; targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH); int offset = boxSizeCombo->currentText().toInt()/subBinX; int x = starCenter.x(); int y = starCenter.y(); x = (x - offset*2) * subBinX; y = (y - offset*2) * subBinY; int w=offset*4*subBinX; int h=offset*4*subBinY; if (xmaxW) w=maxW-x; if ((y+h)>maxH) h=maxH-y; targetChip->setFrame(x,y,w,h); subFramed = true; QVariantMap settings = frameSettings[targetChip]; settings["x"] = x; settings["y"] = y; settings["w"] = w; settings["h"] = h; settings["binx"] = subBinX; settings["biny"] = subBinY; frameSettings[targetChip] = settings; starCenter.setX(w/(2*subBinX)); starCenter.setY(h/(2*subBinX)); } else if (subFramed && Options::guideSubframeEnabled() == false) { targetChip->resetFrame(); int x,y,w,h; targetChip->getFrame(&x,&y,&w, &h); QVariantMap settings; settings["x"] = x; settings["y"] = y; settings["w"] = w; settings["h"] = h; settings["binx"] = 1; settings["biny"] = 1; frameSettings[targetChip] = settings; subFramed = false; starCenter.setX(w/(2*subBinX)); starCenter.setY(h/(2*subBinX)); //starCenter.setX(0); //starCenter.setY(0); } } break; case GUIDE_DARK: { // Do we need to take a dark frame? if (Options::guideDarkFrameEnabled()) { FITSData * darkData = NULL; QVariantMap settings = frameSettings[targetChip]; uint16_t offsetX = settings["x"].toInt() / settings["binx"].toInt(); uint16_t offsetY = settings["y"].toInt() / settings["biny"].toInt(); darkData = DarkLibrary::Instance()->getDarkFrame(targetChip, exposureIN->value()); connect(DarkLibrary::Instance(), SIGNAL(darkFrameCompleted(bool)), this, SLOT(setCaptureComplete())); connect(DarkLibrary::Instance(), SIGNAL(newLog(QString)), this, SLOT(appendLogText(QString))); actionRequired = true; targetChip->setCaptureFilter((FITSScale) filterCombo->currentIndex()); if (darkData) DarkLibrary::Instance()->subtract(darkData, guideView, targetChip->getCaptureFilter(), offsetX, offsetY); else { bool rc = DarkLibrary::Instance()->captureAndSubtract(targetChip, guideView, exposureIN->value(), offsetX, offsetY); setDarkFrameEnabled(rc); } } } break; case GUIDE_STAR_SELECT: { state = GUIDE_STAR_SELECT; emit newStatus(state); if (Options::guideAutoStarEnabled()) { bool autoStarCaptured = selectAutoStar(); if (autoStarCaptured) { appendLogText(i18n("Auto star selected.")); } else { appendLogText(i18n("Failed to select an auto star.")); state = GUIDE_CALIBRATION_ERROR; emit newStatus(state); setBusy(false); } } else { appendLogText(i18n("Select a guide star to calibrate.")); actionRequired = true; } } break; default: break; } return actionRequired; } void Guide::processGuideOptions() { if (Options::guiderType() != guiderType) { guiderType = static_cast(Options::guiderType()); setGuiderType(Options::guiderType()); } } void Guide::showFITSViewer() { FITSData * data = guideView->getImageData(); if (data) { QUrl url = QUrl::fromLocalFile(data->getFilename()); if (fv.isNull()) { if (Options::singleWindowCapturedFITS()) fv = KStars::Instance()->genericFITSViewer(); else { fv = new FITSViewer(Options::independentWindowFITS() ? NULL : KStars::Instance()); KStars::Instance()->getFITSViewersList().append(fv); } fv->addFITS(&url); FITSView * currentView = fv->getCurrentView(); if (currentView) currentView->getImageData()->setAutoRemoveTemporaryFITS(false); } else fv->updateFITS(&url, 0); fv->show(); } } } diff --git a/kstars/ekos/guide/internalguide/gmath.cpp b/kstars/ekos/guide/internalguide/gmath.cpp index 1b3f8a56e..c0d661409 100644 --- a/kstars/ekos/guide/internalguide/gmath.cpp +++ b/kstars/ekos/guide/internalguide/gmath.cpp @@ -1,1246 +1,1478 @@ /* Ekos guide tool Copyright (C) 2012 Andrew Stepanenko Modified by Jasem Mutlaq for KStars. This application 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. */ #include "Options.h" #include "gmath.h" #include #include #include "vect.h" #include "matr.h" #include "fitsviewer/fitsview.h" +#include "imageautoguiding.h" #define DEF_SQR_0 (8-0) #define DEF_SQR_1 (16-0) #define DEF_SQR_2 (32-0) #define DEF_SQR_3 (64-0) #define DEF_SQR_4 (128-0) const guide_square_t guide_squares[] = { {DEF_SQR_0, DEF_SQR_0 * DEF_SQR_0*1.0}, {DEF_SQR_1, DEF_SQR_1 * DEF_SQR_1*1.0}, {DEF_SQR_2, DEF_SQR_2 * DEF_SQR_2*1.0}, {DEF_SQR_3, DEF_SQR_3 * DEF_SQR_3*1.0}, {DEF_SQR_4, DEF_SQR_4 * DEF_SQR_4*1.0}, {-1, -1} }; const square_alg_t guide_square_alg[] = { { SMART_THRESHOLD, "Smart" }, { CENTROID_THRESHOLD, "Fast"}, { AUTO_THRESHOLD, "Auto" }, { NO_THRESHOLD, "No thresh." }, { -1, {0} } }; // JM: Why not use QPoint? typedef struct { int x, y; } point_t; cgmath::cgmath() : QObject() { // sys... ticks = 0; video_width = -1; video_height = -1; ccd_pixel_width = 0; ccd_pixel_height = 0; focal = 0; aperture = 0; ROT_Z = Matrix(0); preview_mode = true; suspended = false; lost_star = false; useRapidGuide = false; dec_swap = false; subBinX = subBinY = 1; // square variables square_alg_idx = SMART_THRESHOLD; // sky coord. system vars. star_pos = Vector(0); scr_star_pos = Vector(0); reticle_pos = Vector(0); reticle_orts[0] = Vector(0); reticle_orts[1] = Vector(0); reticle_angle = 0; ditherRate[0] = ditherRate[1] = -1; // processing in_params.reset(); out_params.reset(); channel_ticks[GUIDE_RA] = channel_ticks[GUIDE_DEC] = 0; accum_ticks[GUIDE_RA] = accum_ticks[GUIDE_DEC] = 0; drift[GUIDE_RA] = new double[MAX_ACCUM_CNT]; drift[GUIDE_DEC] = new double[MAX_ACCUM_CNT]; memset( drift[GUIDE_RA], 0, sizeof(double)*MAX_ACCUM_CNT ); memset( drift[GUIDE_DEC], 0, sizeof(double)*MAX_ACCUM_CNT ); drift_integral[GUIDE_RA] = drift_integral[GUIDE_DEC] = 0; // statistics do_statistics = true; sum = sqr_sum = 0; delta_prev = sigma_prev = sigma = 0; } cgmath::~cgmath() { delete [] drift[GUIDE_RA]; delete [] drift[GUIDE_DEC]; + foreach(float *region, referenceRegions) + delete [] region; + referenceRegions.clear(); } bool cgmath::setVideoParameters(int vid_wd, int vid_ht , int binX, int binY) { if( vid_wd <= 0 || vid_ht <= 0 ) return false; video_width = vid_wd/binX; video_height = vid_ht/binY; subBinX = binX; subBinY = binY; //set_reticle_params( video_width/2, video_height/2, -1 ); // keep orientation return true; } void cgmath::setGuideView(FITSView * image) { guideView = image; /*if (guideView) { FITSData *image_data = guideView->getImageData(); setDataBuffer(image_data->getImageBuffer()); setVideoParameters(image_data->getWidth(), image_data->getHeight()); }*/ } bool cgmath::setGuiderParameters( double ccd_pix_wd, double ccd_pix_ht, double guider_aperture, double guider_focal ) { if( ccd_pix_wd < 0 ) ccd_pix_wd = 0; if( ccd_pix_ht < 0 ) ccd_pix_ht = 0; if( guider_focal <= 0 ) guider_focal = 1; ccd_pixel_width = ccd_pix_wd / 1000.0; // from mkm to mm ccd_pixel_height = ccd_pix_ht / 1000.0; // from mkm to mm aperture = guider_aperture; focal = guider_focal; return true; } void cgmath::getGuiderParameters( double * ccd_pix_wd, double * ccd_pix_ht, double * guider_aperture, double * guider_focal ) { *ccd_pix_wd = ccd_pixel_width * 1000.0; *ccd_pix_ht = ccd_pixel_height * 1000.0; *guider_aperture = aperture; *guider_focal = focal; } bool cgmath::setReticleParameters( double x, double y, double ang ) { // check frame ranges if( x < 0 ) x = 0; if( y < 0 ) y = 0; if( x >= (double)video_width-1 ) x = (double)video_width-1; if( y >= (double)video_height-1 ) y = (double)video_height-1; reticle_pos = Vector( x, y, 0 ); if( ang >= 0) reticle_angle = ang; ROT_Z = RotateZ( -M_PI*reticle_angle/180.0 ); // NOTE!!! sing '-' derotates star coordinate system reticle_orts[0] = Vector(1, 0, 0) * 100; reticle_orts[1] = Vector(0, 1, 0) * 100; reticle_orts[0] = reticle_orts[0] * ROT_Z; reticle_orts[1] = reticle_orts[1] * ROT_Z; return true; } bool cgmath::getReticleParameters( double * x, double * y, double * ang ) const { *x = reticle_pos.x; *y = reticle_pos.y; if (ang) *ang = reticle_angle; return true; } int cgmath::getSquareAlgorithmIndex( void ) const { return square_alg_idx; } info_params_t cgmath::getInfoParameters( void ) const { info_params_t ret; Vector p; ret.aperture = aperture; ret.focal = focal; ret.focal_ratio = focal / aperture; p = Vector(video_width, video_height, 0); p = point2arcsec( p ); p /= 60; // convert to minutes ret.fov_wd = p.x; ret.fov_ht = p.y; return ret; } uint32_t cgmath::getTicks( void ) const { return ticks; } void cgmath::getStarDrift( double * dx, double * dy ) const { *dx = star_pos.x; *dy = star_pos.y; } void cgmath::getStarScreenPosition( double * dx, double * dy ) const { *dx = scr_star_pos.x; *dy = scr_star_pos.y; } bool cgmath::reset( void ) { square_alg_idx = AUTO_THRESHOLD; // sky coord. system vars. star_pos = Vector(0); scr_star_pos = Vector(0); setReticleParameters( video_width/2, video_height/2, 0.0 ); return true; } /*void cgmath::move_square( double newx, double newy ) { square_pos.x = newx; square_pos.y = newy; // check frame ranges if (lastBinX == subBinX) { if( square_pos.x < 0 ) square_pos.x = 0; if( square_pos.y < 0 ) square_pos.y = 0; if( square_pos.x+(double)square_size > (double)video_width ) square_pos.x = (double)(video_width - square_size); if( square_pos.y+(double)square_size > (double)video_height ) square_pos.y = (double)(video_height - square_size); } // FITS Image takes center coords if (guide_frame) { guide_frame->setTrackingBoxEnabled(true); //guide_frame->setTrackingBoxCenter(QPointF(square_pos.x+square_size/2, square_pos.y+square_size/2)); guide_frame->setTrackingBox(QRect(square_pos.x, square_pos.y, square_size/subBinX, square_size/subBinY)); } } void cgmath::resize_square( int size_idx ) { if( size_idx < 0 || size_idx >= (int)(sizeof(guide_squares)/sizeof(guide_square_t))-1) return; if (square_size != guide_squares[size_idx].size) { square_pos.x += (square_size-guide_squares[size_idx].size)/2; square_pos.y += (square_size-guide_squares[size_idx].size)/2; } square_size = guide_squares[size_idx].size; square_square = guide_squares[size_idx].square; square_idx = size_idx; // check position if (guide_frame) { guide_frame->setTrackingBoxEnabled(true); //guide_frame->setTrackingBoxSize(QSize(square_size,square_size)); guide_frame->setTrackingBox(QRect(square_pos.x/subBinX, square_pos.y/subBinY, square_size/subBinX, square_size/subBinY)); } }*/ void cgmath::setSquareAlgorithm( int alg_idx ) { if( alg_idx < 0 || alg_idx >= (int)(sizeof(guide_square_alg)/sizeof(square_alg_t))-1 ) return; square_alg_idx = alg_idx; in_params.threshold_alg_idx = square_alg_idx; } Vector cgmath::point2arcsec( const Vector &p ) const { Vector arcs; // arcs = 3600*180/pi * (pix*ccd_pix_sz) / focal_len arcs.x = 206264.8062470963552 * p.x * ccd_pixel_width / focal; arcs.y = 206264.8062470963552 * p.y * ccd_pixel_height / focal; return arcs; } bool cgmath::calculateAndSetReticle1D( double start_x, double start_y, double end_x, double end_y, int totalPulse ) { double phi; phi = calculatePhi( start_x, start_y, end_x, end_y ); if( phi < 0 ) return false; setReticleParameters( start_x, start_y, phi ); if (totalPulse > 0) { double x = end_x-start_x; double y = end_y - start_y; double len = sqrt(x*x + y*y); ditherRate[GUIDE_RA] = totalPulse / len; if (Options::guideLogging()) qDebug() << "Guide: Dither RA Rate " << ditherRate[GUIDE_RA] << " ms/Pixel"; } return true; } bool cgmath::calculateAndSetReticle2D( double start_ra_x, double start_ra_y, double end_ra_x, double end_ra_y, double start_dec_x, double start_dec_y, double end_dec_x, double end_dec_y, bool * swap_dec, int totalPulse) { double phi_ra = 0; // angle calculated by GUIDE_RA drift double phi_dec = 0; // angle calculated by GUIDE_DEC drift double phi = 0; Vector ra_vect = Normalize( Vector(end_ra_x - start_ra_x, -(end_ra_y - start_ra_y), 0) ); Vector dec_vect = Normalize( Vector(end_dec_x - start_dec_x, -(end_dec_y - start_dec_y), 0) ); Vector try_increase = dec_vect * RotateZ( M_PI/2 ); Vector try_decrease = dec_vect * RotateZ( -M_PI/2 ); double cos_increase = try_increase & ra_vect; double cos_decrease = try_decrease & ra_vect; bool do_increase = cos_increase > cos_decrease ? true : false; phi_ra = calculatePhi( start_ra_x, start_ra_y, end_ra_x, end_ra_y ); if( phi_ra < 0 ) return false; phi_dec = calculatePhi( start_dec_x, start_dec_y, end_dec_x, end_dec_y ); if( phi_dec < 0 ) return false; if( do_increase ) phi_dec += 90; else phi_dec -= 90; if( phi_dec > 360 )phi_dec -= 360.0; if( phi_dec < 0 )phi_dec += 360.0; if( fabs(phi_dec - phi_ra) > 180 ) { if( phi_ra > phi_dec ) phi_ra -= 360; else phi_dec -= 360; } // average angles phi = (phi_ra + phi_dec) / 2; if( phi < 0 )phi += 360.0; // check DEC if( swap_dec ) *swap_dec = dec_swap = do_increase ? false : true; setReticleParameters( start_ra_x, start_ra_y, phi ); if (totalPulse > 0) { double x = end_ra_x-start_ra_x; double y = end_ra_y - start_ra_y; double len = sqrt(x*x + y*y); ditherRate[GUIDE_RA] = totalPulse / len; if (Options::guideLogging()) qDebug() << "Guide: Dither RA Rate " << ditherRate[GUIDE_RA] << " ms/Pixel"; x = end_dec_x-start_dec_x; y = end_dec_y - start_dec_y; len = sqrt(x*x + y*y); ditherRate[GUIDE_DEC] = totalPulse / len; if (Options::guideLogging()) qDebug() << "Guide: Dither DEC Rate " << ditherRate[GUIDE_DEC] << " ms/Pixel"; } return true; } double cgmath::calculatePhi( double start_x, double start_y, double end_x, double end_y ) const { double delta_x, delta_y; double phi; delta_x = end_x - start_x; delta_y = -(end_y - start_y); //if( (!Vector(delta_x, delta_y, 0)) < 2.5 ) // JM 2015-12-10: Lower threshold to 1 pixel if( (!Vector(delta_x, delta_y, 0)) < 1 ) return -1; // 90 or 270 degrees if( fabs(delta_x) < fabs(delta_y) / 1000000.0 ) { phi = delta_y > 0 ? 90.0 : 270; } else { phi = 180.0/M_PI*atan2( delta_y, delta_x ); if( phi < 0 )phi += 360.0; } return phi; } void cgmath::do_ticks( void ) { ticks++; channel_ticks[GUIDE_RA]++; channel_ticks[GUIDE_DEC]++; if( channel_ticks[GUIDE_RA] >= MAX_ACCUM_CNT ) channel_ticks[GUIDE_RA] = 0; if( channel_ticks[GUIDE_DEC] >= MAX_ACCUM_CNT ) channel_ticks[GUIDE_DEC] = 0; accum_ticks[GUIDE_RA]++; accum_ticks[GUIDE_DEC]++; if( accum_ticks[GUIDE_RA] >= in_params.accum_frame_cnt[GUIDE_RA] ) accum_ticks[GUIDE_RA] = 0; if( accum_ticks[GUIDE_DEC] >= in_params.accum_frame_cnt[GUIDE_DEC] ) accum_ticks[GUIDE_DEC] = 0; } //-------------------- Processing --------------------------- void cgmath::start( void ) { ticks = 0; channel_ticks[GUIDE_RA] = channel_ticks[GUIDE_DEC] = 0; accum_ticks[GUIDE_RA] = accum_ticks[GUIDE_DEC] = 0; drift_integral[GUIDE_RA] = drift_integral[GUIDE_DEC] = 0; out_params.reset(); memset( drift[GUIDE_RA], 0, sizeof(double)*MAX_ACCUM_CNT ); memset( drift[GUIDE_DEC], 0, sizeof(double)*MAX_ACCUM_CNT ); // cleanup stat vars. sum = sqr_sum = 0; delta_prev = sigma_prev = sigma = 0; preview_mode = false; + + // Create reference Image + if (imageGuideEnabled) + { + foreach(float *region, referenceRegions) + delete [] region; + + referenceRegions.clear(); + + referenceRegions = partitionImage(); + + reticle_pos = Vector( 0, 0, 0 ); + } + } void cgmath::stop( void ) { preview_mode = true; } void cgmath::suspend( bool mode ) { suspended = mode; } bool cgmath::isSuspended( void ) const { return suspended; } bool cgmath::isStarLost(void) const { return lost_star; } void cgmath::setLostStar(bool is_lost) { lost_star = is_lost; } +float * cgmath::createFloatImage() const +{ + FITSData * imageData = guideView->getImageData(); + + // #1 Convert to float array + // We only process 1st plane if it is a color image + uint32_t imgSize = imageData->getSize(); + float *imgFloat = new float[imgSize]; + if (imgFloat == NULL) + { + qCritical() << "Not enough memory for float image array!"; + return NULL; + } + + switch (imageData->getDataType()) + { + case TBYTE: + { + uint8_t *buffer = imageData->getImageBuffer(); + for (uint32_t i=0; i < imgSize; i++) + imgFloat[i] = buffer[i]; + } + break; + + case TSHORT: + { + int16_t *buffer = reinterpret_cast(imageData->getImageBuffer()); + for (uint32_t i=0; i < imgSize; i++) + imgFloat[i] = buffer[i]; + } + break; + + case TUSHORT: + { + uint16_t *buffer = reinterpret_cast(imageData->getImageBuffer()); + for (uint32_t i=0; i < imgSize; i++) + imgFloat[i] = buffer[i]; + } + break; + + case TLONG: + { + int32_t *buffer = reinterpret_cast(imageData->getImageBuffer()); + for (uint32_t i=0; i < imgSize; i++) + imgFloat[i] = buffer[i]; + } + break; + + case TULONG: + { + uint32_t *buffer = reinterpret_cast(imageData->getImageBuffer()); + for (uint32_t i=0; i < imgSize; i++) + imgFloat[i] = buffer[i]; + } + break; + + case TFLOAT: + { + float *buffer = reinterpret_cast(imageData->getImageBuffer()); + for (uint32_t i=0; i < imgSize; i++) + imgFloat[i] = buffer[i]; + } + break; + + case TLONGLONG: + { + int64_t *buffer = reinterpret_cast(imageData->getImageBuffer()); + for (uint32_t i=0; i < imgSize; i++) + imgFloat[i] = buffer[i]; + } + break; + + case TDOUBLE: + { + double *buffer = reinterpret_cast(imageData->getImageBuffer()); + for (uint32_t i=0; i < imgSize; i++) + imgFloat[i] = buffer[i]; + } + break; + + default: + return NULL; + } + + return imgFloat; +} + +QVector cgmath::partitionImage() const +{ + QVector regions; + + FITSData * imageData = guideView->getImageData(); + + float *imgFloat = createFloatImage(); + + if (imgFloat == NULL) + return regions; + + const uint32_t width = imageData->getWidth(); + const uint32_t height = imageData->getHeight(); + + uint8_t xRegions = floor(width/regionAxis); + uint8_t yRegions = floor(height/regionAxis); + // Find number of regions to divide the image + //uint8_t regions = xRegions * yRegions; + + float *regionPtr = imgFloat; + + for (uint8_t i=0; i < yRegions; i++) + { + for (uint8_t j=0; j < xRegions; j++) + { + // Allocate space for one region + float *oneRegion = new float[regionAxis*regionAxis]; + // Create points to region and current location of the source image in the desired region + float *oneRegionPtr = oneRegion, *imgFloatPtr = regionPtr + j * regionAxis; + + // copy from image to region line by line + for (uint32_t line=0; line < regionAxis; line++) + { + memcpy(oneRegionPtr, imgFloatPtr, regionAxis); + oneRegionPtr += regionAxis; + imgFloatPtr += width; + } + + regions.append(oneRegion); + } + + // Move regionPtr block by (width * regionAxis) elements + regionPtr += width * regionAxis; + } + + // We're done with imgFloat + delete [] imgFloat; + + return regions; +} + +void cgmath::setRegionAxis(const uint32_t &value) +{ + regionAxis = value; +} + Vector cgmath::findLocalStarPosition( void ) const { if (useRapidGuide) { return Vector(rapidDX , rapidDY, 0); } FITSData * imageData = guideView->getImageData(); + if (imageGuideEnabled) + { + float xshift=0, yshift=0; + + QVector shifts; + float xsum=0, ysum=0; + + QVector imageParition = partitionImage(); + + if (imageParition.isEmpty()) + { + qWarning() << "Failed to partiion regions in image!"; + return Vector(-1,-1,-1); + } + + if (imageParition.count() != referenceRegions.count()) + { + qWarning() << "Mismatch between reference regions #" << referenceRegions.count() << "and image parition regions #" << imageParition.count(); + // Clear memory in case of mis-match + foreach(float *region, imageParition) + { + delete [] region; + } + + return Vector(-1,-1,-1); + } + + for (uint8_t i=0; i < imageParition.count(); i++) + { + ImageAutoGuiding::ImageAutoGuiding1(referenceRegions[i], imageParition[i], regionAxis, &xshift, &yshift); + Vector shift(xshift, yshift, -1); + if (Options::guideLogging()) + qDebug() << "Guide: Region #" << i << ": X-Shift=" << xshift << "Y-Shift=" << yshift; + + xsum += xshift; + ysum += yshift; + shifts.append(shift); + } + + // Delete partitions + foreach(float *region, imageParition) + { + delete [] region; + } + imageParition.clear(); + + float average_x= xsum / referenceRegions.count(); + float average_y= ysum / referenceRegions.count(); + + float median_x = shifts[referenceRegions.count()/2-1].x; + float median_y = shifts[referenceRegions.count()/2-1].y; + + if (Options::guideLogging()) + { + qDebug() << "Guide: Average : X-Shift=" << average_x << "Y-Shift=" << average_y; + qDebug() << "Guide: Median : X-Shift=" << median_x << "Y-Shift=" << median_y; + } + + return Vector(median_x, median_y, -1); + } + switch (imageData->getDataType()) { case TBYTE: return findLocalStarPosition(); break; case TSHORT: return findLocalStarPosition(); break; case TUSHORT: return findLocalStarPosition(); break; case TLONG: return findLocalStarPosition(); break; case TULONG: return findLocalStarPosition(); break; case TFLOAT: return findLocalStarPosition(); break; case TLONGLONG: return findLocalStarPosition(); break; case TDOUBLE: return findLocalStarPosition(); break; default: break; } return Vector(-1,-1,-1); } template Vector cgmath::findLocalStarPosition( void ) const { static double P0 = 0.906, P1 = 0.584, P2 = 0.365, P3 = 0.117, P4 = 0.049, P5 = -0.05, P6 = -0.064, P7 = -0.074, P8 = -0.094; Vector ret; int i, j; double resx, resy, mass, threshold, pval; T * psrc = NULL, *porigin = NULL; T * pptr; QRect trackingBox = guideView->getTrackingBox(); if (trackingBox.isValid() == false) return Vector(-1,-1,-1); FITSData * imageData = guideView->getImageData(); if (imageData == NULL) { if (Options::guideLogging()) qDebug() << "Guide: Cannot process a NULL image."; return Vector(-1,-1,-1); } T * pdata = reinterpret_cast(imageData->getImageBuffer()); if (Options::guideLogging()) qDebug() << "Guide: Tracking Square " << trackingBox; double square_square = trackingBox.width()*trackingBox.width(); psrc = porigin = pdata + trackingBox.y()* video_width + trackingBox.x(); resx = resy = 0; threshold = mass = 0; // several threshold adaptive smart agorithms switch( square_alg_idx ) { case CENTROID_THRESHOLD: { int width = trackingBox.width(); int height = trackingBox.width(); float i0, i1, i2, i3, i4, i5, i6, i7, i8; int ix = 0, iy = 0; int xM4; T * p; double average, fit, bestFit = 0; int minx = 0; int maxx = width; int miny = 0; int maxy = height; for (int x = minx; x < maxx; x++) for (int y = miny; y < maxy; y++) { i0 = i1 = i2 = i3 = i4 = i5 = i6 = i7 = i8 = 0; xM4 = x - 4; p = psrc + (y - 4) * video_width + xM4; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; p = psrc + (y - 3) * video_width + xM4; i8 += *p++; i8 += *p++; i8 += *p++; i7 += *p++; i6 += *p++; i7 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; p = psrc + (y - 2) * video_width + xM4; i8 += *p++; i8 += *p++; i5 += *p++; i4 += *p++; i3 += *p++; i4 += *p++; i5 += *p++; i8 += *p++; i8 += *p++; p = psrc + (y - 1) * video_width + xM4; i8 += *p++; i7 += *p++; i4 += *p++; i2 += *p++; i1 += *p++; i2 += *p++; i4 += *p++; i8 += *p++; i8 += *p++; p = psrc + (y + 0) * video_width + xM4; i8 += *p++; i6 += *p++; i3 += *p++; i1 += *p++; i0 += *p++; i1 += *p++; i3 += *p++; i6 += *p++; i8 += *p++; p = psrc + (y + 1) * video_width + xM4; i8 += *p++; i7 += *p++; i4 += *p++; i2 += *p++; i1 += *p++; i2 += *p++; i4 += *p++; i8 += *p++; i8 += *p++; p = psrc + (y + 2) * video_width + xM4; i8 += *p++; i8 += *p++; i5 += *p++; i4 += *p++; i3 += *p++; i4 += *p++; i5 += *p++; i8 += *p++; i8 += *p++; p = psrc + (y + 3) * video_width + xM4; i8 += *p++; i8 += *p++; i8 += *p++; i7 += *p++; i6 += *p++; i7 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; p = psrc + (y + 4) * video_width + xM4; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; average = (i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8) / 85.0; fit = P0 * (i0 - average) + P1 * (i1 - 4 * average) + P2 * (i2 - 4 * average) + P3 * (i3 - 4 * average) + P4 * (i4 - 8 * average) + P5 * (i5 - 4 * average) + P6 * (i6 - 4 * average) + P7 * (i7 - 8 * average) + P8 * (i8 - 48 * average); if (bestFit < fit) { bestFit = fit; ix = x; iy = y; } } if (bestFit > 50) { double sumX = 0; double sumY = 0; double total = 0; for (int y = iy - 4; y <= iy + 4; y++) { p = psrc + y * width + ix - 4; for (int x = ix - 4; x <= ix + 4; x++) { double w = *p++; sumX += x * w; sumY += y * w; total += w; } } if (total > 0) { ret = (Vector(trackingBox.x(), trackingBox.y(), 0) + Vector(sumX/total , sumY/total, 0)); return ret; } } return Vector(-1,-1,-1); } break; // Alexander's Stepanenko smart threshold algorithm case SMART_THRESHOLD: { point_t bbox_lt = { trackingBox.x()-SMART_FRAME_WIDTH, trackingBox.y()-SMART_FRAME_WIDTH }; point_t bbox_rb = { trackingBox.x()+trackingBox.width()+SMART_FRAME_WIDTH, trackingBox.y()+trackingBox.width()+SMART_FRAME_WIDTH }; int offset = 0; // clip frame if( bbox_lt.x < 0 ) bbox_lt.x = 0; if( bbox_lt.y < 0 ) bbox_lt.y = 0; if( bbox_rb.x > video_width ) bbox_rb.x = video_width; if( bbox_rb.y > video_height ) bbox_rb.y = video_height; // calc top bar int box_wd = bbox_rb.x - bbox_lt.x; int box_ht = trackingBox.y() - bbox_lt.y; int pix_cnt = 0; if( box_wd > 0 && box_ht > 0 ) { pix_cnt += box_wd * box_ht; for( j = bbox_lt.y; j < trackingBox.y(); ++j ) { offset = j*video_width; for( i = bbox_lt.x; i < bbox_rb.x; ++i ) { pptr = pdata + offset + i; threshold += *pptr; } } } // calc left bar box_wd = trackingBox.x() - bbox_lt.x; box_ht = trackingBox.width(); if( box_wd > 0 && box_ht > 0 ) { pix_cnt += box_wd * box_ht; for( j = trackingBox.y(); j < trackingBox.y()+box_ht; ++j ) { offset = j*video_width; for( i = bbox_lt.x; i < trackingBox.x(); ++i ) { pptr = pdata + offset + i; threshold += *pptr; } } } // calc right bar box_wd = bbox_rb.x - trackingBox.x() - trackingBox.width(); box_ht = trackingBox.width(); if( box_wd > 0 && box_ht > 0 ) { pix_cnt += box_wd * box_ht; for( j = trackingBox.y(); j < trackingBox.y()+box_ht; ++j ) { offset = j*video_width; for( i = trackingBox.x()+trackingBox.width(); i < bbox_rb.x; ++i ) { pptr = pdata + offset + i; threshold += *pptr; } } } // calc bottom bar box_wd = bbox_rb.x - bbox_lt.x; box_ht = bbox_rb.y - trackingBox.y() - trackingBox.width(); if( box_wd > 0 && box_ht > 0 ) { pix_cnt += box_wd * box_ht; for( j = trackingBox.y()+trackingBox.width(); j < bbox_rb.y; ++j ) { offset = j*video_width; for( i = bbox_lt.x; i < bbox_rb.x; ++i ) { pptr = pdata + offset + i; threshold += *pptr; } } } // find maximum double max_val = 0; for( j = 0; j < trackingBox.width(); ++j ) { for( i = 0; i < trackingBox.width(); ++i ) { pptr = psrc+i; if( *pptr > max_val ) max_val = *pptr; } psrc += video_width; } threshold /= (double)pix_cnt; // cut by 10% higher then average threshold if( max_val > threshold ) threshold += (max_val - threshold) * SMART_CUT_FACTOR; //log_i("smart thr. = %f cnt = %d", threshold, pix_cnt); break; } // simple adaptive threshold case AUTO_THRESHOLD: { for( j = 0; j < trackingBox.width(); ++j ) { for( i = 0; i < trackingBox.width(); ++i ) { pptr = psrc+i; threshold += *pptr; } psrc += video_width; } threshold /= square_square; break; } // no threshold subtracion default: { } } psrc = porigin; for( j = 0; j < trackingBox.width(); ++j ) { for( i = 0; i < trackingBox.width(); ++i ) { pptr = psrc+i; pval = *pptr - threshold; pval = pval < 0 ? 0 : pval; resx += (double)i * pval; resy += (double)j * pval; mass += pval; } psrc += video_width; } if( mass == 0 )mass = 1; resx /= mass; resy /= mass; ret = Vector(trackingBox.x(), trackingBox.y(), 0) + Vector( resx, resy, 0 ); return ret; } void cgmath::process_axes( void ) { int cnt = 0; double t_delta = 0; if (Options::guideLogging()) qDebug() << "Guide: Processing Axes"; in_params.proportional_gain[0] = Options::rAProportionalGain(); in_params.proportional_gain[1] = Options::dECProportionalGain(); in_params.integral_gain[0] = Options::rAIntegralGain(); in_params.integral_gain[1] = Options::rAIntegralGain(); in_params.derivative_gain[0] = Options::rADerivativeGain(); in_params.derivative_gain[1] = Options::dECDerivativeGain(); in_params.enabled[0] = Options::rAGuideEnabled(); in_params.enabled[1] = Options::dECGuideEnabled(); in_params.min_pulse_length[0] = Options::rAMinimumPulse(); in_params.min_pulse_length[1] = Options::dECMinimumPulse(); in_params.max_pulse_length[0] = Options::rAMaximumPulse(); in_params.max_pulse_length[1] = Options::dECMaximumPulse(); // RA W/E enable // East RA+ enabled? in_params.enabled_axis1[0] = Options::eastRAGuideEnabled(); // West RA- enabled? in_params.enabled_axis2[0] = Options::westRAGuideEnabled(); // DEC N/S enable // North DEC+ enabled? in_params.enabled_axis1[1] = Options::northDECGuideEnabled(); // South DEC- enabled? in_params.enabled_axis2[1] = Options::southDECGuideEnabled(); // process axes... for( int k = GUIDE_RA; k <= GUIDE_DEC; k++ ) { // zero all out commands out_params.pulse_dir[k] = NO_DIR; if( accum_ticks[k] < in_params.accum_frame_cnt[k]-1 ) continue; t_delta = 0; drift_integral[k] = 0; cnt = in_params.accum_frame_cnt[ k ]; for( int i = 0, idx = channel_ticks[k]; i < cnt; ++i ) { t_delta += drift[k][idx]; if (Options::guideLogging()) qDebug() << "Guide: At #" << idx << "drift[" << k << "][" << idx << "] = " << drift[k][idx] << " , t_delta: " << t_delta ; if( idx > 0 ) --idx; else idx = MAX_ACCUM_CNT-1; } for( int i = 0; i < MAX_ACCUM_CNT; ++i ) drift_integral[k] += drift[k][i]; out_params.delta[k] = t_delta / (double)cnt; drift_integral[k] /= (double)MAX_ACCUM_CNT; if (Options::guideLogging()) { //qDebug() << "cnt: " << cnt; qDebug() << "Guide: delta [" << k << "]= " << out_params.delta[k]; qDebug() << "Guide: drift_integral[" << k << "]= " << drift_integral[k]; } out_params.pulse_length[k] = fabs(out_params.delta[k]*in_params.proportional_gain[k] + drift_integral[k]*in_params.integral_gain[k]); out_params.pulse_length[k] = out_params.pulse_length[k] <= in_params.max_pulse_length[k] ? out_params.pulse_length[k] : in_params.max_pulse_length[k]; if (Options::guideLogging()) qDebug() << "Guide: pulse_length [" << k << "]= " << out_params.pulse_length[k]; // calc direction // We do not send pulse if direction is disabled completely, or if direction in a specific axis (e.g. N or S) is disabled if ( !in_params.enabled[k] || (out_params.delta[k] > 0 && !in_params.enabled_axis1[k]) || (out_params.delta[k] < 0 && !in_params.enabled_axis2[k])) { out_params.pulse_dir[k] = NO_DIR; out_params.pulse_length[k] = 0; continue; } if( out_params.pulse_length[k] >= in_params.min_pulse_length[k] ) { if( k == GUIDE_RA ) out_params.pulse_dir[k] = out_params.delta[k] > 0 ? RA_DEC_DIR : RA_INC_DIR; // GUIDE_RA. right dir - decreases GUIDE_RA else { out_params.pulse_dir[k] = out_params.delta[k] > 0 ? DEC_INC_DIR : DEC_DEC_DIR; // GUIDE_DEC. // Reverse DEC direction if we are looking eastward //if (ROT_Z.x[0][0] > 0 || (ROT_Z.x[0][0] ==0 && ROT_Z.x[0][1] > 0)) //out_params.pulse_dir[k] = (out_params.pulse_dir[k] == DEC_INC_DIR) ? DEC_DEC_DIR : DEC_INC_DIR; } } else out_params.pulse_dir[k] = NO_DIR; if (Options::guideLogging()) qDebug() << "Guide: Direction : " << get_direction_string(out_params.pulse_dir[k]); } //emit newAxisDelta(out_params.delta[0], out_params.delta[1]); QTextStream out(logFile); out << ticks << "," << logTime.elapsed() << "," << out_params.delta[0] << "," << out_params.pulse_length[0] << "," << get_direction_string(out_params.pulse_dir[0]) << "," << out_params.delta[1] << "," << out_params.pulse_length[1] << "," << get_direction_string(out_params.pulse_dir[1]) << endl; } void cgmath::performProcessing( void ) { Vector arc_star_pos, arc_reticle_pos; // do nothing if suspended if( suspended ) return; // find guiding star location in scr_star_pos = star_pos = findLocalStarPosition(); if (star_pos.x == -1 || std::isnan(star_pos.x)) { lost_star = true; return; } else lost_star = false; // move square overlay //TODO FIXME //moveSquare( round(star_pos.x) - (double)square_size/(2*subBinX), round(star_pos.y) - (double)square_size/(2*subBinY) ); QVector3D starCenter(star_pos.x,star_pos.y, 0); emit newStarPosition(starCenter, true); if( preview_mode ) return; if (Options::guideLogging()) qDebug() << "Guide: ################## BEGIN PROCESSING ##################"; // translate star coords into sky coord. system // convert from pixels into arcsecs arc_star_pos = point2arcsec( star_pos ); arc_reticle_pos = point2arcsec( reticle_pos ); if (Options::guideLogging()) { qDebug() << "Guide: Star X : " << star_pos.x << " Y : " << star_pos.y; qDebug() << "Guide: Reticle X : " << reticle_pos.x << " Y :" << reticle_pos.y; qDebug() << "Guide: Star RA: " << arc_star_pos.x << " DEC: " << arc_star_pos.y; qDebug() << "Guide: Reticle RA: " << arc_reticle_pos.x << " DEC: " << arc_reticle_pos.y; } // translate into sky coords. star_pos = arc_star_pos - arc_reticle_pos; star_pos.y = -star_pos.y; // invert y-axis as y picture axis is inverted if (Options::guideLogging()) qDebug() << "Guide: -------> BEFORE ROTATION Diff RA: " << star_pos.x << " DEC: " << star_pos.y; star_pos = star_pos * ROT_Z; // both coords are ready for math processing //put coord to drift list drift[GUIDE_RA][channel_ticks[GUIDE_RA]] = star_pos.x; drift[GUIDE_DEC][channel_ticks[GUIDE_DEC]] = star_pos.y; if (Options::guideLogging()) { qDebug() << "Guide: -------> AFTER ROTATION Diff RA: " << star_pos.x << " DEC: " << star_pos.y; qDebug() << "Guide: RA channel ticks: " << channel_ticks[GUIDE_RA] << " DEC channel ticks: " << channel_ticks[GUIDE_DEC]; } // make decision by axes process_axes(); // process statistics calc_square_err(); // finally process tickers do_ticks(); if (Options::guideLogging()) qDebug() << "Guide: ################## FINISH PROCESSING ##################"; } void cgmath::calc_square_err( void ) { if( !do_statistics ) return; // through MAX_ACCUM_CNT values if( ticks == 0 ) return; for( int k = GUIDE_RA; k <= GUIDE_DEC; k++ ) { double sqr_avg = 0; for( int i = 0; i < MAX_ACCUM_CNT; ++i ) sqr_avg += drift[k][i] * drift[k][i]; out_params.sigma[k] = sqrt( sqr_avg / (double)MAX_ACCUM_CNT ); } } void cgmath::setRapidGuide(bool enable) { useRapidGuide = enable; } double cgmath::getDitherRate(int axis) { if (axis < 0 || axis > 1) return -1; return ditherRate[axis]; } void cgmath::setRapidStarData(double dx, double dy) { rapidDX = dx; rapidDY = dy; } void cgmath::setLogFile(QFile * file) { logFile = file; logTime.restart(); } const char * cgmath::get_direction_string(GuideDirection dir) { switch (dir) { case RA_DEC_DIR: return "Decrease RA"; break; case RA_INC_DIR: return "Increase RA"; break; case DEC_DEC_DIR: return "Decrease DEC"; break; case DEC_INC_DIR: return "Increase DEC"; break; default: break; } return "NO DIR"; } +bool cgmath::isImageGuideEnabled() const +{ + return imageGuideEnabled; +} + +void cgmath::setImageGuideEnabled(bool value) +{ + imageGuideEnabled = value; +} + //--------------------------------------------------------------------------------------- cproc_in_params::cproc_in_params() { reset(); } void cproc_in_params::reset( void ) { threshold_alg_idx = CENTROID_THRESHOLD; guiding_rate = 0.5; average = true; for( int k = GUIDE_RA; k <= GUIDE_DEC; k++ ) { enabled[k] = true; accum_frame_cnt[k] = 1; integral_gain[k] = 0; derivative_gain[k] = 0; max_pulse_length[k] = 5000; min_pulse_length[k] = 100; } } cproc_out_params::cproc_out_params() { reset(); } void cproc_out_params::reset( void ) { for( int k = GUIDE_RA; k <= GUIDE_DEC; k++ ) { delta[k] = 0; pulse_dir[k] = NO_DIR; pulse_length[k] = 0; sigma[k] = 0; } } diff --git a/kstars/ekos/guide/internalguide/gmath.h b/kstars/ekos/guide/internalguide/gmath.h index 7159e7d8a..3cd04f408 100644 --- a/kstars/ekos/guide/internalguide/gmath.h +++ b/kstars/ekos/guide/internalguide/gmath.h @@ -1,254 +1,269 @@ /* Ekos guide tool Copyright (C) 2012 Andrew Stepanenko Modified by Jasem Mutlaq for KStars. This application 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. */ #ifndef GMATH_H_ #define GMATH_H_ #include #include #include #include #include #include "fitsviewer/fitsview.h" #include "indi/indicommon.h" #include "vect.h" #include "matr.h" typedef struct { int size; double square; } guide_square_t; #define SMART_THRESHOLD 0 #define CENTROID_THRESHOLD 1 #define AUTO_THRESHOLD 2 #define NO_THRESHOLD 3 typedef struct { int idx; const char name[32]; } square_alg_t; // smart threshold algorithm param // width of outer frame for backgroung calculation #define SMART_FRAME_WIDTH 4 // cut-factor above avarage threshold #define SMART_CUT_FACTOR 0.1 #define GUIDE_RA 0 #define GUIDE_DEC 1 #define CHANNEL_CNT 2 #define DEFAULT_SQR 1 #define MAX_ACCUM_CNT 50 extern const guide_square_t guide_squares[]; extern const square_alg_t guide_square_alg[]; // input params class cproc_in_params { public: cproc_in_params(); void reset( void ); int threshold_alg_idx; double guiding_rate; bool enabled[CHANNEL_CNT]; bool enabled_axis1[CHANNEL_CNT]; bool enabled_axis2[CHANNEL_CNT]; bool average; uint32_t accum_frame_cnt[CHANNEL_CNT]; double proportional_gain[CHANNEL_CNT]; double integral_gain[CHANNEL_CNT]; double derivative_gain[CHANNEL_CNT]; int max_pulse_length[CHANNEL_CNT]; int min_pulse_length[CHANNEL_CNT]; }; //output params class cproc_out_params { public: cproc_out_params(); void reset( void ); double delta[2]; GuideDirection pulse_dir[2]; int pulse_length[2]; double sigma[2]; }; typedef struct { double focal_ratio; double fov_wd, fov_ht; double focal, aperture; } info_params_t; class cgmath : public QObject { Q_OBJECT public: cgmath(); virtual ~cgmath(); // functions bool setVideoParameters( int vid_wd, int vid_ht, int binX, int binY ); bool setGuiderParameters( double ccd_pix_wd, double ccd_pix_ht, double guider_aperture, double guider_focal ); void getGuiderParameters( double * ccd_pix_wd, double * ccd_pix_ht, double * guider_aperture, double * guider_focal ); bool setReticleParameters( double x, double y, double ang ); bool getReticleParameters( double * x, double * y, double * ang ) const; int getSquareIndex( void ) const; int getSquareAlgorithmIndex( void ) const; int getSquareSize() { return squareSize; } void setSquareAlgorithm( int alg_idx ); Matrix getROTZ() { return ROT_Z; } const cproc_out_params * getOutputParameters() const { return &out_params; } info_params_t getInfoParameters( void ) const; uint32_t getTicks( void ) const; void setGuideView(FITSView * image); bool declinationSwapEnabled() { return dec_swap; } void setDeclinationSwapEnabled(bool enable) { dec_swap = enable; } FITSView * getGuideView() { return guideView; } void setPreviewMode(bool enable) { preview_mode = enable; } /*void moveSquare( double newx, double newy ); void resizeSquare( int size_idx ); Vector getSquarePosition() { return square_pos; }*/ // Rapid Guide void setRapidGuide(bool enable); void setRapidStarData(double dx, double dy); // Operations void start( void ); void stop( void ); bool reset( void ); void suspend( bool mode ); bool isSuspended( void ) const; // Star tracking void getStarDrift( double * dx, double * dy ) const; void getStarScreenPosition( double * dx, double * dy ) const; Vector findLocalStarPosition( void ) const; bool isStarLost(void) const; void setLostStar(bool is_lost); // Main processing function void performProcessing( void ); // Math bool calculateAndSetReticle1D( double start_x, double start_y, double end_x, double end_y, int totalPulse=-1); bool calculateAndSetReticle2D( double start_ra_x, double start_ra_y, double end_ra_x, double end_ra_y, double start_dec_x, double start_dec_y, double end_dec_x, double end_dec_y, bool * swap_dec, int totalPulse=-1); double calculatePhi( double start_x, double start_y, double end_x, double end_y ) const; // Dither double getDitherRate(int axis); // Logging void setLogFile(QFile * file); - signals: + bool isImageGuideEnabled() const; + void setImageGuideEnabled(bool value); + + void setRegionAxis(const uint32_t &value); + +signals: void newAxisDelta(double delta_ra, double delta_dec); void newStarPosition(QVector3D, bool); private: // Templated functions template Vector findLocalStarPosition( void ) const; // sys... uint32_t ticks; // global channel ticker QPointer guideView; // pointer to image int video_width, video_height; // video frame dimensions double ccd_pixel_width, ccd_pixel_height, aperture, focal; Matrix ROT_Z; bool preview_mode, suspended, lost_star, dec_swap; // square variables int squareSize; // size of analysing square int square_alg_idx; // index of threshold algorithm int subBinX,subBinY; // sky coord. system vars. Vector star_pos; // position of star in reticle coord. system Vector scr_star_pos; // sctreen star position Vector reticle_pos; Vector reticle_orts[2]; double reticle_angle; // processing uint32_t channel_ticks[2]; uint32_t accum_ticks[2]; double * drift[2]; double drift_integral[2]; // overlays... cproc_in_params in_params; cproc_out_params out_params; // stat math... bool do_statistics; double sum, sqr_sum; double delta_prev, sigma_prev, sigma; // proc void do_ticks( void ); Vector point2arcsec( const Vector &p ) const; void process_axes( void ); void calc_square_err( void ); const char * get_direction_string(GuideDirection dir); // rapid guide - bool useRapidGuide; + bool useRapidGuide=false; double rapidDX, rapidDY; + // Image Guide + bool imageGuideEnabled=false; + // Creates a new float image from the guideView image data. The returned image MUST be deleted later or memory will leak. + float * createFloatImage() const; + // Partition guideView image into NxN square regions each of size axis*axis. The returned vector contains pointers to + // the newly allocated square images. It MUST be deleted later by delete[] or memory will leak. + QVector partitionImage() const; + uint32_t regionAxis=64; + QVector referenceRegions; + // dithering double ditherRate[2]; QFile * logFile; QTime logTime; }; #endif /*GMATH_H_*/ diff --git a/kstars/ekos/guide/internalguide/imageautoguiding.cpp b/kstars/ekos/guide/internalguide/imageautoguiding.cpp new file mode 100644 index 000000000..9eb281505 --- /dev/null +++ b/kstars/ekos/guide/internalguide/imageautoguiding.cpp @@ -0,0 +1,480 @@ +/* Image Guide Algorithm + Copyright (C) 2017 Bob Majewski + + This application 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. + */ + +#include +#include +#include +#include +#include "imageautoguiding.h" + +#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr +#define NR_END 1 +#define FREE_ARG char* + + +#define TWOPI 6.28318530717959 +#define FFITMAX 0.05 + + +//void ImageAutoGuiding1(float *ref,float *im,int n,float *xshift,float *yshift); + +float ***f3tensorSP(long nrl, long nrh, long ncl, long nch, long ndl, long ndh); +void free_f3tensorSP(float ***t, long nrl, long nrh, long ncl, long nch, + long ndl, long ndh); + +float **matrixSP(long nrl, long nrh, long ncl, long nch); + +void free_matrixSP(float **m, long nrl, long nrh, long ncl, long nch); +void nrerrorNR(void); + +void fournNR(float data[], unsigned long nn[], long ndim, long isign); + +void rlft3NR(float ***data, float **speq, unsigned long nn1, unsigned long nn2, + unsigned long nn3, long isign); + +void ShiftEST(float ***testimage,float ***refimage,int n, +float *xshift,float *yshift,int k); + +namespace ImageAutoGuiding +{ + +void ImageAutoGuiding1(float *ref,float *im,int n,float *xshift,float *yshift) +{ + float ***RefImage,***TestImage; + int i,j,k; + float x,y; + + /* Allocate memory */ + + RefImage = f3tensorSP(1,1,1,n,1,n); + TestImage = f3tensorSP(1,1,1,n,1,n); + + /* Load Data */ + + k = 0; + + for(j=1;j<=n;++j) + { + + for(i=1;i<=n;++i) + { + RefImage[1][j][i] = ref[k]; + TestImage[1][j][i] = im[k]; + + k += 1; + } + + } + + /* Calculate Image Shifts */ + + ShiftEST(TestImage,RefImage,n,&x,&y,1); + + *xshift = x; + *yshift = y; + + /* free memory */ + + free_f3tensorSP(RefImage,1,1,1,n,1,n); + free_f3tensorSP(TestImage,1,1,1,n,1,n); + + + +} + +} + +// Calculates Image Shifts + + +void ShiftEST(float ***testimage,float ***refimage,int n, +float *xshift,float *yshift,int k) +{ +int ix,iy,nh,nhplusone; +double deltax,deltay,fx2sum,fy2sum,phifxsum,phifysum,fxfysum; +double fx,fy,ff,fn,re,im,testre,testim,rev,imv,phi; +double power,dem,f2,f2limit; +float **speq; + + + + f2limit = FFITMAX*FFITMAX; + + speq = matrixSP(1,1,1,2*n); + + + nh = n/2; + nhplusone = nh + 1; + + + fn = ((float) n); + ff = 1.0/fn; + + + /* FFT of Reference */ + + for(ix=1;ix<=2*n;++ix) + { + speq[1][ix] = 0.0; + } + + rlft3NR(refimage,speq,1,n,n,1); + + /* FFT of Test Image */ + + for(ix=1;ix<=2*n;++ix) + { + speq[1][ix] = 0.0; + } + + rlft3NR(testimage,speq,1,n,n,1); + + /* Solving for slopes */ + + fx2sum = 0.0; + fy2sum = 0.0; + + phifxsum = 0.0; + phifysum = 0.0; + + fxfysum = 0.0; + + + for(ix =1;ix <= n;++ix) + { + + + if(ix <= nhplusone) + { + fx = ff*((float) (ix-1)); + } + else + { + fx = - ff*((float) (n + 1 - ix)); + } + + + for(iy = 1;iy <= nh;++iy) + { + + fy = ff*((float) (iy-1)); + + f2 = fx*fx + fy*fy; + + /* Limit to Low Spatial Frequencies */ + + if(f2 < f2limit) + { + + + /* Real part reference image */ + + re = refimage[k][ix][2*iy-1]; + + /* Imaginary part reference image */ + + im = refimage[k][ix][2*iy]; + + power = re*re + im*im; + + + /* Real part test image */ + + testre = testimage[k][ix][2*iy-1]; + + /* Imaginary part image */ + + testim = testimage[k][ix][2*iy]; + + + rev = re*testre + im*testim; + imv = re*testim - im*testre; + + /* Find Phase */ + + phi = atan2(imv,rev); + + + fx2sum += power*fx*fx; + fy2sum += power*fy*fy; + + phifxsum += power*fx*phi; + phifysum += power*fy*phi; + + fxfysum += power*fx*fy; + + + + + } + + } + } + + + + + /* calculate subpixel shift */ + + dem = fx2sum*fy2sum - fxfysum*fxfysum; + + + deltax = (phifxsum*fy2sum - fxfysum*phifysum)/(dem*TWOPI); + deltay = (phifysum*fx2sum - fxfysum*phifxsum)/(dem*TWOPI); + + + + free_matrixSP(speq,1,1,1,2*n); + + /* You can change the shift mapping here */ + + + *xshift = deltax; + *yshift = deltay; + + + +} + + +// 2 and 3 Dimensional FFT Routine for Real Data +// Numerical Recipes in C Second Edition +// The Art of Scientific Computing +// 1999 + +void rlft3NR(float ***data, float **speq, unsigned long nn1, unsigned long nn2, + unsigned long nn3, long isign) +{ + void fournNR(float data[], unsigned long nn[], long ndim, long isign); + void nrerror(); + unsigned long i1,i2,i3,j1,j2,j3,nn[4],ii3; + double theta,wpi,wpr,wtemp; + float c1,c2,h1r,h1i,h2r,h2i; + float wi,wr; + + if (1+&data[nn1][nn2][nn3]-&data[1][1][1] != nn1*nn2*nn3) + nrerrorNR(); + c1=0.5; + c2 = -0.5*isign; + theta=isign*(6.28318530717959/nn3); + wtemp=sin(0.5*theta); + wpr = -2.0*wtemp*wtemp; + wpi=sin(theta); + nn[1]=nn1; + nn[2]=nn2; + nn[3]=nn3 >> 1; + if (isign == 1) { + fournNR(&data[1][1][1]-1,nn,3,isign); + for (i1=1;i1<=nn1;i1++) + for (i2=1,j2=0;i2<=nn2;i2++) { + speq[i1][++j2]=data[i1][i2][1]; + speq[i1][++j2]=data[i1][i2][2]; + } + } + for (i1=1;i1<=nn1;i1++) { + j1=(i1 != 1 ? nn1-i1+2 : 1); + wr=1.0; + wi=0.0; + for (ii3=1,i3=1;i3<=(nn3>>2)+1;i3++,ii3+=2) { + for (i2=1;i2<=nn2;i2++) { + if (i3 == 1) { + j2=(i2 != 1 ? ((nn2-i2)<<1)+3 : 1); + h1r=c1*(data[i1][i2][1]+speq[j1][j2]); + h1i=c1*(data[i1][i2][2]-speq[j1][j2+1]); + h2i=c2*(data[i1][i2][1]-speq[j1][j2]); + h2r= -c2*(data[i1][i2][2]+speq[j1][j2+1]); + data[i1][i2][1]=h1r+h2r; + data[i1][i2][2]=h1i+h2i; + speq[j1][j2]=h1r-h2r; + speq[j1][j2+1]=h2i-h1i; + } else { + j2=(i2 != 1 ? nn2-i2+2 : 1); + j3=nn3+3-(i3<<1); + h1r=c1*(data[i1][i2][ii3]+data[j1][j2][j3]); + h1i=c1*(data[i1][i2][ii3+1]-data[j1][j2][j3+1]); + h2i=c2*(data[i1][i2][ii3]-data[j1][j2][j3]); + h2r= -c2*(data[i1][i2][ii3+1]+data[j1][j2][j3+1]); + data[i1][i2][ii3]=h1r+wr*h2r-wi*h2i; + data[i1][i2][ii3+1]=h1i+wr*h2i+wi*h2r; + data[j1][j2][j3]=h1r-wr*h2r+wi*h2i; + data[j1][j2][j3+1]= -h1i+wr*h2i+wi*h2r; + } + } + wr=(wtemp=wr)*wpr-wi*wpi+wr; + wi=wi*wpr+wtemp*wpi+wi; + } + } + if (isign == -1) + fournNR(&data[1][1][1]-1,nn,3,isign); +} + +// Multi-Dimensional FFT Routine for Complex Data +// Numerical Recipes in C Second Edition +// The Art of Scientific Computing +// 1999 +// Used in rlft3 + +void fournNR(float data[], unsigned long nn[], long ndim, long isign) +{ + long idim; + unsigned long i1,i2rev,i3rev,ip1,ip2,ip3,ifp1,ifp2; + register unsigned long i2,i3; + unsigned long ibit,k1,k2,n,nprev,nrem,ntot; + float wi,wr,tempi,tempr; + double theta,wpi,wpr,wtemp; + + for (ntot=1,idim=1;idim<=ndim;idim++) + ntot *= nn[idim]; + nprev=1; + for (idim=ndim;idim>=1;idim--) { + n=nn[idim]; + nrem=ntot/(n*nprev); + ip1=nprev << 1; + ip2=ip1*n; + ip3=ip2*nrem; + i2rev=1; + for (i2=1;i2<=ip2;i2+=ip1) { + if (i2 < i2rev) { + for (i1=i2;i1<=i2+ip1-2;i1+=2) { + for (i3=i1;i3<=ip3;i3+=ip2) { + i3rev=i2rev+i3-i2; + SWAP(data[i3],data[i3rev]); + SWAP(data[i3+1],data[i3rev+1]); + } + } + } + ibit=ip2 >> 1; + while (ibit >= ip1 && i2rev > ibit) { + i2rev -= ibit; + ibit >>= 1; + } + i2rev += ibit; + } + ifp1=ip1; + while (ifp1 < ip2) { + ifp2=ifp1 << 1; + theta=isign*6.28318530717959/(ifp2/ip1); + wtemp=sin(0.5*theta); + wpr = -2.0*wtemp*wtemp; + wpi=sin(theta); + wr=1.0; + wi=0.0; + for (i3=1;i3<=ifp1;i3+=ip1) { + for (i1=i3;i1<=i3+ip1-2;i1+=2) { + for (i2=i1;i2<=ip3;i2+=ifp2) { + k1=i2; + k2=k1+ifp1; + tempr=(double)wr*data[k2]-(double)wi*data[k2+1]; + tempi=(double)wr*data[k2+1]+(double)wi*data[k2]; + data[k2]=data[k1]-tempr; + data[k2+1]=data[k1+1]-tempi; + data[k1] += tempr; + data[k1+1] += tempi; + } + } + wr=(wtemp=wr)*wpr-wi*wpi+wr; + wi=wi*wpr+wtemp*wpi+wi; + } + ifp1=ifp2; + } + nprev *= n; + } +} + +void nrerrorNR(void) +{ + +} + +// Numerical Recipes memory allocation routines +// One based arrays + + +float **matrixSP(long nrl, long nrh, long ncl, long nch) +/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + float **m; + + /* allocate pointers to rows */ + m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*))); + if (!m) nrerrorNR(); + m += NR_END; + m -= nrl; + + /* allocate rows and set pointers to them */ + m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float))); + if (!m[nrl]) nrerrorNR(); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + + +float ***f3tensorSP(long nrl, long nrh, long ncl, long nch, long ndl, long ndh) +/* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */ +{ + long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1,ndep=ndh-ndl+1; + float ***t; + + /* allocate pointers to pointers to rows */ + t=(float ***) malloc((size_t)((nrow+NR_END)*sizeof(float**))); + if (!t) nrerrorNR(); + t += NR_END; + t -= nrl; + + /* allocate pointers to rows and set pointers to them */ + t[nrl]=(float **) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float*))); + if (!t[nrl]) nrerrorNR(); + t[nrl] += NR_END; + t[nrl] -= ncl; + + /* allocate rows and set pointers to them */ + t[nrl][ncl]=(float *) malloc((size_t)((nrow*ncol*ndep+NR_END)*sizeof(float))); + if (!t[nrl][ncl]) nrerrorNR(); + t[nrl][ncl] += NR_END; + t[nrl][ncl] -= ndl; + + for(j=ncl+1;j<=nch;j++) t[nrl][j]=t[nrl][j-1]+ndep; + for(i=nrl+1;i<=nrh;i++) { + t[i]=t[i-1]+ncol; + t[i][ncl]=t[i-1][ncl]+ncol*ndep; + for(j=ncl+1;j<=nch;j++) t[i][j]=t[i][j-1]+ndep; + } + + /* return pointer to array of pointers to rows */ + return t; +} + +void free_matrixSP(float **m, long nrl, long nrh, long ncl, long nch) +/* free a float matrix allocated by matrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_f3tensorSP(float ***t, long nrl, long nrh, long ncl, long nch, + long ndl, long ndh) +/* free a float f3tensor allocated by f3tensor() */ +{ + free((FREE_ARG) (t[nrl][ncl]+ndl-NR_END)); + free((FREE_ARG) (t[nrl]+ncl-NR_END)); + free((FREE_ARG) (t+nrl-NR_END)); +} + + + + + + + diff --git a/kstars/ekos/guide/internalguide/imageautoguiding.h b/kstars/ekos/guide/internalguide/imageautoguiding.h new file mode 100644 index 000000000..64a6d567e --- /dev/null +++ b/kstars/ekos/guide/internalguide/imageautoguiding.h @@ -0,0 +1,32 @@ +/* Image Guide Algorithm + Copyright (C) 2017 Bob Majewski + + This application 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. + */ + +// Robert Majewski + +// ImageAutoGuiding1 is self contained +// ref is the reference image +// im is the test image +// Image Size n x n + + +// The Input Image and the Reference images are zero based one dimensional vectors +// They MUST be Square Images +// n MUST be a Power of 2 use 128,256,512 +// 256 X 256 is A good Choice +// These should be portions of the camera imagery + + +namespace ImageAutoGuiding +{ + +void ImageAutoGuiding1(float *ref,float *im,int n,float *xshift,float *yshift); + +} + + diff --git a/kstars/ekos/guide/internalguide/internalguider.cpp b/kstars/ekos/guide/internalguide/internalguider.cpp index 96c0d74c5..74363544b 100644 --- a/kstars/ekos/guide/internalguide/internalguider.cpp +++ b/kstars/ekos/guide/internalguide/internalguider.cpp @@ -1,812 +1,886 @@ /* Ekos Internal Guider Class Copyright (C) 2016 Jasem Mutlaq . Based on lin_guider This application 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. */ #include #include #include "auxiliary/kspaths.h" #include "auxiliary/QProgressIndicator.h" #include "internalguider.h" #include "gmath.h" #include "Options.h" #define MAX_DITHER_RETIRES 20 namespace Ekos { InternalGuider::InternalGuider() { // Create math object pmath = new cgmath(); - //connect(pmath, SIGNAL(newAxisDelta(double,double)), this, SIGNAL(newAxisDelta(double,double))); - //connect(pmath, SIGNAL(newAxisDelta(double,double)), this, SLOT(updateGuideDriver(double,double))); - //connect(pmath, SIGNAL(newStarPosition(QVector3D,bool)), this, SLOT(setStarPosition(QVector3D,bool))); connect(pmath, SIGNAL(newStarPosition(QVector3D,bool)), this, SIGNAL(newStarPosition(QVector3D,bool))); // Calibration calibrationStage = CAL_IDLE; - //is_started = false; - axis = GUIDE_RA; + state = GUIDE_IDLE; + auto_drift_time = 5; start_x1 = start_y1 = 0; end_x1 = end_y1 = 0; start_x2 = start_y2 = 0; end_x2 = end_y2 = 0; } InternalGuider::~InternalGuider() { delete (pmath); } bool InternalGuider::guide() { if (state == GUIDE_SUSPENDED) return true; if (state >= GUIDE_GUIDING) { - return processGuiding(); + if (imageGuideEnabled) + return processImageGuiding(); + else + return processGuiding(); } guideFrame->disconnect(this); QString logFileName = KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/guide_log.txt"; logFile.setFileName(logFileName); logFile.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&logFile); out << "Guiding rate,x15 arcsec/sec: " << Options::guidingRate() << endl; out << "Focal,mm: " << mountFocalLength << endl; out << "Aperture,mm: " << mountAperture << endl; out << "F/D: " << mountFocalLength/mountAperture << endl; out << "Frame #, Time Elapsed (ms), RA Error (arcsec), RA Correction (ms), RA Correction Direction, DEC Error (arcsec), DEC Correction (ms), DEC Correction Direction" << endl; pmath->setLogFile(&logFile); pmath->start(); m_lostStarTries=0; // TODO re-enable rapid check later on #if 0 m_isStarted = true; m_useRapidGuide = ui.rapidGuideCheck->isChecked(); if (m_useRapidGuide) guideModule->startRapidGuide(); emit newStatus(Ekos::GUIDE_GUIDING); guideModule->setSuspended(false); first_frame = true; if (ui.subFrameCheck->isEnabled() && ui.subFrameCheck->isChecked() && m_isSubFramed == false) first_subframe = true; capture(); #endif isFirstFrame = true; state = GUIDE_GUIDING; emit newStatus(state); emit frameCaptureRequested(); return true; } bool InternalGuider::abort() { calibrationStage = CAL_IDLE; if (state == GUIDE_CALIBRATING || state == GUIDE_GUIDING || state == GUIDE_DITHERING) emit newStatus(GUIDE_ABORTED); else emit newStatus(GUIDE_IDLE); state = GUIDE_IDLE; return true; } bool InternalGuider::suspend() { state = GUIDE_SUSPENDED; emit newStatus(state); pmath->suspend(true); return true; } bool InternalGuider::resume() { state = GUIDE_GUIDING; emit newStatus(state); pmath->suspend(false); emit frameCaptureRequested(); return true; } bool InternalGuider::dither(double pixels) { static Vector target_pos; static unsigned int retries=0; //if (ui.ditherCheck->isChecked() == false) //return false; double cur_x, cur_y, ret_angle; pmath->getReticleParameters(&cur_x, &cur_y, &ret_angle); pmath->getStarScreenPosition( &cur_x, &cur_y ); Matrix ROT_Z = pmath->getROTZ(); //qDebug() << "Star Pos X " << cur_x << " Y " << cur_y; if (state != GUIDE_DITHERING) { retries =0; // JM 2016-05-8: CCD would abort if required. //targetChip->abortExposure(); int polarity = (rand() %2 == 0) ? 1 : -1; double angle = ((double) rand() / RAND_MAX) * M_PI/2.0; double diff_x = pixels * cos(angle); double diff_y = pixels * sin(angle); if (pmath->declinationSwapEnabled()) diff_y *= -1; if (polarity > 0) target_pos = Vector( cur_x, cur_y, 0 ) + Vector( diff_x, diff_y, 0 ); else target_pos = Vector( cur_x, cur_y, 0 ) - Vector( diff_x, diff_y, 0 ); if (Options::guideLogging()) qDebug() << "Guide: Dithering process started.. Reticle Target Pos X " << target_pos.x << " Y " << target_pos.y; pmath->setReticleParameters(target_pos.x, target_pos.y, ret_angle); state = GUIDE_DITHERING; emit newStatus(state); processGuiding(); return true; } Vector star_pos = Vector( cur_x, cur_y, 0 ) - Vector( target_pos.x, target_pos.y, 0 ); star_pos.y = -star_pos.y; star_pos = star_pos * ROT_Z; if (Options::guideLogging()) qDebug() << "Guide: Dithering in progress. Diff star X:" << star_pos.x << "Y:" << star_pos.y; if (fabs(star_pos.x) < 1 && fabs(star_pos.y) < 1) { pmath->setReticleParameters(cur_x, cur_y, ret_angle); if (Options::guideLogging()) qDebug() << "Guide: Dither complete."; //emit ditherComplete(); emit newStatus(Ekos::GUIDE_DITHERING_SUCCESS); // Back to guiding state = GUIDE_GUIDING; } else { if (++retries > MAX_DITHER_RETIRES) { emit newStatus(Ekos::GUIDE_DITHERING_ERROR); abort(); return false; } processGuiding(); } return true; } bool InternalGuider::calibrate() { bool ccdInfo=true, scopeInfo=true; QString errMsg; if (subW == 0 || subH == 0) { errMsg = "CCD"; ccdInfo = false; } if (mountAperture == 0 || mountFocalLength == 0) { scopeInfo = false; if (ccdInfo == false) errMsg += " & Telescope"; else errMsg += "Telescope"; } if (ccdInfo == false || scopeInfo == false) { KMessageBox::error(NULL, i18n("%1 info are missing. Please set the values in INDI Control Panel.", errMsg), i18n("Missing Information")); return false; } if (state != GUIDE_CALIBRATING) { calibrationStage = CAL_IDLE; state = GUIDE_CALIBRATING; emit newStatus(GUIDE_CALIBRATING); } if (calibrationStage > CAL_START) { processCalibration(); return true; } guideFrame->disconnect(this); // Must reset dec swap before we run any calibration procedure! emit DESwapChanged(false); pmath->setDeclinationSwapEnabled(false); pmath->setLostStar(false); calibrationStage = CAL_START; // automatic // If two axies (RA/DEC) are required if( Options::twoAxisEnabled() ) calibrateRADECRecticle(false); else // Just RA calibrateRADECRecticle(true); return true; } void InternalGuider::processCalibration() { pmath->performProcessing(); if (pmath->isStarLost()) { emit newLog(i18n("Lost track of the guide star. Try increasing the square size or reducing pulse duration.")); reset(); calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); return; } switch (calibrationType) { case CAL_NONE: break; case CAL_RA_AUTO: calibrateRADECRecticle(true); break; case CAL_RA_DEC_AUTO: calibrateRADECRecticle(false); break; } } void InternalGuider::setGuideView(FITSView * guideView) { guideFrame = guideView; pmath->setGuideView(guideFrame); } void InternalGuider::reset() { state = GUIDE_IDLE; //calibrationStage = CAL_IDLE; connect(guideFrame, SIGNAL(trackingStarSelected(int,int)), this, SLOT(trackingStarSelected(int, int)), Qt::UniqueConnection); } void InternalGuider::calibrateRADECRecticle( bool ra_only ) { bool auto_term_ok = false; Q_ASSERT(pmath); int pulseDuration = Options::calibrationPulseDuration(); int totalPulse = pulseDuration * Options::autoModeIterations(); if (ra_only) calibrationType = CAL_RA_AUTO; else calibrationType = CAL_RA_DEC_AUTO; switch(calibrationStage) { case CAL_START: //----- automatic mode ----- auto_drift_time = Options::autoModeIterations(); if (ra_only) turn_back_time = auto_drift_time*2 + auto_drift_time/2; else turn_back_time = auto_drift_time*6; iterations = 0; emit newLog(i18n("RA drifting forward...")); pmath->getReticleParameters(&start_x1, &start_y1, NULL); if (Options::guideLogging()) qDebug() << "Guide: Start X1 " << start_x1 << " Start Y1 " << start_y1; emit newPulse( RA_INC_DIR, pulseDuration ); if (Options::guideLogging()) qDebug() << "Guide: Iteration " << iterations << " Direction: RA_INC_DIR" << " Duration: " << pulseDuration << " ms."; iterations++; calibrationStage = CAL_RA_INC; break; case CAL_RA_INC: emit newPulse( RA_INC_DIR, pulseDuration ); if (Options::guideLogging()) { // Star position resulting from LAST guiding pulse to mount double cur_x, cur_y; pmath->getStarScreenPosition( &cur_x, &cur_y ); qDebug() << "Guide: Iteration #" << iterations-1 << ": STAR " << cur_x << "," << cur_y; qDebug() << "Guide: Iteration " << iterations << " Direction: RA_INC_DIR" << " Duration: " << pulseDuration << " ms."; } iterations++; if (iterations == auto_drift_time) calibrationStage = CAL_RA_DEC; break; case CAL_RA_DEC: { if (iterations == auto_drift_time) { pmath->getStarScreenPosition( &end_x1, &end_y1 ); if (Options::guideLogging()) qDebug() << "Guide: End X1 " << end_x1 << " End Y1 " << end_y1; phi = pmath->calculatePhi( start_x1, start_y1, end_x1, end_y1 ); ROT_Z = RotateZ( -M_PI*phi/180.0 ); // derotates... emit newLog(i18n("RA drifting reverse...")); } //----- Z-check (new!) ----- double cur_x, cur_y; pmath->getStarScreenPosition( &cur_x, &cur_y ); Vector star_pos = Vector( cur_x, cur_y, 0 ) - Vector( start_x1, start_y1, 0 ); star_pos.y = -star_pos.y; star_pos = star_pos * ROT_Z; if (Options::guideLogging()) qDebug() << "Guide: Star x pos is " << star_pos.x << " from original point."; // start point reached... so exit if( star_pos.x < 1.5 ) { pmath->performProcessing(); auto_term_ok = true; } //----- Z-check end ----- if( !auto_term_ok ) { if (iterations < turn_back_time) { emit newPulse( RA_DEC_DIR, pulseDuration ); if (Options::guideLogging()) { // Star position resulting from LAST guiding pulse to mount double cur_x, cur_y; pmath->getStarScreenPosition( &cur_x, &cur_y ); qDebug() << "Guide: Iteration #" << iterations-1 << ": STAR " << cur_x << "," << cur_y; qDebug() << "Guide: Iteration " << iterations << " Direction: RA_DEC_DIR" << " Duration: " << pulseDuration << " ms."; } iterations++; break; } calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); emit newLog(i18np("Guide RA: Scope cannot reach the start point after %1 iteration. Possible mount or drive problems...", "GUIDE_RA: Scope cannot reach the start point after %1 iterations. Possible mount or drive problems...", turn_back_time)); KNotification::event( QLatin1String( "CalibrationFailed" ) , i18n("Guiding calibration failed with errors")); reset(); break; } if (ra_only == false) { calibrationStage = CAL_DEC_INC; start_x2 = cur_x; start_y2 = cur_y; if (Options::guideLogging()) qDebug() << "Guide: Start X2 " << start_x2 << " start Y2 " << start_y2; emit newPulse( DEC_INC_DIR, pulseDuration ); if (Options::guideLogging()) { // Star position resulting from LAST guiding pulse to mount double cur_x, cur_y; pmath->getStarScreenPosition( &cur_x, &cur_y ); qDebug() << "Guide: Iteration #" << iterations-1 << ": STAR " << cur_x << "," << cur_y; qDebug() << "Guide: Iteration " << iterations << " Direction: DEC_INC_DIR" << " Duration: " << pulseDuration << " ms."; } iterations++; dec_iterations = 1; emit newLog(i18n("DEC drifting forward...")); break; } // calc orientation if( pmath->calculateAndSetReticle1D( start_x1, start_y1, end_x1, end_y1, totalPulse) ) { calibrationStage = CAL_IDLE; // FIXME what is this for? //fillInterface(); emit newStatus(Ekos::GUIDE_CALIBRATION_SUCESS); KNotification::event( QLatin1String( "CalibrationSuccessful" ) , i18n("Guiding calibration completed successfully")); //if (ui.autoStarCheck->isChecked()) //guideModule->selectAutoStar(); } else { emit newLog(i18n("Calibration rejected. Star drift is too short.")); calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); KNotification::event( QLatin1String( "CalibrationFailed" ) , i18n("Guiding calibration failed with errors")); } reset(); break; } case CAL_DEC_INC: emit newPulse( DEC_INC_DIR, pulseDuration ); if (Options::guideLogging()) { // Star position resulting from LAST guiding pulse to mount double cur_x, cur_y; pmath->getStarScreenPosition( &cur_x, &cur_y ); qDebug() << "Guide: Iteration #" << iterations-1 << ": STAR " << cur_x << "," << cur_y; qDebug() << "Guide: Iteration " << iterations << " Direction: DEC_INC_DIR" << " Duration: " << pulseDuration << " ms."; } iterations++; dec_iterations++; if (dec_iterations == auto_drift_time) calibrationStage = CAL_DEC_DEC; break; case CAL_DEC_DEC: { if (dec_iterations == auto_drift_time) { pmath->getStarScreenPosition( &end_x2, &end_y2 ); if (Options::guideLogging()) qDebug() << "Guide: End X2 " << end_x2 << " End Y2 " << end_y2; phi = pmath->calculatePhi( start_x2, start_y2, end_x2, end_y2 ); ROT_Z = RotateZ( -M_PI*phi/180.0 ); // derotates... emit newLog(i18n("DEC drifting reverse...")); } //----- Z-check (new!) ----- double cur_x, cur_y; pmath->getStarScreenPosition( &cur_x, &cur_y ); //pmain_wnd->appendLogText(i18n("GUIDE_DEC running back..."); if (Options::guideLogging()) qDebug() << "Guide: Cur X2 " << cur_x << " Cur Y2 " << cur_y; Vector star_pos = Vector( cur_x, cur_y, 0 ) - Vector( start_x2, start_y2, 0 ); star_pos.y = -star_pos.y; star_pos = star_pos * ROT_Z; if (Options::guideLogging()) qDebug() << "Guide: start Pos X " << star_pos.x << " from original point."; // start point reached... so exit if( star_pos.x < 1.5 ) { pmath->performProcessing(); auto_term_ok = true; } //----- Z-check end ----- if( !auto_term_ok ) { if (iterations < turn_back_time) { emit newPulse(DEC_DEC_DIR, pulseDuration ); if (Options::guideLogging()) { // Star position resulting from LAST guiding pulse to mount double cur_x, cur_y; pmath->getStarScreenPosition( &cur_x, &cur_y ); qDebug() << "Guide: Iteration #" << iterations-1 << ": STAR " << cur_x << "," << cur_y; qDebug() << "Guide: Iteration " << iterations << " Direction: DEC_DEC_DIR" << " Duration: " << pulseDuration << " ms."; } iterations++; dec_iterations++; break; } calibrationStage = CAL_ERROR; emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); emit newLog(i18np("Guide DEC: Scope cannot reach the start point after %1 iteration.\nPossible mount or drive problems...", "GUIDE_DEC: Scope cannot reach the start point after %1 iterations.\nPossible mount or drive problems...", turn_back_time)); KNotification::event( QLatin1String( "CalibrationFailed" ) , i18n("Guiding calibration failed with errors")); reset(); break; } bool swap_dec=false; // calc orientation if( pmath->calculateAndSetReticle2D( start_x1, start_y1, end_x1, end_y1, start_x2, start_y2, end_x2, end_y2, &swap_dec, totalPulse ) ) { calibrationStage = CAL_IDLE; //fillInterface(); if (swap_dec) emit newLog(i18n("DEC swap enabled.")); else emit newLog(i18n("DEC swap disabled.")); emit newStatus(Ekos::GUIDE_CALIBRATION_SUCESS); emit DESwapChanged(swap_dec); KNotification::event( QLatin1String( "CalibrationSuccessful" ) , i18n("Guiding calibration completed successfully")); //if (ui.autoStarCheck->isChecked()) //guideModule->selectAutoStar(); } else { emit newLog(i18n("Calibration rejected. Star drift is too short.")); emit newStatus(Ekos::GUIDE_CALIBRATION_ERROR); //ui.startCalibrationLED->setColor(alertColor); calibrationStage = CAL_ERROR; KNotification::event( QLatin1String( "CalibrationFailed" ) , i18n("Guiding calibration failed with errors")); } reset(); break; } default: break; } } void InternalGuider::setStarPosition(QVector3D starCenter) { pmath->setReticleParameters(starCenter.x(), starCenter.y(), -1); } void InternalGuider::trackingStarSelected(int x, int y) { if (calibrationStage == CAL_IDLE) return; //int square_size = guide_squares[pmath->getSquareIndex()].size; pmath->setReticleParameters(x, y, -1); //pmath->moveSquare(x-square_size/(2*pmath->getBinX()), y-square_size/(2*pmath->getBinY())); //update_reticle_pos(x, y); //ui.selectStarLED->setColor(okColor); calibrationStage = CAL_START; //ui.pushButton_StartCalibration->setEnabled(true); /*QVector3D starCenter; starCenter.setX(x); starCenter.setY(y); emit newStarPosition(starCenter, true);*/ //if (ui.autoStarCheck->isChecked()) //if (Options::autoStarEnabled()) //calibrate(); } void InternalGuider::setDECSwap(bool enable) { pmath->setDeclinationSwapEnabled(enable); } void InternalGuider::setSquareAlgorithm(int index) { pmath->setSquareAlgorithm(index); } void InternalGuider::setReticleParameters(double x, double y, double angle) { pmath->setReticleParameters(x,y,angle); } bool InternalGuider::getReticleParameters(double * x, double * y, double * angle) { return pmath->getReticleParameters(x,y,angle); } bool InternalGuider::setGuiderParams(double ccdPixelSizeX, double ccdPixelSizeY, double mountAperture, double mountFocalLength) { this->ccdPixelSizeX = ccdPixelSizeX; this->ccdPixelSizeY = ccdPixelSizeY; this->mountAperture = mountAperture; this->mountFocalLength = mountFocalLength; return pmath->setGuiderParameters(ccdPixelSizeX, ccdPixelSizeY, mountAperture, mountFocalLength); } bool InternalGuider::setFrameParams(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t binX, uint16_t binY) { if( w <= 0 || h <= 0 ) return false; subX = x; subY = y; subW = w; subH = h; subBinX = binX; subBinY = binY; pmath->setVideoParameters(w, h, subBinX, subBinY); return true; } bool InternalGuider::processGuiding() { static int maxPulseCounter=0; const cproc_out_params * out; uint32_t tick = 0; // On first frame, center the box (reticle) around the star so we do not start with an offset the results in // unnecessary guiding pulses. if (isFirstFrame) { if (state == GUIDE_GUIDING) { Vector star_pos = pmath->findLocalStarPosition(); pmath->setReticleParameters(star_pos.x, star_pos.y, -1); } isFirstFrame=false; } // calc math. it tracks square pmath->performProcessing(); if (pmath->isStarLost() && ++m_lostStarTries > 2) { emit newLog(i18n("Lost track of the guide star. Try increasing the square size and check the mount.")); abort(); return false; } else m_lostStarTries = 0; // do pulse out = pmath->getOutputParameters(); // If within 90% of max pulse repeatedly, let's abort if (out->pulse_length[GUIDE_RA] >= (0.9 * Options::rAMaximumPulse()) || out->pulse_length[GUIDE_DEC] >= (0.9 * Options::dECMaximumPulse())) maxPulseCounter++; else maxPulseCounter=0; if (maxPulseCounter >= 3) { emit newLog(i18n("Lost track of the guide star. Aborting guiding...")); abort(); maxPulseCounter=0; return false; } emit newPulse( out->pulse_dir[GUIDE_RA], out->pulse_length[GUIDE_RA], out->pulse_dir[GUIDE_DEC], out->pulse_length[GUIDE_DEC] ); emit frameCaptureRequested(); if (state == GUIDE_DITHERING) return true; tick = pmath->getTicks(); if( tick & 1 ) { // draw some params in window emit newAxisDelta(out->delta[GUIDE_RA], out->delta[GUIDE_DEC]); emit newAxisPulse(out->pulse_length[GUIDE_RA], out->pulse_length[GUIDE_DEC]); emit newAxisSigma(out->sigma[GUIDE_RA], out->sigma[GUIDE_DEC]); } // skip half frames //if( half_refresh_rate && (tick & 1) ) //return; //drift_graph->on_paint(); //pDriftOut->update(); return true; } +bool InternalGuider::processImageGuiding() +{ + static int maxPulseCounter=0; + const cproc_out_params * out; + uint32_t tick = 0; + + // calc math. it tracks square + pmath->performProcessing(); + + if (pmath->isStarLost() && ++m_lostStarTries > 2) + { + emit newLog(i18n("Lost track of phase shift.")); + abort(); + return false; + } + else + m_lostStarTries = 0; + + // do pulse + out = pmath->getOutputParameters(); + + // If within 90% of max pulse repeatedly, let's abort + if (out->pulse_length[GUIDE_RA] >= (0.9 * Options::rAMaximumPulse()) || out->pulse_length[GUIDE_DEC] >= (0.9 * Options::dECMaximumPulse())) + maxPulseCounter++; + else + maxPulseCounter=0; + + if (maxPulseCounter >= 3) + { + emit newLog(i18n("Lost track of phase shift. Aborting guiding...")); + abort(); + maxPulseCounter=0; + return false; + } + + emit newPulse( out->pulse_dir[GUIDE_RA], out->pulse_length[GUIDE_RA], out->pulse_dir[GUIDE_DEC], out->pulse_length[GUIDE_DEC] ); + + emit frameCaptureRequested(); + + if (state == GUIDE_DITHERING) + return true; + + tick = pmath->getTicks(); + + if( tick & 1 ) + { + // draw some params in window + emit newAxisDelta(out->delta[GUIDE_RA], out->delta[GUIDE_DEC]); + + emit newAxisPulse(out->pulse_length[GUIDE_RA], out->pulse_length[GUIDE_DEC]); + + emit newAxisSigma(out->sigma[GUIDE_RA], out->sigma[GUIDE_DEC]); + } + + return true; +} + +bool InternalGuider::isImageGuideEnabled() const +{ + return imageGuideEnabled; +} + +void InternalGuider::setImageGuideEnabled(bool value) +{ + imageGuideEnabled = value; + + pmath->setImageGuideEnabled(value); +} + +void InternalGuider::setRegionAxis(uint32_t value) +{ + pmath->setRegionAxis(value); +} + } diff --git a/kstars/ekos/guide/internalguide/internalguider.h b/kstars/ekos/guide/internalguide/internalguider.h index a94a69789..cd6853208 100644 --- a/kstars/ekos/guide/internalguide/internalguider.h +++ b/kstars/ekos/guide/internalguide/internalguider.h @@ -1,174 +1,164 @@ /* Ekos Internal Guider Class Copyright (C) 2016 Jasem Mutlaq . Based on lin_guider This application 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. */ #ifndef INTERNALGUIDER_H #define INTERNALGUIDER_H #include #include #include "indi/indicommon.h" #include "fitsviewer/fitsview.h" #include "matr.h" #include "../guideinterface.h" class cgmath; namespace Ekos { class InternalGuider : public GuideInterface { - Q_OBJECT + Q_OBJECT - public: - - enum CalibrationStage { CAL_IDLE, CAL_ERROR, CAL_CAPTURE_IMAGE, CAL_SELECT_STAR, CAL_START, CAL_RA_INC, CAL_RA_DEC, CAL_DEC_INC, CAL_DEC_DEC }; - enum CalibrationType { CAL_NONE, CAL_RA_AUTO, CAL_RA_DEC_AUTO }; - - InternalGuider(); - ~InternalGuider(); - - bool Connect() override - { - return true; - } - bool Disconnect() override - { - return true; - } - bool isConnected() override - { - return true; - } - - bool calibrate() override; - bool guide() override; - bool abort() override; - bool suspend() override; - bool resume() override; - bool dither(double pixels) override; - - bool setFrameParams(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t binX, uint16_t binY) override; - bool setGuiderParams(double ccdPixelSizeX, double ccdPixelSizeY, double mountAperture, double mountFocalLength) override; - - // Set Star Position - void setStarPosition(QVector3D starCenter) override; - - // Select algorithm - void setSquareAlgorithm( int index ); - - // Reticle Parameters - void setReticleParameters(double x, double y, double angle); - bool getReticleParameters(double * x, double * y, double * angle); - - // Guide View - void setGuideView(FITSView * guideView); - - - - /// IMPORTED CHECK THEM ALL - - bool start(); - //bool abort(bool silence=false); - - bool isGuiding( void ) const; - void setAO(bool enable); - void setInterface( void ); - void setReady(bool enable) - { - m_isReady = enable; - } - bool isRapidGuide() - { - return m_useRapidGuide; - } - - double getAOLimit(); - void setSubFramed(bool enable) - { - m_isSubFramed = enable; - } - void setGuideOptions(const QString &algorithm, bool useSubFrame, bool useRapidGuide); - - QString getAlgorithm(); - bool useSubFrame(); - bool useRapidGuide(); - - public slots: - void setDECSwap(bool enable); - - // OBSELETE - //void connectPHD2(); - //void setPHD2Connected(); - //void setPHD2Disconnected(); - // Only called by PHD2 - //void toggleExternalGuideStateGUI(Ekos::GuideState state); - - protected slots: - //void openCalibrationOptions(); - //void openGuideOptions(); - - //void capture(); - void trackingStarSelected(int x, int y); - - - signals: - void newPulse( GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs ); - void newPulse( GuideDirection dir, int msecs ); - void DESwapChanged(bool enable); - - private: - - // Calibration - void calibrateRADECRecticle( bool ra_only ); // 1 or 2-axis calibration - void processCalibration(); - - // Guiding - bool processGuiding(); - - cgmath * pmath; - QPointer guideFrame; - bool m_isStarted; - bool m_isReady; - bool m_isSubFramed; - bool isFirstFrame, first_subframe; - bool half_refresh_rate; - int m_lostStarTries; - bool m_useRapidGuide; - int fx,fy,fw,fh; - double ret_x, ret_y, ret_angle; - bool m_isDithering; - - QFile logFile; - - void reset(); - - int axis; - int auto_drift_time; - int turn_back_time; - double start_x1, start_y1; - double end_x1, end_y1; - double start_x2, start_y2; - double end_x2, end_y2; - int iterations, dec_iterations; - double phi; - Matrix ROT_Z; - - CalibrationStage calibrationStage; - CalibrationType calibrationType; +public: + + enum CalibrationStage { CAL_IDLE, CAL_ERROR, CAL_CAPTURE_IMAGE, CAL_SELECT_STAR, CAL_START, CAL_RA_INC, CAL_RA_DEC, CAL_DEC_INC, CAL_DEC_DEC }; + enum CalibrationType { CAL_NONE, CAL_RA_AUTO, CAL_RA_DEC_AUTO }; + + InternalGuider(); + ~InternalGuider(); + + bool Connect() override + { + return true; + } + bool Disconnect() override + { + return true; + } + bool isConnected() override + { + return true; + } + + bool calibrate() override; + bool guide() override; + bool abort() override; + bool suspend() override; + bool resume() override; + bool dither(double pixels) override; + + bool setFrameParams(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t binX, uint16_t binY) override; + bool setGuiderParams(double ccdPixelSizeX, double ccdPixelSizeY, double mountAperture, double mountFocalLength) override; + + // Set Star Position + void setStarPosition(QVector3D starCenter) override; + + // Select algorithm + void setSquareAlgorithm( int index ); + + // Reticle Parameters + void setReticleParameters(double x, double y, double angle); + bool getReticleParameters(double * x, double * y, double * angle); + + // Guide View + void setGuideView(FITSView * guideView); + + // Region Axis + void setRegionAxis(uint32_t value); + + bool start(); + + bool isGuiding( void ) const; + void setAO(bool enable); + void setInterface( void ); + void setReady(bool enable) + { + m_isReady = enable; + } + bool isRapidGuide() + { + return m_useRapidGuide; + } + + double getAOLimit(); + void setSubFramed(bool enable) + { + m_isSubFramed = enable; + } + void setGuideOptions(const QString &algorithm, bool useSubFrame, bool useRapidGuide); + + QString getAlgorithm(); + bool useSubFrame(); + bool useRapidGuide(); + + bool isImageGuideEnabled() const; + void setImageGuideEnabled(bool value); + +public slots: + void setDECSwap(bool enable); + +protected slots: + void trackingStarSelected(int x, int y); + + +signals: + void newPulse( GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs ); + void newPulse( GuideDirection dir, int msecs ); + void DESwapChanged(bool enable); + +private: + + // Calibration + void calibrateRADECRecticle( bool ra_only ); // 1 or 2-axis calibration + void processCalibration(); + + // Guiding + bool processGuiding(); + + // Image Guiding + bool processImageGuiding(); + + cgmath * pmath; + QPointer guideFrame; + bool m_isStarted; + bool m_isReady; + bool m_isSubFramed; + bool isFirstFrame, first_subframe; + bool imageGuideEnabled=false; + int m_lostStarTries; + bool m_useRapidGuide; + bool m_isDithering; + + QFile logFile; + + void reset(); + + int auto_drift_time; + int turn_back_time; + double start_x1, start_y1; + double end_x1, end_y1; + double start_x2, start_y2; + double end_x2, end_y2; + int iterations, dec_iterations; + double phi; + Matrix ROT_Z; + + CalibrationStage calibrationStage; + CalibrationType calibrationType; }; } #endif // INTERNALGUIDER_H diff --git a/kstars/ekos/guide/opsguide.ui b/kstars/ekos/guide/opsguide.ui index 502e30262..b23898966 100644 --- a/kstars/ekos/guide/opsguide.ui +++ b/kstars/ekos/guide/opsguide.ui @@ -1,273 +1,357 @@ OpsGuide 0 0 - 275 - 284 + 261 + 334 + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + Guider Type Use Ekos Native Guider. Internal Guider true guiderTypeButtonGroup Use External PHD2 Guider. Limited functionality. PHD2 false guiderTypeButtonGroup lin_guider guiderTypeButtonGroup Qt::Horizontal 40 20 Host false Port: false false For external guiders, enable receiving guide images in Ekos. Receive external guide frames Settings Algorithm Smart Fast Auto Threshold No Threshold Qt::Horizontal 40 20 Move locked guiding square location after frame capture Dither Number of pixels to move the guiding square in a random direction. 0.100000000000000 10.000000000000000 0.100000000000000 2.000000000000000 pixels Dither after this many frames 1 frames false Rapid Guide + + + + Image Guiding + + + + + + Use Image Guiding + + + + + + + + + Region Axis: + + + + + + + + 64 + + + + + 128 + + + + + 256 + + + + + 512 + + + + + 1024 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + Qt::Vertical 20 40 diff --git a/kstars/kstars.kcfg b/kstars/kstars.kcfg index ec5ced90b..8325d05ad 100644 --- a/kstars/kstars.kcfg +++ b/kstars/kstars.kcfg @@ -1,1900 +1,1908 @@ ksutils.h The screen coordinates of the Time InfoBox. QPoint(0,0) The screen coordinates of the Focus InfoBox. QPoint(600,0) The screen coordinates of the Geographic Location InfoBox. QPoint(0,600) If true, the Time InfoBox will show only its top line of data. true If true, the Focus InfoBox will show only its top line of data. true If true, the Geographic Location InfoBox will show only its top line of data. true Toggles display of all three InfoBoxes. true Toggles display of the Time InfoBox. true Toggles display of the Focus InfoBox. true Toggles display of the Geographic Location InfoBox. true Is the Time InfoBox anchored to a window edge? 0 = not anchored; 1 = anchored to right edge; 2 = anchored to bottom edge; 3 = anchored to bottom and right edges. 0 0 3 Is the Focus InfoBox anchored to a window edge? 0 = not anchored; 1 = anchored to right edge; 2 = anchored to bottom edge; 3 = anchored to bottom and right edges. 1 0 3 Is the Geographic Location InfoBox anchored to a window edge? 0 = not anchored; 1 = anchored to right edge; 2 = anchored to bottom edge; 3 = anchored to bottom and right edges. 2 0 3 Toggle display of the status bar. true Toggle display of the Horizontal coordinates of the mouse cursor in the status bar. true Toggle display of the Equatorial coordinates of the mouse cursor at the current epoch in the status bar. true Toggle display of the Equatorial coordinates of the mouse cursor at the standard epoch in the status bar. false 1024 768 true List of the filenames of custom object catalogs. List of integers toggling display of each custom object catalog (any nonzero value indicates the objects in that catalog will be displayed). List of names for which custom catalogs are to be displayed. Names of objects entered into the find dialog are resolved using online services and stored in the database. This option also toggles the display of such resolved objects on the sky map. true true true false Toggle display of crosshairs centered at telescope's pointed position in the KStars sky map. true Toggle display of INDI messages in the KStars statusbar. true true false The default location of saved FITS files KSUtils::getDefaultPath("fitsDir") INDI server will attempt to bind with ports starting from this port 7624 INDI server will attempt to bind with ports ending with this port 9000 List of the aliases for filter wheel slots. PATH to indiserver binary KSUtils::getDefaultPath("indiServer") false PATH to indi drivers directory KSUtils::getDefaultPath("indiDriversDir") false 320 240 The City name of the current geographic location. Greenwich The Province name of the current geographic location. This is the name of the state for locations in the U. S. The Country name of the current geographic location. United Kingdom The longitude of the current geographic location, in decimal degrees. 0.0 The latitude of the current geographic location, in decimal degrees. 51.468 -10.0 0.0 Two-letter code that determines the dates on which daylight savings time begins and ends (you can view the rules by pressing the "Explain DST Rules" button in the Geographic Location window). -- If true, focus changes will cause the sky to visibly spin to the new position. Otherwise, the display will "snap" instantly to the new position. true The names of the currently selected field-of-view indicators. The list of defined FOV indicator names is listed in the "Settings|FOV Symbols" menu. Telrad If true, trails attached to solar system bodies will fade into the background sky color. true The right ascension of the initial focus position of the sky map, in decimal hours. This value is volatile; it is reset whenever the program shuts down. 180.0 The declination of the initial focus position of the sky map, in decimal degrees. This value is volatile; it is reset whenever the program shuts down. 45.0 The name of the object that should be centered and tracked on startup. If no object should be centered, set to "nothing". This value is volatile; it is reset whenever the program shuts down. nothing True if the skymap should track on its initial position on startup. This value is volatile; it is reset whenever the program shuts down. false Toggle whether KStars should hide some objects while the display is moving, for smoother motion. true Toggle whether constellation boundaries are hidden while the display is in motion. true Toggle whether constellation lines are hidden while the display is in motion. false Choose sky culture. 11 Toggle whether constellation names are hidden while the display is in motion. false Toggle whether the coordinate grids are hidden while the display is in motion. true Toggle whether the Milky Way contour is hidden while the display is in motion. true Toggle whether IC objects are hidden while the display is in motion. true Toggle whether Messier objects are hidden while the display is in motion. true Toggle whether NGC objects are hidden while the display is in motion. true Toggle whether extra objects are hidden while the display is in motion. true Toggle whether solar system objects are hidden while the display is in motion. false Toggle whether faint stars are hidden while the display is in motion. true Toggle whether name labels are hidden while the display is in motion. true Toggle whether asteroids are drawn in the sky map. true Toggle whether asteroid name labels are drawn in the sky map. false Toggle whether comets are drawn in the sky map. true Toggle whether comet name labels are drawn in the sky map. false Toggle whether supernovae are drawn in the sky map. false Toggle whether supernova name labels are drawn in the sky map. false Set magnitude limit for supernovae to be shown on the skymap. 16 Toggle supernova alerts. true Set magnitude limit for supernovae to be alerted. 13 Toggle whether constellation boundaries are drawn in the sky map. false Toggle whether constellation boundary containing the central focus point is highlighted in the sky map. false Toggle whether constellation lines are drawn in the sky map. false Toggle whether constellation art drawn in the sky map. false Toggle whether constellation name labels are drawn in the sky map. false Toggle whether deep-sky objects are drawn in the sky map. true Toggle whether the ecliptic line is drawn in the sky map. false Toggle whether the equator line is drawn in the sky map. false Coordinate grids will automatically change according to active coordinate system. true Toggle whether the equatorial coordinate grid is drawn in the sky map. false Toggle whether the horizontal coordinate grid is drawn in the sky map. false Toggle whether the region below the horizon is opaque. true Toggle whether the horizon line is drawn in the sky map. true Toggle whether flags are drawn in the sky map. true Toggle whether IC objects are drawn in the sky map. false Toggle whether NGC objects are drawn in the sky map. true Toggle whether Messier objects are drawn in the sky map. true Toggle whether Messier objects are rendered as images in the sky map. true Toggle whether extra objects are drawn in the sky map. true Toggle whether the Milky Way contour is drawn in the sky map. true Toggle whether the Milky Way contour is filled. When this option is false, the Milky Way is shown as an outline. true Meta-option to control whether all major planets (and the Sun and Moon) are drawn in the sky map. true Toggle whether major planets (and the Sun and Moon) are rendered as images in the sky map. true Toggle whether major planets (and the Sun and Moon) are labeled in the sky map. true Toggle whether the Sun is drawn in the sky map. true Toggle whether the Moon is drawn in the sky map. true Toggle whether Mercury is drawn in the sky map. true Toggle whether Venus is drawn in the sky map. true Toggle whether Mars is drawn in the sky map. true Toggle whether Jupiter is drawn in the sky map. true Toggle whether Saturn is drawn in the sky map. true Toggle whether Uranus is drawn in the sky map. true Toggle whether Neptune is drawn in the sky map. true Toggle whether Pluto is drawn in the sky map. true Toggle whether stars are drawn in the sky map. true Toggle whether star magnitude (brightness) labels are shown in the sky map. false Toggle whether star name labels are shown in the sky map. true Toggle whether deep-sky object magnitude (brightness) labels are shown in the sky map. false Toggle whether deep-sky object name labels are shown in the sky map. false The timescale above which slewing mode is forced on at all times. 60 The background fill mode for the on-screen information boxes: 0="no BG"; 1="semi-transparent BG"; 2="opaque BG" 1 Algorithm for the mapping projection. 0 Use official IAU abbreviations for constellation names. false Use Latin constellation names. true Use localized constellation names (if localized names are not available, default to Latin names). false Display the sky with horizontal coordinates (when false, equatorial coordinates will be used). true Toggle whether a centered object automatically gets a name label attached. true Toggle whether a centered solar system object automatically gets a trail attached, as long as it remains centered. true Toggle whether the object under the mouse cursor gets a transient name label. true Toggle whether object positions are corrected for the effects of atmospheric refraction (only applies when horizontal coordinates are used). true Toggle whether corrections due to bending of light around the sun are taken into account false Toggle whether the sky is rendered using antialiasing. Lines and shapes are smoother with antialiasing, but rendering the screen will take more time. true The zoom level, measured in pixels per radian. 250. 250. 5000000. The faint magnitude limit for drawing asteroids. 15.0 The maximum magnitude (visibility) to filter the asteroid data download from JPL. 12.000 Controls the relative number of asteroid name labels drawn in the map. 4.0 The faint magnitude limit for drawing deep-sky objects, when fully zoomed in. 16.0 The faint magnitude limit for drawing deep-sky objects, when fully zoomed out. 5.0 When enabled, objects whose magnitudes are unknown, or not available to KStars, are drawn irrespective of the faint limits set. true Sets the density of stars in the field of view 5 The faint magnitude limit for drawing stars, when the map is in motion (only applicable if faint stars are set to be hidden while the map is in motion). 5.0 The relative density for drawing star name and magnitude labels. 2.0 The relative density for drawing deep-sky object name and magnitude labels. 5.0 If true, long names (common names) for deep-sky objects are shown in the labels. false The maximum solar distance for drawing comets. 3.0 Use experimental OpenGL backend (deprecated). false The state of the clock (running or not) true Objects in the observing list will be highlighted with a symbol in the map. true Objects in the observing list will be highlighted with a colored name label in the map. false The observing list will prefer DSS imagery while downloading imagery. true The observing list will prefer SDSS imagery while downloading imagery. false Check this if you use a large Dobsonian telescope. Sorting by percentage current altitude is an easy way of determining what objects are well-placed for observation. However, when using a large Dobsonian telescope, objects close to the zenith are hard to observe. Since tracking there corresponds to a rotation in azimuth, it is both counterintuitive and requires the observer to frequently move the ladder. The region around the zenith where this is particularly frustrating is called the Dobsonian hole. This checkbox makes the observing list consider objects present in the hole as unfit for observation. false This specifies the angular radius of the Dobsonian hole, i.e. the region where a large Dobsonian telescope cannot be pointed easily. 15.00 The name of the color scheme moonless-night.colors If true, then the application window colors will be switched to a dark red theme, for better night vision. false The method for rendering stars: 0="realistic colors"; 1="solid red"; 2="solid black"; 3="solid white"; 4="solid real colors" 0 4 The color saturation level of stars (only applicable when using "realistic colors" mode). 6 10 The color for the angular-distance measurement ruler. #FFF The background color of the on-screen information boxes. #000 The text color for the on-screen information boxes, when activated by a mouse click. #F00 The normal text color of the on-screen information boxes. #FFF The color for the constellation boundary lines. #222 The color for the constellation boundary lines. #222 The color for the constellation figure lines. #555 The color for the constellation names. #AA7 The color for the cardinal compass point labels. #002 The color for the ecliptic line. #663 The color for the equator line. #FFF The color for the equatorial coordinate grid lines. #456 The color for the horizontal coordinate grid lines. #5A3 The color for objects which have extra URL links available. #A00 The color for the horizon line and opaque ground. #5A3 The color for Messier object symbols. #0F0 The color for NGC object symbols. #066 The color for IC object symbols. #439 The color for the Milky Way contour. #123 The color for star name labels. #7AA The color for deep-sky object name labels. #7AA The color for solar system object labels. #439 The color for solar system object trails. #963 The color for the sky background. #002 The color for the artificial horizon region. #C82828 The color for telescope target symbols. #8B8 Color of visible satellites. #00FF00 Color of invisible satellites. #FF0000 Color of satellites labels. #640000 Color of supernova #FFA500 The color for user-added object labels. #439 The color for RA Guide Error bar in Ekos guide module. #00FF00 The color for DEC Guide Error bar in Ekos guide module. #00A5FF The color for solver FOV box in Ekos alignment module. #FFFF00 false Xplanet binary path KSUtils::getDefaultPath("XplanetPath") Set the window’s title. Width of xplanet window 640 Height of xplanet window 480 If true, display a label in the upper right corner. false Show local time. true Show GMT instead of local time. false Specify the text of the first line of the label. By default, it says something like "Looking at Earth". Any instances of %t will be replaced by the target name, and any instances of %o will be replaced by the origin name. Specify the point size. 12 Set the color for the label. #F00 Specify the format for the date/time label. This format string is passed to strftime(3). The default is "%c %Z", which shows the date, time, and time zone in the locale’s appropriate date and time representation. %c %Z false true false false Draw a glare around the sun with a radius of the specified value larger than the Sun. The default value is 28. 28 Place the observer above a random latitude and longitude false Place the observer above the specified longitude and latitude true Render the target body as seen from above the specified latitude (in degrees). The default value is 0. 0 Place the observer above the specified longitude (in degrees). Longitude is positive going east, negative going west (for the earth and moon), so for example Los Angeles is at -118 or 242. The default value is 0. 0 The default is no projection. Multiple bodies will not be shown if this option is specified, although shadows will still be drawn. 0 If true, update view. false Number of seconds to wait before updating 60 Use a file as the background image, with the planet to be superimposed upon it. This option is only meaningful with the -projection option. A color may also be supplied. false Use a file as the background image. false The path of the background image. Use a color as the background. true The color of the background. #000 A star of the specified magnitude will have a pixel brightness of 1. The default value is 10. Stars will be drawn more brightly if this number is larger. 10 If checked, use an arc file to be plotted against the background stars. false Specify an arc file to be plotted against the background stars. If checked, use a config file. false Use the specified configuration file. If checked, use kstars's FOV. false If checked, use the specified marker file. false Specify a file containing user-defined marker data to display against the background stars. If checked, write coordinates of the bounding box for each marker in a file. false Write coordinates of the bounding box for each marker to this file. If checked, use star map file to draw the background stars. false Star map file path This option is only used when creating JPEG images. The quality can range from 0 to 100. The default value is 80. 80 Toggle whether satellite tracks are drawn in the sky map. false Toggle whether satellite tracks are drawn in the sky map. false If selected, satellites will be draw like stars, otherwise, draw satellites as small colored square. false Toggle whether satellite labels are drawn in the sky map. false List of selected satellites. Checking this option causes recomputation of current equatorial coordinates from catalog coordinates (i.e. application of precession, nutation and aberration corrections) for every redraw of the map. This makes processing slower when there are many stars to handle, but is more likely to be bug free. There are known bugs in the rendering of stars when this recomputation is avoided. false The default size for DSS images downloaded from the internet. 15.0 To include parts of the star field, we add some extra padding around DSS images of deep-sky objects. This option configures the total (both sides) padding added to either dimension of the field. 10.0 Checking this option causes KStars to generate verbose debug information for diagnostic purposes. This may cause slowdown of KStars. false Checking this option causes KStars to generate regular debug information. true Checking this option causes KStars to stop generating ANY debug information. false Checking this option causes KStars log debug messages to the default output used by the platform (e.g. Standard Error). true Checking this option causes KStars log debug messages to a log file as specified. false Log FITS Data activity. false Log INDI devices activity. false Log Ekos Capture Module activity. false Log Ekos Focus Module activity. false Log Ekos Guide Module activity. false Log Ekos Alignment Module activity. false Log Ekos Mount Module activity. false Display all captured FITS images in a single tab instead of multiple tabs per image. true Display all captured FITS images in a single FITS Viewer window. By default each camera create its own FITS Viewer instance false Display all opened FITS images in a single FITS Viewer window. true false true true false 4 false false 40.0 0 false Simulators false true false 1 Minimum telescope altitude limit. If the telescope is below this limit, it will be commanded to stop. 0 Maximum telescope altitude limit. If the telescope is above this limit, it will be commanded to stop. 90.0 false If guide deviation exceeds this limit, the exposure will be automatically aborted and only resumed when the deviation is within this limit. 2 If HFR deviation exceeds this limit, the autofocus routine will be automatically started. 0.5 false false If the target hour angle exceeds this value, Ekos will command a meridian flip and if successful it will resume guiding and capture operations. false If set, Ekos will capture a few flat images to determine the optimal exposure time to achieve the desired ADU percentage. 0 0.1 true 2.5 30 false true true Step size of the absolute focuser. The step size TICKS should be adjusted so that when the focuser moves TICKS steps, the difference in HFR is more than 0.1 pixels. Lower the value when you are close to optimal focus. 100 The tolerance specifies the percentage difference between the current focusing position and the minimum obtained during the focusing run. Adjustment of this value is necessary to prevent the focusing algorithm from oscillating back and forth. 1 Set the maximum travel distance of an absolute focuser. 10000 Specifies exposure value of CCD when performing focusing. Lower this value to avoid saturation of bright stars which adversely affects HFR measurement. Increase the value if no stars are detected. 0.5 Set box size to select a focus star. 64 Set horizontal binning of CCD camera while in focus mode. 1 Set vertical binning of CCD camera while in focus mode. 1 true false true false 0 false 0 150 0 0 Specifies exposure value of CCD in seconds when performing plate solving. 1 Set binning index of CCD camera while in alignment mode. Default values 0-3 corresponding to 1x1 to 4x4 binning 0 Display detailed verbose messages of the astrometry solver process while in progress. false 0 0 false false 30 false 1500 true true true true true 1 true 2 true true 30 true Path to astrometry.net solver location. KSUtils::getDefaultPath("AstrometrySolverBinary") false Path to astrometry.net wcsinfo location. KSUtils::getDefaultPath("AstrometryWCSInfo") false Path to astrometry.net file location. KSUtils::getDefaultPath("AstrometryConfFile") false Key to access astrometry.net online web services. You must register with astrometry.net to obtain a key. iczikaqstszeptgs http://nova.astrometry.net true 180 1.0 0 0 localhost 4400 localhost 5656 1000 2 + + + false + + + + 1 + false false false 5 true false false false 2 1 false 2 true true true true true true 133.33 133.33 0 0 0 0 5000 5000 100 100 0.5 true false false 2 5 30 0 0 0 0 0 0 7624