File indexing completed on 2024-03-24 15:17:26

0001 /*
0002     SPDX-FileCopyrightText: 2016 Artem Fedoskin <afedoskin3@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "deepskyitem.h"
0007 
0008 #include "deepskyobject.h"
0009 #include "deepstaritem.h"
0010 #include "labelsitem.h"
0011 #include "Options.h"
0012 #include "rootnode.h"
0013 #include "skymesh.h"
0014 #include "starblockfactory.h"
0015 #include "starcomponent.h"
0016 #include "htmesh/MeshIterator.h"
0017 #include "projections/projector.h"
0018 #include "skynodes/deepskynode.h"
0019 #include "skynodes/dsosymbolnode.h"
0020 
0021 DSOIndexNode::DSOIndexNode(DeepSkyIndex *index, LabelsItem::label_t labelType, QString color)
0022     : m_index(index), m_trixels(new QSGNode), m_labelType(labelType), schemeColor(color)
0023 {
0024     appendChildNode(m_trixels);
0025 }
0026 
0027 void DSOIndexNode::hide()
0028 {
0029     SkyOpacityNode::hide();
0030     SkyMapLite::Instance()->rootNode()->labelsItem()->hideLabels(m_labelType);
0031 }
0032 
0033 void DSOIndexNode::show()
0034 {
0035     SkyOpacityNode::show();
0036     SkyMapLite::Instance()->rootNode()->labelsItem()->showLabels(m_labelType);
0037 }
0038 
0039 DSOTrixelNode::DSOTrixelNode(Trixel trixelID) : TrixelNode(trixelID)
0040 {
0041 }
0042 
0043 void DSOTrixelNode::deleteAllChildNodes()
0044 {
0045     QLinkedList<QPair<SkyObject *, SkyNode *>>::iterator i = m_nodes.begin();
0046 
0047     while (i != m_nodes.end())
0048     {
0049         DeepSkyNode *node = static_cast<DeepSkyNode *>((*i).second);
0050         if (node)
0051         {
0052             node->parent()->removeChildNode(node);
0053             delete node->symbol();
0054             delete node;
0055 
0056             *i = QPair<SkyObject *, SkyNode *>((*i).first, 0);
0057         }
0058         ++i;
0059     }
0060 }
0061 
0062 DeepSkyItem::DeepSkyItem(DeepSkyComponent *dsoComp, RootNode *rootNode)
0063     : SkyItem(LabelsItem::label_t::DEEP_SKY_LABEL, rootNode), m_dsoComp(dsoComp), m_skyMesh(SkyMesh::Instance())
0064 {
0065 
0066     m_other = new DSOIndexNode(&(m_dsoComp->m_OtherIndex), LabelsItem::label_t::DSO_OTHER_LABEL, "NGCColor");
0067     appendChildNode(m_other);
0068 
0069     QSGNode *n = firstChild();
0070 
0071     while (n != 0)
0072     {
0073         DSOIndexNode *indexNode = static_cast<DSOIndexNode *>(n);
0074         DeepSkyIndex *index     = indexNode->m_index;
0075 
0076         QMap<int, DeepSkyList *> result;
0077         QHashIterator<int, DeepSkyList *> it(*index);
0078 
0079         while (it.hasNext())
0080         {
0081             it.next();
0082             result.insert(it.key(), it.value());
0083         }
0084 
0085         QMap<int, DeepSkyList *>::const_iterator i = result.constBegin();
0086 
0087         while (i != result.constEnd())
0088         {
0089             DeepSkyList *dsoList = i.value();
0090 
0091             DSOTrixelNode *trixel = new DSOTrixelNode(i.key());
0092             trixel->m_labels      = rootNode->labelsItem()->addTrixel(indexNode->m_labelType, i.key());
0093 
0094             indexNode->m_trixels->appendChildNode(trixel);
0095             QSGNode *symbols = new QSGNode;
0096 
0097             for (int c = 0; c < dsoList->size(); ++c)
0098             {
0099                 DeepSkyObject *dso = dsoList->at(c);
0100                 trixel->m_nodes.append(QPair<SkyObject *, SkyNode *>(dso, 0));
0101             }
0102 
0103             trixel->m_symbols = symbols;
0104             trixel->appendChildNode(symbols);
0105 
0106             ++i;
0107         }
0108         n = n->nextSibling();
0109     }
0110 }
0111 
0112 void DeepSkyItem::update()
0113 {
0114     if (!m_dsoComp->selected())
0115     {
0116         hide();
0117         return;
0118     }
0119     show();
0120 
0121     bool drawFlag;
0122 
0123     MeshIterator region(m_skyMesh, DRAW_BUF);
0124 
0125     drawFlag = Options::showMessier() && !(Options::hideOnSlew() && Options::hideMessier() && SkyMapLite::IsSlewing());
0126 
0127     updateDeepSkyNode(m_other, drawFlag, &region);
0128 }
0129 
0130 void DeepSkyItem::updateDeepSkyNode(DSOIndexNode *indexNode, bool drawObject, MeshIterator *region, bool drawImage)
0131 {
0132     if (!(drawObject || drawImage))
0133     {
0134         indexNode->hide();
0135         return;
0136     }
0137 
0138     indexNode->show();
0139 
0140     SkyMapLite *map            = SkyMapLite::Instance();
0141     const Projector *projector = map->projector();
0142     KStarsData *data           = KStarsData::Instance();
0143 
0144     UpdateID updateID    = data->updateID();
0145     UpdateID updateNumID = data->updateNumID();
0146 
0147     QColor schemeColor = data->colorScheme()->colorNamed(indexNode->schemeColor);
0148 
0149     bool m_hideLabels = (map->isSlewing() && Options::hideOnSlew()) ||
0150                         !(Options::showDeepSkyMagnitudes() || Options::showDeepSkyNames());
0151 
0152     double maglim              = Options::magLimitDrawDeepSky();
0153     bool showUnknownMagObjects = Options::showUnknownMagObjects();
0154 
0155     //adjust maglimit for ZoomLevel
0156     double lgmin = log10(MINZOOM);
0157     double lgmax = log10(MAXZOOM);
0158     double lgz   = log10(Options::zoomFactor());
0159     if (lgz <= 0.75 * lgmax)
0160         maglim -= (Options::magLimitDrawDeepSky() - Options::magLimitDrawDeepSkyZoomOut()) * (0.75 * lgmax - lgz) /
0161                   (0.75 * lgmax - lgmin);
0162 
0163     double labelMagLim = Options::deepSkyLabelDensity();
0164     labelMagLim += (Options::magLimitDrawDeepSky() - labelMagLim) * (lgz - lgmin) / (lgmax - lgmin);
0165     if (labelMagLim > Options::magLimitDrawDeepSky())
0166         labelMagLim = Options::magLimitDrawDeepSky();
0167 
0168     int regionID = 0;
0169     if (region->hasNext())
0170     {
0171         regionID = region->next();
0172     }
0173 
0174     DSOTrixelNode *trixel = static_cast<DSOTrixelNode *>(indexNode->m_trixels->firstChild());
0175     double delLim         = SkyMapLite::deleteLimit();
0176 
0177     /*Unlike DeepStarItem and StarItem where all trixels are set, in DeepSkyItem number of trixels is different
0178     across the catalogs. We are comparing trixelID and regionID to hide trixels that are not visible and skip
0179     regionIDs that are not present in this catalog*/
0180     while (trixel != 0)
0181     {
0182         //Hide all trixels that has smaller trixelID than the next visible trixel
0183         if (trixel->trixelID() < regionID)
0184         {
0185             trixel->hide();
0186             trixel->m_labels->hide();
0187 
0188             if (trixel->hideCount() > delLim)
0189             {
0190                 trixel->deleteAllChildNodes();
0191             }
0192         }
0193         else if (trixel->trixelID() > regionID)
0194         {
0195             /*Keep iterating over regionID if current trixel's trixelID is larger than regionID. If there are no more
0196             visible regions then hide/delete remaining trixels*/
0197             if (region->hasNext())
0198             {
0199                 regionID = region->next();
0200             }
0201             else
0202             {
0203                 while (trixel != 0)
0204                 {
0205                     trixel->hide();
0206                     trixel->m_labels->hide();
0207 
0208                     if (trixel->hideCount() > delLim)
0209                     {
0210                         trixel->deleteAllChildNodes();
0211                     }
0212                     trixel = static_cast<DSOTrixelNode *>(trixel->nextSibling());
0213                 }
0214                 break;
0215             }
0216             continue;
0217         }
0218         else //Current trixelID is equal to regionID meaning that current trixel is visible
0219         {
0220             trixel->show();
0221             trixel->m_labels->show();
0222 
0223             if (region->hasNext())
0224             {
0225                 regionID = region->next();
0226             }
0227 
0228             QLinkedList<QPair<SkyObject *, SkyNode *>>::iterator i = (&trixel->m_nodes)->begin();
0229 
0230             while (i != (&trixel->m_nodes)->end())
0231             {
0232                 DeepSkyObject *dsoObj = static_cast<DeepSkyObject *>((*i).first);
0233                 DeepSkyNode *dsoNode  = static_cast<DeepSkyNode *>((*i).second);
0234 
0235                 if (dsoObj->updateID != updateID)
0236                 {
0237                     dsoObj->updateID = updateID;
0238                     if (dsoObj->updateNumID != updateNumID)
0239                     {
0240                         dsoObj->updateCoords(data->updateNum());
0241                     }
0242                     dsoObj->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0243                 }
0244 
0245                 float mag  = dsoObj->mag();
0246                 float size = dsoObj->a() * dms::PI * Options::zoomFactor() / 10800.0;
0247 
0248                 //only draw objects if flags set, it's bigger than 1 pixel (unless
0249                 //zoom > 2000.), and it's brighter than maglim (unless mag is
0250                 //undefined (=99.9)
0251                 bool sizeCriterion = (size > 1.0 || Options::zoomFactor() > 2000.);
0252                 bool magCriterion = (mag < (float)maglim) || (showUnknownMagObjects && (std::isnan(mag) || mag > FAINTEST_MAGNITUDE));
0253 
0254                 bool drawLabel = false;
0255 
0256                 if (!(m_hideLabels || mag > labelMagLim))
0257                     drawLabel = true;
0258 
0259                 if (dsoNode)
0260                 {
0261                     //Delete particular DSONode if its hideCount is larger than the limit
0262                     if (dsoNode->hideCount() > delLim)
0263                     {
0264                         trixel->removeChildNode(dsoNode);
0265 
0266                         delete dsoNode->symbol();
0267                         delete dsoNode;
0268 
0269                         *i = QPair<SkyObject *, SkyNode *>((*i).first, 0);
0270                     }
0271                     else
0272                     {
0273                         if (sizeCriterion && magCriterion)
0274                         {
0275                             dsoNode->setColor(schemeColor, trixel);
0276                             dsoNode->update(drawImage, drawLabel);
0277                         }
0278                         else
0279                         {
0280                             dsoNode->hide();
0281                         }
0282                     }
0283                 }
0284                 else
0285                 {
0286                     if (sizeCriterion && magCriterion && projector->checkVisibility(dsoObj))
0287                     {
0288                         QPointF pos;
0289 
0290                         bool visible = false;
0291                         pos          = projector->toScreen(dsoObj, true, &visible);
0292                         if (visible && projector->onScreen(pos))
0293                         {
0294                             //Create new DeepSkyNode and its symbol if it is currently visible
0295                             DSOSymbolNode *dsoSymbol = new DSOSymbolNode(dsoObj, schemeColor);
0296                             trixel->m_symbols->appendChildNode(dsoSymbol);
0297 
0298                             DeepSkyNode *dsoNode =
0299                                 new DeepSkyNode(dsoObj, dsoSymbol, indexNode->m_labelType, trixel->trixelID());
0300                             trixel->appendChildNode(dsoNode);
0301 
0302                             *i = QPair<SkyObject *, SkyNode *>((*i).first, static_cast<SkyNode *>(dsoNode));
0303                             dsoNode->update(drawImage, drawLabel, pos);
0304                         }
0305                     }
0306                 }
0307                 ++i;
0308             }
0309         }
0310         trixel = static_cast<DSOTrixelNode *>(trixel->nextSibling());
0311     }
0312 
0313     region->reset();
0314 }