Celestia

Форк
0
/
starbrowser.cpp 
380 строк · 10.2 Кб
1
// starbrowser.cpp
2
//
3
// Copyright (C) 2023, The Celestia Development Team
4
//
5
// Original version:
6
// Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
7
// Incorporates elements from qtcelestialbrowser.cpp
8
// Copyright (C) 2007-2008, Celestia Development Team
9
//
10
// Star browser tool for Celestia.
11
//
12
// This program is free software; you can redistribute it and/or
13
// modify it under the terms of the GNU General Public License
14
// as published by the Free Software Foundation; either version 2
15
// of the License, or (at your option) any later version.
16

17
#include "starbrowser.h"
18

19
#include <algorithm>
20
#include <cassert>
21
#include <cmath>
22

23
#include "star.h"
24
#include "stardb.h"
25
#include "univcoord.h"
26
#include "universe.h"
27

28
namespace celestia::engine
29
{
30

31
namespace
32
{
33

34
inline float
35
distanceSquared(const Star* star,
36
                double jd,
37
                const Eigen::Vector3f& pos,
38
                const UniversalCoord& ucPos)
39
{
40
    // For the purposes of building the list, we can use the squared distance
41
    // to avoid evaluating unnecessary square roots.
42
    float distance = (pos - star->getPosition()).squaredNorm();
43

44
    // If the stars are closer than one light year, use
45
    // a more precise distance estimate.
46
    if (distance < 1.0f)
47
        distance = static_cast<float>((ucPos - star->getPosition(jd)).toLy().squaredNorm());
48

49
    return distance;
50
}
51

52
class DistanceComparison
53
{
54
public:
55
    DistanceComparison(double jd, const Eigen::Vector3f& pos, const UniversalCoord& ucPos);
56

57
    StarBrowserRecord createRecord(const Star*) const;
58
    void finalizeRecord(StarBrowserRecord&) const;
59

60
    bool operator()(const StarBrowserRecord&, const StarBrowserRecord&) const;
61

62
private:
63
    double m_jd;
64
    Eigen::Vector3f m_pos;
65
    UniversalCoord m_ucPos;
66
};
67

68
DistanceComparison::DistanceComparison(double jd, const Eigen::Vector3f& pos, const UniversalCoord& ucPos) :
69
    m_jd(jd), m_pos(pos), m_ucPos(ucPos)
70
{
71
}
72

73
StarBrowserRecord
74
DistanceComparison::createRecord(const Star* star) const
75
{
76
    StarBrowserRecord result(star);
77
    result.distance = distanceSquared(star, m_jd, m_pos, m_ucPos);
78
    return result;
79
}
80

81
void
82
DistanceComparison::finalizeRecord(StarBrowserRecord& record) const
83
{
84
    record.distance = std::sqrt(record.distance);
85
    record.appMag = record.star->getApparentMagnitude(record.distance);
86
}
87

88
bool
89
DistanceComparison::operator()(const StarBrowserRecord& lhs, const StarBrowserRecord& rhs) const
90
{
91
    return lhs.distance < rhs.distance;
92
}
93

94
class AppMagComparison
95
{
96
public:
97
    AppMagComparison(double jd, const Eigen::Vector3f& pos, const UniversalCoord& ucPos);
98

99
    StarBrowserRecord createRecord(const Star*) const;
100
    void finalizeRecord(const StarBrowserRecord&) const { /* no-op */ }
101

102
    bool operator()(const StarBrowserRecord&, const StarBrowserRecord&) const;
103

104
private:
105
    double m_jd;
106
    Eigen::Vector3f m_pos;
107
    UniversalCoord m_ucPos;
108
};
109

110
AppMagComparison::AppMagComparison(double jd, const Eigen::Vector3f& pos, const UniversalCoord& ucPos) :
111
    m_jd(jd), m_pos(pos), m_ucPos(ucPos)
112
{
113
}
114

115
StarBrowserRecord
116
AppMagComparison::createRecord(const Star* star) const
117
{
118
    StarBrowserRecord result(star);
119
    result.distance = std::sqrt(distanceSquared(star, m_jd, m_pos, m_ucPos));
120
    result.appMag = result.star->getApparentMagnitude(result.distance);
121
    return result;
122
}
123

124
bool
125
AppMagComparison::operator()(const StarBrowserRecord& lhs, const StarBrowserRecord& rhs) const
126
{
127
    return lhs.appMag < rhs.appMag;
128
}
129

130
class AbsMagComparison
131
{
132
public:
133
    AbsMagComparison(double jd, const Eigen::Vector3f& pos, const UniversalCoord& ucPos);
134

135
    StarBrowserRecord createRecord(const Star*) const;
136
    void finalizeRecord(StarBrowserRecord&) const;
137

138
    bool operator()(const StarBrowserRecord&, const StarBrowserRecord&) const;
139

140
private:
141
    double m_jd;
142
    Eigen::Vector3f m_pos;
143
    UniversalCoord m_ucPos;
144
};
145

146
AbsMagComparison::AbsMagComparison(double jd, const Eigen::Vector3f& pos, const UniversalCoord& ucPos) :
147
    m_jd(jd), m_pos(pos), m_ucPos(ucPos)
148
{
149
}
150

151
StarBrowserRecord
152
AbsMagComparison::createRecord(const Star* star) const
153
{
154
    return StarBrowserRecord(star);
155
}
156

157
void
158
AbsMagComparison::finalizeRecord(StarBrowserRecord& record) const
159
{
160
    record.distance = std::sqrt(distanceSquared(record.star, m_jd, m_pos, m_ucPos));
161
    record.appMag = record.star->getApparentMagnitude(record.distance);
162
}
163

164
bool
165
AbsMagComparison::operator()(const StarBrowserRecord& lhs, const StarBrowserRecord& rhs) const
166
{
167
    return lhs.star->getAbsoluteMagnitude() < rhs.star->getAbsoluteMagnitude();
168
}
169

170
class StarFilter
171
{
172
public:
173
    StarFilter(StarBrowser::Filter, const SolarSystemCatalog*);
174
    bool operator()(const Star*) const;
175

176
    void setSpectralTypeFilter(const std::function<bool(const char*)>&);
177

178
private:
179
    StarBrowser::Filter m_filter;
180
    const SolarSystemCatalog* m_solarSystems;
181
    std::function<bool(const char*)> m_spectralTypeFilter{ nullptr };
182
};
183

184
StarFilter::StarFilter(StarBrowser::Filter filter, const SolarSystemCatalog* solarSystems) :
185
    m_filter(filter), m_solarSystems(solarSystems)
186
{
187
}
188

189
void
190
StarFilter::setSpectralTypeFilter(const std::function<bool(const char*)>& filter)
191
{
192
    m_spectralTypeFilter = filter;
193
}
194

195
bool
196
parentHasPlanets(const SolarSystemCatalog* solarSystems, const Star* star)
197
{
198
    // When searching for visible stars only, also take planets orbiting the
199
    // parent barycenters into account
200
    const auto end = solarSystems->end();
201
    for (;;)
202
    {
203
        star = star->getOrbitBarycenter();
204
        if (star == nullptr || star->getVisibility())
205
            return false;
206

207
        if (solarSystems->find(star->getIndex()) != end)
208
            return true;
209
    }
210
}
211

212
bool
213
StarFilter::operator()(const Star* star) const
214
{
215
    // If ordering is done by brightness, filter out barycenters by default
216
    bool visibleOnly = util::is_set(m_filter, StarBrowser::Filter::Visible);
217
    if (visibleOnly && !star->getVisibility())
218
        return false;
219

220
    if (util::is_set(m_filter, StarBrowser::Filter::Multiple))
221
    {
222
        auto barycenter = star->getOrbitBarycenter();
223

224
        // Check the number of stars orbiting the barycenter to handle cases
225
        // like the Sun orbiting the Solar System Barycenter
226
        if (barycenter == nullptr || barycenter->getOrbitingStars().size() < 2)
227
            return false;
228
    }
229

230
    if (util::is_set(m_filter, StarBrowser::Filter::WithPlanets) &&
231
        m_solarSystems->find(star->getIndex()) == m_solarSystems->end() &&
232
        !(visibleOnly && parentHasPlanets(m_solarSystems, star)))
233
    {
234
        return false;
235
    }
236

237
    return (util::is_set(m_filter, StarBrowser::Filter::SpectralType) && m_spectralTypeFilter)
238
        ? m_spectralTypeFilter(star->getSpectralType())
239
        : true;
240
}
241

242
template<typename C>
243
void populateRecords(std::vector<StarBrowserRecord>& records,
244
                     const C& comparison,
245
                     const StarFilter& filter,
246
                     std::uint32_t size,
247
                     const StarDatabase& stardb)
248
{
249
    records.clear();
250
    if (size == 0)
251
        return;
252

253
    records.reserve(size);
254

255
    std::uint32_t totalStars = stardb.size();
256
    if (totalStars == 0)
257
        return;
258

259
    records.reserve(size);
260
    std::uint32_t index = 0;
261

262
    // Add all stars that match the filter until we fill up the list
263
    for (;;)
264
    {
265
        if (index == totalStars)
266
        {
267
            std::sort(records.begin(), records.end(), comparison);
268
            for (StarBrowserRecord& record : records)
269
            {
270
                comparison.finalizeRecord(record);
271
            }
272
            return;
273
        }
274

275
        if (const Star* star = stardb.getStar(index); filter(star))
276
        {
277
            if (records.size() == size)
278
                break;
279

280
            records.push_back(comparison.createRecord(star));
281
        }
282

283
        ++index;
284
    }
285

286
    // We have filled up the number of requested stars, so only add stars that
287
    // are better than the worst star in the list according to the predicate.
288
    std::make_heap(records.begin(), records.end(), comparison);
289

290
    for (; index < totalStars; ++index)
291
    {
292
        const Star* star = stardb.getStar(index);
293
        if (!filter(star))
294
            continue;
295

296
        StarBrowserRecord record = comparison.createRecord(star);
297
        if (comparison(record, records.front()))
298
        {
299
            std::pop_heap(records.begin(), records.end(), comparison);
300
            records.back() = record;
301
            std::push_heap(records.begin(), records.end(), comparison);
302
        }
303
    }
304

305
    std::sort_heap(records.begin(), records.end(), comparison);
306
    for (StarBrowserRecord& record : records)
307
    {
308
        comparison.finalizeRecord(record);
309
    }
310
}
311

312
} // end unnamed namespace
313

314
StarBrowser::StarBrowser(const Universe* universe,
315
                         std::uint32_t size,
316
                         Comparison comparison,
317
                         Filter filter) :
318
    m_universe(universe),
319
    m_size(size),
320
    m_comparison(comparison),
321
    m_filter(filter)
322
{
323
    if (m_size < MinListStars)
324
        m_size = MinListStars;
325
    else if (m_size > MaxListStars)
326
        m_size = MaxListStars;
327
}
328

329
bool
330
StarBrowser::setSize(std::uint32_t size)
331
{
332
    m_size = size;
333
    if (m_size < MinListStars)
334
    {
335
        m_size = MinListStars;
336
        return false;
337
    }
338
    if (m_size > MaxListStars)
339
    {
340
        m_size = MaxListStars;
341
        return false;
342
    }
343
    return true;
344
}
345

346
void
347
StarBrowser::setPosition(const UniversalCoord& ucPos)
348
{
349
    m_ucPos = ucPos;
350
    m_pos = m_ucPos.toLy().cast<float>();
351
}
352

353
void
354
StarBrowser::populate(std::vector<StarBrowserRecord>& records) const
355
{
356
    StarFilter filter(m_filter, m_universe->getSolarSystemCatalog());
357
    if (m_spectralTypeFilter)
358
        filter.setSpectralTypeFilter(m_spectralTypeFilter);
359
    const auto stardb = m_universe->getStarCatalog();
360
    if (stardb == nullptr)
361
        return;
362

363
    switch (m_comparison)
364
    {
365
    case Comparison::Nearest:
366
        populateRecords(records, DistanceComparison(m_jd, m_pos, m_ucPos), filter, m_size, *stardb);
367
        return;
368
    case Comparison::ApparentMagnitude:
369
        populateRecords(records, AppMagComparison(m_jd, m_pos, m_ucPos), filter, m_size, *stardb);
370
        return;
371
    case Comparison::AbsoluteMagnitude:
372
        populateRecords(records, AbsMagComparison(m_jd, m_pos, m_ucPos), filter, m_size, *stardb);
373
        return;
374
    default:
375
        assert(0);
376
        return;
377
    }
378
}
379

380
} // end namespace celestia::engine
381

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.