1 /*
2 SPDX-FileCopyrightText: 2012 Samikshan Bairagya <samikshan@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "skyobjitem.h"
8
9 #include "catalogobject.h"
10 #include "ksfilereader.h"
11 #include "kspaths.h"
12 #include "ksplanetbase.h"
13 #include "kstarsdata.h"
14 #include "ksutils.h"
15
SkyObjItem(SkyObject * so)16 SkyObjItem::SkyObjItem(SkyObject *so)
17 : m_Name(so->name()), m_LongName(so->longname()), m_TypeName(so->typeName()), m_So(so)
18 {
19 switch (so->type())
20 {
21 case SkyObject::PLANET:
22 case SkyObject::MOON:
23 m_Type = Planet;
24 break;
25 case SkyObject::STAR:
26 case SkyObject::CATALOG_STAR:
27 case SkyObject::MULT_STAR:
28 m_Type = Star;
29 break;
30 case SkyObject::CONSTELLATION:
31 case SkyObject::ASTERISM:
32 m_Type = Constellation;
33 break;
34 case SkyObject::GALAXY:
35 m_Type = Galaxy;
36 break;
37 case SkyObject::OPEN_CLUSTER:
38 case SkyObject::GLOBULAR_CLUSTER:
39 case SkyObject::GALAXY_CLUSTER:
40 m_Type = Cluster;
41 break;
42 case SkyObject::PLANETARY_NEBULA:
43 case SkyObject::SUPERNOVA_REMNANT:
44 case SkyObject::GASEOUS_NEBULA:
45 case SkyObject::DARK_NEBULA:
46 m_Type = Nebula;
47 break;
48 case SkyObject::SUPERNOVA:
49 m_Type = Supernova;
50 }
51
52 setPosition(m_So);
53 }
54
data(int role)55 QVariant SkyObjItem::data(int role)
56 {
57 switch (role)
58 {
59 case DispNameRole:
60 return getDescName();
61 case DispImageRole:
62 return getImageURL(true);
63 case DispSummaryRole:
64 return getSummary(true);
65 case CategoryRole:
66 return getType();
67 case CategoryNameRole:
68 return getTypeName();
69 default:
70 return QVariant();
71 }
72 }
73
74 ///Moved to skyobjlistmodel.cpp
75 /*
76 QHash<int, QByteArray> SkyObjItem::roleNames() const
77 {
78 QHash<int, QByteArray> roles;
79 roles[DispNameRole] = "dispName";
80 roles[CategoryRole] = "type";
81 roles[CategoryNameRole] = "typeName";
82 return roles;
83 }
84 */
85
setPosition(SkyObject * so)86 void SkyObjItem::setPosition(SkyObject *so)
87 {
88 double altitude;
89 dms azimuth;
90 if (so->type() == SkyObject::SATELLITE)
91 {
92 altitude = so->alt().Degrees();
93 azimuth = so->az();
94 }
95 else
96 {
97 KStarsData *data = KStarsData::Instance();
98 KStarsDateTime ut = data->geo()->LTtoUT(
99 KStarsDateTime(QDateTime::currentDateTime().toLocalTime()));
100 SkyPoint sp = so->recomputeCoords(ut, data->geo());
101
102 //check altitude of object at this time.
103 sp.EquatorialToHorizontal(data->lst(), data->geo()->lat());
104 altitude = sp.alt().Degrees();
105 azimuth = sp.az();
106 }
107
108 double rounded_altitude = (int)(altitude / 5.0) * 5.0;
109
110 if (rounded_altitude <= 0)
111 m_Position = "<span style='color:red'>" +
112 xi18n("NOT VISIBLE: About %1 degrees below the %2 horizon",
113 -rounded_altitude, KSUtils::toDirectionString(azimuth)) +
114 "</span>";
115 else
116 m_Position = "<span style='color:yellow'>" +
117 xi18n("Now visible: About %1 degrees above the %2 horizon",
118 rounded_altitude, KSUtils::toDirectionString(azimuth)) +
119 "</span>";
120 }
121
findImage(const QString & prefix,const SkyObject & obj,const QString & suffix)122 QString findImage(const QString &prefix, const SkyObject &obj, const QString &suffix)
123 {
124 static const auto base =
125 KSPaths::writableLocation(QStandardPaths::AppDataLocation);
126 QDirIterator search(
127 base,
128 QStringList() << prefix + obj.name().toLower().remove(' ').remove('/') + suffix,
129 QDir::Files, QDirIterator::Subdirectories);
130
131 return search.hasNext() ? QUrl::fromLocalFile(search.next()).url() : "";
132 }
getImageURL(bool preferThumb) const133 QString SkyObjItem::getImageURL(bool preferThumb) const
134 {
135 const auto &thumbURL = findImage("thumb-", *m_So, ".png");
136
137 const auto &fullSizeURL = findImage("image-", *m_So, ".png");
138 const auto &wikiImageURL =
139 QUrl::fromLocalFile(KSPaths::locate(QStandardPaths::AppDataLocation,
140 "descriptions/wikiImage-" +
141 m_So->name().toLower().remove(' ') +
142 ".png"))
143 .url();
144 QString XPlanetURL =
145 QUrl::fromLocalFile(KSPaths::locate(QStandardPaths::AppDataLocation,
146 "xplanet/" + m_So->name() + ".png"))
147 .url();
148
149 //First try to return the preferred file
150 if (!thumbURL.isEmpty() && preferThumb)
151 return thumbURL;
152 if (!fullSizeURL.isEmpty() && (!preferThumb))
153 return fullSizeURL;
154
155 //If that fails, try to return the large image first, then the thumb, and then if it is a planet, the xplanet image. Finally if all else fails, the wiki image.
156 QString fname = fullSizeURL;
157
158 if (fname.isEmpty())
159 {
160 fname = thumbURL;
161 }
162 if (fname.isEmpty() && m_Type == Planet)
163 {
164 fname = XPlanetURL;
165 }
166 if (fname.isEmpty())
167 {
168 fname = wikiImageURL;
169 }
170 return fname;
171 }
172
getSummary(bool includeDescription) const173 QString SkyObjItem::getSummary(bool includeDescription) const
174 {
175 if (includeDescription)
176 {
177 QString description = loadObjectDescription();
178 if(description.indexOf(".") > 0) //This will shorten the description in the list to just a sentence, whereas in the larger space of the Object Information Summary, it is a full paragraph.
179 return m_So->typeName() + "<BR>" + getRADE() + "<BR>" + getAltAz() + "<BR><BR>" + description.left(description.indexOf(".") + 1);
180 else
181 return m_So->typeName() + "<BR>" + getRADE() + "<BR>" + getAltAz() + "<BR><BR>" + description;
182 }
183 else
184 return m_So->typeName() + "<BR>" + getRADE() + "<BR>" + getAltAz();
185 }
186
getSurfaceBrightness() const187 QString SkyObjItem::getSurfaceBrightness() const
188 {
189 /** Surface Brightness is applicable only for extended light sources like
190 * Deep-Sky Objects. Here we use the formula SB = m + log10(a*b/4)
191 * where m is the magnitude of the sky-object. a and b are the major and minor
192 * axis lengths of the objects respectively in arcminutes. SB is the surface
193 * brightness obtained in mag * arcminutes^-2
194 */
195
196 auto *dso = dynamic_cast<CatalogObject*>(m_So);
197 float SB = m_So->mag();
198
199 if (dso != nullptr)
200 SB += 2.5 * log10(dso->a() * dso->b() / 4);
201
202 switch (getType())
203 {
204 case Galaxy:
205 case Nebula:
206 return QLocale().toString(SB, 'f', 2) + "<BR> (mag/arcmin^2)";
207 default:
208 return QString(" --"); // Not applicable for other sky-objects
209 }
210 }
211
getSize() const212 QString SkyObjItem::getSize() const
213 {
214 switch (getType())
215 {
216 case Galaxy:
217 case Cluster:
218 case Nebula:
219 return QLocale().toString(((CatalogObject *)m_So)->a(), 'f', 2) + "\"";
220 case Planet:
221 return QLocale().toString(((KSPlanetBase *)m_So)->angSize(), 'f', 2) + "\"";
222 default:
223 return QString(" --");
224 }
225 }
226
loadObjectDescription() const227 inline QString SkyObjItem::loadObjectDescription() const
228 {
229 QFile file;
230 QString fname = "description-" + getName().toLower().remove(' ') + ".html";
231 //determine filename in local user KDE directory tree.
232 file.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("descriptions/" + fname));
233
234 if (file.exists())
235 {
236 if (file.open(QIODevice::ReadOnly))
237 {
238 QTextStream in(&file);
239 QString line;
240 line = in.readLine(); //This should only read the description since the source is on the next line
241 file.close();
242 return line;
243 }
244 }
245 return getTypeName();
246 }
247
getRADE() const248 QString SkyObjItem::getRADE() const
249 {
250 return "RA: " + m_So->ra().toHMSString() + "<BR>DE: " + m_So->dec().toDMSString();
251 }
252
getAltAz() const253 QString SkyObjItem::getAltAz() const
254 {
255 return "Alt: " + QString::number(m_So->alt().Degrees(), 'f', 2) +
256 ", Az: " + QString::number(m_So->az().Degrees(), 'f', 2);
257 }
258
getMagnitude() const259 float SkyObjItem::getMagnitude() const
260 {
261 return m_So->mag();
262 }
263