File indexing completed on 2024-07-14 07:17:19

0001 /*
0002     SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
0003     SPDX-FileCopyrightText: 2021 Valentin Boettcher <hiro at protagon.space; @hiro98:tchncs.de>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #pragma once
0009 
0010 #include "skycomponent.h"
0011 #include "catalogsdb.h"
0012 #include "catalogobject.h"
0013 #include "skymesh.h"
0014 #include "trixelcache.h"
0015 #include "Options.h"
0016 
0017 #include "polyfills/qstring_hash.h"
0018 #include <unordered_map>
0019 
0020 class SkyMesh;
0021 class SkyMap;
0022 
0023 /**
0024  * \brief Represents objects loaded from an sqlite backed, trixel
0025  * indexed catalog.
0026  *
0027  * The component doesn't follow the traditional list approach and
0028  * loads it's skyobjects into an LRU cache (`TrixelCache`). For
0029  * puproses of compatiblility with object search etc. some of the
0030  * brightest objects are loaded into `m_static_objects` and registered
0031  * within the component system. Furthermore, if some part of the code
0032  * demands a pointer to a CatalogObject, it will be allocated into
0033  * `m_static_objects` on demand.
0034  *
0035  * If you want to access DSOs in _new_ code you should use a local
0036  * instance of `CatalogsDB::DBManager` instead and call `dropCache` if
0037  * necessary.
0038  *
0039  * \sa CatalogsDB::DBManager
0040  */
0041 class CatalogsComponent : public SkyComponent
0042 {
0043     public:
0044         using ObjectList = std::vector<CatalogObject>;
0045 
0046         /**
0047          * Constructs the Catalogscomponent with a \p parent and a
0048          * database file under the path \p db_filename. If \p load_ngc is
0049          * specified, an attempt is made to load the default catalog from
0050          * the default location into the db.
0051          *
0052          * The lru cache for the objects will be initialized to a capacity
0053          * configurable by Options::dSOCachePercentage.
0054          */
0055         explicit CatalogsComponent(SkyComposite *parent, const QString &db_filename,
0056                                    bool load_default = false);
0057 
0058         ~CatalogsComponent() override = default;
0059 
0060         /**
0061          * Draws the objects in the currently visible trixels by
0062          * dynamically loading them from the database.
0063          */
0064         void draw(SkyPainter *skyp) override;
0065 
0066         /**
0067          * Set the cache size to the new \p percentage.
0068          *
0069          * The cache stores the objects of a certain \p percentage of all
0070          * trixels. Setting `percentage = 100` short circuits the cache and loads
0071          * all the objects into memory. This is reasonable for catalog sizes up
0072          * to `10_000` objects.
0073          */
0074         void resizeCache(const int percentage)
0075         {
0076             m_mainCache.set_size(calculateCacheSize(percentage));
0077             m_unknownMagCache.set_size(calculateCacheSize(percentage));
0078         };
0079 
0080         /**
0081          * \short Search the underlying database for an object with the \p
0082          * name. \sa `CatalogsDB::DBManager::find_object_by_name` for
0083          * details.
0084          *
0085          * If multiple objects match, the one with the hightest magnitude is
0086          * returned.
0087          *
0088          * \return a pointer to the SkyObject whose name matches the argument, or
0089          * a nullptr pointer if no match was found. (Due to way KStars works)
0090          */
0091         SkyObject *findByName(const QString &name, bool exact = true) override;
0092 
0093         void objectsInArea(QList<SkyObject *> &list, const SkyRegion &region) override;
0094 
0095         SkyObject *objectNearest(SkyPoint *p, double &maxrad) override;
0096 
0097         /**
0098          * Insert an object \p obj into `m_static_objects` and return a
0099          * reference to the newly inserted object. If the object is
0100          * already present in the list, return a reference to
0101          * that. Furthermore the object will be updated
0102          * (`CatalogObject::JITupdate`) and inserted into the parent's
0103          * `objectLists`.
0104          */
0105         CatalogObject &insertStaticObject(const CatalogObject &obj);
0106 
0107         /**
0108          * Clear the internal cache and effectively reload all objects
0109          * from the database.
0110          */
0111         void dropCache()
0112         {
0113             m_mainCache.clear();
0114             m_unknownMagCache.clear();
0115             m_catalog_colors = m_db_manager.get_catalog_colors();
0116         };
0117 
0118         /**
0119          * Wether to show the DSOs.
0120          */
0121         bool selected() override
0122         {
0123             return Options::showDeepSky();
0124         };
0125 
0126     private:
0127         /**
0128          * The database interface for the catalog.
0129          */
0130         CatalogsDB::DBManager m_db_manager;
0131 
0132         /**
0133          * A pointer to a SkyMesh of the appropriate level.
0134          *
0135          * @note The use of a pointer here is a legacy from the
0136          * SkyComponent implementation.
0137          */
0138         SkyMesh *m_skyMesh;
0139 
0140         /**
0141          * The main container for the currently loaded objects.
0142          */
0143         ObjectList m_objects;
0144 
0145         /**
0146          * The cache holding the DSOs of known magnitude
0147          */
0148         TrixelCache<ObjectList> m_mainCache;
0149 
0150         /**
0151          * The cache holding the DSOs of unknown magnitude
0152          */
0153         TrixelCache<ObjectList> m_unknownMagCache;
0154 
0155         /**
0156          * A trixel indexed map of lists containing manually loaded
0157          * `CatalogObject`s.
0158          *
0159          * Because some `KStars` internal code requires pointers to SkyObjects
0160          * and this component doesn't hold its objects, we have create a space to
0161          * to own the objets that we create in methods like `findByName`. Thus it
0162          * is expected that this list won't hold many objects and doesn't have to
0163          * be emptied at runtime. The objects in this map are not drawn and have
0164          * to be updated manually.
0165          *
0166          * __No objects should ever be removed from this list, as references and
0167          * pointers to list members are required to remain valid.__
0168          *
0169          * __In new code, a local instance of `CatalogsDB::DBManager` should be
0170          * used when access to CatalogObjects is required. Call `dropCache` if
0171          * required.__
0172          */
0173         std::unordered_map<Trixel, CatalogsDB::CatalogObjectList> m_static_objects;
0174 
0175         /**
0176          * A cache for catalog colors.
0177          */
0178         CatalogsDB::ColorMap m_catalog_colors;
0179 
0180         //@{
0181         /** Helpers */
0182 
0183         void updateSkyMesh(SkyMap &map, MeshBufNum_t buf = DRAW_BUF);
0184         size_t calculateCacheSize(const unsigned int percentage)
0185         {
0186             return m_skyMesh->size() * percentage / 100.f;
0187         }
0188 
0189         /**
0190          * Try importing the old skycomponents database.
0191          */
0192         void tryImportSkyComponents();
0193 
0194         //@}
0195 };