1 /*
2 * Copyright (C) 2009 Timothy Reaves
3 * Copyright (C) 2011 Bogdan Marinov
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20 #include "Oculars.hpp"
21 #include "OcularsGuiPanel.hpp"
22
23 #include "GridLinesMgr.hpp"
24 #include "LabelMgr.hpp"
25 #include "ConstellationMgr.hpp"
26 #include "AsterismMgr.hpp"
27 #include "MilkyWay.hpp"
28 #include "SkyGui.hpp"
29 #include "StelActionMgr.hpp"
30 #include "StelApp.hpp"
31 #include "StelCore.hpp"
32 #include "StelFileMgr.hpp"
33 #include "StelGui.hpp"
34 #include "StelGuiItems.hpp"
35 #include "StelLocaleMgr.hpp"
36 #include "StelMainView.hpp"
37 #include "StelModuleMgr.hpp"
38 #include "StelMovementMgr.hpp"
39 #include "StelObjectMgr.hpp"
40 #include "StelPainter.hpp"
41 #include "StelProjector.hpp"
42 #include "StelTextureMgr.hpp"
43 #include "StelTranslator.hpp"
44 #include "SolarSystem.hpp"
45 #include "NebulaMgr.hpp"
46 #include "StelUtils.hpp"
47 #include "StelPropertyMgr.hpp"
48 #include "LandscapeMgr.hpp"
49
50 #include <QAction>
51 #include <QDebug>
52 #include <QDir>
53 #include <QGraphicsWidget>
54 #include <QKeyEvent>
55 #include <QMenu>
56 #include <QMouseEvent>
57 #include <QPixmap>
58 #include <QMessageBox>
59
60 #include <cmath>
61 #include <stdexcept>
62
63 extern void qt_set_sequence_auto_mnemonic(bool b);
64
65 static QSettings *settings; //!< The settings as read in from the ini file.
66
67 /* ****************************************************************************************************************** */
68 #if 0
69 #pragma mark -
70 #pragma mark StelModuleMgr Methods
71 #endif
72 /* ****************************************************************************************************************** */
73 //! This method is the one called automatically by the StelModuleMgr just
74 //! after loading the dynamic library
getStelModule() const75 StelModule* OcularsStelPluginInterface::getStelModule() const
76 {
77 return new Oculars();
78 }
79
getPluginInfo() const80 StelPluginInfo OcularsStelPluginInterface::getPluginInfo() const
81 {
82 // Allow to load the resources when used as a static plugin
83 Q_INIT_RESOURCE(Oculars);
84
85 StelPluginInfo info;
86 info.id = "Oculars";
87 info.displayedName = N_("Oculars");
88 info.authors = "Timothy Reaves";
89 info.contact = STELLARIUM_DEV_URL;
90 info.description = N_("Shows the sky as if looking through a telescope eyepiece. (Only magnification and field of view are simulated.) It can also show a sensor frame and a Telrad sight.");
91 info.version = OCULARS_PLUGIN_VERSION;
92 info.license = OCULARS_PLUGIN_LICENSE;
93 return info;
94 }
95
96
97 /* ****************************************************************************************************************** */
98 #if 0
99 #pragma mark -
100 #pragma mark Instance Methods
101 #endif
102 /* ****************************************************************************************************************** */
Oculars()103 Oculars::Oculars()
104 : selectedCCDIndex(-1)
105 , selectedOcularIndex(-1)
106 , selectedTelescopeIndex(-1)
107 , selectedLensIndex(-1)
108 , selectedCCDRotationAngle(0.0)
109 , selectedCCDPrismPositionAngle(0.0)
110 , arrowButtonScale(150)
111 , flagShowCCD(false)
112 , flagShowOculars(false)
113 , flagShowCrosshairs(false)
114 , flagShowTelrad(false)
115 , usageMessageLabelID(-1)
116 , flagCardinalPointsMain(false)
117 , flagAdaptationMain(false)
118 , flagLimitStarsMain(false)
119 , magLimitStarsMain(0.0)
120 , flagLimitStarsOculars(false)
121 , magLimitStarsOculars(0.0)
122 , flagAutoLimitMagnitude(false)
123 , flagLimitDSOsMain(false)
124 , magLimitDSOsMain(0.0)
125 , flagLimitPlanetsMain(false)
126 , magLimitPlanetsMain(0.0)
127 , relativeStarScaleMain(1.0)
128 , absoluteStarScaleMain(1.0)
129 , relativeStarScaleOculars(1.0)
130 , absoluteStarScaleOculars(1.0)
131 , relativeStarScaleCCD(1.0)
132 , absoluteStarScaleCCD(1.0)
133 , flagMoonScaleMain(false)
134 , flagMinorBodiesScaleMain(false)
135 , flagSunScaleMain(false)
136 , flagPlanetsScaleMain(false)
137 , flagDSOPropHintMain(false)
138 , milkyWaySaturation(1.0)
139 , maxEyepieceAngle(0.0)
140 , flagRequireSelection(true)
141 , flagScaleImageCircle(true)
142 , flagGuiPanelEnabled(false)
143 , flagDMSDegrees(false)
144 , flagSemiTransparency(false)
145 , transparencyMask(85)
146 , flagHideGridsLines(false)
147 , flagGridLinesDisplayedMain(true)
148 , flagConstellationLinesMain(true)
149 , flagConstellationBoundariesMain(true)
150 , flagAsterismLinesMain(true)
151 , flagRayHelpersLinesMain(true)
152 , flipVertMain(false)
153 , flipHorzMain(false)
154 , pxmapGlow(Q_NULLPTR)
155 , pxmapOnIcon(Q_NULLPTR)
156 , pxmapOffIcon(Q_NULLPTR)
157 , toolbarButton(Q_NULLPTR)
158 , flagShowOcularsButton(false)
159 , ocularDialog(Q_NULLPTR)
160 , ready(false)
161 , actionShowOcular(Q_NULLPTR)
162 , actionShowCrosshairs(Q_NULLPTR)
163 , actionShowSensor(Q_NULLPTR)
164 , actionShowTelrad(Q_NULLPTR)
165 , actionConfiguration(Q_NULLPTR)
166 , actionMenu(Q_NULLPTR)
167 , actionTelescopeIncrement(Q_NULLPTR)
168 , actionTelescopeDecrement(Q_NULLPTR)
169 , actionOcularIncrement(Q_NULLPTR)
170 , actionOcularDecrement(Q_NULLPTR)
171 , guiPanel(Q_NULLPTR)
172 , guiPanelFontSize(12)
173 , textColor(0.)
174 , lineColor(0.)
175 , focuserColor(0.)
176 , actualFOV(0.)
177 , initialFOV(0.)
178 , flagInitFOVUsage(false)
179 , flagInitDirectionUsage(false)
180 , flagAutosetMountForCCD(false)
181 , flagScalingFOVForTelrad(false)
182 , flagScalingFOVForCCD(true)
183 , flagShowResolutionCriteria(false)
184 , equatorialMountEnabledMain(false)
185 , reticleRotation(0.)
186 , flagShowCcdCropOverlay(false)
187 , flagShowCcdCropOverlayPixelGrid(false)
188 , ccdCropOverlayHSize(DEFAULT_CCD_CROP_OVERLAY_SIZE)
189 , ccdCropOverlayVSize(DEFAULT_CCD_CROP_OVERLAY_SIZE)
190 , flagShowContour(false)
191 , flagShowCardinals(false)
192 , flagAlignCrosshair(false)
193 , telradFOV(0.5f,2.f,4.f)
194 , flagShowFocuserOverlay(false)
195 , flagUseSmallFocuserOverlay(false)
196 , flagUseMediumFocuserOverlay(true)
197 , flagUseLargeFocuserOverlay(true)
198 {
199 setObjectName("Oculars");
200 // Design font size is 14, based on default app fontsize 13.
201 setFontSizeFromApp(StelApp::getInstance().getScreenFontSize());
202 connect(&StelApp::getInstance(), SIGNAL(screenFontSizeChanged(int)), this, SLOT(setFontSizeFromApp(int)));
203
204 ccds = QList<CCD *>();
205 oculars = QList<Ocular *>();
206 telescopes = QList<Telescope *>();
207 lenses = QList<Lens *> ();
208
209 #ifdef Q_OS_MAC
210 qt_set_sequence_auto_mnemonic(true);
211 #endif
212 }
213
~Oculars()214 Oculars::~Oculars()
215 {
216 delete ocularDialog;
217 ocularDialog = Q_NULLPTR;
218 if (guiPanel)
219 delete guiPanel;
220 if (pxmapGlow)
221 delete pxmapGlow;
222 if (pxmapOnIcon)
223 delete pxmapOnIcon;
224 if (pxmapOffIcon)
225 delete pxmapOffIcon;
226
227 qDeleteAll(ccds);
228 ccds.clear();
229 qDeleteAll(telescopes);
230 telescopes.clear();
231 qDeleteAll(oculars);
232 oculars.clear();
233 qDeleteAll(lenses);
234 lenses.clear();
235 }
236
getSettings()237 QSettings* Oculars::getSettings()
238 {
239 return settings;
240 }
241
242
243 /* ****************************************************************************************************************** */
244 #if 0
245 #pragma mark -
246 #pragma mark StelModule Methods
247 #endif
248 /* ****************************************************************************************************************** */
configureGui(bool show)249 bool Oculars::configureGui(bool show)
250 {
251 if (show)
252 {
253 ocularDialog->setVisible(true);
254 }
255
256 return ready;
257 }
258
deinit()259 void Oculars::deinit()
260 {
261 // update the ini file.
262 settings->remove("ccd");
263 settings->remove("ocular");
264 settings->remove("telescope");
265 settings->remove("lens");
266 int index = 0;
267 for (auto* ccd : qAsConst(ccds))
268 {
269 ccd->writeToSettings(settings, index);
270 index++;
271 }
272 index = 0;
273 for (auto* ocular : qAsConst(oculars))
274 {
275 ocular->writeToSettings(settings, index);
276 index++;
277 }
278 index = 0;
279 for (auto* telescope : qAsConst(telescopes))
280 {
281 telescope->writeToSettings(settings, index);
282 index++;
283 }
284 index = 0;
285 for (auto* lens : qAsConst(lenses))
286 {
287 lens->writeToSettings(settings, index);
288 index++;
289 }
290
291 settings->setValue("ocular_count", oculars.count());
292 settings->setValue("telescope_count", telescopes.count());
293 settings->setValue("ccd_count", ccds.count());
294 settings->setValue("lens_count", lenses.count());
295 settings->setValue("ocular_index", selectedOcularIndex);
296 settings->setValue("telescope_index", selectedTelescopeIndex);
297 settings->setValue("ccd_index", selectedCCDIndex);
298 settings->setValue("lens_index", selectedLensIndex);
299
300 StelCore *core = StelApp::getInstance().getCore();
301 StelSkyDrawer *skyDrawer = core->getSkyDrawer();
302 disconnect(skyDrawer, SIGNAL(customStarMagLimitChanged(double)), this, SLOT(setMagLimitStarsOcularsManual(double)));
303 disconnect(skyDrawer, SIGNAL(flagStarMagnitudeLimitChanged(bool)), this, SLOT(handleStarMagLimitToggle(bool)));
304 if (flagShowCCD)
305 {
306 // Retrieve and restore star scales
307 relativeStarScaleCCD=skyDrawer->getRelativeStarScale();
308 absoluteStarScaleCCD=skyDrawer->getAbsoluteStarScale();
309 skyDrawer->setRelativeStarScale(relativeStarScaleMain);
310 skyDrawer->setAbsoluteStarScale(absoluteStarScaleMain);
311 }
312 else if (flagShowOculars)
313 {
314 qDebug() << "Oculars::deinit() .. restoring skyDrawer values while ocular view is active";
315
316 if (!getFlagAutoLimitMagnitude())
317 {
318 flagLimitStarsOculars=skyDrawer->getFlagStarMagnitudeLimit();
319 magLimitStarsOculars=skyDrawer->getCustomStarMagnitudeLimit();
320 }
321 skyDrawer->setCustomStarMagnitudeLimit(magLimitStarsMain);
322 skyDrawer->setFlagStarMagnitudeLimit(flagLimitStarsMain);
323 // Retrieve and restore star scales
324 relativeStarScaleOculars=skyDrawer->getRelativeStarScale();
325 absoluteStarScaleOculars=skyDrawer->getAbsoluteStarScale();
326 skyDrawer->setRelativeStarScale(relativeStarScaleMain);
327 skyDrawer->setAbsoluteStarScale(absoluteStarScaleMain);
328 }
329
330 settings->setValue("stars_scale_relative", QString::number(relativeStarScaleOculars, 'f', 2));
331 settings->setValue("stars_scale_absolute", QString::number(absoluteStarScaleOculars, 'f', 2));
332 settings->setValue("stars_scale_relative_ccd", QString::number(relativeStarScaleCCD, 'f', 2));
333 settings->setValue("stars_scale_absolute_ccd", QString::number(absoluteStarScaleCCD, 'f', 2));
334 settings->setValue("limit_stellar_magnitude_oculars_val", QString::number(magLimitStarsOculars, 'f', 2));
335 settings->setValue("limit_stellar_magnitude_oculars", flagLimitStarsOculars);
336 settings->setValue("text_color", textColor.toStr());
337 settings->setValue("line_color", lineColor.toStr());
338 settings->setValue("focuser_color", focuserColor.toStr());
339 settings->sync();
340
341 disconnect(this, SIGNAL(selectedOcularChanged(int)), this, SLOT(updateOcularReticle()));
342 //disconnect(&StelApp::getInstance(), SIGNAL(colorSchemeChanged(const QString&)), this, SLOT(setStelStyle(const QString&)));
343 disconnect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslateGui()));
344
345 protractorTexture.clear();
346 protractorFlipVTexture.clear();
347 protractorFlipHTexture.clear();
348 protractorFlipHVTexture.clear();
349 }
350
351 //! Draw any parts on the screen which are for our module
draw(StelCore * core)352 void Oculars::draw(StelCore* core)
353 {
354 if (flagShowTelrad)
355 {
356 paintTelrad();
357 }
358 else if (flagShowOculars)
359 {
360 if (selectedOcularIndex >= 0)
361 {
362 paintOcularMask(core);
363 if (flagShowCrosshairs)
364 paintCrosshairs();
365
366 if (!flagGuiPanelEnabled)
367 {
368 // Paint the information in the upper-right hand corner
369 paintText(core);
370 }
371 }
372 else
373 {
374 qWarning() << "Oculars: the selected ocular index of "
375 << selectedOcularIndex << " is greater than the ocular count of "
376 << oculars.count() << ". Module disabled!";
377 }
378 }
379 else if (flagShowCCD)
380 {
381 paintCCDBounds();
382 if (!flagGuiPanelEnabled)
383 {
384 // Paint the information in the upper-right hand corner
385 paintText(core);
386 }
387 }
388 }
389
390 //! Determine which "layer" the plugin's drawing will happen on.
getCallOrder(StelModuleActionName actionName) const391 double Oculars::getCallOrder(StelModuleActionName actionName) const
392 {
393 double order = 1000.0; // Very low priority, unless we interact.
394
395 if (actionName==StelModule::ActionHandleMouseMoves ||
396 actionName==StelModule::ActionHandleMouseClicks)
397 {
398 // Make sure we are called before MovementMgr (we need to even call it once!)
399 order = StelApp::getInstance().getModuleMgr().getModule("StelMovementMgr")->getCallOrder(actionName) - 1.0;
400 }
401 else if (actionName==StelModule::ActionDraw)
402 {
403 order = GETSTELMODULE(LabelMgr)->getCallOrder(actionName) + 100.0;
404 }
405 return order;
406 }
407
handleMouseClicks(class QMouseEvent * event)408 void Oculars::handleMouseClicks(class QMouseEvent* event)
409 {
410 StelCore *core = StelApp::getInstance().getCore();
411 const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000, StelCore::RefractionAuto);
412 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
413 qreal ppx = params.devicePixelsPerPixel;
414
415 if (guiPanel)
416 {
417 // Remove all events on the sky within Ocular GUI Panel.
418 if (event->x()>guiPanel->pos().x() && event->y()>(prj->getViewportHeight()-guiPanel->size().height()))
419 {
420 event->setAccepted(true);
421 return;
422 }
423 }
424
425 // In case we show oculars with black circle, ignore mouse presses outside image circle:
426 // https://sourceforge.net/p/stellarium/discussion/278769/thread/57893bb3/?limit=25#75c0
427 if ((flagShowOculars) ) //&& !getFlagUseSemiTransparency()) // Not sure: ignore or allow selection of semi-hidden stars?
428 {
429 float wh = prj->getViewportWidth()*0.5f; // get half of width of the screen
430 float hh = prj->getViewportHeight()*0.5f; // get half of height of the screen
431 float mx = event->x()-wh; // point 0 in center of the screen, axis X directed to right
432 float my = event->y()-hh; // point 0 in center of the screen, axis Y directed to bottom
433
434 double inner = 0.5 * params.viewportFovDiameter * ppx;
435 // See if we need to scale the mask
436 if (flagScaleImageCircle && oculars[selectedOcularIndex]->apparentFOV() > 0.0 && !oculars[selectedOcularIndex]->isBinoculars())
437 {
438 inner = oculars[selectedOcularIndex]->apparentFOV() * inner / maxEyepieceAngle;
439 }
440
441 if (mx*mx+my*my>static_cast<float>(inner*inner)) // click outside ocular circle? Gobble event.
442 {
443 event->setAccepted(true);
444 return;
445 }
446 }
447
448 StelMovementMgr *movementManager = core->getMovementMgr();
449
450 if (flagShowOculars)
451 movementManager->handleMouseClicks(event); // force it here for selection!
452
453 if (StelApp::getInstance().getStelObjectMgr().getWasSelected())
454 {
455 if (flagShowOculars)
456 {
457 // center the selected object in the ocular, and track.
458 movementManager->setFlagTracking(true);
459 }
460 else
461 {
462 // remove the usage label if it is being displayed.
463 hideUsageMessageIfDisplayed();
464 }
465 }
466 else if(flagShowOculars)
467 {
468 // The ocular is displayed, but no object is selected. So don't track the stars. We may have locked
469 // the position of the screen if the movement keys were used. so call this to be on the safe side.
470 movementManager->setFlagLockEquPos(false);
471 }
472 event->setAccepted(false);
473 }
474
init()475 void Oculars::init()
476 {
477 // Load settings from ocular.ini
478 try {
479 validateAndLoadIniFile();
480 // assume all is well
481 ready = true;
482
483 setFlagRequireSelection(settings->value("require_selection_to_zoom", true).toBool());
484 flagScaleImageCircle = settings->value("use_max_exit_circle", false).toBool();
485 int ocularCount = settings->value("ocular_count", 0).toInt();
486 int actualOcularCount = ocularCount;
487 for (int index = 0; index < ocularCount; index++)
488 {
489 Ocular *newOcular = Ocular::ocularFromSettings(settings, index);
490 if (newOcular != Q_NULLPTR)
491 {
492 oculars.append(newOcular);
493 }
494 else
495 {
496 actualOcularCount--;
497 }
498 }
499 if (actualOcularCount < 1)
500 {
501 if (actualOcularCount < ocularCount)
502 {
503 qWarning() << "The Oculars ini file appears to be corrupt; delete it.";
504 }
505 else
506 {
507 qWarning() << "There are no oculars defined for the Oculars plugin; plugin will be disabled.";
508 }
509 ready = false;
510 }
511 else
512 {
513 selectedOcularIndex = settings->value("ocular_index", 0).toInt();
514 }
515
516 int ccdCount = settings->value("ccd_count", 0).toInt();
517 int actualCcdCount = ccdCount;
518 for (int index = 0; index < ccdCount; index++)
519 {
520 CCD *newCCD = CCD::ccdFromSettings(settings, index);
521 if (newCCD != Q_NULLPTR)
522 {
523 ccds.append(newCCD);
524 }
525 else
526 {
527 actualCcdCount--;
528 }
529 }
530 if (actualCcdCount < ccdCount)
531 {
532 qWarning() << "The Oculars ini file appears to be corrupt; delete it.";
533 ready = false;
534 }
535 selectedCCDIndex = settings->value("ccd_index", 0).toInt();
536
537 int telescopeCount = settings->value("telescope_count", 0).toInt();
538 int actualTelescopeCount = telescopeCount;
539 for (int index = 0; index < telescopeCount; index++)
540 {
541 Telescope *newTelescope = Telescope::telescopeFromSettings(settings, index);
542 if (newTelescope != Q_NULLPTR)
543 {
544 telescopes.append(newTelescope);
545 }
546 else
547 {
548 actualTelescopeCount--;
549 }
550 }
551 if (actualTelescopeCount < 1)
552 {
553 if (actualTelescopeCount < telescopeCount)
554 {
555 qWarning() << "The Oculars ini file appears to be corrupt; delete it.";
556 }
557 else
558 {
559 qWarning() << "There are no telescopes defined for the Oculars plugin; plugin will be disabled.";
560 }
561 ready = false;
562 }
563 else
564 {
565 selectedTelescopeIndex = settings->value("telescope_index", 0).toInt();
566 }
567
568 int lensCount = settings->value("lens_count", 0).toInt();
569 int actualLensCount = lensCount;
570 for (int index = 0; index<lensCount; index++)
571 {
572 Lens *newLens = Lens::lensFromSettings(settings, index);
573 if (newLens != Q_NULLPTR)
574 {
575 lenses.append(newLens);
576 }
577 else
578 {
579 actualLensCount--;
580 }
581 }
582 if (lensCount > 0 && actualLensCount < lensCount)
583 {
584 qWarning() << "The Oculars ini file appears to be corrupt; delete it.";
585 }
586 selectedLensIndex=settings->value("lens_index", -1).toInt(); // Lens is not selected by default!
587
588 pxmapGlow = new QPixmap(":/graphicGui/miscGlow32x32.png");
589 pxmapOnIcon = new QPixmap(":/ocular/bt_ocular_on.png");
590 pxmapOffIcon = new QPixmap(":/ocular/bt_ocular_off.png");
591
592 ocularDialog = new OcularDialog(this, &ccds, &oculars, &telescopes, &lenses);
593 initializeActivationActions();
594 determineMaxEyepieceAngle();
595
596 guiPanelFontSize=settings->value("gui_panel_fontsize", 12).toInt();
597 enableGuiPanel(settings->value("enable_control_panel", true).toBool());
598 textColor=Vec3f(settings->value("text_color", "0.8,0.48,0.0").toString());
599 lineColor=Vec3f(settings->value("line_color", "0.77,0.14,0.16").toString());
600 telradFOV=Vec4f(settings->value("telrad_fov", "0.5,2.0,4.0,0.0").toString());
601 focuserColor=Vec3f(settings->value("focuser_color", "0.0,0.67,1.0").toString());
602
603 // This must come ahead of setFlagAutosetMountForCCD (GH #505)
604 StelPropertyMgr* propMgr=StelApp::getInstance().getStelPropertyManager();
605 equatorialMountEnabledMain = propMgr->getStelPropertyValue("StelMovementMgr.equatorialMount").toBool();
606
607 // For historical reasons, name of .ini entry and description of checkbox (and therefore flag name) are reversed.
608 setFlagDMSDegrees( ! settings->value("use_decimal_degrees", false).toBool());
609 setFlagAutoLimitMagnitude(settings->value("autolimit_stellar_magnitude", true).toBool());
610 flagLimitStarsOculars=settings->value("limit_stellar_magnitude_oculars", false).toBool();
611 magLimitStarsOculars=settings->value("limit_stellar_magnitude_oculars_val", 12.).toDouble();
612 connect(this, SIGNAL(flagAutoLimitMagnitudeChanged(bool)), this, SLOT(handleAutoLimitToggle(bool))); // only after first initialisation!
613 setFlagInitFovUsage(settings->value("use_initial_fov", false).toBool());
614 setFlagInitDirectionUsage(settings->value("use_initial_direction", false).toBool());
615 setFlagUseSemiTransparency(settings->value("use_semi_transparency", false).toBool());
616 setTransparencyMask(settings->value("transparency_mask", 85).toInt());
617 setFlagHideGridsLines(settings->value("hide_grids_and_lines", true).toBool());
618 setFlagAutosetMountForCCD(settings->value("use_mount_autoset", false).toBool());
619 setFlagScalingFOVForTelrad(settings->value("use_telrad_fov_scaling", true).toBool());
620 setFlagScalingFOVForCCD(settings->value("use_ccd_fov_scaling", true).toBool());
621 setFlagShowResolutionCriteria(settings->value("show_resolution_criteria", false).toBool());
622 // TODO: Remove this conversion tool in version 0.21 or 0.22
623 if (settings->value("arrow_scale").toDouble()<100.) // convert old value and type
624 setArrowButtonScale(static_cast<int>(settings->value("arrow_scale", 1.5).toDouble()*100.));
625 else
626 setArrowButtonScale(settings->value("arrow_scale", 150).toInt());
627 setFlagShowOcularsButton(settings->value("show_toolbar_button", false).toBool());
628 relativeStarScaleOculars=settings->value("stars_scale_relative", 1.0).toDouble();
629 absoluteStarScaleOculars=settings->value("stars_scale_absolute", 1.0).toDouble();
630 relativeStarScaleCCD=settings->value("stars_scale_relative_ccd", 1.0).toDouble();
631 absoluteStarScaleCCD=settings->value("stars_scale_absolute_ccd", 1.0).toDouble();
632 setFlagShowCcdCropOverlay(settings->value("show_ccd_crop_overlay", false).toBool());
633 setFlagShowCcdCropOverlayPixelGrid(settings-> value("ccd_crop_overlay_pixel_grid",false).toBool());
634 setCcdCropOverlayHSize(settings->value("ccd_crop_overlay_hsize", DEFAULT_CCD_CROP_OVERLAY_SIZE).toInt());
635 setCcdCropOverlayVSize(settings->value("ccd_crop_overlay_vsize", DEFAULT_CCD_CROP_OVERLAY_SIZE).toInt());
636 setFlagShowContour(settings->value("show_ocular_contour", false).toBool());
637 setFlagShowCardinals(settings->value("show_ocular_cardinals", false).toBool());
638 setFlagAlignCrosshair(settings->value("align_crosshair", false).toBool());
639 setFlagShowFocuserOverlay(settings->value("show_focuser_overlay", false).toBool());
640 setFlagUseSmallFocuserOverlay(settings->value("use_small_focuser_overlay", false).toBool());
641 setFlagUseMediumFocuserOverlay(settings->value("use_medium_focuser_overlay", true).toBool());
642 setFlagUseLargeFocuserOverlay(settings->value("use_large_focuser_overlay", false).toBool());
643 }
644 catch (std::runtime_error& e)
645 {
646 qWarning() << "WARNING: unable to locate ocular.ini file or create a default one for Ocular plugin: " << e.what();
647 ready = false;
648 }
649
650 protractorTexture = StelApp::getInstance().getTextureManager().createTexture(":/ocular/Protractor.png");
651 protractorFlipHTexture = StelApp::getInstance().getTextureManager().createTexture(":/ocular/ProtractorFlipH.png");
652 protractorFlipVTexture = StelApp::getInstance().getTextureManager().createTexture(":/ocular/ProtractorFlipV.png");
653 protractorFlipHVTexture = StelApp::getInstance().getTextureManager().createTexture(":/ocular/ProtractorFlipHV.png");
654 // enforce check existence of reticle for the current eyepiece
655 updateOcularReticle();
656
657 connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslateGui()));
658 connect(this, SIGNAL(selectedOcularChanged(int)), this, SLOT(updateOcularReticle()));
659 StelCore *core = StelApp::getInstance().getCore();
660 StelSkyDrawer *skyDrawer = core->getSkyDrawer();
661 connect(skyDrawer, SIGNAL(flagStarMagnitudeLimitChanged(bool)), this, SLOT(handleStarMagLimitToggle(bool)));
662 }
663
664 /* ****************************************************************************************************************** */
665 #if 0
666 #pragma mark -
667 #pragma mark Private slots Methods
668 #endif
669 /* ****************************************************************************************************************** */
determineMaxEyepieceAngle()670 void Oculars::determineMaxEyepieceAngle()
671 {
672 if (ready)
673 {
674 for (const auto* ocular : oculars)
675 {
676 if (ocular->apparentFOV() > maxEyepieceAngle)
677 {
678 maxEyepieceAngle = ocular->apparentFOV();
679 }
680 }
681 }
682 // ensure it is not zero
683 if (maxEyepieceAngle == 0.0)
684 {
685 maxEyepieceAngle = 1.0;
686 }
687 }
688
instrumentChanged()689 void Oculars::instrumentChanged()
690 {
691 // We only zoom if in ocular mode.
692 if (flagShowOculars)
693 {
694 // If we are already in Ocular mode, we must reset scalings because zoom() also resets.
695 StelSkyDrawer *skyDrawer = StelApp::getInstance().getCore()->getSkyDrawer();
696 skyDrawer->setRelativeStarScale(relativeStarScaleMain);
697 skyDrawer->setAbsoluteStarScale(absoluteStarScaleMain);
698 zoom(true);
699 }
700 else if (flagShowCCD)
701 setScreenFOVForCCD();
702 }
703
setFlagScaleImageCircle(bool state)704 void Oculars::setFlagScaleImageCircle(bool state)
705 {
706 if (state)
707 {
708 determineMaxEyepieceAngle();
709 }
710 flagScaleImageCircle = state;
711 settings->setValue("use_max_exit_circle", state);
712 settings->sync();
713 emit flagScaleImageCircleChanged(state);
714 }
715
setScreenFOVForCCD()716 void Oculars::setScreenFOVForCCD()
717 {
718 // CCD is not shown and FOV scaling is disabled, but telescope is changed - do not change FOV!
719 if (!(getFlagScalingFOVForCCD() && flagShowCCD))
720 return;
721
722 Lens * lens = selectedLensIndex >=0 ? lenses[selectedLensIndex] : Q_NULLPTR;
723 if (selectedCCDIndex > -1 && selectedTelescopeIndex > -1)
724 {
725 StelCore *core = StelApp::getInstance().getCore();
726 StelMovementMgr *movementManager = core->getMovementMgr();
727 double actualFOVx = ccds[selectedCCDIndex]->getActualFOVx(telescopes[selectedTelescopeIndex], lens);
728 double actualFOVy = ccds[selectedCCDIndex]->getActualFOVy(telescopes[selectedTelescopeIndex], lens);
729 if (actualFOVx < actualFOVy)
730 {
731 actualFOVx = actualFOVy;
732 }
733 double factor = 1.75;
734 if (ccds[selectedCCDIndex]->hasOAG()) factor *= 2;
735 movementManager->setFlagTracking(true);
736 movementManager->zoomTo(actualFOVx * factor, 0.f);
737 }
738 }
739
enableGuiPanel(bool enable)740 void Oculars::enableGuiPanel(bool enable)
741 {
742 if (enable)
743 {
744 if (!guiPanel)
745 {
746 StelGui* gui= dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
747 if (gui)
748 {
749 guiPanel = new OcularsGuiPanel(this, gui->getSkyGui());
750 if (flagShowOculars)
751 guiPanel->showOcularGui();
752 else if (flagShowCCD)
753 guiPanel->showCcdGui();
754 }
755 }
756 }
757 else
758 {
759 if (guiPanel)
760 {
761 guiPanel->hide();
762 delete guiPanel;
763 guiPanel = Q_NULLPTR;
764 }
765 }
766 flagGuiPanelEnabled = enable;
767 settings->setValue("enable_control_panel", enable);
768 settings->sync();
769 emit flagGuiPanelEnabledChanged(enable);
770 }
771
retranslateGui()772 void Oculars::retranslateGui()
773 {
774 if (guiPanel)
775 {
776 // TODO: Fix this hack!
777
778 // Delete and re-create the panel to retranslate its trings
779 guiPanel->hide();
780 delete guiPanel;
781 guiPanel = Q_NULLPTR;
782
783 StelGui* gui= dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
784 if (gui)
785 {
786 guiPanel = new OcularsGuiPanel(this, gui->getSkyGui());
787 if (flagShowOculars)
788 guiPanel->showOcularGui();
789 else if (flagShowCCD)
790 guiPanel->showCcdGui();
791 }
792 }
793 }
794
updateOcularReticle(void)795 void Oculars::updateOcularReticle(void)
796 {
797 reticleRotation = 0.0;
798 QString reticleTexturePath=oculars[selectedOcularIndex]->reticlePath();
799 if (reticleTexturePath.length()==0)
800 reticleTexture=StelTextureSP();
801 else
802 {
803 StelTextureMgr& manager = StelApp::getInstance().getTextureManager();
804 //Load OpenGL textures
805 StelTexture::StelTextureParams params;
806 params.generateMipmaps = true;
807 reticleTexture = manager.createTexture(reticleTexturePath, params);
808 }
809 }
810
811 /* ****************************************************************************************************************** */
812 #if 0
813 #pragma mark -
814 #pragma mark Slots Methods
815 #endif
816 /* ****************************************************************************************************************** */
updateLists()817 void Oculars::updateLists()
818 {
819 if (oculars.isEmpty())
820 {
821 selectedOcularIndex = -1;
822 enableOcular(false);
823 }
824 else
825 {
826 if (selectedOcularIndex >= oculars.count())
827 selectedOcularIndex = oculars.count() - 1;
828
829 if (flagShowOculars)
830 emit selectedOcularChanged(selectedOcularIndex);
831 }
832
833 if (telescopes.isEmpty())
834 {
835 selectedTelescopeIndex = -1;
836 enableOcular(false);
837 toggleCCD(false);
838 }
839 else
840 {
841 if (selectedTelescopeIndex >= telescopes.count())
842 selectedTelescopeIndex = telescopes.count() - 1;
843
844 if (flagShowOculars || flagShowCCD)
845 emit selectedTelescopeChanged(selectedTelescopeIndex);
846 }
847
848 if (ccds.isEmpty())
849 {
850 selectedCCDIndex = -1;
851 toggleCCD(false);
852 }
853 else
854 {
855 if (selectedCCDIndex >= ccds.count())
856 selectedCCDIndex = ccds.count() - 1;
857
858 if (flagShowCCD)
859 emit selectedCCDChanged(selectedCCDIndex);
860 }
861
862 if (lenses.isEmpty())
863 selectedLensIndex = -1;
864 else
865 {
866 if (selectedLensIndex >= lenses.count())
867 selectedLensIndex = lenses.count() - 1;
868 }
869 }
870
ccdRotationReset()871 void Oculars::ccdRotationReset()
872 {
873 if (selectedCCDIndex<0)
874 return;
875 CCD *ccd = ccds[selectedCCDIndex];
876 if (ccd)
877 {
878 ccd->setChipRotAngle(0.0);
879 emit(selectedCCDChanged(selectedCCDIndex));
880 emit selectedCCDRotationAngleChanged(0.0);
881 }
882 }
883
prismPositionAngleReset()884 void Oculars::prismPositionAngleReset()
885 {
886 if (selectedCCDIndex<0)
887 return;
888 CCD *ccd = ccds[selectedCCDIndex];
889 if (ccd)
890 {
891 ccd->setPrismPosAngle(0.0);
892 emit(selectedCCDChanged(selectedCCDIndex));
893 emit selectedCCDPrismPositionAngleChanged(0.0);
894 }
895 }
896
setSelectedCCDRotationAngle(double angle)897 void Oculars::setSelectedCCDRotationAngle(double angle)
898 {
899 if (selectedCCDIndex<0)
900 return;
901
902 CCD *ccd = ccds[selectedCCDIndex];
903 if (ccd)
904 {
905 ccd->setChipRotAngle(angle);
906 emit selectedCCDRotationAngleChanged(angle);
907 }
908 }
909
getSelectedCCDRotationAngle() const910 double Oculars::getSelectedCCDRotationAngle() const
911 {
912 if (selectedCCDIndex<0)
913 return 0.0;
914 CCD *ccd = ccds[selectedCCDIndex];
915 if (ccd) return ccd->chipRotAngle();
916 else return 0.0;
917 }
918
setSelectedCCDPrismPositionAngle(double angle)919 void Oculars::setSelectedCCDPrismPositionAngle(double angle)
920 {
921 if (selectedCCDIndex<0)
922 return;
923
924 CCD *ccd = ccds[selectedCCDIndex];
925 if (ccd)
926 {
927 ccd->setPrismPosAngle(angle);
928 emit selectedCCDPrismPositionAngleChanged(angle);
929 }
930 }
931
getSelectedCCDPrismPositionAngle() const932 double Oculars::getSelectedCCDPrismPositionAngle() const
933 {
934 if (selectedCCDIndex<0)
935 return 0.0;
936 CCD *ccd = ccds[selectedCCDIndex];
937 if (ccd) return ccd->prismPosAngle();
938 else return 0.0;
939 }
940
enableOcular(bool enableOcularMode)941 void Oculars::enableOcular(bool enableOcularMode)
942 {
943 if (enableOcularMode)
944 {
945 // Close the sensor view if it's displayed
946 if (flagShowCCD)
947 {
948 toggleCCD(false);
949 flagShowCCD = false;
950 selectedCCDIndex = -1;
951 }
952
953 // Close the Telrad sight if it's displayed
954 if (flagShowTelrad)
955 {
956 toggleTelrad(false);
957 }
958
959 // Check to ensure that we have enough oculars & telescopes, as they may have been edited in the config dialog
960 if (oculars.count() == 0)
961 {
962 selectedOcularIndex = -1;
963 qWarning() << "No oculars found";
964 }
965 else if (oculars.count() > 0 && selectedOcularIndex == -1)
966 {
967 selectedOcularIndex = 0;
968 }
969 if (telescopes.count() == 0)
970 {
971 selectedTelescopeIndex = -1;
972 qWarning() << "No telescopes found";
973 }
974 else if (telescopes.count() > 0 && selectedTelescopeIndex == -1)
975 {
976 selectedTelescopeIndex = 0;
977 }
978 }
979
980 if (!ready || selectedOcularIndex == -1 || (selectedTelescopeIndex == -1 && !isBinocularDefined()))
981 {
982 qWarning() << "The Oculars module has been disabled.";
983 return;
984 }
985
986 StelCore *core = StelApp::getInstance().getCore();
987 LabelMgr* labelManager = GETSTELMODULE(LabelMgr);
988
989 // Toggle the ocular view on & off. To toggle on, we want to ensure there is a selected object.
990 if (!flagShowOculars && !flagShowTelrad && flagRequireSelection && !StelApp::getInstance().getStelObjectMgr().getWasSelected() )
991 {
992 if (usageMessageLabelID == -1)
993 {
994 QFontMetrics metrics(font);
995 QString labelText = q_("Please select an object before switching to ocular view.");
996 StelProjector::StelProjectorParams projectorParams = core->getCurrentStelProjectorParams();
997 int yPositionOffset = qRound(projectorParams.viewportXywh[3]*projectorParams.viewportCenterOffset[1]);
998 int xPosition = qRound(projectorParams.viewportCenter[0] - 0.5 * metrics.boundingRect(labelText).width());
999 int yPosition = qRound(projectorParams.viewportCenter[1] - yPositionOffset - 0.5 * metrics.height());
1000 const char *tcolor = "#99FF99";
1001 usageMessageLabelID = labelManager->labelScreen(labelText, xPosition, yPosition,
1002 true, font.pixelSize(), tcolor);
1003 }
1004 }
1005 else
1006 {
1007 if (selectedOcularIndex != -1)
1008 {
1009 // remove the usage label if it is being displayed.
1010 hideUsageMessageIfDisplayed();
1011 flagShowOculars = enableOcularMode;
1012 zoom(false);
1013 //BM: I hope this is the right place...
1014 if (guiPanel)
1015 guiPanel->showOcularGui();
1016 }
1017 }
1018
1019 emit enableOcularChanged(flagShowOculars);
1020 }
1021
decrementCCDIndex()1022 void Oculars::decrementCCDIndex()
1023 {
1024 selectedCCDIndex--;
1025 if (selectedCCDIndex == -1)
1026 {
1027 selectedCCDIndex = ccds.count() - 1;
1028 }
1029 emit(selectedCCDChanged(selectedCCDIndex));
1030 }
1031
decrementOcularIndex()1032 void Oculars::decrementOcularIndex()
1033 {
1034 selectedOcularIndex--;
1035 if (selectedOcularIndex == -1)
1036 {
1037 selectedOcularIndex = oculars.count() - 1;
1038 }
1039 // validate the new selection
1040 if (selectedOcularIndex > -1 && !oculars[selectedOcularIndex]->isBinoculars())
1041 {
1042 if ( selectedTelescopeIndex == -1 && telescopes.count() == 0)
1043 {
1044 // reject the change
1045 selectedOcularIndex++;
1046 }
1047
1048 if (selectedTelescopeIndex == -1)
1049 selectedTelescopeIndex = 0;
1050 }
1051 emit(selectedOcularChanged(selectedOcularIndex));
1052 }
1053
decrementTelescopeIndex()1054 void Oculars::decrementTelescopeIndex()
1055 {
1056 selectedTelescopeIndex--;
1057 if (selectedTelescopeIndex == -1)
1058 {
1059 selectedTelescopeIndex = telescopes.count() - 1;
1060 }
1061 emit(selectedTelescopeChanged(selectedTelescopeIndex));
1062 }
1063
decrementLensIndex()1064 void Oculars::decrementLensIndex()
1065 {
1066 selectedLensIndex--;
1067 if (selectedLensIndex == lenses.count())
1068 {
1069 selectedLensIndex = -1;
1070 }
1071 if (selectedLensIndex == -2)
1072 {
1073 selectedLensIndex = lenses.count() - 1;
1074 }
1075 emit(selectedLensChanged(selectedLensIndex));
1076 }
1077
rotateReticleClockwise()1078 void Oculars::rotateReticleClockwise()
1079 {
1080 // Step: 5 degrees
1081 reticleRotation -= 5.0;
1082 }
1083
rotateReticleCounterclockwise()1084 void Oculars::rotateReticleCounterclockwise()
1085 {
1086 // Step: 5 degrees
1087 reticleRotation += 5.0;
1088 }
1089
displayPopupMenu()1090 void Oculars::displayPopupMenu()
1091 {
1092 QMenu * popup = new QMenu(&StelMainView::getInstance());
1093
1094 if (flagShowOculars)
1095 {
1096 // We are in Oculars mode
1097 // We want to show all of the Oculars, and if the current ocular is not a binocular,
1098 // we will also show the telescopes.
1099 if (!oculars.isEmpty())
1100 {
1101 popup->addAction(q_("&Previous ocular"), this, SLOT(decrementOcularIndex()));
1102 popup->addAction(q_("&Next ocular"), this, SLOT(incrementOcularIndex()));
1103 QMenu* submenu = new QMenu(q_("Select &ocular"), popup);
1104 int availableOcularCount = 0;
1105 for (int index = 0; index < oculars.count(); ++index)
1106 {
1107 QString label;
1108 if (availableOcularCount < 10)
1109 {
1110 label = QString("&%1: %2").arg(availableOcularCount).arg(oculars[index]->name());
1111 }
1112 else
1113 {
1114 label = oculars[index]->name();
1115 }
1116 //BM: Does this happen at all any more?
1117 QAction* action = Q_NULLPTR;
1118 if (selectedTelescopeIndex != -1 || oculars[index]->isBinoculars())
1119 {
1120 action = submenu->addAction(label, [=](){selectOcularAtIndex(index);});
1121 availableOcularCount++;
1122 }
1123
1124 if (action && index == selectedOcularIndex)
1125 {
1126 action->setCheckable(true);
1127 action->setChecked(true);
1128 }
1129 }
1130 popup->addMenu(submenu);
1131 popup->addSeparator();
1132 }
1133
1134 // If there is more than one telescope, show the prev/next/list complex.
1135 // If the selected ocular is a binoculars, show nothing.
1136 if (telescopes.count() > 1 && (selectedOcularIndex > -1 && !oculars[selectedOcularIndex]->isBinoculars()))
1137 {
1138 QMenu* submenu = addTelescopeSubmenu(popup);
1139 popup->addMenu(submenu);
1140 submenu = addLensSubmenu(popup);
1141 popup->addMenu(submenu);
1142 popup->addSeparator();
1143 }
1144
1145 QAction* action = popup->addAction(q_("Toggle &crosshair"));
1146 action->setCheckable(true);
1147 action->setChecked(flagShowCrosshairs);
1148 connect(action, SIGNAL(toggled(bool)), actionShowCrosshairs, SLOT(setChecked(bool)));
1149 }
1150 else
1151 {
1152 // We are not in ocular mode
1153 // We want to show the CCD's, and if a CCD is selected, the telescopes
1154 //(as a CCD requires a telescope) and the general menu items.
1155 QAction* action = new QAction(q_("Configure &Oculars"), popup);
1156 action->setCheckable(true);
1157 action->setChecked(ocularDialog->visible());
1158 connect(action, SIGNAL(triggered(bool)), ocularDialog, SLOT(setVisible(bool)));
1159 popup->addAction(action);
1160 popup->addSeparator();
1161
1162 if (!flagShowTelrad)
1163 {
1164 QAction* action = popup->addAction(q_("Toggle &CCD"));
1165 action->setCheckable(true);
1166 action->setChecked(flagShowCCD);
1167 connect(action, SIGNAL(toggled(bool)), actionShowSensor, SLOT(setChecked(bool)));
1168 }
1169
1170 if (!flagShowCCD)
1171 {
1172 QAction* action = popup->addAction(q_("Toggle &Telrad"));
1173 action->setCheckable(true);
1174 action->setChecked(flagShowTelrad);
1175 connect(action, SIGNAL(toggled(bool)), actionShowTelrad, SLOT(setChecked(bool)));
1176 }
1177
1178 popup->addSeparator();
1179 if (flagShowCCD && selectedCCDIndex > -1 && selectedTelescopeIndex > -1)
1180 {
1181 popup->addAction(q_("&Previous CCD"), this, SLOT(decrementCCDIndex()));
1182 popup->addAction(q_("&Next CCD"), this, SLOT(incrementCCDIndex()));
1183 QMenu* submenu = new QMenu(q_("&Select CCD"), popup);
1184 for (int index = 0; index < ccds.count(); ++index)
1185 {
1186 QString label;
1187 if (index < 10)
1188 {
1189 label = QString("&%1: %2").arg(index).arg(ccds[index]->name());
1190 }
1191 else
1192 {
1193 label = ccds[index]->name();
1194 }
1195 QAction* action = submenu->addAction(label, [=](){selectCCDAtIndex(index);});
1196 if (index == selectedCCDIndex)
1197 {
1198 action->setCheckable(true);
1199 action->setChecked(true);
1200 }
1201 }
1202 popup->addMenu(submenu);
1203
1204 submenu = new QMenu(q_("&Rotate CCD"), popup);
1205 submenu->addAction(QString("&1: -90") + QChar(0x00B0), [=](){rotateCCD(-90);});
1206 submenu->addAction(QString("&2: -45") + QChar(0x00B0), [=](){rotateCCD(-45);});
1207 submenu->addAction(QString("&3: -15") + QChar(0x00B0), [=](){rotateCCD(-15);});
1208 submenu->addAction(QString("&4: -5") + QChar(0x00B0), [=](){rotateCCD(-5);});
1209 submenu->addAction(QString("&5: -1") + QChar(0x00B0), [=](){rotateCCD(-1);});
1210 submenu->addAction(QString("&6: +1") + QChar(0x00B0), [=](){rotateCCD(1);});
1211 submenu->addAction(QString("&7: +5") + QChar(0x00B0), [=](){rotateCCD(5);});
1212 submenu->addAction(QString("&8: +15") + QChar(0x00B0), [=](){rotateCCD(15);});
1213 submenu->addAction(QString("&9: +45") + QChar(0x00B0), [=](){rotateCCD(45);});
1214 submenu->addAction(QString("&0: +90") + QChar(0x00B0), [=](){rotateCCD(90);});
1215
1216 submenu->addAction(q_("&Reset rotation"), this, SLOT(ccdRotationReset()));
1217 popup->addMenu(submenu);
1218 popup->addSeparator();
1219 }
1220 if (flagShowCCD && selectedCCDIndex > -1 && telescopes.count() > 1)
1221 {
1222 QMenu* submenu = addTelescopeSubmenu(popup);
1223 popup->addMenu(submenu);
1224 submenu = addLensSubmenu(popup);
1225 popup->addMenu(submenu);
1226 popup->addSeparator();
1227 }
1228 }
1229
1230 #ifdef Q_OS_WIN
1231 popup->showTearOffMenu(QCursor::pos());
1232 #endif
1233 popup->exec(QCursor::pos());
1234 delete popup;
1235 }
1236
incrementCCDIndex()1237 void Oculars::incrementCCDIndex()
1238 {
1239 selectedCCDIndex++;
1240 if (selectedCCDIndex == ccds.count())
1241 {
1242 selectedCCDIndex = 0;
1243 }
1244 emit selectedCCDChanged(selectedCCDIndex);
1245 }
1246
incrementOcularIndex()1247 void Oculars::incrementOcularIndex()
1248 {
1249 selectedOcularIndex++;
1250 if (selectedOcularIndex == oculars.count())
1251 {
1252 selectedOcularIndex = 0;
1253 }
1254 // validate the new selection
1255 if (selectedOcularIndex > -1 && !oculars[selectedOcularIndex]->isBinoculars())
1256 {
1257 if ( selectedTelescopeIndex == -1 && telescopes.count() == 0)
1258 {
1259 // reject the change
1260 selectedOcularIndex++;
1261 }
1262
1263 if (selectedTelescopeIndex == -1)
1264 selectTelescopeAtIndex(0);
1265 }
1266 emit selectedOcularChanged(selectedOcularIndex);
1267 }
1268
incrementTelescopeIndex()1269 void Oculars::incrementTelescopeIndex()
1270 {
1271 selectedTelescopeIndex++;
1272 if (selectedTelescopeIndex == telescopes.count())
1273 {
1274 selectedTelescopeIndex = 0;
1275 }
1276 emit selectedTelescopeChanged(selectedTelescopeIndex);
1277 }
1278
incrementLensIndex()1279 void Oculars::incrementLensIndex()
1280 {
1281 selectedLensIndex++;
1282 if (selectedLensIndex == lenses.count())
1283 {
1284 selectedLensIndex = -1;
1285 }
1286 emit selectedLensChanged(selectedLensIndex);
1287 }
1288
disableLens()1289 void Oculars::disableLens()
1290 {
1291 selectedLensIndex = -1;
1292 emit selectedLensChanged(selectedLensIndex);
1293 }
1294
rotateCCD(int amount)1295 void Oculars::rotateCCD(int amount)
1296 {
1297 CCD *ccd = ccds[selectedCCDIndex];
1298 if (!ccd) return;
1299 double angle = ccd->chipRotAngle();
1300 angle += amount;
1301 if (angle >= 360)
1302 {
1303 angle -= 360;
1304 }
1305 else if (angle <= -360)
1306 {
1307 angle += 360;
1308 }
1309 ccd->setChipRotAngle(angle);
1310 emit selectedCCDRotationAngleChanged(angle);
1311 }
1312
rotatePrism(int amount)1313 void Oculars::rotatePrism(int amount)
1314 {
1315 CCD *ccd = ccds[selectedCCDIndex];
1316 if (!ccd) return;
1317 double angle = ccd->prismPosAngle();
1318 angle += amount;
1319 if (angle >= 360)
1320 {
1321 angle -= 360;
1322 }
1323 else if (angle <= -360)
1324 {
1325 angle += 360;
1326 }
1327 ccd->setPrismPosAngle(angle);
1328 emit selectedCCDPrismPositionAngleChanged(angle);
1329 }
1330
selectCCDAtIndex(int index)1331 void Oculars::selectCCDAtIndex(int index)
1332 {
1333 if (index > -1 && index < ccds.count())
1334 {
1335 selectedCCDIndex = index;
1336 emit selectedCCDChanged(index);
1337 }
1338 }
1339
selectOcularAtIndex(int index)1340 void Oculars::selectOcularAtIndex(int index)
1341 {
1342 if (selectedTelescopeIndex == -1)
1343 selectTelescopeAtIndex(0);
1344
1345 if (index > -1 && index < oculars.count() && (telescopes.count() >= 0 || oculars[index]->isBinoculars()))
1346 {
1347 selectedOcularIndex = index;
1348 emit selectedOcularChanged(index);
1349 }
1350 }
1351
selectTelescopeAtIndex(int index)1352 void Oculars::selectTelescopeAtIndex(int index)
1353 {
1354 if (index > -1 && index < telescopes.count())
1355 {
1356 selectedTelescopeIndex = index;
1357 emit selectedTelescopeChanged(index);
1358 }
1359 }
1360
selectLensAtIndex(int index)1361 void Oculars::selectLensAtIndex(int index)
1362 {
1363 if (index > -2 && index < lenses.count())
1364 {
1365 selectedLensIndex = index;
1366 emit selectedLensChanged(index);
1367 }
1368 }
1369
toggleCCD(bool show)1370 void Oculars::toggleCCD(bool show)
1371 {
1372 //If there are no sensors...
1373 if (ccds.isEmpty() || telescopes.isEmpty())
1374 {
1375 //TODO: BM: Make this an on-screen message and/or disable the button
1376 //if there are no sensors.
1377 if (show)
1378 {
1379 qWarning() << "Oculars plugin: Unable to display a sensor boundary: No sensors or telescopes are defined.";
1380 QMessageBox::warning(&StelMainView::getInstance(), q_("Warning!"), q_("Unable to display a sensor boundary: No sensors or telescopes are defined."), QMessageBox::Ok);
1381 }
1382 flagShowCCD = false;
1383 selectedCCDIndex = -1;
1384 show = false;
1385 }
1386
1387 StelCore *core = StelApp::getInstance().getCore();
1388 StelMovementMgr *movementManager = core->getMovementMgr();
1389 StelSkyDrawer *skyDrawer = core->getSkyDrawer();
1390 if (show)
1391 {
1392 initialFOV = movementManager->getCurrentFov();
1393 //Mutually exclusive with the ocular mode
1394 hideUsageMessageIfDisplayed();
1395 if (flagShowOculars)
1396 enableOcular(false);
1397
1398 if (flagShowTelrad) {
1399 toggleTelrad(false);
1400 }
1401
1402 if (selectedTelescopeIndex < 0)
1403 {
1404 selectedTelescopeIndex = 0;
1405 }
1406 if (selectedCCDIndex < 0)
1407 {
1408 selectedCCDIndex = 0;
1409 }
1410 flagShowCCD = true;
1411 setScreenFOVForCCD();
1412
1413 // Change scales for stars. (Even restoring from ocular view has restored main program's values at this point.)
1414 relativeStarScaleMain=skyDrawer->getRelativeStarScale();
1415 absoluteStarScaleMain=skyDrawer->getAbsoluteStarScale();
1416 skyDrawer->setRelativeStarScale(relativeStarScaleCCD);
1417 skyDrawer->setAbsoluteStarScale(absoluteStarScaleCCD);
1418
1419 if (guiPanel)
1420 {
1421 guiPanel->showCcdGui();
1422 }
1423 }
1424 else
1425 {
1426 flagShowCCD = false;
1427
1428 // Restore star scales
1429 relativeStarScaleCCD=skyDrawer->getRelativeStarScale();
1430 absoluteStarScaleCCD=skyDrawer->getAbsoluteStarScale();
1431 skyDrawer->setRelativeStarScale(relativeStarScaleMain);
1432 skyDrawer->setAbsoluteStarScale(absoluteStarScaleMain);
1433 //Zoom out
1434 if (getFlagInitFovUsage())
1435 movementManager->zoomTo(movementManager->getInitFov());
1436 else if (!flagShowTelrad)
1437 movementManager->zoomTo(initialFOV);
1438
1439 if (getFlagInitDirectionUsage())
1440 movementManager->setViewDirectionJ2000(core->altAzToJ2000(movementManager->getInitViewingDirection(), StelCore::RefractionOff));
1441
1442 if (getFlagAutosetMountForCCD())
1443 {
1444 StelPropertyMgr* propMgr=StelApp::getInstance().getStelPropertyManager();
1445 propMgr->setStelPropertyValue("StelMovementMgr.equatorialMount", equatorialMountEnabledMain);
1446 }
1447
1448 if (guiPanel)
1449 {
1450 guiPanel->foldGui();
1451 }
1452 }
1453
1454 emit enableCCDChanged(flagShowCCD);
1455 }
1456
toggleCCD()1457 void Oculars::toggleCCD()
1458 {
1459 toggleCCD(!flagShowCCD);
1460 }
1461
toggleCrosshairs(bool show)1462 void Oculars::toggleCrosshairs(bool show)
1463 {
1464 if(show != flagShowCrosshairs)
1465 {
1466 flagShowCrosshairs = show;
1467 emit enableCrosshairsChanged(show);
1468 }
1469 }
1470
toggleTelrad(bool show)1471 void Oculars::toggleTelrad(bool show)
1472 {
1473 if(show!=flagShowTelrad)
1474 {
1475 flagShowTelrad = show;
1476
1477 StelMovementMgr* movementMgr = StelApp::getInstance().getCore()->getMovementMgr();
1478 if (show)
1479 {
1480 hideUsageMessageIfDisplayed();
1481 enableOcular(false);
1482 toggleCCD(false);
1483 // NOTE: Added special zoom level for Telrad
1484 if (flagScalingFOVForTelrad)
1485 {
1486 float fov = qMax(qMax(telradFOV[0], telradFOV[1]), qMax(telradFOV[2], telradFOV[3]));
1487 movementMgr->zoomTo(static_cast<double>(fov)*2.);
1488 }
1489 }
1490 else if (getFlagInitFovUsage()) // Restoration of FOV is needed?
1491 movementMgr->zoomTo(movementMgr->getInitFov());
1492
1493 if (getFlagInitDirectionUsage())
1494 movementMgr->setViewDirectionJ2000(StelApp::getInstance().getCore()->altAzToJ2000(movementMgr->getInitViewingDirection(), StelCore::RefractionOff));
1495
1496 emit enableTelradChanged(flagShowTelrad);
1497 }
1498 }
1499
toggleTelrad()1500 void Oculars::toggleTelrad()
1501 {
1502 toggleTelrad(!flagShowTelrad);
1503 }
1504
1505 /* ****************************************************************************************************************** */
1506 #if 0
1507 #pragma mark -
1508 #pragma mark Private Methods
1509 #endif
1510 /* ****************************************************************************************************************** */
initializeActivationActions()1511 void Oculars::initializeActivationActions()
1512 {
1513 QString ocularsGroup = N_("Oculars");
1514 actionShowOcular = addAction("actionShow_Oculars", ocularsGroup, N_("Ocular view"), "enableOcular", "Ctrl+O");
1515 actionMenu = addAction("actionShow_Ocular_Menu", ocularsGroup, N_("Oculars popup menu"), "displayPopupMenu()", "Alt+O");
1516 actionShowCrosshairs = addAction("actionShow_Ocular_Crosshairs", ocularsGroup, N_("Show crosshairs"), "enableCrosshairs", "Alt+C");
1517 actionShowSensor = addAction("actionShow_Sensor", ocularsGroup, N_("Image sensor frame"), "enableCCD");
1518 actionShowTelrad = addAction("actionShow_Telrad", ocularsGroup, N_("Telrad sight"), "enableTelrad", "Ctrl+B");
1519 actionConfiguration = addAction("actionShow_Oculars_dialog", ocularsGroup, N_("Show settings dialog"), ocularDialog, "visible", ""); // Allow assign shortkey
1520 addAction("actionShow_Oculars_GUI", ocularsGroup, N_("Toggle Oculars button bar"), "flagGuiPanelEnabled"); // Allow assign shortkey
1521 // Select next telescope via keyboard
1522 addAction("actionShow_Telescope_Increment", ocularsGroup, N_("Select next telescope"), "incrementTelescopeIndex()");
1523 // Select previous telescope via keyboard
1524 addAction("actionShow_Telescope_Decrement", ocularsGroup, N_("Select previous telescope"), "decrementTelescopeIndex()");
1525 // Select next eyepiece via keyboard
1526 addAction("actionShow_Ocular_Increment", ocularsGroup, N_("Select next eyepiece"), "incrementOcularIndex()");
1527 // Select previous eyepiece via keyboard
1528 addAction("actionShow_Ocular_Decrement", ocularsGroup, N_("Select previous eyepiece"), "decrementOcularIndex()");
1529 addAction("actionShow_Ocular_Rotate_Reticle_Clockwise", ocularsGroup, N_("Rotate reticle pattern of the eyepiece clockwise"), "rotateReticleClockwise()", "Alt+M");
1530 addAction("actionShow_Ocular_Rotate_Reticle_Counterclockwise", ocularsGroup, N_("Rotate reticle pattern of the eyepiece counterclockwise"), "rotateReticleCounterclockwise()", "Shift+Alt+M");
1531 addAction("actionShow_Sensor_Crop_Overlay", ocularsGroup, N_("Toggle sensor crop overlay"), "toggleCropOverlay()");
1532 addAction("actionShow_Sensor_Pixel_Grid", ocularsGroup, N_("Toggle sensor pixel grid"), "togglePixelGrid()");
1533 addAction("actionShow_Sensor_Focuser_Overlay", ocularsGroup, N_("Toggle focuser overlay"), "toggleFocuserOverlay()");
1534
1535 connect(this, SIGNAL(selectedCCDChanged(int)), this, SLOT(instrumentChanged()));
1536 connect(this, SIGNAL(selectedOcularChanged(int)), this, SLOT(instrumentChanged()));
1537 connect(this, SIGNAL(selectedTelescopeChanged(int)), this, SLOT(instrumentChanged()));
1538 connect(this, SIGNAL(selectedLensChanged(int)), this, SLOT(instrumentChanged()));
1539 }
1540
isBinocularDefined()1541 bool Oculars::isBinocularDefined()
1542 {
1543 bool binocularFound = false;
1544 for (auto* ocular : oculars)
1545 {
1546 if (ocular->isBinoculars())
1547 {
1548 binocularFound = true;
1549 break;
1550 }
1551 }
1552 return binocularFound;
1553 }
1554
paintCCDBounds()1555 void Oculars::paintCCDBounds()
1556 {
1557 int fontSize = StelApp::getInstance().getScreenFontSize();
1558 StelCore *core = StelApp::getInstance().getCore();
1559 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
1560 Lens *lens = selectedLensIndex >=0 ? lenses[selectedLensIndex] : Q_NULLPTR;
1561
1562 const StelProjectorP projector = core->getProjection(StelCore::FrameEquinoxEqu);
1563 double screenFOV = static_cast<double>(params.fov);
1564 Vec2i centerScreen(projector->getViewportPosX() + projector->getViewportWidth() / 2,
1565 projector->getViewportPosY() + projector->getViewportHeight() / 2);
1566
1567 // draw sensor rectangle
1568 if (selectedCCDIndex > -1 && selectedTelescopeIndex > -1)
1569 {
1570 CCD *ccd = ccds[selectedCCDIndex];
1571 if (ccd)
1572 {
1573 StelPainter painter(projector);
1574 painter.setColor(lineColor);
1575 painter.setFont(font);
1576 Telescope *telescope = telescopes[selectedTelescopeIndex];
1577
1578 const double ccdXRatio = ccd->getActualFOVx(telescope, lens) / screenFOV;
1579 const double ccdYRatio = ccd->getActualFOVy(telescope, lens) / screenFOV;
1580
1581 const double fovX = ccd->getActualFOVx(telescope, lens);
1582 const double fovY = ccd->getActualFOVy(telescope, lens);
1583
1584 // As the FOV is based on the narrow aspect of the screen, we need to calculate
1585 // height & width based soley off of that dimension.
1586 int aspectIndex = 2;
1587 if (params.viewportXywh[2] > params.viewportXywh[3])
1588 {
1589 aspectIndex = 3;
1590 }
1591 const float width = params.viewportXywh[aspectIndex] * static_cast<float>(ccdXRatio * params.devicePixelsPerPixel);
1592 const float height = params.viewportXywh[aspectIndex] * static_cast<float>(ccdYRatio * params.devicePixelsPerPixel);
1593
1594 // Get Crop size taking into account the binning rounded to the lower limit and limiting it to sensor size
1595 const float actualCropOverlayX = (std::min(ccd->resolutionX(), ccdCropOverlayHSize) / ccd->binningX()) * ccd->binningX();
1596 const float actualCropOverlayY = (std::min(ccd->resolutionY(), ccdCropOverlayVSize) / ccd->binningY()) * ccd->binningY();
1597 // Calculate the size of the CCD crop overlay
1598 const float overlayWidth = width * actualCropOverlayX / ccd->resolutionX();
1599 const float overlayHeight = height * actualCropOverlayY / ccd->resolutionY();
1600
1601 //calculate the size of a pixel in the image
1602 float pixelProjectedWidth = width /ccd->resolutionX() * ccd->binningX();
1603 float pixelProjectedHeight = height /ccd->resolutionY()* ccd->binningY();
1604
1605 double polarAngle = 0;
1606 // if the telescope is Equatorial derotate the field
1607 if (telescope->isEquatorial())
1608 {
1609 Vec3d CPos;
1610 Vector2<qreal> cpos = projector->getViewportCenter();
1611 projector->unProject(cpos[0], cpos[1], CPos);
1612 Vec3d CPrel(CPos);
1613 CPrel[2]*=0.2;
1614 Vec3d crel;
1615 projector->project(CPrel, crel);
1616 polarAngle = atan2(cpos[1] - crel[1], cpos[0] - crel[0]) * (-180.0)/M_PI; // convert to degrees
1617 if (CPos[2] > 0) polarAngle += 90.0;
1618 else polarAngle -= 90.0;
1619 }
1620
1621 if (getFlagAutosetMountForCCD())
1622 {
1623 StelPropertyMgr* propMgr=StelApp::getInstance().getStelPropertyManager();
1624 propMgr->setStelPropertyValue("actionSwitch_Equatorial_Mount", telescope->isEquatorial());
1625 polarAngle = 0;
1626 }
1627
1628 if (width > 0.0f && height > 0.0f)
1629 {
1630 QPoint a, b;
1631 QTransform transform = QTransform().translate(centerScreen[0], centerScreen[1]).rotate(-(ccd->chipRotAngle() + polarAngle));
1632 // bottom line
1633 a = transform.map(QPoint(static_cast<int>(-width*0.5f), static_cast<int>(-height*0.5f)));
1634 b = transform.map(QPoint(static_cast<int>(width*0.5f), static_cast<int>(-height*0.5f)));
1635 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1636 // top line
1637 a = transform.map(QPoint(static_cast<int>(-width*0.5f), static_cast<int>(height*0.5f)));
1638 b = transform.map(QPoint(static_cast<int>(width*0.5f), static_cast<int>(height*0.5f)));
1639 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1640 // left line
1641 a = transform.map(QPoint(static_cast<int>(-width*0.5f), static_cast<int>(-height*0.5f)));
1642 b = transform.map(QPoint(static_cast<int>(-width*0.5f), static_cast<int>(height*0.5f)));
1643 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1644 // right line
1645 a = transform.map(QPoint(static_cast<int>(width*0.5f), static_cast<int>(height*0.50f)));
1646 b = transform.map(QPoint(static_cast<int>(width*0.5f), static_cast<int>(-height*0.5f)));
1647 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1648
1649 // Tool for showing a resolution box overlay
1650 if (flagShowCcdCropOverlay)
1651 {
1652 // bottom line
1653 a = transform.map(QPoint(static_cast<int>(-overlayWidth*0.5f), static_cast<int>(-overlayHeight*0.5f)));
1654 b = transform.map(QPoint(static_cast<int>(overlayWidth*0.5f), static_cast<int>(-overlayHeight*0.5f)));
1655 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1656 // top line
1657 a = transform.map(QPoint(static_cast<int>(-overlayWidth*0.5f), static_cast<int>(overlayHeight*0.5f)));
1658 b = transform.map(QPoint(static_cast<int>(overlayWidth*0.5f), static_cast<int>(overlayHeight*0.5f)));
1659 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1660 // left line
1661 a = transform.map(QPoint(static_cast<int>(-overlayWidth*0.5f), static_cast<int>(-overlayHeight*0.5f)));
1662 b = transform.map(QPoint(static_cast<int>(-overlayWidth*0.5f), static_cast<int>(overlayHeight*0.5f)));
1663 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1664 // right line
1665 a = transform.map(QPoint(static_cast<int>(overlayWidth*0.5f), static_cast<int>(overlayHeight*0.5f)));
1666 b = transform.map(QPoint(static_cast<int>(overlayWidth*0.5f), static_cast<int>(-overlayHeight*0.5f)));
1667 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1668
1669 // Tool to show full CCD grid overlay
1670 if (flagShowCcdCropOverlayPixelGrid)
1671 {
1672 // vertical lines
1673 for (int l =1 ; l< actualCropOverlayX/ccd->binningX(); l++ )
1674 {
1675 a = transform.map(QPoint(static_cast<int>(overlayWidth*0.5f- l*pixelProjectedWidth), static_cast<int>(-overlayHeight*0.5f)));
1676 b = transform.map(QPoint(static_cast<int>(overlayWidth*0.5f- l*pixelProjectedWidth), static_cast<int>(overlayHeight*0.5f)));
1677 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1678 }
1679 // horizontal lines
1680 for (int l =1 ; l< actualCropOverlayY/ccd->binningY(); l++ )
1681 {
1682 a = transform.map(QPoint(static_cast<int>(-overlayWidth*0.5f), static_cast<int>(overlayHeight*0.5f - l*pixelProjectedHeight)));
1683 b = transform.map(QPoint(static_cast<int>(overlayWidth*0.5f), static_cast<int>(overlayHeight*0.5f - l*pixelProjectedHeight)));
1684 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1685 }
1686 }
1687 }
1688 if(ccd->hasOAG())
1689 {
1690 const double InnerOAGRatio = ccd->getInnerOAGRadius(telescope, lens) / screenFOV;
1691 const double OuterOAGRatio = ccd->getOuterOAGRadius(telescope, lens) / screenFOV;
1692 const double prismXRatio = ccd->getOAGActualFOVx(telescope, lens) / screenFOV;
1693 const int in_oag_r = qRound(params.viewportXywh[aspectIndex] * InnerOAGRatio * params.devicePixelsPerPixel);
1694 const int out_oag_r = qRound(params.viewportXywh[aspectIndex] * OuterOAGRatio * params.devicePixelsPerPixel);
1695 const int h_width = qRound(params.viewportXywh[aspectIndex] * prismXRatio * params.devicePixelsPerPixel * 0.5);
1696
1697 painter.drawCircle(centerScreen[0], centerScreen[1], in_oag_r);
1698 painter.drawCircle(centerScreen[0], centerScreen[1], out_oag_r);
1699
1700 QTransform oag_transform = QTransform().translate(centerScreen[0], centerScreen[1]).rotate(-(ccd->chipRotAngle() + polarAngle + ccd->prismPosAngle()));
1701
1702 // bottom line
1703 a = oag_transform.map(QPoint(-h_width, in_oag_r));
1704 b = oag_transform.map(QPoint(h_width, in_oag_r));
1705 painter.drawLine2d(a.x(),a.y(), b.x(), b.y());
1706 // top line
1707 a = oag_transform.map(QPoint(-h_width, out_oag_r));
1708 b = oag_transform.map(QPoint(h_width, out_oag_r));
1709 painter.drawLine2d(a.x(),a.y(), b.x(), b.y());
1710 // left line
1711 a = oag_transform.map(QPoint(-h_width, out_oag_r));
1712 b = oag_transform.map(QPoint(-h_width, in_oag_r));
1713 painter.drawLine2d(a.x(),a.y(), b.x(), b.y());
1714 // right line
1715 a = oag_transform.map(QPoint(h_width, out_oag_r));
1716 b = oag_transform.map(QPoint(h_width, in_oag_r));
1717 painter.drawLine2d(a.x(),a.y(), b.x(), b.y());
1718 }
1719
1720 // Tool for planning a mosaic astrophotography: shows a small cross at center of CCD's
1721 // frame and equatorial coordinates for epoch J2000.0 of that center.
1722 // Details: https://bugs.launchpad.net/stellarium/+bug/1404695
1723
1724 const double ratioLimit = 0.25;
1725 const double ratioLimitCrop = 0.75;
1726 if (ccdXRatio>=ratioLimit || ccdYRatio>=ratioLimit)
1727 {
1728 // draw cross at center
1729 const int cross = qRound(10 * params.devicePixelsPerPixel); // use permanent size of cross (10px)
1730 a = transform.map(QPoint(-cross, -cross));
1731 b = transform.map(QPoint(cross, cross));
1732 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1733 a = transform.map(QPoint(-cross, cross));
1734 b = transform.map(QPoint(cross, -cross));
1735 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1736 // calculate coordinates of the center and show it
1737 Vec3d centerPosition;
1738 projector->unProject(centerScreen[0], centerScreen[1], centerPosition);
1739 double cx, cy;
1740 QString cxt, cyt;
1741 StelUtils::rectToSphe(&cx,&cy,core->equinoxEquToJ2000(centerPosition, StelCore::RefractionOff)); // Calculate RA/DE (J2000.0) and show it...
1742 bool withDecimalDegree = StelApp::getInstance().getFlagShowDecimalDegrees();
1743 if (withDecimalDegree)
1744 {
1745 cxt = StelUtils::radToDecDegStr(cx, 5, false, true);
1746 cyt = StelUtils::radToDecDegStr(cy);
1747 }
1748 else
1749 {
1750 cxt = StelUtils::radToHmsStr(cx, true);
1751 cyt = StelUtils::radToDmsStr(cy, true);
1752 }
1753 float scaleFactor = static_cast<float>(1.2 * params.devicePixelsPerPixel);
1754 // Coordinates of center of visible field of view for CCD (red rectangle)
1755 QString coords = QString("%1:").arg(qc_("RA/Dec (J2000.0) of cross", "abbreviated in the plugin"));
1756 a = transform.map(QPoint(qRound(-width*0.5f), qRound(height*0.5f + 5.f + fontSize*scaleFactor)));
1757 painter.drawText(a.x(), a.y(), coords, static_cast<float>(-(ccd->chipRotAngle() + polarAngle)));
1758 coords = QString("%1/%2").arg(cxt.simplified()).arg(cyt);
1759 a = transform.map(QPoint(qRound(-width*0.5f), qRound(height*0.5f + 5.f)));
1760 painter.drawText(a.x(), a.y(), coords, static_cast<float>(-(ccd->chipRotAngle() + polarAngle)));
1761 // Dimensions of visible field of view for CCD (red rectangle)
1762 a = transform.map(QPoint(qRound(-width*0.5f), qRound(-height*0.5f - fontSize*scaleFactor)));
1763 painter.drawText(a.x(), a.y(), getDimensionsString(fovX, fovY), static_cast<float>(-(ccd->chipRotAngle() + polarAngle)));
1764 // Horizontal and vertical scales of visible field of view for CCD (red rectangle)
1765 //TRANSLATORS: Unit of measure for scale - arc-seconds per pixel
1766 QString unit = q_("\"/px");
1767 QString scales = QString("%1%3 %4 %2%3")
1768 .arg(QString::number(fovX*3600*ccd->binningX()/ccd->resolutionX(), 'f', 4))
1769 .arg(QString::number(fovY*3600*ccd->binningY()/ccd->resolutionY(), 'f', 4))
1770 .arg(unit)
1771 .arg(QChar(0x00D7));
1772 a = transform.map(QPoint(qRound(width*0.5f - painter.getFontMetrics().boundingRect(scales).width()*params.devicePixelsPerPixel), qRound(-height*0.5f - fontSize*scaleFactor)));
1773 painter.drawText(a.x(), a.y(), scales, static_cast<float>(-(ccd->chipRotAngle() + polarAngle)));
1774 // Rotation angle of visible field of view for CCD (red rectangle)
1775 QString angle = QString("%1%2").arg(QString::number(ccd->chipRotAngle(), 'f', 1)).arg(QChar(0x00B0));
1776 a = transform.map(QPoint(qRound(width*0.5f - painter.getFontMetrics().boundingRect(angle).width()*params.devicePixelsPerPixel), qRound(height*0.5f + 5.f)));
1777 painter.drawText(a.x(), a.y(), angle, static_cast<float>(-(ccd->chipRotAngle() + polarAngle)));
1778
1779 if(flagShowCcdCropOverlay && (ccdXRatio>=ratioLimitCrop || ccdYRatio>=ratioLimitCrop))
1780 {
1781 // show the CCD crop overlay text
1782 QString resolutionOverlayText = QString("%1%3 %4 %2%3")
1783 .arg(QString::number(actualCropOverlayX, 'd', 0))
1784 .arg(QString::number(actualCropOverlayY, 'd', 0))
1785 .arg(qc_("px", "pixel"))
1786 .arg(QChar(0x00D7));
1787 if(actualCropOverlayX!=ccdCropOverlayHSize || actualCropOverlayY!=ccdCropOverlayVSize)
1788 resolutionOverlayText.append(" [*]");
1789 a = transform.map(QPoint(qRound(overlayWidth*0.5f - painter.getFontMetrics().boundingRect(resolutionOverlayText).width()*params.devicePixelsPerPixel), qRound(-overlayHeight*0.5f - fontSize*scaleFactor)));
1790 painter.drawText(a.x(), a.y(), resolutionOverlayText, static_cast<float>(-(ccd->chipRotAngle() + polarAngle)));
1791 }
1792 }
1793
1794 if (getFlagShowFocuserOverlay())
1795 {
1796 painter.setColor(focuserColor);
1797 if (getFlagUseSmallFocuserOverlay())
1798 painter.drawCircle(centerScreen[0], centerScreen[1], qRound(params.viewportXywh[aspectIndex] * (0.5*ccd->getFocuserFOV(telescope, lens, 1.25)/ screenFOV) * params.devicePixelsPerPixel));
1799 if (getFlagUseMediumFocuserOverlay())
1800 painter.drawCircle(centerScreen[0], centerScreen[1], qRound(params.viewportXywh[aspectIndex] * (0.5*ccd->getFocuserFOV(telescope, lens, 2.)/ screenFOV) * params.devicePixelsPerPixel));
1801 if (getFlagUseLargeFocuserOverlay())
1802 painter.drawCircle(centerScreen[0], centerScreen[1], qRound(params.viewportXywh[aspectIndex] * (0.5*ccd->getFocuserFOV(telescope, lens, 3.3)/ screenFOV) * params.devicePixelsPerPixel));
1803 }
1804 }
1805 }
1806 }
1807 }
1808
paintCrosshairs()1809 void Oculars::paintCrosshairs()
1810 {
1811 StelCore *core = StelApp::getInstance().getCore();
1812 const StelProjectorP projector = core->getProjection(StelCore::FrameEquinoxEqu);
1813 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
1814 // Center of screen
1815 Vec2i centerScreen(projector->getViewportPosX()+projector->getViewportWidth()/2,
1816 projector->getViewportPosY()+projector->getViewportHeight()/2);
1817 float length = 0.5f * static_cast<float>(params.viewportFovDiameter);
1818 // See if we need to scale the length
1819 if (flagScaleImageCircle && oculars[selectedOcularIndex]->apparentFOV() > 0.0 && !oculars[selectedOcularIndex]->isBinoculars())
1820 {
1821 length *= static_cast<float>(oculars[selectedOcularIndex]->apparentFOV() / maxEyepieceAngle);
1822 }
1823 length *= static_cast<float>(params.devicePixelsPerPixel);
1824 double polarAngle = 0.;
1825 if (getFlagAlignCrosshair())
1826 {
1827 Vec3d CPos;
1828 Vector2<qreal> cpos = projector->getViewportCenter();
1829 projector->unProject(cpos[0], cpos[1], CPos);
1830 Vec3d CPrel(CPos);
1831 CPrel[2]*=0.2;
1832 Vec3d crel;
1833 projector->project(CPrel, crel);
1834 polarAngle = atan2(cpos[1] - crel[1], cpos[0] - crel[0]) * (-180.0)/M_PI; // convert to degrees
1835 if (CPos[2] > 0) polarAngle += 90.0;
1836 else polarAngle -= 90.0;
1837 }
1838 // Draw the lines
1839 StelPainter painter(projector);
1840 painter.setColor(lineColor);
1841 QPoint a, b;
1842 int hw = qRound(length);
1843 QTransform ch_transform = QTransform().translate(centerScreen[0], centerScreen[1]).rotate(-polarAngle);
1844 a = ch_transform.map(QPoint(0, -hw));
1845 b = ch_transform.map(QPoint(0, hw));
1846 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1847 a = ch_transform.map(QPoint(-hw, 0));
1848 b = ch_transform.map(QPoint(hw, 0));
1849 painter.drawLine2d(a.x(), a.y(), b.x(), b.y());
1850 }
1851
paintTelrad()1852 void Oculars::paintTelrad()
1853 {
1854 if (!flagShowOculars)
1855 {
1856 StelCore *core = StelApp::getInstance().getCore();
1857 const StelProjectorP projector = core->getProjection(StelCore::FrameEquinoxEqu);
1858 // StelPainter drawing
1859 StelPainter painter(projector);
1860 painter.setColor(lineColor);
1861 Vec2i centerScreen(projector->getViewportPosX()+projector->getViewportWidth()/2,
1862 projector->getViewportPosY()+projector->getViewportHeight()/2);
1863 const float pixelsPerRad = projector->getPixelPerRadAtCenter(); // * params.devicePixelsPerPixel;
1864 if (telradFOV[0]>0.f) painter.drawCircle(centerScreen[0], centerScreen[1], 0.5f * pixelsPerRad * static_cast<float>(M_PI/180) * (telradFOV[0]));
1865 if (telradFOV[1]>0.f) painter.drawCircle(centerScreen[0], centerScreen[1], 0.5f * pixelsPerRad * static_cast<float>(M_PI/180) * (telradFOV[1]));
1866 if (telradFOV[2]>0.f) painter.drawCircle(centerScreen[0], centerScreen[1], 0.5f * pixelsPerRad * static_cast<float>(M_PI/180) * (telradFOV[2]));
1867 if (telradFOV[3]>0.f) painter.drawCircle(centerScreen[0], centerScreen[1], 0.5f * pixelsPerRad * static_cast<float>(M_PI/180) * (telradFOV[3]));
1868 }
1869 }
1870
paintOcularMask(const StelCore * core)1871 void Oculars::paintOcularMask(const StelCore *core)
1872 {
1873 if (oculars[selectedOcularIndex]->hasPermanentCrosshair())
1874 paintCrosshairs();
1875
1876 const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz);
1877 StelPainter painter(prj);
1878 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
1879
1880 double inner = 0.5 * params.viewportFovDiameter * params.devicePixelsPerPixel;
1881 // See if we need to scale the mask
1882 if (flagScaleImageCircle && oculars[selectedOcularIndex]->apparentFOV() > 0.0 && !oculars[selectedOcularIndex]->isBinoculars())
1883 {
1884 inner = oculars[selectedOcularIndex]->apparentFOV() * inner / maxEyepieceAngle;
1885 }
1886 Vec2i centerScreen(prj->getViewportPosX()+prj->getViewportWidth()/2, prj->getViewportPosY()+prj->getViewportHeight()/2);
1887
1888 painter.setBlending(true);
1889 // Paint the reticale, if needed
1890 if (!reticleTexture.isNull())
1891 {
1892 painter.setColor(lineColor);
1893 reticleTexture->bind();
1894 /* Why it need?
1895 int textureHeight;
1896 int textureWidth;
1897 reticleTexture->getDimensions(textureWidth, textureHeight);
1898 */
1899 painter.drawSprite2dMode(centerScreen[0], centerScreen[1], static_cast<float>(inner / params.devicePixelsPerPixel), static_cast<float>(reticleRotation));
1900 }
1901
1902 const float alpha = getFlagUseSemiTransparency() ? getTransparencyMask()*0.01f : 1.f;
1903 painter.setColor(0.f,0.f,0.f,alpha);
1904
1905 GLfloat outerRadius = static_cast<GLfloat>(params.viewportXywh[2] * params.devicePixelsPerPixel + params.viewportXywh[3] * params.devicePixelsPerPixel);
1906 GLint slices = 239;
1907
1908 GLfloat sinCache[240];
1909 GLfloat cosCache[240];
1910 GLfloat vertices[(240+1)*2][3];
1911 GLfloat deltaRadius;
1912 GLfloat radiusHigh;
1913
1914 /* Compute length (needed for normal calculations) */
1915 deltaRadius=outerRadius-static_cast<GLfloat>(inner);
1916
1917 /* Cache is the vertex locations cache */
1918 for (int i=0; i<=slices; i++)
1919 {
1920 GLfloat angle=static_cast<GLfloat>(M_PI*2.0)*i/slices;
1921 sinCache[i]=static_cast<GLfloat>(sinf(angle));
1922 cosCache[i]=static_cast<GLfloat>(cosf(angle));
1923 }
1924
1925 sinCache[slices]=sinCache[0];
1926 cosCache[slices]=cosCache[0];
1927
1928 /* Enable arrays */
1929 painter.enableClientStates(true);
1930 painter.setVertexPointer(3, GL_FLOAT, vertices);
1931
1932 radiusHigh=outerRadius-deltaRadius;
1933 for (int i=0; i<=slices; i++)
1934 {
1935 vertices[i*2][0]= centerScreen[0] + outerRadius*sinCache[i];
1936 vertices[i*2][1]= centerScreen[1] + outerRadius*cosCache[i];
1937 vertices[i*2][2] = 0.0;
1938 vertices[i*2+1][0]= centerScreen[0] + radiusHigh*sinCache[i];
1939 vertices[i*2+1][1]= centerScreen[1] + radiusHigh*cosCache[i];
1940 vertices[i*2+1][2] = 0.0;
1941 }
1942 painter.drawFromArray(StelPainter::TriangleStrip, (slices+1)*2, 0, false);
1943 painter.enableClientStates(false);
1944
1945 if (getFlagShowContour())
1946 {
1947 painter.setColor(lineColor);
1948 painter.drawCircle(centerScreen[0], centerScreen[1], static_cast<float>(inner));
1949 }
1950
1951 if (getFlagShowCardinals())
1952 {
1953 // Compute polar angle for cardinals and show it
1954 const StelProjectorP projector = core->getProjection(StelCore::FrameEquinoxEqu);
1955 Vec3d CPos;
1956 Vector2<qreal> cpos = projector->getViewportCenter();
1957 projector->unProject(cpos[0], cpos[1], CPos);
1958 Vec3d CPrel(CPos);
1959 CPrel[2]*=0.2;
1960 Vec3d crel;
1961 projector->project(CPrel, crel);
1962 double polarAngle = atan2(cpos[1] - crel[1], cpos[0] - crel[0]) * (-180.0)/M_PI; // convert to degrees
1963 if (CPos[2] > 0)
1964 polarAngle += 90.0;
1965 else
1966 polarAngle -= 90.0;
1967
1968 painter.setColor(lineColor);
1969 bool flipH = core->getFlipHorz();
1970 bool flipV = core->getFlipVert();
1971 if (flipH && flipV)
1972 protractorFlipHVTexture->bind();
1973 else if (flipH && !flipV)
1974 protractorFlipHTexture->bind();
1975 else if (!flipH && flipV)
1976 protractorFlipVTexture->bind();
1977 else
1978 protractorTexture->bind();
1979 painter.drawSprite2dMode(centerScreen[0], centerScreen[1], static_cast<float>(inner / params.devicePixelsPerPixel), static_cast<float>(-polarAngle));
1980 }
1981 }
1982
paintText(const StelCore * core)1983 void Oculars::paintText(const StelCore* core)
1984 {
1985 const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz);
1986 StelPainter painter(prj);
1987
1988 // Get the current instruments
1989 CCD *ccd = Q_NULLPTR;
1990 if(selectedCCDIndex != -1)
1991 {
1992 ccd = ccds[selectedCCDIndex];
1993 }
1994 Ocular *ocular = Q_NULLPTR;
1995 if(selectedOcularIndex !=-1)
1996 {
1997 ocular = oculars[selectedOcularIndex];
1998 }
1999 Telescope *telescope = Q_NULLPTR;
2000 if(selectedTelescopeIndex != -1)
2001 {
2002 telescope = telescopes[selectedTelescopeIndex];
2003 }
2004 Lens *lens = selectedLens();
2005
2006 // set up the color and the GL state
2007 painter.setColor(textColor);
2008 painter.setBlending(true);
2009
2010 // Get the X & Y positions, and the line height
2011 painter.setFont(font);
2012 QString widthString = "MMMMMMMMMMMMMMMMMMMMM";
2013 const double insetFromRHS = painter.getFontMetrics().boundingRect(widthString).width();
2014 StelProjector::StelProjectorParams projectorParams = core->getCurrentStelProjectorParams();
2015 int yPositionOffset = qRound(projectorParams.viewportXywh[3]*projectorParams.viewportCenterOffset[1]);
2016 int xPosition = qRound(projectorParams.devicePixelsPerPixel*projectorParams.viewportXywh[2] - insetFromRHS);
2017 int yPosition = qRound(projectorParams.devicePixelsPerPixel*projectorParams.viewportXywh[3] - yPositionOffset - 20);
2018 const int lineHeight = painter.getFontMetrics().height();
2019
2020 // The Ocular
2021 if (flagShowOculars && ocular!=Q_NULLPTR)
2022 {
2023 QString ocularNumberLabel;
2024 QString name = ocular->name();
2025 QString ocularI18n = q_("Ocular");
2026 if (ocular->isBinoculars())
2027 ocularI18n = q_("Binocular");
2028 if (name.isEmpty())
2029 {
2030 ocularNumberLabel = QString("%1 #%2").arg(ocularI18n).arg(selectedOcularIndex);
2031 }
2032 else
2033 {
2034 ocularNumberLabel = QString("%1 #%2: %3").arg(ocularI18n).arg(selectedOcularIndex).arg(name);
2035 }
2036 // The name of the ocular could be really long.
2037 if (name.length() > widthString.length())
2038 {
2039 xPosition -= qRound(insetFromRHS*0.5);
2040 }
2041 painter.drawText(xPosition, yPosition, ocularNumberLabel);
2042 yPosition-=lineHeight;
2043
2044 if (!ocular->isBinoculars())
2045 {
2046 // TRANSLATORS: FL = Focal length
2047 QString eFocalLengthLabel = QString(q_("Ocular FL: %1 mm")).arg(QString::number(ocular->effectiveFocalLength(), 'f', 1));
2048 painter.drawText(xPosition, yPosition, eFocalLengthLabel);
2049 yPosition-=lineHeight;
2050
2051 QString ocularFov = QString::number(ocular->apparentFOV(), 'f', 2);
2052 ocularFov.append(QChar(0x00B0));//Degree sign
2053 // TRANSLATORS: aFOV = apparent field of view
2054 QString ocularFOVLabel = QString(q_("Ocular aFOV: %1")).arg(ocularFov);
2055 painter.drawText(xPosition, yPosition, ocularFOVLabel);
2056 yPosition-=lineHeight;
2057
2058 QString lensNumberLabel;
2059 // Barlow and Shapley lens
2060 if (lens != Q_NULLPTR) // it's null if lens is not selected (lens index = -1)
2061 {
2062 QString lensName = lens->getName();
2063 if (lensName.isEmpty())
2064 {
2065 lensNumberLabel = QString(q_("Lens #%1")).arg(selectedLensIndex);
2066 }
2067 else
2068 {
2069 lensNumberLabel = QString (q_("Lens #%1: %2")).arg(selectedLensIndex).arg(lensName);
2070 }
2071 }
2072 else
2073 {
2074 lensNumberLabel = QString (q_("Lens: none"));
2075 }
2076 painter.drawText(xPosition, yPosition, lensNumberLabel);
2077 yPosition-=lineHeight;
2078
2079 if (telescope!=Q_NULLPTR)
2080 {
2081 QString telescopeName = telescope->name();
2082 QString telescopeString = "";
2083
2084 if (telescopeName.isEmpty())
2085 telescopeString = QString("%1").arg(selectedTelescopeIndex);
2086 else
2087 telescopeString = QString("%1: %2").arg(selectedTelescopeIndex).arg(telescopeName);
2088
2089 painter.drawText(xPosition, yPosition, QString(q_("Telescope #%1")).arg(telescopeString));
2090 yPosition-=lineHeight;
2091
2092 // General info
2093 double mag = ocular->magnification(telescope, lens);
2094 QString magString = QString::number(mag, 'f', 1);
2095 magString.append(QChar(0x02E3)); // Was 0x00D7
2096 magString.append(QString(" (%1D)").arg(QString::number(mag/telescope->diameter(), 'f', 2)));
2097
2098 painter.drawText(xPosition, yPosition, QString(q_("Magnification: %1")).arg(magString));
2099 yPosition-=lineHeight;
2100
2101 if (mag>0)
2102 {
2103 QString exitPupil = QString::number(telescope->diameter()/mag, 'f', 2);
2104
2105 painter.drawText(xPosition, yPosition, QString(q_("Exit pupil: %1 mm")).arg(exitPupil));
2106 yPosition-=lineHeight;
2107 }
2108
2109 QString fovString = QString::number(ocular->actualFOV(telescope, lens), 'f', 5);
2110 fovString.append(QChar(0x00B0));//Degree sign
2111
2112 painter.drawText(xPosition, yPosition, QString(q_("FOV: %1")).arg(fovString));
2113 }
2114 }
2115 }
2116
2117 // The CCD
2118 if (flagShowCCD && ccd!=Q_NULLPTR)
2119 {
2120 QString ccdSensorLabel, ccdInfoLabel, ccdBinningInfo;
2121 QString name = "";
2122 QString telescopeName = "";
2123 double fovX = 0.0;
2124 double fovY = 0.0;
2125 if (telescope!=Q_NULLPTR)
2126 {
2127 fovX = ccd->getActualFOVx(telescope, lens);
2128 fovY = ccd->getActualFOVy(telescope, lens);
2129 name = ccd->name();
2130 telescopeName = telescope->name();
2131 }
2132
2133 ccdInfoLabel = QString(q_("Dimensions: %1")).arg(getDimensionsString(fovX, fovY));
2134 ccdBinningInfo = QString("%1: %2 %4 %3").arg(q_("Binning")).arg(ccd->binningX()).arg(ccd->binningY()).arg(QChar(0x00D7));
2135
2136 if (name.isEmpty())
2137 {
2138 ccdSensorLabel = QString(q_("Sensor #%1")).arg(selectedCCDIndex);
2139 }
2140 else
2141 {
2142 ccdSensorLabel = QString(q_("Sensor #%1: %2"))
2143 .arg(selectedCCDIndex)
2144 .arg(name);
2145 }
2146 // The telescope
2147 QString telescopeNumberLabel;
2148 if (telescopeName.isEmpty())
2149 {
2150 telescopeNumberLabel = QString(q_("Telescope #%1"))
2151 .arg(selectedTelescopeIndex);
2152 }
2153 else
2154 {
2155 telescopeNumberLabel = QString(q_("Telescope #%1: %2"))
2156 .arg(selectedTelescopeIndex)
2157 .arg(telescopeName);
2158 }
2159 painter.drawText(xPosition, yPosition, ccdSensorLabel);
2160 yPosition-=lineHeight;
2161 painter.drawText(xPosition, yPosition, ccdInfoLabel);
2162 yPosition-=lineHeight;
2163 painter.drawText(xPosition, yPosition, ccdBinningInfo);
2164 yPosition-=lineHeight;
2165 painter.drawText(xPosition, yPosition, telescopeNumberLabel);
2166 }
2167 }
2168
validateAndLoadIniFile()2169 void Oculars::validateAndLoadIniFile()
2170 {
2171 // Ensure the module directory exists
2172 StelFileMgr::makeSureDirExistsAndIsWritable(StelFileMgr::getUserDir()+"/modules/Oculars");
2173 StelFileMgr::Flags flags = static_cast<StelFileMgr::Flags>(StelFileMgr::Directory|StelFileMgr::Writable);
2174 QString ocularIniPath = StelFileMgr::findFile("modules/Oculars/", flags) + "ocular.ini";
2175 if (ocularIniPath.isEmpty())
2176 return;
2177
2178 // If the ini file does not already exist, create it from the resource in the QT resource
2179 if(!QFileInfo(ocularIniPath).exists())
2180 {
2181 QFile src(":/ocular/default_ocular.ini");
2182 if (!src.copy(ocularIniPath))
2183 {
2184 qWarning() << "Oculars::validateIniFile cannot copy default_ocular.ini resource to [non-existing] "
2185 + ocularIniPath;
2186 }
2187 else
2188 {
2189 qDebug() << "Oculars::validateAndLoadIniFile() copied default_ocular.ini to " << QDir::toNativeSeparators(ocularIniPath);
2190 // The resource is read only, and the new file inherits this, so set write-able.
2191 QFile dest(ocularIniPath);
2192 dest.setPermissions(dest.permissions() | QFile::WriteOwner);
2193 }
2194 }
2195 else
2196 {
2197 qDebug() << "Oculars::validateAndLoadIniFile() ocular.ini exists at: " << QDir::toNativeSeparators(ocularIniPath) << ". Checking version...";
2198 QSettings mySettings(ocularIniPath, QSettings::IniFormat);
2199 const float ocularsVersion = mySettings.value("oculars_version", 0.0).toFloat();
2200 qWarning() << "Oculars::validateAndLoadIniFile() found existing ini file version " << ocularsVersion;
2201
2202 if (ocularsVersion < MIN_OCULARS_INI_VERSION)
2203 {
2204 qWarning() << "Oculars::validateAndLoadIniFile() existing ini file version " << ocularsVersion
2205 << " too old to use; required version is " << MIN_OCULARS_INI_VERSION << ". Copying over new one.";
2206 // delete last "old" file, if it exists
2207 QFile deleteFile(ocularIniPath + ".old");
2208 deleteFile.remove();
2209
2210 // Rename the old one, and copy over a new one
2211 QFile oldFile(ocularIniPath);
2212 if (!oldFile.rename(ocularIniPath + ".old"))
2213 {
2214 qWarning() << "Oculars::validateAndLoadIniFile() cannot move ocular.ini resource to ocular.ini.old at path " + QDir::toNativeSeparators(ocularIniPath);
2215 }
2216 else
2217 {
2218 qWarning() << "Oculars::validateAndLoadIniFile() ocular.ini resource renamed to ocular.ini.old at path " + QDir::toNativeSeparators(ocularIniPath);
2219 QFile src(":/ocular/default_ocular.ini");
2220 if (!src.copy(ocularIniPath))
2221 {
2222 qWarning() << "Oculars::validateIniFile cannot copy default_ocular.ini resource to [non-existing] " + QDir::toNativeSeparators(ocularIniPath);
2223 }
2224 else
2225 {
2226 qDebug() << "Oculars::validateAndLoadIniFile() copied default_ocular.ini to " << QDir::toNativeSeparators(ocularIniPath);
2227 // The resource is read only, and the new file inherits this... make sure the new file
2228 // is writable by the Stellarium process so that updates can be done.
2229 QFile dest(ocularIniPath);
2230 dest.setPermissions(dest.permissions() | QFile::WriteOwner);
2231 }
2232 }
2233 }
2234 }
2235 settings = new QSettings(ocularIniPath, QSettings::IniFormat, this);
2236 }
2237
unzoomOcular()2238 void Oculars::unzoomOcular()
2239 {
2240 Q_ASSERT(flagShowOculars == false);
2241 StelCore *core = StelApp::getInstance().getCore();
2242 StelMovementMgr *movementManager = core->getMovementMgr();
2243 StelSkyDrawer *skyDrawer = core->getSkyDrawer();
2244
2245 if (flagHideGridsLines)
2246 toggleLines(true);
2247
2248 StelApp::getInstance().getStelPropertyManager()->setStelPropertyValue("MilkyWay.saturation", milkyWaySaturation);
2249 disconnect(skyDrawer, SIGNAL(customStarMagLimitChanged(double)), this, SLOT(setMagLimitStarsOcularsManual(double)));
2250 // restore values, but keep current to enable toggling.
2251 if (!getFlagAutoLimitMagnitude())
2252 {
2253 flagLimitStarsOculars=skyDrawer->getFlagStarMagnitudeLimit();
2254 magLimitStarsOculars=skyDrawer->getCustomStarMagnitudeLimit();
2255 }
2256 skyDrawer->setCustomStarMagnitudeLimit(magLimitStarsMain);
2257 skyDrawer->setFlagStarMagnitudeLimit(flagLimitStarsMain);
2258 relativeStarScaleOculars=skyDrawer->getRelativeStarScale();
2259 absoluteStarScaleOculars=skyDrawer->getAbsoluteStarScale();
2260 skyDrawer->setRelativeStarScale(relativeStarScaleMain);
2261 skyDrawer->setAbsoluteStarScale(absoluteStarScaleMain);
2262 skyDrawer->setFlagLuminanceAdaptation(flagAdaptationMain);
2263 skyDrawer->setFlagPlanetMagnitudeLimit(flagLimitPlanetsMain);
2264 skyDrawer->setFlagNebulaMagnitudeLimit(flagLimitDSOsMain);
2265 skyDrawer->setCustomPlanetMagnitudeLimit(magLimitPlanetsMain);
2266 skyDrawer->setCustomNebulaMagnitudeLimit(magLimitDSOsMain);
2267 movementManager->setFlagEnableZoomKeys(true);
2268 movementManager->setFlagEnableMouseZooming(true);
2269
2270 GETSTELMODULE(SolarSystem)->setFlagMoonScale(flagMoonScaleMain);
2271 GETSTELMODULE(SolarSystem)->setFlagMinorBodyScale(flagMinorBodiesScaleMain);
2272 GETSTELMODULE(SolarSystem)->setFlagSunScale(flagSunScaleMain);
2273 GETSTELMODULE(SolarSystem)->setFlagPlanetScale(flagPlanetsScaleMain);
2274 GETSTELMODULE(NebulaMgr)->setHintsProportional(flagDSOPropHintMain);
2275
2276 // Set the screen display
2277 core->setFlipHorz(flipHorzMain);
2278 core->setFlipVert(flipVertMain);
2279
2280 if (getFlagInitFovUsage())
2281 movementManager->zoomTo(movementManager->getInitFov());
2282 else if (!flagShowTelrad)
2283 movementManager->zoomTo(initialFOV);
2284
2285 if (getFlagInitDirectionUsage())
2286 movementManager->setViewDirectionJ2000(core->altAzToJ2000(movementManager->getInitViewingDirection(), StelCore::RefractionOff));
2287 }
2288
zoom(bool zoomedIn)2289 void Oculars::zoom(bool zoomedIn)
2290 {
2291 if (flagShowOculars && selectedOcularIndex == -1)
2292 {
2293 // The user cycled out the selected ocular
2294 flagShowOculars = false;
2295 }
2296
2297 if (flagShowOculars)
2298 {
2299 if (!zoomedIn)
2300 {
2301 StelCore *core = StelApp::getInstance().getCore();
2302 StelPropertyMgr* propMgr=StelApp::getInstance().getStelPropertyManager();
2303
2304 if (flagHideGridsLines)
2305 {
2306 // Store current state for later resetting
2307 flagGridLinesDisplayedMain = propMgr->getStelPropertyValue("GridLinesMgr.gridlinesDisplayed").toBool();
2308 flagCardinalPointsMain = propMgr->getStelPropertyValue("LandscapeMgr.cardinalsPointsDisplayed").toBool();
2309 flagConstellationLinesMain = propMgr->getStelPropertyValue("ConstellationMgr.linesDisplayed").toBool();
2310 flagConstellationBoundariesMain = propMgr->getStelPropertyValue("ConstellationMgr.boundariesDisplayed").toBool();
2311 flagAsterismLinesMain = propMgr->getStelPropertyValue("AsterismMgr.linesDisplayed").toBool();
2312 flagRayHelpersLinesMain = propMgr->getStelPropertyValue("AsterismMgr.rayHelpersDisplayed").toBool();
2313 }
2314
2315 StelSkyDrawer *skyDrawer = core->getSkyDrawer();
2316 // Current state
2317 flagAdaptationMain = skyDrawer->getFlagLuminanceAdaptation();
2318 flagLimitStarsMain = skyDrawer->getFlagStarMagnitudeLimit();
2319 flagLimitPlanetsMain = skyDrawer->getFlagPlanetMagnitudeLimit();
2320 flagLimitDSOsMain = skyDrawer->getFlagNebulaMagnitudeLimit();
2321 magLimitStarsMain = skyDrawer->getCustomStarMagnitudeLimit();
2322 magLimitPlanetsMain = skyDrawer->getCustomPlanetMagnitudeLimit();
2323 magLimitDSOsMain = skyDrawer->getCustomNebulaMagnitudeLimit();
2324 relativeStarScaleMain = skyDrawer->getRelativeStarScale();
2325 absoluteStarScaleMain = skyDrawer->getAbsoluteStarScale();
2326
2327 flagMoonScaleMain = propMgr->getStelPropertyValue("SolarSystem.flagMoonScale").toBool();
2328 flagMinorBodiesScaleMain = propMgr->getStelPropertyValue("SolarSystem.flagMinorBodyScale").toBool();
2329 flagSunScaleMain = propMgr->getStelPropertyValue("SolarSystem.flagSunScale").toBool();
2330 flagPlanetsScaleMain = propMgr->getStelPropertyValue("SolarSystem.flagPlanetScale").toBool();
2331
2332 flagDSOPropHintMain = propMgr->getStelPropertyValue("NebulaMgr.hintsProportional").toBool();
2333 milkyWaySaturation = propMgr->getStelPropertyValue("MilkyWay.saturation").toDouble();
2334
2335 flipHorzMain = core->getFlipHorz();
2336 flipVertMain = core->getFlipVert();
2337
2338 StelMovementMgr *movementManager = core->getMovementMgr();
2339 initialFOV = movementManager->getCurrentFov();
2340 }
2341
2342 // set new state
2343 zoomOcular();
2344 }
2345 else
2346 {
2347 //reset to original state
2348 unzoomOcular();
2349 }
2350 }
2351
toggleLines(bool visible)2352 void Oculars::toggleLines(bool visible)
2353 {
2354 if (flagShowTelrad)
2355 return;
2356
2357 StelPropertyMgr* propMgr=StelApp::getInstance().getStelPropertyManager();
2358
2359 if (visible)
2360 {
2361 propMgr->setStelPropertyValue("GridLinesMgr.gridlinesDisplayed", flagGridLinesDisplayedMain);
2362 propMgr->setStelPropertyValue("LandscapeMgr.cardinalsPointsDisplayed", flagCardinalPointsMain);
2363 propMgr->setStelPropertyValue("ConstellationMgr.linesDisplayed", flagConstellationLinesMain);
2364 propMgr->setStelPropertyValue("ConstellationMgr.boundariesDisplayed", flagConstellationBoundariesMain);
2365 propMgr->setStelPropertyValue("AsterismMgr.linesDisplayed", flagAsterismLinesMain);
2366 propMgr->setStelPropertyValue("AsterismMgr.rayHelpersDisplayed", flagRayHelpersLinesMain);
2367 }
2368 else
2369 {
2370 propMgr->setStelPropertyValue("GridLinesMgr.gridlinesDisplayed", false);
2371 propMgr->setStelPropertyValue("LandscapeMgr.cardinalsPointsDisplayed", false);
2372 propMgr->setStelPropertyValue("ConstellationMgr.linesDisplayed", false);
2373 propMgr->setStelPropertyValue("ConstellationMgr.boundariesDisplayed", false);
2374 propMgr->setStelPropertyValue("AsterismMgr.linesDisplayed", false);
2375 propMgr->setStelPropertyValue("AsterismMgr.rayHelpersDisplayed", false);
2376 }
2377 }
2378
zoomOcular()2379 void Oculars::zoomOcular()
2380 {
2381 Q_ASSERT(flagShowOculars == true);
2382 StelCore *core = StelApp::getInstance().getCore();
2383 StelMovementMgr *movementManager = core->getMovementMgr();
2384 StelSkyDrawer *skyDrawer = core->getSkyDrawer();
2385
2386 if (flagHideGridsLines)
2387 toggleLines(false);
2388
2389 skyDrawer->setFlagLuminanceAdaptation(false);
2390 StelApp::getInstance().getStelPropertyManager()->setStelPropertyValue("MilkyWay.saturation", 0.f);
2391
2392 GETSTELMODULE(SolarSystem)->setFlagMoonScale(false);
2393 GETSTELMODULE(SolarSystem)->setFlagMinorBodyScale(false);
2394 GETSTELMODULE(SolarSystem)->setFlagSunScale(false);
2395 GETSTELMODULE(SolarSystem)->setFlagPlanetScale(false);
2396 GETSTELMODULE(NebulaMgr)->setHintsProportional(false);
2397
2398 movementManager->setFlagTracking(true);
2399 movementManager->setFlagEnableZoomKeys(false);
2400 movementManager->setFlagEnableMouseZooming(false);
2401
2402 // We won't always have a selected object
2403 if (StelApp::getInstance().getStelObjectMgr().getWasSelected())
2404 {
2405 StelObjectP selectedObject = StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0];
2406 movementManager->moveToJ2000(selectedObject->getEquinoxEquatorialPos(core), movementManager->mountFrameToJ2000(Vec3d(0., 0., 1.)), 0.0, StelMovementMgr::ZoomIn);
2407 }
2408
2409 // Set the screen display
2410 Ocular * ocular = oculars[selectedOcularIndex];
2411 Telescope * telescope = Q_NULLPTR;
2412 Lens * lens = Q_NULLPTR;
2413 // Only consider flip is we're not binoculars
2414 if (ocular->isBinoculars())
2415 {
2416 core->setFlipHorz(false);
2417 core->setFlipVert(false);
2418 }
2419 else
2420 {
2421 if (selectedLensIndex >= 0)
2422 {
2423 lens = lenses[selectedLensIndex];
2424 }
2425 telescope = telescopes[selectedTelescopeIndex];
2426 core->setFlipHorz(telescope->isHFlipped());
2427 core->setFlipVert(telescope->isVFlipped());
2428 }
2429
2430 // Change relative and absolute scales for stars
2431 relativeStarScaleMain=skyDrawer->getRelativeStarScale();
2432 skyDrawer->setRelativeStarScale(relativeStarScaleOculars);
2433 absoluteStarScaleMain=skyDrawer->getAbsoluteStarScale();
2434 skyDrawer->setAbsoluteStarScale(absoluteStarScaleOculars);
2435
2436 // Limit stars and DSOs magnitude. Either compute limiting magnitude for the telescope/ocular,
2437 // or just use the custom oculars mode value.
2438
2439 // TODO: set lim. mag without also activating flag it if it should not be activated.
2440
2441 double limitMag=magLimitStarsOculars;
2442 if (getFlagAutoLimitMagnitude() || flagLimitStarsOculars )
2443 {
2444 if (getFlagAutoLimitMagnitude())
2445 {
2446 disconnect(skyDrawer, SIGNAL(customStarMagLimitChanged(double)), this, SLOT(setMagLimitStarsOcularsManual(double))); // we want to keep the old manual value.
2447 limitMag = computeLimitMagnitude(ocular, telescope);
2448 // TODO: Is it really good to apply the star formula to DSO?
2449 skyDrawer->setFlagNebulaMagnitudeLimit(true);
2450 skyDrawer->setCustomNebulaMagnitudeLimit(limitMag);
2451 }
2452 else
2453 { // It's possible that the user changes the custom magnitude while viewing, and then changes the ocular.
2454 // Therefore we need a temporary connection.
2455 connect(skyDrawer, SIGNAL(customStarMagLimitChanged(double)), this, SLOT(setMagLimitStarsOcularsManual(double)));
2456 }
2457 skyDrawer->setFlagStarMagnitudeLimit(true);
2458 }
2459 skyDrawer->setCustomStarMagnitudeLimit(limitMag);
2460
2461 actualFOV = ocular->actualFOV(telescope, lens);
2462 // See if the mask was scaled; if so, correct the actualFOV.
2463 if (flagScaleImageCircle && ocular->apparentFOV() > 0.0 && !ocular->isBinoculars())
2464 {
2465 actualFOV = maxEyepieceAngle * actualFOV / ocular->apparentFOV();
2466 }
2467 movementManager->zoomTo(actualFOV, 0.f);
2468 }
2469
hideUsageMessageIfDisplayed()2470 void Oculars::hideUsageMessageIfDisplayed()
2471 {
2472 if (usageMessageLabelID > -1)
2473 {
2474 LabelMgr *labelManager = GETSTELMODULE(LabelMgr);
2475 labelManager->setLabelShow(usageMessageLabelID, false);
2476 labelManager->deleteLabel(usageMessageLabelID);
2477 usageMessageLabelID = -1;
2478 }
2479 }
2480
selectedLens()2481 Lens* Oculars::selectedLens()
2482 {
2483 if (selectedLensIndex >= 0 && selectedLensIndex < lenses.count())
2484 {
2485 return lenses[selectedLensIndex];
2486 }
2487 return Q_NULLPTR;
2488 }
2489
addLensSubmenu(QMenu * parent)2490 QMenu* Oculars::addLensSubmenu(QMenu* parent)
2491 {
2492 Q_ASSERT(parent);
2493
2494 QMenu *submenu = new QMenu(q_("&Lens"), parent);
2495 submenu->addAction(q_("&Previous lens"), this, SLOT(decrementLensIndex()));
2496 submenu->addAction(q_("&Next lens"), this, SLOT(incrementLensIndex()));
2497 submenu->addSeparator();
2498 submenu->addAction(q_("None"), this, SLOT(disableLens()));
2499
2500 for (int index = 0; index < lenses.count(); ++index)
2501 {
2502 QString label;
2503 if (index < 10)
2504 {
2505 label = QString("&%1: %2").arg(index).arg(lenses[index]->getName());
2506 }
2507 else
2508 {
2509 label = lenses[index]->getName();
2510 }
2511 QAction* action = submenu->addAction(label, [=](){selectLensAtIndex(index);});
2512 if (index == selectedLensIndex)
2513 {
2514 action->setCheckable(true);
2515 action->setChecked(true);
2516 }
2517 }
2518 return submenu;
2519 }
2520
addTelescopeSubmenu(QMenu * parent)2521 QMenu* Oculars::addTelescopeSubmenu(QMenu *parent)
2522 {
2523 Q_ASSERT(parent);
2524
2525 QMenu* submenu = new QMenu(q_("&Telescope"), parent);
2526 submenu->addAction(q_("&Previous telescope"), this, SLOT(decrementTelescopeIndex()));
2527 submenu->addAction(q_("&Next telescope"), this, SLOT(incrementTelescopeIndex()));
2528 submenu->addSeparator();
2529 for (int index = 0; index < telescopes.count(); ++index)
2530 {
2531 QString label;
2532 if (index < 10)
2533 {
2534 label = QString("&%1: %2").arg(index).arg(telescopes[index]->name());
2535 }
2536 else
2537 {
2538 label = telescopes[index]->name();
2539 }
2540 QAction* action = submenu->addAction(label, [=](){selectTelescopeAtIndex(index);});
2541 if (index == selectedTelescopeIndex)
2542 {
2543 action->setCheckable(true);
2544 action->setChecked(true);
2545 }
2546 }
2547
2548 return submenu;
2549 }
2550
setFlagDMSDegrees(const bool b)2551 void Oculars::setFlagDMSDegrees(const bool b)
2552 {
2553 flagDMSDegrees = b;
2554 settings->setValue("use_decimal_degrees", !b);
2555 settings->sync();
2556 emit flagDMSDegreesChanged(b);
2557 }
2558
getFlagDMSDegrees() const2559 bool Oculars::getFlagDMSDegrees() const
2560 {
2561 return flagDMSDegrees;
2562 }
2563
setFlagRequireSelection(const bool b)2564 void Oculars::setFlagRequireSelection(const bool b)
2565 {
2566 flagRequireSelection = b;
2567 settings->setValue("require_selection_to_zoom", b);
2568 settings->sync();
2569 emit flagRequireSelectionChanged(b);
2570 }
2571
getFlagRequireSelection() const2572 bool Oculars::getFlagRequireSelection() const
2573 {
2574 return flagRequireSelection;
2575 }
2576
setFlagAutoLimitMagnitude(const bool b)2577 void Oculars::setFlagAutoLimitMagnitude(const bool b)
2578 {
2579 flagAutoLimitMagnitude = b;
2580 settings->setValue("autolimit_stellar_magnitude", b);
2581 settings->sync();
2582 emit flagAutoLimitMagnitudeChanged(b);
2583 }
2584
getFlagAutoLimitMagnitude() const2585 bool Oculars::getFlagAutoLimitMagnitude() const
2586 {
2587 return flagAutoLimitMagnitude;
2588 }
2589
setMagLimitStarsOcularsManual(double mag)2590 void Oculars::setMagLimitStarsOcularsManual(double mag)
2591 {
2592 magLimitStarsOculars = mag;
2593 settings->setValue("limit_stellar_magnitude_oculars_val", mag);
2594 settings->sync();
2595 // This is no property, no need to emit a signal.
2596 }
2597
getMagLimitStarsOcularsManual() const2598 double Oculars::getMagLimitStarsOcularsManual() const
2599 {
2600 return magLimitStarsOculars;
2601 }
2602
setFlagInitFovUsage(const bool b)2603 void Oculars::setFlagInitFovUsage(const bool b)
2604 {
2605 flagInitFOVUsage = b;
2606 settings->setValue("use_initial_fov", b);
2607 settings->sync();
2608 emit flagInitFOVUsageChanged(b);
2609 }
2610
getFlagInitFovUsage() const2611 bool Oculars::getFlagInitFovUsage() const
2612 {
2613 return flagInitFOVUsage;
2614 }
2615
setFlagInitDirectionUsage(const bool b)2616 void Oculars::setFlagInitDirectionUsage(const bool b)
2617 {
2618 flagInitDirectionUsage = b;
2619 settings->setValue("use_initial_direction", b);
2620 settings->sync();
2621 emit flagInitDirectionUsageChanged(b);
2622 }
2623
getFlagInitDirectionUsage() const2624 bool Oculars::getFlagInitDirectionUsage() const
2625 {
2626 return flagInitDirectionUsage;
2627 }
2628
setFlagAutosetMountForCCD(const bool b)2629 void Oculars::setFlagAutosetMountForCCD(const bool b)
2630 {
2631 flagAutosetMountForCCD = b;
2632 settings->setValue("use_mount_autoset", b);
2633 settings->sync();
2634
2635 if (!b)
2636 {
2637 StelPropertyMgr* propMgr=StelApp::getInstance().getStelPropertyManager();
2638 propMgr->setStelPropertyValue("StelMovementMgr.equatorialMount", equatorialMountEnabledMain);
2639 }
2640 emit flagAutosetMountForCCDChanged(b);
2641 }
2642
getFlagAutosetMountForCCD() const2643 bool Oculars::getFlagAutosetMountForCCD() const
2644 {
2645 return flagAutosetMountForCCD;
2646 }
2647
setFlagScalingFOVForTelrad(const bool b)2648 void Oculars::setFlagScalingFOVForTelrad(const bool b)
2649 {
2650 flagScalingFOVForTelrad = b;
2651 settings->setValue("use_telrad_fov_scaling", b);
2652 settings->sync();
2653 emit flagScalingFOVForTelradChanged(b);
2654 }
2655
getFlagScalingFOVForTelrad() const2656 bool Oculars::getFlagScalingFOVForTelrad() const
2657 {
2658 return flagScalingFOVForTelrad;
2659 }
2660
setTelradFOV(Vec4f fov)2661 void Oculars::setTelradFOV(Vec4f fov)
2662 {
2663 telradFOV = fov;
2664 settings->setValue("telrad_fov", fov.toStr());
2665 settings->sync();
2666 emit telradFOVChanged(fov);
2667 }
2668
getTelradFOV() const2669 Vec4f Oculars::getTelradFOV() const
2670 {
2671 return telradFOV;
2672 }
2673
setFlagScalingFOVForCCD(const bool b)2674 void Oculars::setFlagScalingFOVForCCD(const bool b)
2675 {
2676 flagScalingFOVForCCD = b;
2677 settings->setValue("use_ccd_fov_scaling", b);
2678 settings->sync();
2679 emit flagScalingFOVForCCDChanged(b);
2680 }
2681
getFlagScalingFOVForCCD() const2682 bool Oculars::getFlagScalingFOVForCCD() const
2683 {
2684 return flagScalingFOVForCCD;
2685 }
2686
setFlagUseSemiTransparency(const bool b)2687 void Oculars::setFlagUseSemiTransparency(const bool b)
2688 {
2689 flagSemiTransparency = b;
2690 settings->setValue("use_semi_transparency", b);
2691 settings->sync();
2692 emit flagUseSemiTransparencyChanged(b);
2693 }
2694
getFlagUseSemiTransparency() const2695 bool Oculars::getFlagUseSemiTransparency() const
2696 {
2697 return flagSemiTransparency;
2698 }
2699
setTransparencyMask(const int v)2700 void Oculars::setTransparencyMask(const int v)
2701 {
2702 transparencyMask = v;
2703 settings->setValue("transparency_mask", v);
2704 settings->sync();
2705 emit transparencyMaskChanged(v);
2706 }
2707
getTransparencyMask() const2708 int Oculars::getTransparencyMask() const
2709 {
2710 return transparencyMask;
2711 }
2712
setFlagShowResolutionCriteria(const bool b)2713 void Oculars::setFlagShowResolutionCriteria(const bool b)
2714 {
2715 flagShowResolutionCriteria = b;
2716 settings->setValue("show_resolution_criteria", b);
2717 settings->sync();
2718 emit flagShowResolutionCriteriaChanged(b);
2719 }
2720
getFlagShowResolutionCriteria() const2721 bool Oculars::getFlagShowResolutionCriteria() const
2722 {
2723 return flagShowResolutionCriteria;
2724 }
2725
setCcdCropOverlayHSize(int size)2726 void Oculars::setCcdCropOverlayHSize(int size) {
2727 ccdCropOverlayHSize = size;
2728 settings->setValue("ccd_crop_overlay_hsize", size);
2729 settings->sync();
2730 emit ccdCropOverlayHSizeChanged(size);
2731 }
2732
setCcdCropOverlayVSize(int size)2733 void Oculars::setCcdCropOverlayVSize(int size) {
2734 ccdCropOverlayVSize = size;
2735 settings->setValue("ccd_crop_overlay_vsize", size);
2736 settings->sync();
2737 emit ccdCropOverlayVSizeChanged(size);
2738 }
2739
setFlagShowCcdCropOverlay(const bool b)2740 void Oculars::setFlagShowCcdCropOverlay(const bool b)
2741 {
2742 flagShowCcdCropOverlay = b;
2743 settings->setValue("show_ccd_crop_overlay", b);
2744 settings->sync();
2745 emit flagShowCcdCropOverlayChanged(b);
2746 }
2747
getFlagShowCcdCropOverlay(void) const2748 bool Oculars::getFlagShowCcdCropOverlay(void) const
2749 {
2750 return flagShowCcdCropOverlay;
2751 }
2752
setFlagShowCcdCropOverlayPixelGrid(const bool b)2753 void Oculars::setFlagShowCcdCropOverlayPixelGrid(const bool b)
2754 {
2755 flagShowCcdCropOverlayPixelGrid = b;
2756 settings->setValue("ccd_crop_overlay_pixel_grid", b);
2757 settings->sync();
2758 emit flagShowCcdCropOverlayPixelGridChanged(b);
2759 }
2760
getFlagShowCcdCropOverlayPixelGrid(void) const2761 bool Oculars::getFlagShowCcdCropOverlayPixelGrid(void) const
2762 {
2763 return flagShowCcdCropOverlayPixelGrid;
2764 }
2765
2766
setFlagShowFocuserOverlay(const bool b)2767 void Oculars::setFlagShowFocuserOverlay(const bool b)
2768 {
2769 flagShowFocuserOverlay = b;
2770 settings->setValue("show_focuser_overlay", b);
2771 settings->sync();
2772 emit flagShowFocuserOverlayChanged(b);
2773 }
2774
getFlagShowFocuserOverlay(void) const2775 bool Oculars::getFlagShowFocuserOverlay(void) const
2776 {
2777 return flagShowFocuserOverlay;
2778 }
2779
setFlagUseSmallFocuserOverlay(const bool b)2780 void Oculars::setFlagUseSmallFocuserOverlay(const bool b)
2781 {
2782 flagUseSmallFocuserOverlay = b;
2783 settings->setValue("use_small_focuser_overlay", b);
2784 settings->sync();
2785 emit flagUseSmallFocuserOverlayChanged(b);
2786 }
2787
getFlagUseSmallFocuserOverlay(void) const2788 bool Oculars::getFlagUseSmallFocuserOverlay(void) const
2789 {
2790 return flagUseSmallFocuserOverlay;
2791 }
2792
setFlagUseMediumFocuserOverlay(const bool b)2793 void Oculars::setFlagUseMediumFocuserOverlay(const bool b)
2794 {
2795 flagUseMediumFocuserOverlay = b;
2796 settings->setValue("use_medium_focuser_overlay", b);
2797 settings->sync();
2798 emit flagUseMediumFocuserOverlayChanged(b);
2799 }
2800
getFlagUseMediumFocuserOverlay(void) const2801 bool Oculars::getFlagUseMediumFocuserOverlay(void) const
2802 {
2803 return flagUseMediumFocuserOverlay;
2804 }
2805
setFlagUseLargeFocuserOverlay(const bool b)2806 void Oculars::setFlagUseLargeFocuserOverlay(const bool b)
2807 {
2808 flagUseLargeFocuserOverlay = b;
2809 settings->setValue("use_large_focuser_overlay", b);
2810 settings->sync();
2811 emit flagUseLargeFocuserOverlayChanged(b);
2812 }
2813
getFlagUseLargeFocuserOverlay(void) const2814 bool Oculars::getFlagUseLargeFocuserOverlay(void) const
2815 {
2816 return flagUseLargeFocuserOverlay;
2817 }
2818
setFlagShowContour(const bool b)2819 void Oculars::setFlagShowContour(const bool b)
2820 {
2821 flagShowContour = b;
2822 settings->setValue("show_ocular_contour", b);
2823 settings->sync();
2824 emit flagShowContourChanged(b);
2825 }
2826
getFlagShowContour(void) const2827 bool Oculars::getFlagShowContour(void) const
2828 {
2829 return flagShowContour;
2830 }
2831
setFlagShowCardinals(const bool b)2832 void Oculars::setFlagShowCardinals(const bool b)
2833 {
2834 flagShowCardinals = b;
2835 settings->setValue("show_ocular_cardinals", b);
2836 settings->sync();
2837 emit flagShowCardinalsChanged(b);
2838 }
2839
getFlagShowCardinals(void) const2840 bool Oculars::getFlagShowCardinals(void) const
2841 {
2842 return flagShowCardinals;
2843 }
2844
setFlagAlignCrosshair(const bool b)2845 void Oculars::setFlagAlignCrosshair(const bool b)
2846 {
2847 flagAlignCrosshair = b;
2848 settings->setValue("align_crosshair", b);
2849 settings->sync();
2850 emit flagAlignCrosshairChanged(b);
2851 }
2852
getFlagAlignCrosshair(void) const2853 bool Oculars::getFlagAlignCrosshair(void) const
2854 {
2855 return flagAlignCrosshair;
2856 }
2857
setArrowButtonScale(const int val)2858 void Oculars::setArrowButtonScale(const int val)
2859 {
2860 arrowButtonScale = val;
2861 settings->setValue("arrow_scale", val);
2862 settings->sync();
2863 emit arrowButtonScaleChanged(val);
2864 }
2865
getArrowButtonScale() const2866 int Oculars::getArrowButtonScale() const
2867 {
2868 return arrowButtonScale;
2869 }
2870
setFlagHideGridsLines(const bool b)2871 void Oculars::setFlagHideGridsLines(const bool b)
2872 {
2873 if (b != flagHideGridsLines)
2874 {
2875 flagHideGridsLines = b;
2876 settings->setValue("hide_grids_and_lines", b);
2877 settings->sync();
2878 emit flagHideGridsLinesChanged(b);
2879
2880 if (b && flagShowOculars)
2881 {
2882 // Store current state for later resetting
2883 StelPropertyMgr* propMgr=StelApp::getInstance().getStelPropertyManager();
2884 flagGridLinesDisplayedMain = propMgr->getStelPropertyValue("GridLinesMgr.gridlinesDisplayed").toBool();
2885 flagCardinalPointsMain = propMgr->getStelPropertyValue("LandscapeMgr.cardinalsPointsDisplayed").toBool();
2886 flagConstellationLinesMain = propMgr->getStelPropertyValue("ConstellationMgr.linesDisplayed").toBool();
2887 flagConstellationBoundariesMain = propMgr->getStelPropertyValue("ConstellationMgr.boundariesDisplayed").toBool();
2888 flagAsterismLinesMain = propMgr->getStelPropertyValue("AsterismMgr.linesDisplayed").toBool();
2889 flagRayHelpersLinesMain = propMgr->getStelPropertyValue("AsterismMgr.rayHelpersDisplayed").toBool();
2890 toggleLines(false);
2891 }
2892 else if (!b && flagShowOculars)
2893 {
2894 // Restore main program state
2895 toggleLines(true);
2896 }
2897 }
2898 }
2899
getFlagHideGridsLines() const2900 bool Oculars::getFlagHideGridsLines() const
2901 {
2902 return flagHideGridsLines;
2903 }
2904
getDimensionsString(double fovX,double fovY) const2905 QString Oculars::getDimensionsString(double fovX, double fovY) const
2906 {
2907 QString stringFovX, stringFovY;
2908 if (getFlagDMSDegrees())
2909 {
2910 if (fovX >= 1.0)
2911 {
2912 int degrees = static_cast<int>(fovX);
2913 double minutes = (fovX - degrees) * 60.;
2914 stringFovX = QString::number(degrees) + QChar(0x00B0) + QString::number(minutes, 'f', 2) + QChar(0x2032);
2915 }
2916 else
2917 {
2918 double minutes = fovX * 60.;
2919 stringFovX = QString::number(minutes, 'f', 2) + QChar(0x2032);
2920 }
2921
2922 if (fovY >= 1.0)
2923 {
2924 int degrees = static_cast<int>(fovY);
2925 double minutes = (fovY - degrees) * 60.;
2926 stringFovY = QString::number(degrees) + QChar(0x00B0) + QString::number(minutes, 'f', 2) + QChar(0x2032);
2927 }
2928 else
2929 {
2930 double minutes = fovY * 60;
2931 stringFovY = QString::number(minutes, 'f', 2) + QChar(0x2032);
2932 }
2933 }
2934 else
2935 {
2936 stringFovX = QString::number(fovX, 'f', 5) + QChar(0x00B0);
2937 stringFovY = QString::number(fovY, 'f', 5) + QChar(0x00B0);
2938 }
2939
2940 return stringFovX + QChar(0x00D7) + stringFovY;
2941 }
2942
2943 // Define whether the button toggling eyepieces should be visible
setFlagShowOcularsButton(bool b)2944 void Oculars::setFlagShowOcularsButton(bool b)
2945 {
2946 StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
2947 if (gui)
2948 {
2949 if (b==true) {
2950 if (toolbarButton==Q_NULLPTR) {
2951 // Create the oculars button
2952 toolbarButton = new StelButton(Q_NULLPTR, *pxmapOnIcon, *pxmapOffIcon, *pxmapGlow, "actionShow_Oculars", false, "actionShow_Oculars_dialog");
2953 }
2954 gui->getButtonBar()->addButton(toolbarButton, "065-pluginsGroup");
2955 } else {
2956 gui->getButtonBar()->hideButton("actionShow_Oculars");
2957 }
2958 }
2959 flagShowOcularsButton = b;
2960 settings->setValue("show_toolbar_button", b);
2961 settings->sync();
2962
2963 emit flagShowOcularsButtonChanged(b);
2964 }
2965
2966
setGuiPanelFontSize(int size)2967 void Oculars::setGuiPanelFontSize(int size)
2968 {
2969 // This forces a redraw of the panel.
2970 if (size!=guiPanelFontSize)
2971 {
2972 bool guiPanelVisible=guiPanel;
2973 if (guiPanelVisible)
2974 enableGuiPanel(false);
2975 guiPanelFontSize=size;
2976 if (guiPanelVisible)
2977 enableGuiPanel(true);
2978
2979 settings->setValue("gui_panel_fontsize", size);
2980 settings->sync();
2981 emit guiPanelFontSizeChanged(size);
2982 }
2983 }
2984
toggleCropOverlay()2985 void Oculars::toggleCropOverlay()
2986 {
2987 setFlagShowCcdCropOverlay(!getFlagShowCcdCropOverlay());
2988 }
2989
togglePixelGrid()2990 void Oculars::togglePixelGrid()
2991 {
2992 setFlagShowCcdCropOverlayPixelGrid(!getFlagShowCcdCropOverlayPixelGrid());
2993 }
2994
toggleFocuserOverlay()2995 void Oculars::toggleFocuserOverlay()
2996 {
2997 setFlagShowFocuserOverlay(!getFlagShowFocuserOverlay());
2998 }
2999
computeLimitMagnitude(Ocular * ocular,Telescope * telescope)3000 double Oculars::computeLimitMagnitude(Ocular *ocular, Telescope *telescope)
3001 {
3002 // Simplified calculation of the penetrating power of the telescope
3003 double diameter = 0.;
3004 if (ocular->isBinoculars())
3005 diameter = ocular->fieldStop();
3006 else
3007 diameter = telescope!=Q_NULLPTR ? telescope->diameter() : 0.1; // Avoid a potential call of null pointer, and a log(0) error.
3008
3009 // A better formula for telescopic limiting magnitudes?
3010 // North, G.; Journal of the British Astronomical Association, vol.107, no.2, p.82
3011 // http://adsabs.harvard.edu/abs/1997JBAA..107...82N
3012 return 4.5 + 4.4*std::log10(diameter);
3013 }
3014
handleAutoLimitToggle(bool on)3015 void Oculars::handleAutoLimitToggle(bool on)
3016 {
3017 if (!flagShowOculars)
3018 return;
3019
3020 // When we are in Oculars mode, we must toggle between the auto limit and manual limit. Logic taken from zoomOcular()/unzoomOcular()
3021 StelCore *core = StelApp::getInstance().getCore();
3022 StelSkyDrawer *skyDrawer = core->getSkyDrawer();
3023 if (on)
3024 {
3025 Ocular * ocular = oculars[selectedOcularIndex];
3026 Telescope * telescope = Q_NULLPTR;
3027 if (!ocular->isBinoculars())
3028 {
3029 telescope = telescopes[selectedTelescopeIndex];
3030 }
3031 disconnect(skyDrawer, SIGNAL(customStarMagLimitChanged(double)), this, SLOT(setMagLimitStarsOcularsManual(double))); // keep the old manual value in config.
3032 double limitMag = computeLimitMagnitude(ocular, telescope);
3033 // TODO: Is it really good to apply the star formula to DSO?
3034 skyDrawer->setFlagNebulaMagnitudeLimit(true);
3035 skyDrawer->setCustomNebulaMagnitudeLimit(limitMag);
3036 skyDrawer->setFlagStarMagnitudeLimit(true);
3037 skyDrawer->setCustomStarMagnitudeLimit(limitMag);
3038 }
3039 else
3040 {
3041 connect(skyDrawer, SIGNAL(customStarMagLimitChanged(double)), this, SLOT(setMagLimitStarsOcularsManual(double)));
3042 skyDrawer->setCustomStarMagnitudeLimit(magLimitStarsOculars);
3043 skyDrawer->setFlagStarMagnitudeLimit(flagLimitStarsOculars);
3044 }
3045 }
3046
3047 // Handle switching the main program's star limitation flag
handleStarMagLimitToggle(bool on)3048 void Oculars::handleStarMagLimitToggle(bool on)
3049 {
3050 if (!flagShowOculars)
3051 return;
3052
3053 flagLimitStarsOculars=on;
3054 // It only makes sense to switch off the auto-limit when we switch off the limit.
3055 if (!on)
3056 {
3057 setFlagAutoLimitMagnitude(false);
3058 }
3059 }
3060