3
// Copyright (C) 2001-2009, the Celestia Development Team
4
// Original version by Chris Laurel, Fridger Schrempp, and Toti
6
// This program is free software; you can redistribute it and/or
7
// modify it under the terms of the GNU General Public License
8
// as published by the Free Software Foundation; either version 2
9
// of the License, or (at your option) any later version.
12
#include <fmt/printf.h>
14
#include <celmath/intersect.h>
15
#include <celmath/ray.h>
16
#include <celutil/gettext.h>
18
#include "galaxyform.h"
22
using namespace std::string_view_literals;
24
using celestia::engine::GalacticFormManager;
25
namespace math = celestia::math;
33
constexpr std::array GalaxyTypeNames =
35
GalaxyTypeName{ "Irr", GalaxyType::Irr },
36
GalaxyTypeName{ "S0", GalaxyType::S0 },
37
GalaxyTypeName{ "Sa", GalaxyType::Sa },
38
GalaxyTypeName{ "Sb", GalaxyType::Sb },
39
GalaxyTypeName{ "Sc", GalaxyType::Sc },
40
GalaxyTypeName{ "SBa", GalaxyType::SBa },
41
GalaxyTypeName{ "SBb", GalaxyType::SBb },
42
GalaxyTypeName{ "SBc", GalaxyType::SBc },
43
GalaxyTypeName{ "E0", GalaxyType::E0 },
44
GalaxyTypeName{ "E1", GalaxyType::E1 },
45
GalaxyTypeName{ "E2", GalaxyType::E2 },
46
GalaxyTypeName{ "E3", GalaxyType::E3 },
47
GalaxyTypeName{ "E4", GalaxyType::E4 },
48
GalaxyTypeName{ "E5", GalaxyType::E5 },
49
GalaxyTypeName{ "E6", GalaxyType::E6 },
50
GalaxyTypeName{ "E7", GalaxyType::E7 },
53
float Galaxy::lightGain = 0.0f;
55
float Galaxy::getDetail() const
60
void Galaxy::setDetail(float d)
65
const char* Galaxy::getType() const
67
return GalaxyTypeNames[static_cast<std::size_t>(type)].name;
70
void Galaxy::setType(const std::string& typeStr)
72
type = GalaxyType::Irr;
73
auto iter = std::find_if(std::begin(GalaxyTypeNames), std::end(GalaxyTypeNames),
74
[&](const GalaxyTypeName& g) { return g.name == typeStr; });
75
if (iter != std::end(GalaxyTypeNames))
79
void Galaxy::setForm(const fs::path& customTmpName, const fs::path& resDir)
81
if (customTmpName.empty())
83
form = static_cast<int>(type);
87
if (fs::path fullName = resDir / customTmpName; fs::exists(fullName))
88
form = GalacticFormManager::get()->getCustomForm(fullName);
90
form = GalacticFormManager::get()->getCustomForm(fs::path("models") / customTmpName);
94
std::string Galaxy::getDescription() const
96
return fmt::sprintf(_("Galaxy (Hubble type: %s)"), getType());
99
DeepSkyObjectType Galaxy::getObjType() const
101
return DeepSkyObjectType::Galaxy;
104
int Galaxy::getFormId() const
109
bool Galaxy::pick(const Eigen::ParametrizedLine<double, 3>& ray,
110
double& distanceToPicker,
111
double& cosAngleToBoundCenter) const
113
const auto* galacticForm = GalacticFormManager::get()->getForm(form);
114
if (galacticForm == nullptr || !isVisible())
117
// The ellipsoid should be slightly larger to compensate for the fact
118
// that blobs are considered points when galaxies are built, but have size
119
// when they are drawn.
120
float yscale = (type > GalaxyType::Irr && type < GalaxyType::E0)
121
? kMaxSpiralThickness
122
: galacticForm->scale.y() + kRadiusCorrection;
123
Eigen::Vector3d ellipsoidAxes(getRadius()*(galacticForm->scale.x() + kRadiusCorrection),
125
getRadius()*(galacticForm->scale.z() + kRadiusCorrection));
126
Eigen::Matrix3d rotation = getOrientation().cast<double>().toRotationMatrix();
128
return math::testIntersection(
129
math::transformRay(Eigen::ParametrizedLine<double, 3>(ray.origin() - getPosition(), ray.direction()),
131
math::Ellipsoidd(ellipsoidAxes),
133
cosAngleToBoundCenter);
136
bool Galaxy::load(const AssociativeArray* params, const fs::path& resPath)
138
setDetail(params->getNumber<float>("Detail").value_or(1.0f));
140
if (const auto* typeName = params->getString("Type"); typeName == nullptr)
146
if (auto customTmpName = params->getPath("CustomTemplate"sv); customTmpName.has_value())
147
setForm(customTmpName.value(), resPath);
151
return DeepSkyObject::load(params, resPath);
154
GalaxyType Galaxy::getGalaxyType() const
159
float Galaxy::getBrightnessCorrection(const Eigen::Vector3f &offset) const
161
Eigen::Quaternionf orientation = getOrientation().conjugate();
163
// corrections to avoid excessive brightening if viewed e.g. edge-on
164
float brightness_corr = 1.0f;
165
if (type != GalaxyType::Irr && (type < GalaxyType::E0 || type > GalaxyType::E3)) // all galaxies, except ~round elliptics and irregular
167
float cosi = (orientation * Eigen::Vector3f::UnitY()).dot(offset) / offset.norm();
168
brightness_corr = std::max(0.2f, std::sqrt(std::abs(cosi)));
169
if (type > GalaxyType::E3) // only elliptics with higher ellipticities
171
float cosi = (orientation * Eigen::Vector3f::UnitX()).dot(offset) / offset.norm();
172
brightness_corr = std::max(0.45f, brightness_corr * std::abs(cosi));
176
float btot = (type == GalaxyType::Irr || type >= GalaxyType::E0) ? 2.5f : 5.0f;
177
return (4.0f * lightGain + 1.0f) * btot * brightness_corr;
180
std::uint64_t Galaxy::getRenderMask() const
182
return Renderer::ShowGalaxies;
185
unsigned int Galaxy::getLabelMask() const
187
return Renderer::GalaxyLabels;
190
void Galaxy::increaseLightGain()
192
lightGain = std::min(1.0f, lightGain + 0.05f);
195
void Galaxy::decreaseLightGain()
197
lightGain = std::max(0.0f, lightGain - 0.05f);
200
float Galaxy::getLightGain()
205
void Galaxy::setLightGain(float lg)
207
lightGain = std::clamp(lg, 0.0f, 1.0f);
210
std::ostream& operator<<(std::ostream& s, const GalaxyType& sc)
212
return s << GalaxyTypeNames[static_cast<std::size_t>(sc)].name;