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

0001 /*
0002     SPDX-FileCopyrightText: 2007 James B. Bowlin <bowlin@mindspring.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "skymesh.h"
0008 
0009 #include "kstarsdata.h"
0010 #ifndef KSTARS_LITE
0011 #include "skymap.h"
0012 #endif
0013 #include "htmesh/MeshIterator.h"
0014 #include "htmesh/MeshBuffer.h"
0015 #include "projections/projector.h"
0016 #include "skyobjects/starobject.h"
0017 
0018 #include <QPainter>
0019 #include <QPolygonF>
0020 #include <QPointF>
0021 
0022 QMap<int, SkyMesh *> SkyMesh::pinstances;
0023 int SkyMesh::defaultLevel = -1;
0024 
0025 SkyMesh *SkyMesh::Create(int level)
0026 {
0027     SkyMesh *newInstance = pinstances.value(level, nullptr);
0028     if (newInstance != nullptr)
0029         return newInstance;
0030 
0031     newInstance = new SkyMesh(level);
0032     pinstances.insert(level, newInstance);
0033     if (defaultLevel < 0)
0034         defaultLevel = newInstance->level();
0035 
0036     return newInstance;
0037 }
0038 
0039 SkyMesh *SkyMesh::Instance()
0040 {
0041     return pinstances.value(defaultLevel, nullptr);
0042 }
0043 
0044 SkyMesh *SkyMesh::Instance(int level)
0045 {
0046     return pinstances.value(level, nullptr);
0047 }
0048 
0049 SkyMesh::SkyMesh(int level)
0050     : HTMesh(level, level, NUM_MESH_BUF), m_drawID(0), m_KSNumbers(0)
0051 {
0052     errLimit = HTMesh::size() / 4;
0053     m_inDraw = false;
0054 }
0055 
0056 void SkyMesh::aperture(SkyPoint *p0, double radius, MeshBufNum_t bufNum)
0057 {
0058     KStarsData *data = KStarsData::Instance();
0059     // FIXME: simple copying leads to incorrect results because RA0 && dec0 are both zero sometimes
0060     SkyPoint p1(p0->ra(), p0->dec());
0061     long double now = data->updateNum()->julianDay();
0062     p1.catalogueCoord(now);
0063 
0064     if (radius == 1.0)
0065     {
0066         SkyPoint p2 = p1;
0067         p2.updateCoordsNow(data->updateNum());
0068     }
0069 
0070     HTMesh::intersect(p1.ra().Degrees(), p1.dec().Degrees(), radius, (BufNum)bufNum);
0071     m_drawID++;
0072 }
0073 
0074 Trixel SkyMesh::index(const SkyPoint *p)
0075 {
0076     return HTMesh::index(p->ra0().Degrees(), p->dec0().Degrees());
0077 }
0078 
0079 Trixel SkyMesh::indexStar(StarObject *star)
0080 {
0081     double ra, dec;
0082     star->getIndexCoords(&m_KSNumbers, &ra, &dec);
0083     return HTMesh::index(ra, dec);
0084 }
0085 
0086 void SkyMesh::indexStar(StarObject *star1, StarObject *star2)
0087 {
0088     double ra1, ra2, dec1, dec2;
0089     star1->getIndexCoords(&m_KSNumbers, &ra1, &dec1);
0090     star2->getIndexCoords(&m_KSNumbers, &ra2, &dec2);
0091     HTMesh::intersect(ra1, dec1, ra2, dec2);
0092 }
0093 
0094 void SkyMesh::index(const SkyPoint *p, double radius, MeshBufNum_t bufNum)
0095 {
0096     HTMesh::intersect(p->ra().Degrees(), p->dec().Degrees(), radius, (BufNum)bufNum);
0097 }
0098 
0099 void SkyMesh::index(const SkyPoint *p1, const SkyPoint *p2)
0100 {
0101     HTMesh::intersect(p1->ra0().Degrees(), p1->dec0().Degrees(), p2->ra0().Degrees(), p2->dec0().Degrees());
0102 }
0103 
0104 void SkyMesh::index(const SkyPoint *p1, const SkyPoint *p2, const SkyPoint *p3)
0105 {
0106     HTMesh::intersect(p1->ra0().Degrees(), p1->dec0().Degrees(), p2->ra0().Degrees(), p2->dec0().Degrees(),
0107                       p3->ra0().Degrees(), p3->dec0().Degrees());
0108 }
0109 
0110 void SkyMesh::index(const SkyPoint *p1, const SkyPoint *p2, const SkyPoint *p3, const SkyPoint *p4)
0111 {
0112     HTMesh::intersect(p1->ra0().Degrees(), p1->dec0().Degrees(), p2->ra0().Degrees(), p2->dec0().Degrees(),
0113                       p3->ra0().Degrees(), p3->dec0().Degrees(), p4->ra0().Degrees(), p4->dec0().Degrees());
0114 }
0115 
0116 void SkyMesh::index(const QPointF &p1, const QPointF &p2, const QPointF &p3)
0117 {
0118     HTMesh::intersect(p1.x() * 15.0, p1.y(), p2.x() * 15.0, p2.y(), p3.x() * 15.0, p3.y());
0119 }
0120 
0121 void SkyMesh::index(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
0122 {
0123     HTMesh::intersect(p1.x() * 15.0, p1.y(), p2.x() * 15.0, p2.y(), p3.x() * 15.0, p3.y(), p4.x() * 15.0, p4.y());
0124 }
0125 
0126 const IndexHash &SkyMesh::indexLine(SkyList *points)
0127 {
0128     return indexLine(points, nullptr);
0129 }
0130 
0131 const IndexHash &SkyMesh::indexStarLine(SkyList *points)
0132 {
0133     SkyPoint *pThis, *pLast;
0134 
0135     indexHash.clear();
0136 
0137     if (points->isEmpty())
0138         return indexHash;
0139 
0140     pLast = points->at(0).get();
0141     for (int i = 1; i < points->size(); i++)
0142     {
0143         pThis = points->at(i).get();
0144 
0145         indexStar((StarObject *)pThis, (StarObject *)pLast);
0146         MeshIterator region(this);
0147 
0148         while (region.hasNext())
0149         {
0150             indexHash[region.next()] = true;
0151         }
0152         pLast = pThis;
0153     }
0154     return indexHash;
0155 }
0156 
0157 const IndexHash &SkyMesh::indexLine(SkyList *points, IndexHash *skip)
0158 {
0159     SkyPoint *pThis, *pLast;
0160 
0161     indexHash.clear();
0162 
0163     if (points->isEmpty())
0164         return indexHash;
0165 
0166     pLast = points->at(0).get();
0167     for (int i = 1; i < points->size(); i++)
0168     {
0169         pThis = points->at(i).get();
0170 
0171         if (skip != nullptr && skip->contains(i))
0172         {
0173             pLast = pThis;
0174             continue;
0175         }
0176 
0177         index(pThis, pLast);
0178         MeshIterator region(this);
0179 
0180         if (region.size() > errLimit)
0181         {
0182             HTMesh::setDebug(10);
0183             index(pThis, pLast);
0184             HTMesh::setDebug(0);
0185         }
0186 
0187         // This was used to track down a bug in my HTMesh code. The bug was caught
0188         // and fixed but I've left this debugging code in for now.  -jbb
0189 
0190         else
0191         {
0192             while (region.hasNext())
0193             {
0194                 indexHash[region.next()] = true;
0195             }
0196         }
0197         pLast = pThis;
0198     }
0199     return indexHash;
0200 }
0201 
0202 // ----- Create HTMesh Index for Polygons -----
0203 // Create (mostly) 4-point polygons that cover the mw polygon and
0204 // all share the same first vertex.  Use indexHash to eliminate
0205 // the many duplicate indices that are generated with this procedure.
0206 // There are probably faster and better ways to do this.
0207 
0208 const IndexHash &SkyMesh::indexPoly(SkyList *points)
0209 {
0210     indexHash.clear();
0211 
0212     if (points->size() < 3)
0213         return indexHash;
0214 
0215     SkyPoint *startP = points->first().get();
0216 
0217     int end = points->size() - 2; // 1) size - 1  -> last index,
0218     // 2) minimum of 2 points
0219 
0220     for (int p = 1; p <= end; p += 2)
0221     {
0222         if (p == end)
0223         {
0224             index(startP, points->at(p).get(), points->at(p + 1).get());
0225         }
0226         else
0227         {
0228             index(startP, points->at(p).get(), points->at(p + 1).get(), points->at(p + 2).get());
0229         }
0230 
0231         MeshIterator region(this);
0232         while (region.hasNext())
0233         {
0234             indexHash[region.next()] = true;
0235         }
0236     }
0237     return indexHash;
0238 }
0239 
0240 const IndexHash &SkyMesh::indexPoly(const QPolygonF *points)
0241 {
0242     indexHash.clear();
0243 
0244     if (points->size() < 3)
0245         return indexHash;
0246 
0247     const QPointF startP = points->first();
0248 
0249     int end = points->size() - 2; // 1) size - 1  -> last index,
0250     // 2) minimum of 2 points
0251     for (int p = 1; p <= end; p += 2)
0252     {
0253         if (p == end)
0254         {
0255             index(startP, points->at(p), points->at(p + 1));
0256         }
0257         else
0258         {
0259             index(startP, points->at(p), points->at(p + 1), points->at(p + 2));
0260         }
0261 
0262         MeshIterator region(this);
0263         while (region.hasNext())
0264         {
0265             indexHash[region.next()] = true;
0266         }
0267     }
0268     return indexHash;
0269 }
0270 
0271 // NOTE: SkyMesh::draw() is primarily used for debugging purposes, to
0272 // show the trixels to enable visualizing them. Thus, it is not
0273 // necessary that this be compatible with GL unless we abandon the
0274 // QPainter some day, or the need arises to use this for some other
0275 // purpose. -- asimha
0276 void SkyMesh::draw(QPainter &psky, MeshBufNum_t bufNum)
0277 {
0278 #ifndef KSTARS_LITE
0279     SkyMap *map      = SkyMap::Instance();
0280     KStarsData *data = KStarsData::Instance();
0281 
0282     double r1, d1, r2, d2, r3, d3;
0283 
0284     MeshIterator region(this, bufNum);
0285     while (region.hasNext())
0286     {
0287         Trixel trixel = region.next();
0288         vertices(trixel, &r1, &d1, &r2, &d2, &r3, &d3);
0289         SkyPoint s1(r1 / 15.0, d1);
0290         SkyPoint s2(r2 / 15.0, d2);
0291         SkyPoint s3(r3 / 15.0, d3);
0292         s1.EquatorialToHorizontal(data->lst(), data->geo()->lat());
0293         s2.EquatorialToHorizontal(data->lst(), data->geo()->lat());
0294         s3.EquatorialToHorizontal(data->lst(), data->geo()->lat());
0295         QPointF q1 = map->projector()->toScreen(&s1);
0296         QPointF q2 = map->projector()->toScreen(&s2);
0297         QPointF q3 = map->projector()->toScreen(&s3);
0298         psky.drawLine(q1, q2);
0299         psky.drawLine(q2, q3);
0300         psky.drawLine(q3, q1);
0301         // Draw the name of the trixel
0302         QString TrixelNumberString;
0303         TrixelNumberString.setNum(trixel);
0304         psky.drawText((q1 + q2 + q3) / 3.0, TrixelNumberString);
0305     }
0306 #else
0307     Q_UNUSED(psky);
0308     Q_UNUSED(bufNum);
0309 #endif
0310 }
0311 
0312 const SkyRegion &SkyMesh::skyRegion(const SkyPoint &_p1, const SkyPoint &_p2)
0313 {
0314     std::shared_ptr<SkyPoint> p1(new SkyPoint(_p1));
0315     std::shared_ptr<SkyPoint> p2(new SkyPoint(_p2));
0316     std::shared_ptr<SkyPoint> p3(new SkyPoint(p1->ra(), p2->dec()));
0317     std::shared_ptr<SkyPoint> p4(new SkyPoint(p2->ra(), p1->dec()));
0318     SkyList skylist;
0319 
0320     skylist.push_back(p1);
0321     skylist.push_back(p2);
0322     skylist.push_back(p3);
0323     skylist.push_back(p4);
0324     return indexPoly(&skylist);
0325 }