Kstars

conjunctions.cpp
1 /*
2  SPDX-FileCopyrightText: 2008 Akarsh Simha <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 
6 
7  Much of the code here is taken from Pablo de Vicente's
8  modcalcplanets.cpp
9 
10 */
11 
12 #include "conjunctions.h"
13 
14 #include "geolocation.h"
15 #include "ksconjunct.h"
16 #include "kstars.h"
17 #include "ksnotification.h"
18 #include "kstarsdata.h"
19 #include "skymap.h"
20 #include "dialogs/finddialog.h"
21 #include "dialogs/locationdialog.h"
22 #include "skycomponents/skymapcomposite.h"
23 #include "skyobjects/kscomet.h"
24 #include "skyobjects/kspluto.h"
25 #include "ksplanetbase.h"
26 
27 #include <QFileDialog>
28 #include <QProgressDialog>
29 #include <QStandardItemModel>
30 #include <QtConcurrent>
31 
32 ConjunctionsTool::ConjunctionsTool(QWidget *parentSplit) : QFrame(parentSplit)
33 {
34  setupUi(this);
35 
36  KStarsData *kd = KStarsData::Instance();
38  KStarsDateTime dtStop(dtStart.djd() + 365.24); // TODO: Refine
39 
40  //startDate -> setDateTime( dtStart.dateTime() );
41  //stopDate -> setDateTime( dtStop.dateTime() );
42  //TODO Check if this change works
43  startDate->setDateTime(dtStart);
44  stopDate->setDateTime(dtStop);
45 
46  geoPlace = kd->geo();
47  LocationButton->setText(geoPlace->fullName());
48 
49 
50  pNames[KSPlanetBase::MERCURY] = i18n("Mercury");
51  pNames[KSPlanetBase::VENUS] = i18n("Venus");
52  pNames[KSPlanetBase::MARS] = i18n("Mars");
53  pNames[KSPlanetBase::JUPITER] = i18n("Jupiter");
54  pNames[KSPlanetBase::SATURN] = i18n("Saturn");
55  pNames[KSPlanetBase::URANUS] = i18n("Uranus");
56  pNames[KSPlanetBase::NEPTUNE] = i18n("Neptune");
57  //pNames[KSPlanetBase::PLUTO] = i18nc("Asteroid name (optional)", "Pluto");
58  pNames[KSPlanetBase::SUN] = i18n("Sun");
59  pNames[KSPlanetBase::MOON] = i18n("Moon");
60 
61  // Initialize the Maximum Separation box to 1 degree
62  maxSeparationBox->setUnits(dmsBox::DEGREES);
63  maxSeparationBox->show(1.0_deg);
64 
65  //FilterEdit->showClearButton = true;
66  ClearFilterButton->setIcon(QIcon::fromTheme("edit-clear"));
67 
68  // signals and slots connections
69  connect(LocationButton, SIGNAL(clicked()), this, SLOT(slotLocation()));
70  connect(Obj1FindButton, SIGNAL(clicked()), this, SLOT(slotFindObject()));
71 
72  // Mode Change
73  connect(ModeSelector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ConjunctionsTool::setMode);
74 
75  //connect(ComputeButton, SIGNAL(clicked()), this, SLOT(slotCompute()));
76  connect(ComputeButton, &QPushButton::clicked, [this]()
77  {
78  QtConcurrent::run(this, &ConjunctionsTool::slotCompute);
79  });
80  connect(FilterTypeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(slotFilterType(int)));
81  connect(ClearButton, SIGNAL(clicked()), this, SLOT(slotClear()));
82  connect(ExportButton, SIGNAL(clicked()), this, SLOT(slotExport()));
83  connect(OutputList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotGoto()));
84  connect(ClearFilterButton, SIGNAL(clicked()), FilterEdit, SLOT(clear()));
85  connect(FilterEdit, SIGNAL(textChanged(QString)), this, SLOT(slotFilterReg(QString)));
86 
87  m_Model = new QStandardItemModel(0, 5, this);
88 
89  setMode(ModeSelector->currentIndex());
90 
91  // Init filter type combobox
92  FilterTypeComboBox->clear();
93  FilterTypeComboBox->addItem(i18n("Single Object"));
94  FilterTypeComboBox->addItem(i18n("Any"));
95  FilterTypeComboBox->addItem(i18n("Stars"));
96  FilterTypeComboBox->addItem(i18n("Solar System"));
97  FilterTypeComboBox->addItem(i18n("Planets"));
98  FilterTypeComboBox->addItem(i18n("Comets"));
99  FilterTypeComboBox->addItem(i18n("Asteroids"));
100  FilterTypeComboBox->addItem(i18n("Open Clusters"));
101  FilterTypeComboBox->addItem(i18n("Globular Clusters"));
102  FilterTypeComboBox->addItem(i18n("Gaseous Nebulae"));
103  FilterTypeComboBox->addItem(i18n("Planetary Nebulae"));
104  FilterTypeComboBox->addItem(i18n("Galaxies"));
105 
106  Obj2ComboBox->clear();
107  for (int i = 0; i < KSPlanetBase::UNKNOWN_PLANET; ++i)
108  {
109  // Obj1ComboBox->insertItem( i, pNames[i] );
110  Obj2ComboBox->insertItem(i, pNames[i]);
111  }
112 
113  maxSeparationBox->setEnabled(true);
114 
115  //Set up the Table Views
116  m_Model->setHorizontalHeaderLabels(QStringList() << i18n("Conjunction/Opposition") << i18n("Date & Time (UT)")
117  << i18n("Object 1") << i18n("Object 2") << i18n("Separation"));
118  m_SortModel = new QSortFilterProxyModel(this);
119  m_SortModel->setSourceModel(m_Model);
120  OutputList->setModel(m_SortModel);
121  OutputList->setSortingEnabled(true);
122  OutputList->horizontalHeader()->setStretchLastSection(true);
123  OutputList->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
124  OutputList->horizontalHeader()->resizeSection(2, 100);
125  OutputList->horizontalHeader()->resizeSection(3, 100);
126  OutputList->horizontalHeader()->resizeSection(4, 120); //is it bad way to fix default size of columns ?
127 
128  show();
129 }
130 
131 void ConjunctionsTool::slotGoto()
132 {
133  int index = m_SortModel->mapToSource(OutputList->currentIndex()).row(); // Get the number of the line
134  long double jd = outputJDList.value(index);
135  KStarsDateTime dt;
136  KStars *ks = KStars::Instance();
137  KStarsData *data = KStarsData::Instance();
138  SkyMap *map = ks->map();
139 
140  // Show conjunction
141  data->setLocation(*geoPlace);
142  dt.setDJD(jd);
143  data->changeDateTime(dt);
144  map->setClickedObject(data->skyComposite()->findByName(m_Model->data(m_Model->index(index, 2)).toString()));
145  map->setClickedPoint(map->clickedObject());
146  map->slotCenter();
147 }
148 
149 void ConjunctionsTool::slotFindObject()
150 {
151  if (FindDialog::Instance()->exec() == QDialog::Accepted)
152  {
153  if (!FindDialog::Instance()->targetObject())
154  return;
155  Object1 = SkyObject_s(FindDialog::Instance()->targetObject()->clone());
156  if (Object1 != nullptr)
157  Obj1FindButton->setText(Object1->name());
158  }
159 }
160 
161 void ConjunctionsTool::setMode(int new_mode)
162 {
163  // unlikely to happen
164  if(new_mode == -1 || new_mode > 2)
165  {
166  ModeSelector->setCurrentIndex(0);
167  return;
168  }
169 
170  mode = static_cast<MODE>(new_mode);
171 }
172 
173 void ConjunctionsTool::slotLocation()
174 {
175  QPointer<LocationDialog> ld(new LocationDialog(this));
176  if (ld->exec() == QDialog::Accepted && ld)
177  {
178  geoPlace = ld->selectedCity();
179  LocationButton->setText(geoPlace->fullName());
180  }
181  delete ld;
182 }
183 
184 void ConjunctionsTool::slotFilterType(int)
185 {
186  // Disable find button if the user select an object type
187  if (FilterTypeComboBox->currentIndex() == 0)
188  Obj1FindButton->setEnabled(true);
189  else
190  Obj1FindButton->setEnabled(false);
191 }
192 
193 void ConjunctionsTool::slotClear()
194 {
195  m_Model->setRowCount(0);
196  outputJDList.clear();
197  m_index = 0;
198 }
199 
200 void ConjunctionsTool::slotExport()
201 {
202  int i, j;
203  QByteArray line;
204 
205  //QFile file( KFileDialog::getSaveFileName( QDir::homePath(), "*|All files", this, "Save Conjunctions" ) );
206  QFile file(QFileDialog::getSaveFileName(nullptr, i18nc("@title:window", "Save Conjunctions"), QDir::homePath(), "*|All files"));
207 
209 
210  for (i = 0; i < m_Model->rowCount(); ++i)
211  {
212  for (j = 0; j < m_Model->columnCount(); ++j)
213  {
214  line.append(m_Model->data(m_Model->index(i, j)).toByteArray());
215  if (j < m_Model->columnCount() - 1)
216  line.append(";");
217  else
218  line.append("\n");
219  }
220  file.write(line);
221  line.clear();
222  }
223 
224  file.close();
225 }
226 
227 void ConjunctionsTool::slotFilterReg(const QString &filter)
228 {
230  m_SortModel->setFilterKeyColumn(-1);
231 }
232 
233 void ConjunctionsTool::slotCompute(void)
234 {
235  KStarsDateTime dtStart(startDate->dateTime()); // Start date
236  KStarsDateTime dtStop(stopDate->dateTime()); // Stop date
237  long double startJD = dtStart.djd(); // Start julian day
238  long double stopJD = dtStop.djd(); // Stop julian day
239  bool opposition = false; // true=opposition, false=conjunction
240  if (mode == OPPOSITION)
241  opposition = true;
242  QStringList objects; // List of sky object used as Object1
243  KStarsData *data = KStarsData::Instance();
244  int progress = 0;
245 
246  // Check if we have a valid angle in maxSeparationBox
247  dms maxSeparation(0.0);
248  bool ok;
249  maxSeparation = maxSeparationBox->createDms(&ok);
250 
251  if (!ok)
252  {
253  KSNotification::sorry(i18n("Maximum separation entered is not a valid angle. Use the What's this help feature "
254  "for information on how to enter a valid angle"));
255  return;
256  }
257 
258  // Check if Object1 and Object2 are set
259  if (FilterTypeComboBox->currentIndex() == 0 && Object1 == nullptr)
260  {
261  KSNotification::sorry(i18n("Please select an object to check conjunctions with, by clicking on the \'Find Object\' button."));
262  return;
263  }
264  Object2.reset(KSPlanetBase::createPlanet(Obj2ComboBox->currentIndex()));
265  if (FilterTypeComboBox->currentIndex() == 0 && Object1->name() == Object2->name())
266  {
267  // FIXME: Must free the created Objects
268  KSNotification::sorry(i18n("Please select two different objects to check conjunctions with."));
269  return;
270  }
271 
272  // Init KSConjunct object
273  KSConjunct ksc;
274  connect(&ksc, SIGNAL(madeProgress(int)), this, SLOT(showProgress(int)));
275  ksc.setGeoLocation(geoPlace);
276 
277  switch (FilterTypeComboBox->currentIndex())
278  {
279  case 1: // All object types
280  foreach (int type, data->skyComposite()->objectNames().keys())
281  objects += data->skyComposite()->objectNames(type);
282  break;
283  case 2: // Stars
284  objects += data->skyComposite()->objectNames(SkyObject::STAR);
285  objects += data->skyComposite()->objectNames(SkyObject::CATALOG_STAR);
286  break;
287  case 3: // Solar system
288  objects += data->skyComposite()->objectNames(SkyObject::PLANET);
289  objects += data->skyComposite()->objectNames(SkyObject::COMET);
290  objects += data->skyComposite()->objectNames(SkyObject::ASTEROID);
291  objects += data->skyComposite()->objectNames(SkyObject::MOON);
292  objects += i18n("Sun");
293  // Remove Object2 planet
294  objects.removeAll(Object2->name());
295  break;
296  case 4: // Planet
297  objects += data->skyComposite()->objectNames(SkyObject::PLANET);
298  // Remove Object2 planet
299  objects.removeAll(Object2->name());
300  break;
301  case 5: // Comet
302  objects += data->skyComposite()->objectNames(SkyObject::COMET);
303  break;
304  case 6: // Asteroid
305  objects += data->skyComposite()->objectNames(SkyObject::ASTEROID);
306  break;
307  case 7: // Open Clusters
308  objects = data->skyComposite()->objectNames(SkyObject::OPEN_CLUSTER);
309  break;
310  case 8: // Open Clusters
311  objects = data->skyComposite()->objectNames(SkyObject::GLOBULAR_CLUSTER);
312  break;
313  case 9: // Gaseous nebulae
314  objects = data->skyComposite()->objectNames(SkyObject::GASEOUS_NEBULA);
315  break;
316  case 10: // Planetary nebula
317  objects = data->skyComposite()->objectNames(SkyObject::PLANETARY_NEBULA);
318  break;
319  case 11: // Galaxies
320  objects = data->skyComposite()->objectNames(SkyObject::GALAXY);
321  break;
322  }
323 
324  // Remove all Jupiter and Saturn moons
325  // KStars crash if we compute a conjunction between a planet and one of this moon
326  if (FilterTypeComboBox->currentIndex() == 1 || FilterTypeComboBox->currentIndex() == 3 ||
327  FilterTypeComboBox->currentIndex() == 6)
328  {
329  objects.removeAll("Io");
330  objects.removeAll("Europa");
331  objects.removeAll("Ganymede");
332  objects.removeAll("Callisto");
333  objects.removeAll("Mimas");
334  objects.removeAll("Enceladus");
335  objects.removeAll("Tethys");
336  objects.removeAll("Dione");
337  objects.removeAll("Rhea");
338  objects.removeAll("Titan");
339  objects.removeAll("Hyperion");
340  objects.removeAll("Iapetus");
341  }
342 
343  ksc.setMaxSeparation(maxSeparation);
344  ksc.setObject2(Object2);
345  ksc.setOpposition(opposition);
346 
347  if (FilterTypeComboBox->currentIndex() != 0)
348  {
349  // Show a progress dialog while processing
350  QProgressDialog progressDlg(i18n("Compute conjunction..."), i18n("Abort"), 0, objects.count(), this);
351  progressDlg.setWindowTitle(i18nc("@title:window", "Conjunction"));
352  progressDlg.setWindowModality(Qt::WindowModal);
353  progressDlg.setValue(0);
354 
355  for (auto &object : objects)
356  {
357  // If the user click on the 'cancel' button
358  if (progressDlg.wasCanceled())
359  break;
360 
361  // Update progress dialog
362  ++progress;
363  progressDlg.setValue(progress);
364  progressDlg.setLabelText(i18n("Compute conjunction between %1 and %2", Object2->name(), object));
365 
366  // Compute conjuction
367  Object1 = std::shared_ptr<SkyObject>(data->skyComposite()->findByName(object)->clone());
368  ksc.setObject1(Object1);
369  showConjunctions(ksc.findClosestApproach(startJD, stopJD),
370  object, Object2->name());
371  }
372 
373  progressDlg.setValue(objects.count());
374  }
375  else
376  {
377  // Change cursor while we search for conjunction
379 
380  ComputeStack->setCurrentIndex(1);
381 
382  ksc.setObject1(Object1);
383  showConjunctions(ksc.findClosestApproach(startJD, stopJD),
384  Object1->name(), Object2->name());
385  ComputeStack->setCurrentIndex(0);
386 
387  // Restore cursor
389  }
390 
391  Object2.reset();
392 }
393 
394 void ConjunctionsTool::showProgress(int n)
395 {
396  progress->setValue(n);
397 }
398 
399 void ConjunctionsTool::showConjunctions(const QMap<long double, dms> &conjunctionlist, const QString &object1,
400  const QString &object2)
401 {
402  KStarsDateTime dt;
403  QList<QStandardItem *> itemList;
404 
405  for (auto it = conjunctionlist.constBegin(); it != conjunctionlist.constEnd(); ++it)
406  {
407  dt.setDJD(it.key());
408  QStandardItem *typeItem;
409 
410  if (mode == CONJUNCTION)
411  typeItem = new QStandardItem(i18n("Conjunction"));
412  else
413  typeItem = new QStandardItem(i18n("Opposition"));
414 
415  itemList << typeItem
416  //FIXME TODO is this ISO date? is there a ready format to use?
417  //<< new QStandardItem( QLocale().toString( dt.dateTime(), "YYYY-MM-DDTHH:mm:SS" ) )
418  //<< new QStandardItem( QLocale().toString( dt, Qt::ISODate) )
419  << new QStandardItem(dt.toString(Qt::ISODate)) << new QStandardItem(object1)
420  << new QStandardItem(object2) << new QStandardItem(it.value().toDMSString());
421  m_Model->appendRow(itemList);
422  itemList.clear();
423 
424  outputJDList.insert(m_index, it.key());
425  ++m_index;
426  }
427 }
428 
429 void ConjunctionsTool::setUpConjunctionOpposition()
430 {
431 
432 }
QMap::const_iterator constBegin() const const
static KStarsDateTime currentDateTime()
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
QFuture< T > run(Function function,...)
void setLocation(const GeoLocation &l)
Set the GeoLocation according to the argument.
Definition: kstarsdata.cpp:403
QString fullName() const
Definition: geolocation.cpp:46
CaseInsensitive
void setRowCount(int rows)
QByteArray & append(char ch)
void clear()
const T value(const Key &key, const T &defaultValue) const const
void setFilterKeyColumn(int column)
WindowModal
QList< Key > keys() const const
void clicked(bool checked)
Implements algorithms to find close conjunctions of planets in a given time range....
Definition: ksconjunct.h:24
QIcon fromTheme(const QString &name)
SkyMap * map() const
Definition: kstars.h:143
QString homePath()
QByteArray toByteArray() const const
void clear()
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const const override
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual SkyObject * clone() const
Create copy of object.
Definition: skyobject.cpp:50
static KStars * Instance()
Definition: kstars.h:125
virtual void show() override
makes this node visible
Definition: skyitem.cpp:23
QMap::iterator insert(const Key &key, const T &value)
virtual QVariant data(const QModelIndex &index, int role) const const override
SkyObject * findByName(const QString &name, bool exact=true) override
Search the children of this SkyMapComposite for a SkyObject whose name matches the argument.
void changeDateTime(const KStarsDateTime &newDate)
Change the current simulation date/time to the KStarsDateTime argument.
Definition: kstarsdata.cpp:327
QString i18n(const char *text, const TYPE &arg...)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
KGuiItem clear()
QMap::const_iterator constEnd() const const
GeoLocation * geo()
Definition: kstarsdata.h:229
WaitCursor
This is the main window for KStars. In addition to the GUI elements, the class contains the program c...
Definition: kstars.h:92
QMap< long double, dms > findClosestApproach(long double startJD, long double stopJD, const std::function< void(long double, dms)> &callback={})
Compute the closest approach of two planets in the given range.
int row() const const
SkyMapComposite * skyComposite()
Definition: kstarsdata.h:165
void setFilterRegExp(const QString &pattern)
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
int count() const const
void setOverrideCursor(const QCursor &cursor)
Canvas widget for displaying the sky bitmap; also handles user interaction events.
Definition: skymap.h:52
void currentIndexChanged(int index)
void clear()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
virtual int rowCount(const QModelIndex &parent) const const override
virtual int columnCount(const QModelIndex &parent) const const override
void restoreOverrideCursor()
void setGeoLocation(GeoLocation *geo)
Sets the geographic location to compute conjunctions at.
QString toString(Qt::DateFormat format) const const
QFuture< void > map(Sequence &sequence, MapFunctor function)
void setMaxSeparation(double sep)
setMaxSeparation
void appendRow(const QList< QStandardItem * > &items)
QString toString() const const
void setDJD(long double jd)
Assign the static_cast<long double> Julian Day value, which includes the time of day encoded in the f...
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sun Aug 14 2022 04:13:55 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.